def test_array_field(): s_f = StringField() n_f = NumberField() field = ArrayField(Var({ 'role_1': s_f, 'role_2': n_f, })) schema = field.get_schema(role='role_1') assert schema['items'] == s_f.get_schema() schema = field.get_schema(role='role_2') assert schema['items'] == n_f.get_schema() schema = field.get_schema() assert 'items' not in schema _ = lambda value: Var({'role_1': value}) field = ArrayField(s_f, min_items=_(1), max_items=_(2), unique_items=_(True), additional_items=_(True)) assert field.get_schema() == { 'type': 'array', 'items': s_f.get_schema(), } assert field.get_schema(role='role_1') == { 'type': 'array', 'items': s_f.get_schema(), 'minItems': 1, 'maxItems': 2, 'uniqueItems': True, 'additionalItems': True, }
def test_array_field(): f = ArrayField(items=()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() assert list(e.value.steps) == [FieldStep(f), AttributeStep('items')] f = ArrayField(items=( Var({'role_x': StringField()}), Var({'role_x': IntField()}), )) role = 'role_y' with pytest.raises(SchemaGenerationException) as e: f.get_schema(role='role_y') assert list(e.value.steps) == [ FieldStep(f, role=role), AttributeStep('items', role=role) ] f = ArrayField(items=(None, None)) with pytest.raises(SchemaGenerationException) as e: f.get_schema() assert list( e.value.steps) == [FieldStep(f), AttributeStep('items'), ItemStep(0)] f = ArrayField(items=object()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() assert list(e.value.steps) == [FieldStep(f), AttributeStep('items')] f = ArrayField(additional_items=object()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() assert list( e.value.steps) == [FieldStep(f), AttributeStep('additional_items')] f = ArrayField(items=FieldStub()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert e.message == FieldStub.ERROR_MESSAGE assert list(e.steps) == [FieldStep(f), AttributeStep('items')] f = ArrayField(items=(FieldStub(), )) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert e.message == FieldStub.ERROR_MESSAGE assert list(e.steps) == [FieldStep(f), AttributeStep('items'), ItemStep(0)] f = ArrayField(additional_items=FieldStub()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert e.message == FieldStub.ERROR_MESSAGE assert list(e.steps) == [FieldStep(f), AttributeStep('additional_items')]
class Task(Document): class Options(object): title = 'Task' description = 'A task.' definition_id = 'task' id = IntField(required=Var({'response': True})) name = StringField(required=True, min_length=5) type = StringField(required=True, enum=['TYPE_1', 'TYPE_2']) created_at = DateTimeField(required=True) author = Var({'response': DocumentField(User)})
def test_var(): value_1 = object() value_2 = object() value_3 = object() var = Var([ ('role_1', value_1), ('role_2', value_2), (not_('role_3'), value_3), ]) assert len(var.values) == 3 for matcher, value in var.values: assert callable(matcher) assert type(value) == object assert var.resolve('role_1') == Resolution(value_1, 'role_1') assert var.resolve('role_2') == Resolution(value_2, 'role_2') assert var.resolve('default') == Resolution(value_3, 'default') var = Var([ (not_('role_3'), value_3), ('role_1', value_1), ('role_2', value_2), ]) assert var.resolve('role_1') == Resolution(value_3, 'role_1') assert var.resolve('role_2') == Resolution(value_3, 'role_2') assert var.resolve('default') == Resolution(value_3, 'default') assert var.resolve('role_3') == Resolution(None, 'role_3') var = Var([ ('role_1', value_1), ('role_2', value_2), ], propagate='role_2') assert callable(var.propagate)
def test_helpers(): when = lambda *args: Var({ not_(*args): False }, default=True) assert when(RESPONSE_ROLE).resolve(RESPONSE_ROLE).value assert not when(RESPONSE_ROLE).resolve(REQUEST_ROLE).value
class User(Document): login = StringField() friends = ArrayField( Var({ 'db_role': db_role_friends_field, 'request_role': request_role_friends_field, }))
def test_not_field(): for f in [NotField(object()), NotField(Var({'role_x': object()}))]: with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'not a BaseField' in e.message assert list(e.steps) == [FieldStep(f), AttributeStep('field')]
class Message(Document): with Scope(DB_ROLE) as db: db.uuid = StringField(required=True) created_at = IntField( required=when_not(PARTIAL_RESPONSE_ROLE, REQUEST_ROLE)) text = StringField(required=when_not(PARTIAL_RESPONSE_ROLE)) field_that_is_never_present = Var( {'NEVER': StringField(required=True)})
def test_keyword_of_fields(field_cls): f = field_cls(object()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'not a list or a tuple' in e.message assert list(e.steps) == [FieldStep(f), AttributeStep('fields')] f = field_cls([]) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'empty' in e.message assert list(e.steps) == [FieldStep(f), AttributeStep('fields')] f = field_cls([object()]) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'not resolvable' in e.message assert list( e.steps) == [FieldStep(f), AttributeStep('fields'), ItemStep(0)] role = 'role_x' f = field_cls([Var({role: object()})]) with pytest.raises(SchemaGenerationException) as e: f.get_schema(role=role) e = e.value assert 'not a BaseField' in e.message assert list(e.steps) == [ FieldStep(f, role), AttributeStep('fields', role), ItemStep(0, role) ] with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'empty' in e.message assert list(e.steps) == [FieldStep(f), AttributeStep('fields')] # test nested field errors f = field_cls([FieldStub()]) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert e.message == FieldStub.ERROR_MESSAGE assert list( e.steps) == [FieldStep(f), AttributeStep('fields'), ItemStep(0)]
def test_keyword_of_fields(keyword, field_cls): s_f = StringField() n_f = NumberField() i_f = IntField() field = field_cls([n_f, Var({'role_1': s_f}), Var({'role_2': i_f})]) assert field.get_schema() == {keyword: [n_f.get_schema()]} assert field.get_schema(role='role_1') == { keyword: [n_f.get_schema(), s_f.get_schema()] } assert field.get_schema(role='role_2') == { keyword: [n_f.get_schema(), i_f.get_schema()] } field = field_cls( Var( { 'role_1': [n_f, Var({'role_1': s_f}), Var({'role_2': i_f})], 'role_2': [Var({'role_2': i_f})], }, propagate='role_1')) assert field.get_schema() == {keyword: []} assert field.get_schema(role='role_1') == { keyword: [n_f.get_schema(), s_f.get_schema()] } assert field.get_schema(role='role_2') == {keyword: []}
def test_keyword_of_fields(keyword, field_cls): s_f = StringField() n_f = NumberField() i_f = IntField() field = field_cls([n_f, Var({'role_1': s_f}), Var({'role_2': i_f})]) assert s(field.get_schema()) == {keyword: [n_f.get_schema()]} assert s(field.get_schema(role='role_1')) == { keyword: [n_f.get_schema(), s_f.get_schema()] } assert s(field.get_schema(role='role_2')) == { keyword: [n_f.get_schema(), i_f.get_schema()] } field = field_cls( Var( { 'role_1': [n_f, Var({'role_1': s_f}), Var({'role_2': i_f})], 'role_2': [Var({'role_2': i_f})], }, propagate='role_1')) assert s(field.get_schema(role='role_1')) == { keyword: [n_f.get_schema(), s_f.get_schema()] } with pytest.raises(SchemaGenerationException): field.get_schema(role='role_2')
def test_base_field(): _ = lambda value: Var({'role_1': value}) field = BaseSchemaField(default=_(lambda: 1), enum=_(lambda: [1, 2, 3]), title=_('Title'), description=_('Description')) schema = field._update_schema_with_common_fields({}) assert schema == {} schema = field._update_schema_with_common_fields(schema, role='role_1') assert schema == { 'title': 'Title', 'description': 'Description', 'enum': [1, 2, 3], 'default': 1, }
def test_string_field(): _ = lambda value: Var({'role_1': value}) field = StringField(format=_('date-time'), min_length=_(1), max_length=_(2)) assert field.get_schema() == {'type': 'string'} assert field.get_schema(role='role_1') == { 'type': 'string', 'format': 'date-time', 'minLength': 1, 'maxLength': 2, } with pytest.raises(ValueError) as e: StringField(pattern=_('(')) assert str(e.value) == 'Invalid regular expression: unbalanced parenthesis'
def test_var(): value_1 = object() value_2 = object() value_3 = object() var = Var([ ('role_1', value_1), ('role_2', value_2), (not_('role_3'), value_3), ]) assert var.resolve('role_1') == Resolution(value_1, 'role_1') assert var.resolve('role_2') == Resolution(value_2, 'role_2') assert var.resolve('default') == Resolution(value_3, 'default') var = Var([ (not_('role_3'), value_3), ('role_1', value_1), ('role_2', value_2), ]) assert var.resolve('role_1') == Resolution(value_3, 'role_1') assert var.resolve('role_2') == Resolution(value_3, 'role_2') assert var.resolve('default') == Resolution(value_3, 'default') assert var.resolve('role_3') == Resolution(None, 'role_3')
def test_dict_field(): s_f = StringField() _ = lambda value: Var({'role_1': value}) field = DictField(properties=Var( { 'role_1': { 'name': Var({'role_1': s_f}) }, 'role_2': { 'name': Var({'role_2': s_f}) }, }, propagate='role_1'), pattern_properties=Var( { 'role_1': { '.*': Var({'role_1': s_f}) }, 'role_2': { '.*': Var({'role_2': s_f}) }, }, propagate='role_1'), additional_properties=_(s_f), min_properties=_(1), max_properties=_(2)) assert s(field.get_schema()) == s({'type': 'object'}) assert s(field.get_schema(role='role_1')) == s({ 'type': 'object', 'properties': { 'name': s_f.get_schema(), }, 'patternProperties': { '.*': s_f.get_schema(), }, 'additionalProperties': s_f.get_schema(), 'minProperties': 1, 'maxProperties': 2, }) assert s(field.get_schema(role='role_2')) == s({ 'type': 'object', 'properties': {}, 'patternProperties': {}, })
def test_var(): value_1 = object() value_2 = object() value_3 = object() var = Var([ ('role_1', value_1), ('role_2', value_2), (Not('role_3'), value_3), ]) assert var.resolve('role_1') == value_1 assert var.resolve('role_2') == value_2 assert var.resolve('default') == value_3 var = Var([ (Not('role_3'), value_3), ('role_1', value_1), ('role_2', value_2), ]) assert var.resolve('role_1') == value_3 assert var.resolve('role_2') == value_3 assert var.resolve('default') == value_3 assert var.resolve('role_3') is None
class Options(object): definition_id = Var({'role_1': 'a'})
class User(Document): id = Var({'response': IntField(required=True)}) login = StringField(required=True)
class A(Document): id = Var({'response': StringField(required=True)}) b = DocumentField(B)
class B(Document): name = Var({ 'response': StringField(required=True), 'request': StringField(), })
def test_not_field(): s_f = StringField() field = NotField(Var({'role_1': s_f})) assert field.get_schema() == {'not': {}} assert field.get_schema(role='role_1') == {'not': s_f.get_schema()}
def test_dict_field(): f = DictField(properties={'a': object()}) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'not resolvable' in e.message assert list( e.steps) == [FieldStep(f), AttributeStep('properties'), ItemStep('a')] f = DictField(pattern_properties={'a.*': object()}) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'not resolvable' in e.message assert list(e.steps) == [ FieldStep(f), AttributeStep('pattern_properties'), ItemStep('a.*') ] f = DictField(additional_properties=object()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'not a BaseField or a bool' in e.message assert list( e.steps) == [FieldStep(f), AttributeStep('additional_properties')] f = DictField(properties={'a': FieldStub()}) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert e.message == FieldStub.ERROR_MESSAGE assert list( e.steps) == [FieldStep(f), AttributeStep('properties'), ItemStep('a')] f = DictField(pattern_properties={'a.*': FieldStub()}) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert e.message == FieldStub.ERROR_MESSAGE assert list(e.steps) == [ FieldStep(f), AttributeStep('pattern_properties'), ItemStep('a.*') ] f = DictField(additional_properties=FieldStub()) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert e.message == FieldStub.ERROR_MESSAGE assert list( e.steps) == [FieldStep(f), AttributeStep('additional_properties')] for kwarg_value in (object(), Var({'role_x': object()})): for kwarg in ('properties', 'pattern_properties'): f = DictField(**{kwarg: kwarg_value}) with pytest.raises(SchemaGenerationException) as e: f.get_schema(role='role_x') e = e.value assert 'not a dict' in e.message assert list(e.steps) == [ FieldStep(f, role='role_x'), AttributeStep(kwarg, role='role_x') ] f = DictField(additional_properties=kwarg_value) with pytest.raises(SchemaGenerationException) as e: f.get_schema(role='role_x') e = e.value assert 'not a BaseField or a bool' in e.message assert list(e.steps) == [ FieldStep(f, role='role_x'), AttributeStep('additional_properties', role='role_x') ] f = DictField(pattern_properties={'((((': StringField()}) with pytest.raises(SchemaGenerationException) as e: f.get_schema() e = e.value assert 'unbalanced parenthesis' in e.message assert list(e.steps) == [FieldStep(f), AttributeStep('pattern_properties')]
class A(Document): a = Var({'role_1': DocumentField('self')})
def test_scopes_basics(): when_not = lambda *args: Var({all_but(*args): True}, default=False) when = lambda *args: Var({all_but(*args): False}, default=True) class Message(Document): with Scope(DB_ROLE) as db: db.uuid = StringField(required=True) created_at = IntField( required=when_not(PARTIAL_RESPONSE_ROLE, REQUEST_ROLE)) text = StringField(required=when_not(PARTIAL_RESPONSE_ROLE)) class User(Document): class Options(object): roles_to_propagate = all_but(PARTIAL_RESPONSE_ROLE) with Scope(DB_ROLE) as db: db._id = StringField(required=True) db.version = StringField(required=True) with Scope(lambda r: r.startswith(RESPONSE_ROLE) or r == REQUEST_ROLE ) as response: response.id = StringField(required=when_not(PARTIAL_RESPONSE_ROLE)) with Scope(all_but(REQUEST_ROLE)) as request: request.messages = ArrayField( DocumentField(Message), required=when_not(PARTIAL_RESPONSE_ROLE)) schema = User.get_schema(role=DB_ROLE) sort_required_keys(schema) expected_required = sorted(['_id', 'version', 'messages']) expected_properties = { '_id': { 'type': 'string' }, 'version': { 'type': 'string' }, 'messages': { 'type': 'array', 'items': { 'type': 'object', 'additionalProperties': False, 'properties': { 'created_at': { 'type': 'integer' }, 'text': { 'type': 'string' }, 'uuid': { 'type': 'string' } }, 'required': sorted(['uuid', 'created_at', 'text']), }, }, } assert schema['required'] == expected_required assert schema['properties'] == expected_properties schema = User.get_schema(role=REQUEST_ROLE) sort_required_keys(schema) expected_required = sorted(['id']) expected_properties = { 'id': { 'type': 'string' }, } assert schema['required'] == expected_required assert schema['properties'] == expected_properties schema = User.get_schema(role=RESPONSE_ROLE) sort_required_keys(schema) expected_required = sorted(['id', 'messages']) expected_properties = { 'id': { 'type': 'string' }, 'messages': { 'type': 'array', 'items': { 'type': 'object', 'additionalProperties': False, 'properties': { 'created_at': { 'type': 'integer' }, 'text': { 'type': 'string' }, }, 'required': sorted(['created_at', 'text']), }, }, } assert schema['required'] == expected_required assert schema['properties'] == expected_properties schema = User.get_schema(role=PARTIAL_RESPONSE_ROLE) sort_required_keys(schema) expected_properties = { 'id': { 'type': 'string' }, 'messages': { 'type': 'array', 'items': { 'type': 'object', 'additionalProperties': False, 'properties': { 'created_at': { 'type': 'integer' }, 'text': { 'type': 'string' }, }, 'required': sorted(['created_at', 'text']), }, }, } assert 'required' not in schema assert schema['properties'] == expected_properties
def test_scopes_basics(): when_not = lambda *args: Var({not_(*args): True}, default=False) class Message(Document): with Scope(DB_ROLE) as db: db.uuid = StringField(required=True) created_at = IntField( required=when_not(PARTIAL_RESPONSE_ROLE, REQUEST_ROLE)) text = StringField(required=when_not(PARTIAL_RESPONSE_ROLE)) field_that_is_never_present = Var( {'NEVER': StringField(required=True)}) class User(Document): class Options(object): roles_to_propagate = not_(PARTIAL_RESPONSE_ROLE) with Scope(DB_ROLE) as db: db._id = StringField(required=True) db.version = StringField(required=True) with Scope(lambda r: r.startswith(RESPONSE_ROLE) or r == REQUEST_ROLE ) as response: response.id = StringField(required=when_not(PARTIAL_RESPONSE_ROLE)) with Scope(not_(REQUEST_ROLE)) as not_request: not_request.messages = ArrayField( DocumentField(Message), required=when_not(PARTIAL_RESPONSE_ROLE)) resolution = Message.resolve_field('text') assert resolution.value == Message.text assert resolution.role == DEFAULT_ROLE resolution = Message.resolve_field('field_that_is_never_present') assert resolution.value is None assert resolution.role == DEFAULT_ROLE resolution = Message.resolve_field('non-existent') assert resolution.value is None assert resolution.role == DEFAULT_ROLE schema = User.get_schema(role=DB_ROLE) expected_required = sorted(['_id', 'version', 'messages']) expected_properties = { '_id': { 'type': 'string' }, 'version': { 'type': 'string' }, 'messages': { 'type': 'array', 'items': { 'type': 'object', 'additionalProperties': False, 'properties': { 'created_at': { 'type': 'integer' }, 'text': { 'type': 'string' }, 'uuid': { 'type': 'string' } }, 'required': sorted(['uuid', 'created_at', 'text']), }, }, } assert sorted(schema['required']) == expected_required assert sort_required_keys( schema['properties']) == sort_required_keys(expected_properties) assert dict(User.resolve_and_iter_fields(DB_ROLE)) == { '_id': User.db._id, 'version': User.db.version, 'messages': User.not_request.messages, } schema = User.get_schema(role=REQUEST_ROLE) expected_required = sorted(['id']) expected_properties = { 'id': { 'type': 'string' }, } assert sorted(schema['required']) == expected_required assert sort_required_keys( schema['properties']) == sort_required_keys(expected_properties) assert dict(User.resolve_and_iter_fields(REQUEST_ROLE)) == { 'id': User.response.id, } schema = User.get_schema(role=RESPONSE_ROLE) expected_required = sorted(['id', 'messages']) expected_properties = { 'id': { 'type': 'string' }, 'messages': { 'type': 'array', 'items': { 'type': 'object', 'additionalProperties': False, 'properties': { 'created_at': { 'type': 'integer' }, 'text': { 'type': 'string' }, }, 'required': sorted(['created_at', 'text']), }, }, } assert sorted(schema['required']) == expected_required assert sort_required_keys( schema['properties']) == sort_required_keys(expected_properties) assert dict(User.resolve_and_iter_fields(RESPONSE_ROLE)) == { 'id': User.response.id, 'messages': User.not_request.messages, } schema = User.get_schema(role=PARTIAL_RESPONSE_ROLE) expected_properties = { 'id': { 'type': 'string' }, 'messages': { 'type': 'array', 'items': { 'type': 'object', 'additionalProperties': False, 'properties': { 'created_at': { 'type': 'integer' }, 'text': { 'type': 'string' }, }, 'required': sorted(['created_at', 'text']), }, }, } assert 'required' not in schema assert sort_required_keys( schema['properties']) == sort_required_keys(expected_properties) assert dict(Message.resolve_and_iter_fields(PARTIAL_RESPONSE_ROLE)) == { 'created_at': Message.created_at, 'text': Message.text, }