def validate_slice_json(slice, state = None): if slice is None: return None, None state = conv.add_ancestor_to_state(state, slice) validated_slice, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( base = validate_values_holder_json, comment = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), rate = conv.pipe( validate_values_holder_json, conv.not_none, ), threshold = conv.pipe( validate_values_holder_json, conv.not_none, ), ), constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), )(slice, state = state) conv.remove_ancestor_from_state(state, slice) return validated_slice, errors
def validate_parameter_xml_json(parameter, state = None): if parameter is None: return None, None state = conv.add_ancestor_to_state(state, parameter) validated_parameter, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( code = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.not_none, ), description = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, ), format = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(xml_json_formats), ), tail = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), taille = conv.pipe( conv.test_isinstance(basestring), conv.test_in([ 'moinsde20', 'plusde20', ]), ), text = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), type = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(json_unit_by_xml_json_type), ), VALUE = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_value_xml_json, drop_none_items = True, ), make_validate_values_xml_json_dates(require_consecutive_dates = True), conv.empty_to_none, conv.not_none, ), ), constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), )(parameter, state = state) conv.remove_ancestor_from_state(state, parameter) return validated_parameter, errors
def validate_slice_json(slice, state=None): if slice is None: return None, None state = conv.add_ancestor_to_state(state, slice) validated_slice, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( base=validate_values_holder_json, comment=conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), rate=conv.pipe( validate_values_holder_json, conv.not_none, ), threshold=conv.pipe( validate_values_holder_json, conv.not_none, ), ), constructor=collections.OrderedDict, drop_none_values='missing', keep_value_order=True, ), )(slice, state=state) conv.remove_ancestor_from_state(state, slice) return validated_slice, errors
def validate_scale_xml_json(scale, state = None): if scale is None: return None, None state = conv.add_ancestor_to_state(state, scale) validated_scale, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( code = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.not_none, ), description = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, ), option = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(( 'contrib', 'main-d-oeuvre', 'noncontrib', )), ), TRANCHE = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_slice_xml_json, drop_none_items = True, ), validate_slices_xml_json_dates, conv.empty_to_none, conv.not_none, ), tail = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), text = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), type = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(( 'monetary', )), ), ), constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), )(scale, state = state) conv.remove_ancestor_from_state(state, scale) return validated_scale, errors
def validate_dated_slice_json(slice, state = None): if slice is None: return None, None state = conv.add_ancestor_to_state(state, slice) validated_slice, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( base = conv.pipe( validate_dated_value_json, conv.test_greater_or_equal(0), ), constant_amount = validate_dated_value_json, comment = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), rate = conv.pipe( validate_dated_value_json, conv.test_between(0, 1), ), threshold = conv.pipe( validate_dated_value_json, conv.test_greater_or_equal(0), ), date = conv.pipe( validate_dated_value_json, conv.test_between(0, 1), #TODO: changer ), ), constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), )(slice, state = state) conv.remove_ancestor_from_state(state, slice) return validated_slice, errors
def validate_dated_slice_json(slice, state=None): if slice is None: return None, None state = conv.add_ancestor_to_state(state, slice) validated_slice, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( base=conv.pipe( validate_dated_value_json, conv.test_greater_or_equal(0), ), constant_amount=validate_dated_value_json, comment=conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), rate=conv.pipe( validate_dated_value_json, conv.test_between(0, 1), ), threshold=conv.pipe( validate_dated_value_json, conv.test_greater_or_equal(0), ), date=conv.pipe( validate_dated_value_json, conv.test_between(0, 1), #TODO: changer ), ), constructor=collections.OrderedDict, drop_none_values='missing', keep_value_order=True, ), )(slice, state=state) conv.remove_ancestor_from_state(state, slice) return validated_slice, errors
def validate_value_json(value, state = None): if value is None: return None, None container = state.ancestors[-1] value_converter = dict( boolean = conv.condition( conv.test_isinstance(int), conv.test_in((0, 1)), conv.test_isinstance(bool), ), float = conv.condition( conv.test_isinstance(int), conv.anything_to_float, conv.test_isinstance(float), ), integer = conv.condition( conv.test_isinstance(float), conv.pipe( conv.test(lambda number: round(number) == number), conv.function(int), ), conv.test_isinstance(int), ), rate = conv.condition( conv.test_isinstance(int), conv.anything_to_float, conv.test_isinstance(float), ), )[container.get('format') or 'float'] # Only parameters have a "format". state = conv.add_ancestor_to_state(state, value) validated_value, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( { u'comment': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), u'from': conv.pipe( conv.test_isinstance(basestring), conv.iso8601_input_to_date, conv.date_to_iso8601_str, conv.not_none, ), u'to': conv.pipe( conv.test_isinstance(basestring), conv.iso8601_input_to_date, conv.date_to_iso8601_str, conv.not_none, ), u'value': conv.pipe( value_converter, conv.not_none, ), }, constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), )(value, state = state) conv.remove_ancestor_from_state(state, value) return validated_value, errors
def validate_node_json(node, state = None): if node is None: return None, None state = conv.add_ancestor_to_state(state, node) validated_node, error = conv.test_isinstance(dict)(node, state = state) if error is not None: conv.remove_ancestor_from_state(state, node) return validated_node, error validated_node, errors = conv.struct( { '@context': conv.pipe( conv.test_isinstance(basestring), conv.make_input_to_url(full = True), conv.test_equals(u'http://openfisca.fr/contexts/legislation.jsonld'), ), '@type': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.test_in((u'Node', u'Parameter', u'Scale')), conv.not_none, ), 'comment': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), 'description': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, ), }, constructor = collections.OrderedDict, default = conv.noop, drop_none_values = 'missing', keep_value_order = True, )(validated_node, state = state) if errors is not None: conv.remove_ancestor_from_state(state, node) return validated_node, errors validated_node.pop('@context', None) # Remove optional @context everywhere. It will be added to root node later. node_converters = { '@type': conv.noop, 'comment': conv.noop, 'description': conv.noop, } node_type = validated_node['@type'] if node_type == u'Node': node_converters.update(dict( children = conv.pipe( conv.test_isinstance(dict), conv.uniform_mapping( conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.not_none, ), conv.pipe( validate_node_json, conv.not_none, ), ), conv.empty_to_none, conv.not_none, ), )) elif node_type == u'Parameter': node_converters.update(dict( format = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in([ 'boolean', 'float', 'integer', 'rate', ]), ), unit = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(units), ), values = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_value_json, drop_none_items = True, ), make_validate_values_json_dates(require_consecutive_dates = True), conv.empty_to_none, conv.not_none, ), )) else: assert node_type == u'Scale' node_converters.update(dict( option = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(( 'contrib', 'main-d-oeuvre', 'noncontrib', )), ), slices = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_slice_json, drop_none_items = True, ), validate_slices_json_dates, conv.empty_to_none, conv.not_none, ), unit = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(( 'currency', )), ), )) validated_node, errors = conv.struct( node_converters, constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, )(validated_node, state = state) conv.remove_ancestor_from_state(state, node) return validated_node, errors
def validate_value_xml_json(value, state = None): if value is None: return None, None container = state.ancestors[-1] value_converter = dict( bool = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.test_in([u'0', u'1']), ), float = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.test_conv(conv.anything_to_float), ), integer = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.test_conv(conv.anything_to_strict_int), ), percent = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.test_conv(conv.anything_to_float), ), date = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, #TODO: add a new conv ? conv.test_conv(conv.anything_to_strict_int), ), )[container.get('format') or 'float'] # Only CODE have a "format". state = conv.add_ancestor_to_state(state, value) validated_value, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( code = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, ), deb = conv.pipe( conv.test_isinstance(basestring), conv.iso8601_input_to_date, conv.date_to_iso8601_str, conv.not_none, ), fin = conv.pipe( conv.test_isinstance(basestring), conv.iso8601_input_to_date, conv.date_to_iso8601_str, conv.not_none, ), format = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(xml_json_formats), conv.test_equals(container.get('format')), ), tail = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), text = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), type = conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in([ 'age', 'days', 'hours', 'monetary', 'months', ]), conv.test_equals(container.get('type')), ), valeur = conv.pipe( value_converter, conv.not_none, ), ), constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), )(value, state = state) conv.remove_ancestor_from_state(state, value) return validated_value, errors
def validate_slice_xml_json(slice, state = None): if slice is None: return None, None state = conv.add_ancestor_to_state(state, slice) validated_slice, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( ASSIETTE = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_values_holder_xml_json, drop_none_items = True, ), conv.empty_to_none, conv.test(lambda l: len(l) == 1, error = N_(u"List must contain one and only one item")), ), code = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, ), MONTANT = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_values_holder_xml_json, drop_none_items = True, ), conv.empty_to_none, conv.test(lambda l: len(l) == 1, error = N_(u"List must contain one and only one item")), ), SEUIL = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_values_holder_xml_json, drop_none_items = True, ), conv.empty_to_none, conv.test(lambda l: len(l) == 1, error = N_(u"List must contain one and only one item")), conv.not_none, ), tail = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), TAUX = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_values_holder_xml_json, drop_none_items = True, ), conv.empty_to_none, conv.test(lambda l: len(l) == 1, error = N_(u"List must contain one and only one item")), ), text = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), ), constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), conv.test(lambda slice: bool(slice.get('MONTANT')) ^ bool(slice.get('TAUX')), error = N_(u"Either MONTANT or TAUX must be provided")), )(slice, state = state) conv.remove_ancestor_from_state(state, slice) return validated_slice, errors
def validate_node_xml_json(node, state = None): if node is None: return None, None state = conv.add_ancestor_to_state(state, node) validated_node, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( dict( BAREME = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_scale_xml_json, drop_none_items = True, ), conv.empty_to_none, ), CODE = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_parameter_xml_json, drop_none_items = True, ), conv.empty_to_none, ), code = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.not_none, ), description = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, ), NODE = conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_node_xml_json, drop_none_items = True, ), conv.empty_to_none, ), tail = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), text = conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), ), constructor = collections.OrderedDict, drop_none_values = 'missing', keep_value_order = True, ), )(node, state = state) if errors is None: children_groups_key = ('BAREME', 'CODE', 'NODE', 'VALBYTRANCHES') if all( validated_node.get(key) is None for key in children_groups_key ): error = state._(u"At least one of the following items must be present: {}").format(state._(u', ').join( u'"{}"'.format(key) for key in children_groups_key )) errors = dict( (key, error) for key in children_groups_key ) else: errors = {} children_code = set() for key in children_groups_key: for child_index, child in enumerate(validated_node.get(key) or []): child_code = child['code'] if child_code in children_code: errors.setdefault(key, {}).setdefault(child_index, {})['code'] = state._(u"Duplicate value") else: children_code.add(child_code) conv.remove_ancestor_from_state(state, node) return validated_node, errors or None
def validate_value_json(value, state=None): if value is None: return None, None container = state.ancestors[-1] value_converter = dict( boolean=conv.condition( conv.test_isinstance(int), conv.test_in((0, 1)), conv.test_isinstance(bool), ), float=conv.condition( conv.test_isinstance(int), conv.anything_to_float, conv.test_isinstance(float), ), integer=conv.condition( conv.test_isinstance(float), conv.pipe( conv.test(lambda number: round(number) == number), conv.function(int), ), conv.test_isinstance(int), ), rate=conv.condition( conv.test_isinstance(int), conv.anything_to_float, conv.test_isinstance(float), ), )[container.get('format') or 'float'] # Only parameters have a "format". state = conv.add_ancestor_to_state(state, value) validated_value, errors = conv.pipe( conv.test_isinstance(dict), conv.struct( { u'comment': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), u'from': conv.pipe( conv.test_isinstance(basestring), conv.iso8601_input_to_date, conv.date_to_iso8601_str, conv.not_none, ), u'to': conv.pipe( conv.test_isinstance(basestring), conv.iso8601_input_to_date, conv.date_to_iso8601_str, conv.not_none, ), u'value': conv.pipe( value_converter, conv.not_none, ), }, constructor=collections.OrderedDict, drop_none_values='missing', keep_value_order=True, ), )(value, state=state) conv.remove_ancestor_from_state(state, value) return validated_value, errors
def validate_node_json(node, state=None): if node is None: return None, None state = conv.add_ancestor_to_state(state, node) validated_node, error = conv.test_isinstance(dict)(node, state=state) if error is not None: conv.remove_ancestor_from_state(state, node) return validated_node, error validated_node, errors = conv.struct( { '@context': conv.pipe( conv.test_isinstance(basestring), conv.make_input_to_url(full=True), conv.test_equals( u'http://openfisca.fr/contexts/legislation.jsonld'), ), '@type': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.test_in((u'Node', u'Parameter', u'Scale')), conv.not_none, ), 'comment': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_text, ), 'description': conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, ), }, constructor=collections.OrderedDict, default=conv.noop, drop_none_values='missing', keep_value_order=True, )(validated_node, state=state) if errors is not None: conv.remove_ancestor_from_state(state, node) return validated_node, errors validated_node.pop( '@context', None ) # Remove optional @context everywhere. It will be added to root node later. node_converters = { '@type': conv.noop, 'comment': conv.noop, 'description': conv.noop, } node_type = validated_node['@type'] if node_type == u'Node': node_converters.update( dict(children=conv.pipe( conv.test_isinstance(dict), conv.uniform_mapping( conv.pipe( conv.test_isinstance(basestring), conv.cleanup_line, conv.not_none, ), conv.pipe( validate_node_json, conv.not_none, ), ), conv.empty_to_none, conv.not_none, ), )) elif node_type == u'Parameter': node_converters.update( dict( format=conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in([ 'boolean', 'float', 'integer', 'rate', ]), ), unit=conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(units), ), values=conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_value_json, drop_none_items=True, ), make_validate_values_json_dates( require_consecutive_dates=True), conv.empty_to_none, conv.not_none, ), )) else: assert node_type == u'Scale' node_converters.update( dict( option=conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(( 'contrib', 'main-d-oeuvre', 'noncontrib', )), ), slices=conv.pipe( conv.test_isinstance(list), conv.uniform_sequence( validate_slice_json, drop_none_items=True, ), validate_slices_json_dates, conv.empty_to_none, conv.not_none, ), unit=conv.pipe( conv.test_isinstance(basestring), conv.input_to_slug, conv.test_in(('currency', )), ), )) validated_node, errors = conv.struct( node_converters, constructor=collections.OrderedDict, drop_none_values='missing', keep_value_order=True, )(validated_node, state=state) conv.remove_ancestor_from_state(state, node) return validated_node, errors