def test_links(): f1 = Mock(return_value=[1]) f2 = Mock(return_value=[2]) f3 = Mock(return_value=[['boners']]) f4 = Mock(return_value=[['julio']]) graph = Graph([ Node('a', [ Field('d', None, f3), Field('e', None, f4), ]), Root([ Link('b', Sequence[TypeRef['a']], f1, requires=None), Link('c', Sequence[TypeRef['a']], f2, requires=None), ]), ]) result = execute(graph, build([Q.b[Q.d], Q.c[Q.e]])) check_result(result, {'b': [{'d': 'boners'}], 'c': [{'e': 'julio'}]}) assert result.index == {'a': {1: {'d': 'boners'}, 2: {'e': 'julio'}}} f1.assert_called_once_with() f2.assert_called_once_with() with reqs_eq_patcher(): f3.assert_called_once_with([query.Field('d')], [1]) f4.assert_called_once_with([query.Field('e')], [2])
def test_complex_field(): engine = Engine(SyncExecutor()) def get_a(fields, ids): return [[{'s': 'bar'} for _ in fields] for _ in ids] ll_graph = Graph([ Node('Foo', [ Field('a', Record[{ 's': String }], get_a), ]), ]) foo_sg = SubGraph(ll_graph, 'Foo') hl_graph = Graph([ Node('Foo', [ Field('a', Record[{ 's': String }], foo_sg), ]), Root([ Link('foo', TypeRef['Foo'], lambda: 1, requires=None), ]), ]) result = engine.execute(hl_graph, build([Q.foo[Q.a[Q.s]]])) check_result(result, {'foo': {'a': {'s': 'bar'}}})
def test_node_complex_fields(): f1 = Mock(return_value=[1]) f2 = Mock(return_value=[[{'f': 'marshes'}]]) f3 = Mock(return_value=[[{'g': 'colline'}]]) f4 = Mock(return_value=[[[{'h': 'magi'}]]]) graph = Graph([ Node('a', [ Field('b', Optional[Record[{'f': Integer}]], f2), Field('c', Record[{'g': Integer}], f3), Field('d', Sequence[Record[{'h': Integer}]], f4), ]), Root([ Link('e', Sequence[TypeRef['a']], f1, requires=None), ]), ]) check_result( execute(graph, build([Q.e[Q.b[Q.f], Q.c[Q.g], Q.d[Q.h]]])), {'e': [{'b': {'f': 'marshes'}, 'c': {'g': 'colline'}, 'd': [{'h': 'magi'}]}]}, ) f1.assert_called_once_with() f2.assert_called_once_with( [q.Link('b', q.Node([q.Field('f')]))], [1], ) f3.assert_called_once_with( [q.Link('c', q.Node([q.Field('g')]))], [1], ) f4.assert_called_once_with( [q.Link('d', q.Node([q.Field('h')]))], [1], )
def test_links(): fb = Mock(return_value=[1]) fc = Mock(return_value=[2]) fi = Mock(return_value=[3]) fd = Mock(return_value=[['boners']]) fe = Mock(return_value=[['julio']]) graph = Graph([ Node('a', [ Field('d', None, fd), Field('e', None, fe), ]), Root([ Field('i', None, fi), Link('b', Sequence[TypeRef['a']], fb, requires=None), Link('c', Sequence[TypeRef['a']], fc, requires='i'), ]), ]) result = execute(graph, build([Q.b[Q.d], Q.c[Q.e]])) check_result(result, {'b': [{'d': 'boners'}], 'c': [{'e': 'julio'}]}) fi.assert_called_once_with([q.Field('i')]) fb.assert_called_once_with() fc.assert_called_once_with(3) fd.assert_called_once_with([q.Field('d')], [1]) fe.assert_called_once_with([q.Field('e')], [2])
def test_link_optional(value, expected): graph = Graph([ Node('Bar', [ Field('baz', Integer, _), ]), Node('Foo', [ Link('bar', Optional[TypeRef['Bar']], _, requires=None), ]), Root([ Link('foo', Optional[TypeRef['Foo']], _, requires=None), ]), ]) query = build([ Q.foo[Q.bar[Q.baz, ], ], ]) index = Index() index[ROOT.node][ROOT.ident].update({ 'foo': Reference('Foo', 1), }) index['Foo'][1].update({ 'bar': value, }) index['Bar'][2].update({'baz': 42}) result = Proxy(index, ROOT, query) assert Denormalize(graph, result).process(query) == { 'foo': { 'bar': expected, }, }
def test_pass_context_link(): f1 = pass_context(Mock(return_value=[1])) f2 = Mock(return_value=[['boners']]) graph = Graph([ Node('a', [ Field('b', None, f2), ]), Root([ Link('c', Sequence[TypeRef['a']], f1, requires=None), ]), ]) result = execute(graph, build([Q.c[Q.b]]), {'fibs': 'dossil'}) check_result(result, {'c': [{'b': 'boners'}]}) assert result.index == {'a': {1: {'b': 'boners'}}} f1.assert_called_once_with(ANY) with reqs_eq_patcher(): f2.assert_called_once_with([query.Field('b')], [1]) ctx = f1.call_args[0][0] assert isinstance(ctx, Context) assert ctx['fibs'] == 'dossil' with pytest.raises(KeyError) as err: _ = ctx['invalid'] # noqa err.match('is not specified in the query context')
def check_refs(types, expr, query_items): ast, functions = to_expr(expr) query = build(query_items) env = fn_types(functions) env.update(types['__root__'].__field_types__) ast = check(ast, types, env) expr_reqs = RequirementsExtractor.extract(types, ast) assert expr_reqs == query
def test_field_option_missing(): graph = Graph([ Root([ Field('poofy', None, Mock(), options=[Option('mohism', None)]), ]), ]) with pytest.raises(TypeError) as err: execute(graph, build([Q.poofy])) err.match('^Required option "mohism" for Field\(\'poofy\', ' '(.*) was not provided$')
def test_field_option_valid(option, args, result): f = Mock(return_value=['baking']) graph = Graph([ Root([ Field('auslese', None, f, options=[option]), ]), ]) check_result(execute(graph, build([Q.auslese(**args)])), {'auslese': 'baking'}) f.assert_called_once_with([q.Field('auslese', options=result)])
def test_query_reading(): from hiku.builder import build, Q from hiku.export.protobuf import export binary_message = export(build([Q.characters[Q.name]])).SerializeToString() from hiku.readers.protobuf import read query = read(binary_message) result = hiku_engine.execute(GRAPH, query) assert all(c['name'] for c in result['characters'])
def test_root_node_field_func_result_validation(value): with pytest.raises(TypeError) as err: execute( Graph([ Root([ Node('a', [Field('b', None, Mock(return_value=value))]), ]), ]), build([Q.a[Q.b]]), ) err.match( re.escape("Can't store field values, node: 'a', fields: ['b'], " "expected: list (len: 1), returned: {value!r}".format( value=value)))
def test_link_option_missing(): graph = Graph([ Node('slices', [ Field('papeete', None, Mock()), ]), Root([ Link('eclairs', Sequence[TypeRef['slices']], Mock(), requires=None, options=[Option('nocks', None)]), ]), ]) with pytest.raises(TypeError) as err: execute(graph, build([Q.eclairs[Q.papeete]])) err.match(r'^Required option "nocks" for Link\(\'eclairs\', ' r'(.*) was not provided$')
def test_result_serialization(): from hiku.builder import build, Q from hiku.writers.protobuf import populate import example_pb2 query = build([Q.characters[Q.name]]) result = hiku_engine.execute(GRAPH, query) pb_result = example_pb2.Root() populate(pb_result, GRAPH, result, query) # to send afterwards pb_result.SerializeToString()
def test_link_option_valid(option, args, result): f1 = Mock(return_value=[1]) f2 = Mock(return_value=[['aunder']]) graph = Graph([ Node('a', [ Field('c', None, f2), ]), Root([ Link('b', Sequence[TypeRef['a']], f1, requires=None, options=[option]), ]), ]) check_result(execute(graph, build([Q.b(**args)[Q.c]])), {'b': [{'c': 'aunder'}]}) f1.assert_called_once_with(result) f2.assert_called_once_with([q.Field('c')], [1])
def test_root_fields(): f1 = Mock(return_value=['boiardo']) f2 = Mock(return_value=['isolde']) graph = Graph([ Root([ Field('a', None, f1), Field('b', None, f2), ]), ]) result = execute(graph, build([Q.a, Q.b])) check_result(result, {'a': 'boiardo', 'b': 'isolde'}) f1.assert_called_once_with([q.Field('a')]) f2.assert_called_once_with([q.Field('b')])
def test_root_link_many_func_result_validation(): with pytest.raises(TypeError) as err: execute( Graph([ Node('a', [ Field('b', None, Mock(return_value=[[3], [4]])), ]), Root([ Link('c', Sequence[TypeRef['a']], Mock(return_value=123), requires=None), ]), ]), build([Q.c[Q.b]]), ) err.match(re.escape( "Can't store link values, node: '__root__', link: 'c', " "expected: list, returned: 123" ))
def test(): query = build([ Q.tyan, Q.turlock[Q.gange], Q.tiber(ramsons='defaces')[Q.decifer(botches='auxerre'), Q.exocet(brogues='hygiea'), ], ]) with reqs_eq_patcher(): assert query == Node([ Field('tyan'), Link('turlock', Node([Field('gange')])), Link( 'tiber', Node([ Field('decifer', options={'botches': 'auxerre'}), Field('exocet', options={'brogues': 'hygiea'}), ]), {'ramsons': 'defaces'}), ])
def test_node_field_func_result_validation(value): with pytest.raises(TypeError) as err: execute( Graph([ Node('a', [ Field('b', None, Mock(return_value=value)), ]), Root([ Link('c', Sequence[TypeRef['a']], Mock(return_value=[1, 2]), requires=None), ]), ]), build([Q.c[Q.b]]), ) err.match(re.escape( "Can't store field values, node: 'a', fields: ['b'], " "expected: list (len: 2) of lists (len: 1), returned: {value!r}" .format(value=value) ))
def test_root_node_fields(): f1 = Mock(return_value=['khios']) f2 = Mock(return_value=['cambay']) graph = Graph([ Root([ Node('a', [ Field('b', None, f1), Field('c', None, f2), ]), ]), ]) result = execute(graph, build([Q.a[Q.b, Q.c]])) check_result(result, {'a': {'b': 'khios', 'c': 'cambay'}}) with reqs_eq_patcher(): f1.assert_called_once_with([query.Field('b')]) f2.assert_called_once_with([query.Field('c')])
def test_pass_context_field(): f = pass_context(Mock(return_value=['boiardo'])) graph = Graph([ Root([ Field('a', None, f), ]), ]) check_result(execute(graph, build([Q.a]), {'vetch': 'shadier'}), {'a': 'boiardo'}) f.assert_called_once_with(ANY, [q.Field('a')]) ctx = f.call_args[0][0] assert isinstance(ctx, Context) assert ctx['vetch'] == 'shadier' with pytest.raises(KeyError) as err: _ = ctx['invalid'] # noqa err.match('is not specified in the query context')
def test_node_fields(): f1 = Mock(return_value=[1]) f2 = Mock(return_value=[['harkis']]) f3 = Mock(return_value=[['slits']]) graph = Graph([ Node('a', [ Field('b', None, f2), Field('c', None, f3), ]), Root([ Link('d', Sequence[TypeRef['a']], f1, requires=None), ]), ]) result = execute(graph, build([Q.d[Q.b, Q.c]])) check_result(result, {'d': [{'b': 'harkis', 'c': 'slits'}]}) f1.assert_called_once_with() f2.assert_called_once_with([q.Field('b')], [1]) f3.assert_called_once_with([q.Field('c')], [1])
def test_link_sequence(): graph = Graph([ Node('Bar', [ Field('baz', Integer, _), ]), Node('Foo', [ Link('bar', Sequence[TypeRef['Bar']], _, requires=None), ]), Root([ Link('foo', Sequence[TypeRef['Foo']], _, requires=None), ]), ]) query = build([ Q.foo[Q.bar[Q.baz, ], ], ]) index = Index() index[ROOT.node][ROOT.ident].update({ 'foo': [Reference('Foo', 1)], }) index['Foo'][1].update({ 'bar': [Reference('Bar', 2), Reference('Bar', 3)], }) index['Bar'][2].update({'baz': 42}) index['Bar'][3].update({'baz': 43}) result = Proxy(index, ROOT, query) assert Denormalize(graph, result).process(query) == { 'foo': [ { 'bar': [ { 'baz': 42 }, { 'baz': 43 }, ], }, ], }
def test_node_link_without_requirements(): f1 = Mock(return_value=[1]) f2 = Mock(return_value=[2]) f3 = Mock(return_value=[['arnhild']]) graph = Graph([ Node('a', [ Field('c', None, f3), ]), Node('b', [ Link('d', Sequence[TypeRef['a']], f2, requires=None), ]), Root([ Link('e', Sequence[TypeRef['b']], f1, requires=None), ]), ]) result = execute(graph, build([Q.e[Q.d[Q.c]]])) check_result(result, {'e': [{'d': [{'c': 'arnhild'}]}]}) f1.assert_called_once_with() f2.assert_called_once_with() f3.assert_called_once_with([q.Field('c')], [2])
def test_node_link_many_func_result_validation(value): with pytest.raises(TypeError) as err: execute( Graph([ Node('a', [ Field('b', None, Mock(return_value=[[1], [2]])) ]), Node('c', [ Field('d', None, Mock(return_value=[[3], [4]])), Link('e', Sequence[TypeRef['a']], Mock(return_value=value), requires='d'), ]), Root([ Link('f', Sequence[TypeRef['c']], Mock(return_value=[1, 2]), requires=None), ]), ]), build([Q.f[Q.e[Q.b]]]), ) err.match(re.escape( "Can't store link values, node: 'c', link: 'e', expected: " "list (len: 2) of lists, returned: {!r}".format(value) ))
def test_query_export(): from hiku.protobuf import query_pb2 node = query_pb2.Node() link = node.items.add().link link.name = 'characters' field = link.node.items.add().field field.name = 'name' from hiku.builder import build, Q from hiku.export.protobuf import export query = build([ Q.characters[Q.name, ], ]) message = export(query) assert message == node binary_message = message.SerializeToString() assert binary_message
def test_node_link_without_requirements(): f1 = Mock(return_value=[1]) f2 = Mock(return_value=[2]) f3 = Mock(return_value=[['arnhild']]) graph = Graph([ Node('a', [ Field('c', None, f3), ]), Node('b', [ Link('d', Sequence[TypeRef['a']], f2, requires=None), ]), Root([ Link('e', Sequence[TypeRef['b']], f1, requires=None), ]), ]) result = execute(graph, build([Q.e[Q.d[Q.c]]])) check_result(result, {'e': [{'d': [{'c': 'arnhild'}]}]}) assert result.index == { 'a': { 2: { 'c': 'arnhild' } }, 'b': { 1: { 'd': [result.ref('a', 2)] } }, } f1.assert_called_once_with() f2.assert_called_once_with() with reqs_eq_patcher(): f3.assert_called_once_with([query.Field('c')], [2])
def check_ref(ref_chain, types, arg_type, query_items): ref_ = ref(ref_chain) ref_query = type_to_query(arg_type) if arg_type else None query = build(query_items) assert ref_to_req(types, ref_, ref_query) == query
def query_python(): query = build([ Q.characters[Q.name, Q.species, ], ]) return query
def check_extract(node, types, query_items): node_query = RequirementsExtractor.extract(types, node) query = build(query_items) assert node_query == query
def check_type(type_, query_items): type_query = type_to_query(type_) query = build(query_items) assert type_query == query