def test_reverse(): person = Schema( Field('name'), Field('date_of_birth', source_name='dob', mapping=Mappings.date()), Field('weight', mapping=int), ) serialized = {'name': 'A', 'dob': '2000-01-01', 'weight': '60'} deserialized = { 'name': 'A', 'date_of_birth': dt.datetime(2000, 1, 1), 'weight': 60 } assert person.load(serialized) == person(serialized) == deserialized serializer = person.reverse() assert serializer.f.name assert serializer.f.dob assert serializer.f.weight with pytest.raises(AttributeError): assert not serializer.f.date_of_birth assert serializer(deserialized) == { 'name': 'A', 'dob': '2000-01-01', 'weight': 60 } assert serializer.f.name.dump('A') == 'A' assert serializer.f.dob.dump('2000-01-01') == dt.datetime(2000, 1, 1) assert serializer.f.weight.dump('60') == 60 assert serializer.dump(serialized) == deserialized
def test_reverse_reverses_mapping_and_names(): f = Field(name='x', mapping=Mapping(int, str), source_name='x_at_source') g = f.reverse() assert g.mapping.loader == f.mapping.dumper assert g.mapping.dumper == f.mapping.loader assert g.source_names == ['x'] assert g.name == 'x_at_source'
def test_fields_set_in_class_declaration(): a = Field('a') b = Field('b') class s(Schema): fields = [a, b] assert s.fields == [a, b]
def test_clone_accepts_reverse(): f = Field(name='x', mapping=Mapping(int, str)) assert f('5') == 5 assert f.dump('5') == '5' g = f.clone(reverse=True) assert g(5) == '5' assert g.dump('5') == 5
def test_load(): create_user = Schema( Field('username'), Field('password', default=None), ) d = create_user.load({'username': '******'}) assert d.username == 'admin' assert d.password is None
def test_date_and_datetime_fields(): assert Field(name='datetime', mapping=Mappings.datetime()).dump( dt.datetime(2018, 12, 31, 16, 55, 33)) == '2018-12-31 16:55:33' assert Field(name='date', mapping=Mappings.date()).dump(dt.datetime(2018, 12, 31)) == '2018-12-31' assert Field(name='date', mapping=Mappings.date()).dump(None) is None assert Field(name='date', mapping=Mappings.datetime()).dump(None) is None
def test_list_of_dates_serialization(): list_of_dates = [ dt.datetime(2018, 1, 1), dt.datetime(2018, 2, 1), dt.datetime(2018, 3, 1) ] mapping = Field(name='dates', mapping=Mappings.list(Mappings.date())) assert mapping.dump(list_of_dates) == [ '2018-01-01', '2018-02-01', '2018-03-01' ]
def test_forbidden_field(): user = Schema( Field('username'), Field('password', forbidden=True), ) user.load({'username': '******'}) with pytest.raises(Field.Forbidden): user.load({'username': '******', 'password': '******'})
def test_instance_factory_on_the_fly(): class Person: def __init__(self, name=None, date_of_birth=None): self.name = name self.date_of_birth = date_of_birth person_schema = Schema(Field('name'), Field('date_of_birth', mapping=Mappings.date()), instance_factory=Person) person = person_schema.load({'date_of_birth': '1995-10-11'}) assert isinstance(person, Person) assert person.name is None assert person.date_of_birth == dt.datetime(1995, 10, 11)
def test_field_min_max(): f = Field(name='name', min=1, max=10, mapping=int) with pytest.raises(Field.Invalid): f.load('-1') with pytest.raises(Field.Invalid): f.load('11') assert f.load(10) == 10 assert f.load('10') == 10 assert f.load(1) == 1 assert f.load('1') == 1
def test_field_min_len_max_len(): f1 = Field(name='name', min_len=3, max_len=8) assert f1.load('123') == '123' assert f1.load('12345678') == '12345678' with pytest.raises(Field.Invalid): f1.load('12') with pytest.raises(Field.Invalid): f1.load('123456789') # auto_trim=True assert Field(name='name', min_len=3, max_len=8, auto_trim=True).load('123456789') == '12345678'
def test_field_regex(): f = Field(name='name', regex=r'^[a-z]+$', nullable=True) assert f.load('abc') == 'abc' assert f.load(None) is None with pytest.raises(Field.Invalid): f.load('Abc') with pytest.raises(Field.Invalid): f.load(0)
def test_primitive_type_mappings_are_none_aware(primitive_type): mapping = getattr(Mappings, primitive_type.__name__) assert mapping.load(None) is None assert mapping.dump(None) is None f = Field(name='f', mapping=mapping) assert f.load(None) is None assert f.dump(None) is None g = Field(name='g', mapping=mapping, nullable=False) with pytest.raises(Field.Invalid): g.load(None)
def test_dump(): person = Schema(Field('weight', mapping=int, source_name='weight_in_kgs'), ) assert person.load({'weight_in_kgs': '60'}) == {'weight': 60} assert person.load({'weight_in_kgs': 60}) == {'weight': 60} assert person.load({'weight_in_kgs': None}) == {'weight': None} assert person.dump({'weight': 60}) == {'weight_in_kgs': 60} assert person.dump({'weight': '60'}) == {'weight_in_kgs': 60} assert person.dump({'weight': None}) == {'weight_in_kgs': None}
def test_chained_mappings(): create_user = Schema( Field('username'), Field('password'), Field('created_time', source_name='created', mapping=Mappings.datetime()), ) save_user = Schema( create_user.f.username.map_as('name'), create_user.f.password.map_as('pass'), create_user.f.created_time.reverse(), ) input_dict = {'username': '******', 'password': '******', 'created': '2010-01-01 12:00:00'} assert save_user(create_user(input_dict)) == { 'name': 'marcus', 'pass': '******', 'created': '2010-01-01 12:00:00', }
def test_field_in_container(): f1 = Field(name='f1') c1 = {'f1': 'f1_value'} c2 = {'f2': 'f2_value'} assert f1.has_value_in(c1) assert not f1.has_value_in(c2) assert f1.get_value_in(c1) == 'f1_value' assert f1.get_value_in(c2) is None assert f1.get_value_in(c2, 'default') == 'default' f1.set_value_in(c2, 'new_value') assert c2['f1'] == 'new_value'
def test_list_of_dicts_field(): user = Schema( Field('username'), Field('password', default=None), ) list_of_users = Field(name='users', mapping=Mappings.list(user)) payload = { 'users': [ {'username': '******'}, {'username': '******', 'password': '******'}, {'username': '******', 'email': '*****@*****.**'}, ] } schema = Schema(list_of_users) assert schema.load(payload) == { 'users': [ {'username': '******', 'password': None}, {'username': '******', 'password': '******'}, {'username': '******', 'password': None}, ] }
def test_primitive_fields(): assert Field('first', mapping=int).dump(5) == 5 assert Field('first', mapping=int).dump(None) is None assert Field('second', mapping=str).dump('6') == '6' assert Field('second', mapping=str).dump(None) is None assert Field('third', mapping=float).dump(7.8) == 7.8 assert Field('third', mapping=float).dump(None) is None
def test_list_of_dates(): list_field = Field(name='dates', mapping=Mappings.list(Mappings.date())) assert list_field.dump( [dt.datetime(2018, 1, 1), dt.datetime(2018, 12, 31, 12, 55)]) == [ '2018-01-01', '2018-12-31', ] assert list_field.dump(None) is None assert list_field.dump([]) == [] assert list_field.dump([None]) == [None]
def test_nested_field(): person_schema = Schema( Field('first_name', default=None), Field('last_name', default=None), ) director = Field(name='director', mapping=person_schema, nullable=True) assert director.has_value_in({'director': {}}) assert director.get_value_in({'director': {}}) == {} assert director.get_value_in({'director': {'first_name': 'John', 'last_name': 'Smith'}}) == { 'first_name': 'John', 'last_name': 'Smith', } assert Schema(director).load({'director': {}}) == {'director': {'first_name': None, 'last_name': None}} assert Schema(director).load({'director': None}) == {'director': None}
def test_field_custom_source_names_in_container(): f1 = Field(name='f1', source_names=['f1_source']) assert not hasattr(f1, 'source_name') assert f1.source_names == ['f1_source'] c1 = {'f1': 'f1_value'} c2 = {'f1_source': 'f1_value'} assert not f1.has_value_in(c1) assert f1.get_value_in(c1) is None assert f1.has_value_in(c2) assert f1.get_value_in(c2) == 'f1_value'
def test_all_field_attributes(): str_field = Field( name='name', default='default', mapping=str, max_len=20, min_len=2, choices=['one', 'two', 'three'], required=False, regex=r'^[a-zA-Z]+$', source_names=['name', 'Name'], forbidden=False, nullable=True, ) assert str_field.__dict__ == str_field.clone().__dict__ int_field = Field( name='name', required=True, mapping=int, min=0, max=100, ) assert int_field.__dict__ == int_field.clone().__dict__
class UserSchema(Schema, FlaskRequestSchemaMixin): fields = ( Field('username', required=True), Field('password', source_name='Password'), Field('dob', mapping=Mappings.date(), default=None) )
def test_map_as_accepts_reverse(): f = Field(name='x', mapping=Mapping(int, str)) g = f.map_as('x_str', reverse=True) assert g(5) == '5' assert g.dump('5') == 5
def test_schema_instance_on_the_fly(): schema = Schema(Field('username'), Field('password'), mixins=[FlaskRequestSchemaMixin]) assert isinstance(schema, Schema) assert isinstance(schema, FlaskRequestSchemaMixin) assert schema.f.username assert schema.f.password
def test_field_is_nullable_by_default(): assert Field('one').nullable is True assert Field('two', nullable=False).nullable is False
def test_field_nullable_is_enforced(): with pytest.raises(Field.Invalid) as exc_info: Field('one', nullable=False).load(None) assert exc_info.value.name == 'one' assert exc_info.value.reason == 'nullable'
def test_fields_passed_as_args(): a = Field('a') b = Field('b') schema = Schema(a, b) assert schema.fields == [a, b]
def test_calling_field_means_invoking_field_loader(): f = Field(mapping=Mappings.datetime()) assert f('2017-12-31 23:55:59') == dt.datetime(2017, 12, 31, 23, 55, 59)
def test_initialises_field(): one = Field('one') assert one.name == 'one' assert one.mapping('some_string') == 'some_string' assert one.mapping('10') == '10' assert one.mapping(10) == '10' two = Field('two', 5) assert two.default == 5 assert two.mapping(10) == 10 assert two.mapping('10') == 10 assert two.mapping(None) is None three = Field('three', 'default value') assert three.default == 'default value' assert three.mapping('10') == '10' assert three.mapping(10) == '10' assert three.mapping(None) is None four = Field('four', None, int) assert four.default is None assert four.mapping('10') == 10 assert four.mapping(10) == 10 assert four.mapping(None) is None