def test_ordering_expressions_are_buildable(self): from xotl.ql.expressions import max_ these((parent for parent in this), ordering=lambda parent: +(max_(child.age for child in parent.children)/parent.age)) these(((p, c) for p in this for c in p.children), ordering=lambda p, c: None)
def test_short_circuit(): from xotl.ql import thesefy from xotl.ql.expressions import call from xotl.ql.translation.py import naive_translation from xoutil.compat import integer flag = [0] # A list to allow non-global non-local in Py2k def inc_flag(by=1): flag[0] += 1 return flag[0] @thesefy class Universe(integer): pass Universe.this_instances = [Universe(1780917517912941696167)] query = these(atom for atom in Universe if (call(inc_flag) > 1) & call(inc_flag)) plan = naive_translation(query) list(plan()) assert flag[0] == 1 flag[0] = 0 query = these(atom for atom in Universe if (call(inc_flag) > 0) | call(inc_flag)) plan = naive_translation(query) list(plan()) assert flag[0] == 1
def test_free_terms_are_not_captured(self): from xotl.ql.expressions import any_ these(parent for parent in this('parent') if parent.name if any_(this.children, this.age < 6)) parts = self.bubble.parts self.assertIs(0, len(parts))
def test_partition_vs_limit(): query = these((parent for parent in this), limit=100) assert query.partition.stop == 100 query = these((parent for parent in this), offset=100, limit=100) assert query.partition.stop == 200 query = these((parent for parent in this), offset=100, limit=100, step=2) assert query.partition.stop == 400
def test_complex_query_with_3_tokens(self): query = these( (parent.title + parent.name, child.name + child.nick, toy.name) for parent in this('parent') if parent.children for child in parent.children if child.toys for toy in child.toys if (parent.age > 32) & (child.age < 5) | (toy.type == 'laptop')) p = this('parent') c = p.children t = c.toys filters = query.filters expected_filters = [ ((p.age > 32) & (c.age < 5) | (t.type == 'laptop')), p.children, c.toys ] tokens = query.tokens expected_tokens = [p, c, t] selection = query.selection expected_selection = (p.title + p.name, c.name + c.nick, t.name) with context(UNPROXIFING_CONTEXT): self.assertEqual(selection, expected_selection) self.assertEqual(len(expected_filters), len(filters)) for f in expected_filters: self.assertIn(f, filters) self.assertEqual(len(expected_tokens), len(tokens)) for t in expected_tokens: self.assertIn(t, tokens)
def test_basic_queries(self): from xotl.ql.expressions import count query = these((parent.title + parent.name, count(child.toys)) for parent in this('parent') if parent.age < 40 for child in parent.children if child.age > 5) self.assertTrue(provides_any(query, IQueryObject)) (parent_full_name, child_toys) = query.selection full_name_expectation = this('parent').title + this('parent').name # child_name_expectation = this('parent').children.name child_toys_expectation = count(this('parent').children.toys) parent_age_test = this('parent').age < 40 children_age_test = this('parent').children.age > 5 parent_token = this('parent') children_token = this('parent').children with context(UNPROXIFING_CONTEXT): self.assertEqual(parent_full_name, full_name_expectation) # self.assertEqual(child_name, child_name_expectation) self.assertEqual(child_toys, child_toys_expectation) filters = query.filters self.assertEqual(2, len(filters)) self.assertIn(parent_age_test, filters) self.assertIn(children_age_test, filters) tokens = query.tokens self.assertEqual(2, len(tokens)) self.assertIn(parent_token, tokens) self.assertIn(children_token, tokens)
def test_thesefy_doesnot_messup_identities(self): from itertools import izip from xotl.ql.core import thesefy from xotl.ql.expressions import is_a @thesefy class Person(object): pass @thesefy class Partnership(object): pass query = these((person, partner) for person, partner in izip(Person, Person) for rel in Partnership if (rel.subject == person) & (rel.obj == partner)) filters = list(query.filters) person, partner = query.selection person_is_a_person = is_a(person, Person) partner_is_a_person = is_a(partner, Person) with context(UNPROXIFING_CONTEXT): self.assertNotEqual(person, partner) self.assertIn(person_is_a_person, filters) self.assertIn(partner_is_a_person, filters) filters.remove(person_is_a_person) filters.remove(partner_is_a_person)
def test_thesefy_good_meta(self): from xotl.ql.core import thesefy class Meta(type): def __iter__(self): from xoutil.objects import nameof return iter(this(nameof(self))) @thesefy("Person") class Person(object): __metaclass__ = Meta q = these(who for who in Person if who.age > 30) q1 = these(who for who in this('Person') if who.age > 30) with context(UNPROXIFING_CONTEXT): self.assertEqual(q.selection, q1.selection)
def _resolve_arguments(cls, *children, **kwargs): '''Resolves the first and only positional argument as a sub-query by calling :class:`~xotl.ql.core.these`. If there is more than one positional argument, or even one keyword argument, or the first argument is not a generator object; then it leaves all the arguments the same. ''' import types first, rest = children[0], children[1:] if not first or (rest or kwargs): return children, kwargs else: if isinstance(first, types.GeneratorType): from xotl.ql.core import these first = these(first) # XXX: If this operation itself is enclosed in a # EXPRESSION_CAPTURING it might have occurred that a part # (actually a token's term) was emitted but then used as the # generator, so if the first token's binding original_term *is* # the last part emitted it should be removed from the bubble. bubble = context[EXPRESSION_CAPTURING].get('bubble', None) if bubble: parts = bubble._parts with context(UNPROXIFING_CONTEXT): term = first.tokens[0].expression if getattr(term, 'original_term', None) is parts[-1]: parts.pop(-1) return (first, ), {}
def test_worst_case_must_have_3_filters_and_3_tokens(self): from itertools import izip query = these( person for person, partner in izip(this('person'), this('partner')) for rel in this('relation') if rel.type == 'partnership' if rel.subject == person if rel.object == partner if partner.age > 32) filters = list(query.filters) tokens = list(query.tokens) person, partner, rel = this('person'), this('partner'), this( 'relation') expected_rel_type_filter = rel.type == 'partnership' expected_rel_subject_filter = rel.subject == person expected_rel_obj_filter = rel.object == partner expected_partner_age = partner.age > 32 with context(UNPROXIFING_CONTEXT): self.assertIs(4, len(filters)) self.assertIn(expected_rel_type_filter, filters) self.assertIn(expected_rel_subject_filter, filters) self.assertIn(expected_rel_obj_filter, filters) self.assertIn(expected_partner_age, filters) self.assertIn(person, tokens) self.assertIn(rel, tokens) self.assertIs(3, len(tokens)) self.assertIn(partner, tokens)
def test_basic_queries(): from xotl.ql.expressions import count query = these((parent.title + parent.name, count(child.toys)) for parent in this('parent') if parent.age < 40 for child in parent.children if child.age > 5) assert provides_any(query, IQueryObject) (parent_full_name, child_toys) = query.selection full_name_expectation = this('parent').title + this('parent').name child_toys_expectation = count(this('parent').children.toys) parent_age_test = this('parent').age < 40 children_age_test = this('parent').children.age > 5 parent_token = this('parent') children_token = this('parent').children with context(UNPROXIFING_CONTEXT): assert parent_full_name == full_name_expectation assert child_toys == child_toys_expectation filters = query.filters assert len(filters) == 2 assert parent_age_test in filters assert children_age_test in filters tokens = [tk.expression for tk in query.tokens] assert len(tokens) == 2 assert parent_token in tokens assert children_token in tokens
def test_named_terms_matches_a_token(): ''' Ensures that all terms are named, and they are bound to a token that is in the query. ''' from xoutil.iterators import zip from xotl.ql.core import thesefy from xotl.ql.translation import cotraverse_expression @thesefy class Person(object): pass @thesefy class Partnership(object): pass query = these((person, partner) for person, partner in zip(Person, Person) for rel in Partnership if (rel.subject == person) & (rel.obj == partner) if person.age > 35) tokens = [tk.expression for tk in query.tokens] matches_token = lambda term: (term.name and ( term.binding.expression in tokens or matches_token(term.parent))) with context(UNPROXIFING_CONTEXT): assert all(matches_token(term) for term in cotraverse_expression(*query.filters))
def test_worst_case_must_have_3_filters_and_3_tokens(): from xoutil.iterators import zip query = these(person for person, partner in zip(this('person'), this('partner')) for rel in this('relation') if rel.type == 'partnership' if rel.subject == person if rel.object == partner if partner.age > 32) filters = list(query.filters) tokens = [tk.expression for tk in query.tokens] person, partner, rel = this('person'), this('partner'), this('relation') expected_rel_type_filter = rel.type == 'partnership' expected_rel_subject_filter = rel.subject == person expected_rel_obj_filter = rel.object == partner expected_partner_age = partner.age > 32 with context(UNPROXIFING_CONTEXT): assert len(filters) == 4 assert expected_rel_type_filter in filters assert expected_rel_subject_filter in filters assert expected_rel_obj_filter in filters assert expected_partner_age in filters assert len(tokens) == 3 assert person in tokens assert rel in tokens assert partner in tokens
def test_complex_query_with_3_tokens(): query = these((parent.title + parent.name, child.name + child.nick, toy.name) for parent in this('parent') if parent.children for child in parent.children if child.toys for toy in child.toys if (parent.age > 32) & (child.age < 5) | (toy.type == 'laptop')) p = this('parent') c = p.children t = c.toys filters = query.filters expected_filters = [((p.age > 32) & (c.age < 5) | (t.type == 'laptop')), p.children, c.toys] tokens = [tk.expression for tk in query.tokens] expected_tokens = [p, c, t] selection = query.selection expected_selection = (p.title + p.name, c.name + c.nick, t.name) with context(UNPROXIFING_CONTEXT): assert selection == expected_selection assert len(expected_filters) == len(filters) for f in expected_filters: assert f in filters assert len(expected_tokens) == len(tokens) for t in expected_tokens: assert t in tokens
def test(self): operator = getattr(op, '_python_operator', op) query = these(parent for parent in this('p') if operator(parent.age, parent.check, parent.names)) expected = operator(this('p').age, this('p').check, this('p').names) self.assertIs(1, len(query.filters)) with context(UNPROXIFING_CONTEXT): self.assertEqual(expected, query.filters[0])
def test_query_objects_iteration(): from xotl.ql.translation.py import init @thesefy class Universe(int): pass Universe.this_instances = [Universe(i) for i in range(2, 10)] query = these(atom for atom in Universe) with pytest.raises(Exception): results = list(query) init() results = list(query) # XXX: Only for our implementation of QueryObject first_plan = getattr(query, '_query_execution_plan', None) for atom in Universe.this_instances: assert atom in results assert len(results) == len(Universe.this_instances) again = list(query) second_plan = getattr(query, '_query_execution_plan', None) assert len(results) == len(again) assert first_plan is second_plan from itertools import product assert list(product(results, results)) == list(product(iter(query), iter(query)))
def test_query_object_getitem(): query = these((parent for parent in this), offset=100, limit=100, step=2) query2 = query[:-50] assert query.partition.stop == 400 assert query2.partition.start == 100 assert query2.partition.stop == 350 assert query2.partition.step == 2
def test_token_before_filter(): query = these((parent, child) for parent in this if parent.children for child in parent.children if child.age < 5 for dummy in parent.children) parent, child = query.selection parent_token, children_token, dummy_token = query.tokens expr1, expr2 = query.filters def ok(e1, e2): with context(UNPROXIFING_CONTEXT): assert e1 == e2 ok(expr1, parent.children) ok(expr2, child.age < 5) assert UNPROXIFING_CONTEXT not in context assert not token_before_filter(children_token, expr1), repr((children_token, expr1, expr2)) assert token_before_filter(children_token, expr2, True) assert token_before_filter(parent_token, expr2, True) assert not token_before_filter(dummy_token, expr2, True) assert UNPROXIFING_CONTEXT not in context
def test_complex_query_with_3_tokens(self): query = these((parent.title + parent.name, child.name + child.nick, toy.name) for parent in this('parent') if parent.children for child in parent.children if child.toys for toy in child.toys if (parent.age > 32) & (child.age < 5) | (toy.type == 'laptop')) p = this('parent') c = p.children t = c.toys filters = query.filters expected_filters = [((p.age > 32) & (c.age < 5) | (t.type == 'laptop')), p.children, c.toys] tokens = query.tokens expected_tokens = [p, c, t] selection = query.selection expected_selection = (p.title + p.name, c.name + c.nick, t.name) with context(UNPROXIFING_CONTEXT): self.assertEqual(selection, expected_selection) self.assertEqual(len(expected_filters), len(filters)) for f in expected_filters: self.assertIn(f, filters) self.assertEqual(len(expected_tokens), len(tokens)) for t in expected_tokens: self.assertIn(t, tokens)
def test_worst_case_must_have_3_filters_and_3_tokens(self): from itertools import izip query = these(person for person, partner in izip(this('person'), this('partner')) for rel in this('relation') if rel.type == 'partnership' if rel.subject == person if rel.object == partner if partner.age > 32) filters = list(query.filters) tokens = list(query.tokens) person, partner, rel = this('person'), this('partner'), this('relation') expected_rel_type_filter = rel.type == 'partnership' expected_rel_subject_filter = rel.subject == person expected_rel_obj_filter = rel.object == partner expected_partner_age = partner.age > 32 with context(UNPROXIFING_CONTEXT): self.assertIs(4, len(filters)) self.assertIn(expected_rel_type_filter, filters) self.assertIn(expected_rel_subject_filter, filters) self.assertIn(expected_rel_obj_filter, filters) self.assertIn(expected_partner_age, filters) self.assertIn(person, tokens) self.assertIn(rel, tokens) self.assertIs(3, len(tokens)) self.assertIn(partner, tokens)
def test_named_terms_matches_a_token(self): ''' Ensures that all terms are named, and they are bound to a token that is in the query. ''' from itertools import izip from xotl.ql.core import thesefy from xotl.ql.translate import cofind_tokens @thesefy class Person(object): pass @thesefy class Partnership(object): pass query = these((person, partner) for person, partner in izip(Person, Person) for rel in Partnership if (rel.subject == person) & (rel.obj == partner) if person.age > 35) tokens = query.tokens matches_token = lambda term: (term.name and ( term.binding.expression in tokens or matches_token(term.parent))) with context(UNPROXIFING_CONTEXT): self.assertTrue(all(matches_token(term) for term in cofind_tokens(*query.filters)))
def test_named_terms_matches_a_token(self): ''' Ensures that all terms are named, and they are bound to a token that is in the query. ''' from itertools import izip from xotl.ql.core import thesefy from xotl.ql.translate import cofind_tokens @thesefy class Person(object): pass @thesefy class Partnership(object): pass query = these((person, partner) for person, partner in izip(Person, Person) for rel in Partnership if (rel.subject == person) & (rel.obj == partner) if person.age > 35) tokens = query.tokens matches_token = lambda term: (term.name and ( term.binding.expression in tokens or matches_token(term.parent))) with context(UNPROXIFING_CONTEXT): self.assertTrue( all( matches_token(term) for term in cofind_tokens(*query.filters)))
def test_loosing_tokens(): query = these((child, brother) for parent in this for child in parent.children for brother in parent.children if child is not brother) assert len(query.tokens) == 3
def test_traversing_by_nonexistent_attribute(**kwargs): from xoutil.iterators import dict_update_new from xotl.ql.translation.py import naive_translation dict_update_new(kwargs, dict(only='test_translate.*')) # There's no `childs` attribute in Persons query = these(child for parent in Person if parent.childs & (parent.age > 30) for child in parent.childs if child.age < 10) plan = naive_translation(query, **kwargs) assert list(plan()) == [] # And much less a `foobar` query = these(parent for parent in Person if parent.foobar) plan = naive_translation(query, **kwargs) assert list(plan()) == [] # And traversing through a non-existing stuff doesn't make # any sense either, but should not fail query = these(foos.name for person in Person for foos in person.foobars) plan = naive_translation(query, **kwargs) assert list(plan()) == [] # However either trying to traverse to a second level without testing # should fail query = these(a for p in this for a in p.b.a) plan = naive_translation(query, **kwargs) with pytest.raises(AttributeError): list(plan()) # The same query in a safe fashion query = these(a for p in this if p.b & p.b.a for a in p.b.a) plan = naive_translation(query, **kwargs) assert list(plan()) == [] # Now let's rerun the plan after we create some object that matches x = X() assert list(plan()) == x.b.a
def test_for_generator_as_sole_argument(): from xotl.ql.core import QueryObject from xotl.ql.expressions import all_ query = these(parent for parent in this if all_(child.age < 5 for child in parent.children) if all_(parent.children, this.age < 5) if all_(this.children, this.age < 5)) assert len(query.filters) == 3 assert isinstance(query.filters[0].children[0], QueryObject)
def test_regression_test_token_before_filter_20130401(): assert UNPROXIFING_CONTEXT not in context query = these(who for who in Entity if who.name.starswith('Manuel')) is_entity_filter, name_filter = query.filters token = query.tokens[0] assert len(query.tokens) == 1 assert token_before_filter(token, is_entity_filter, True) assert token_before_filter(token, name_filter, True)
def _test_class(self, Person): from xotl.ql.expressions import is_instance q = these((who for who in Person if who.age > 30), limit=100) # We assume that Person has been thesefied with thesefy('Person') who = domain = this('Person') q1 = these(w for w in domain if is_instance(w, Person) if w.age > 30) is_filter = is_instance(who, Person) age_filter = who.age > 30 with context(UNPROXIFING_CONTEXT): self.assertEqual(2, len(q.filters)) self.assertEqual(2, len(q1.filters)) self.assertIn(is_filter, q.filters) self.assertIn(is_filter, q1.filters) self.assertIn(age_filter, q.filters) self.assertIn(age_filter, q1.filters) self.assertEqual(q.selection, q1.selection) self.assertEqual(q.tokens, q1.tokens)
def test_right_bindings(self): these((parent, child) for parent in this('parent') if parent.children.updated_since(days=1) for child in parent.children if child.age < 4) # The query has two filters: # # this('parent').children & (count(this('parent').children) > 4) # this('parent').children.age < 5 # # If we regard every term `this('parent').children` as the *token*, # what would be the meaning of the first condition? How do we # distinguish from conditions over the named-token and the # expression that generates the token? # i.e in `for child in parent.children`, the `child` token # is *not* the same as the term `parent.children`. # # Now the token of the relevant query might help, but then the # machine should not strip those tokens from query-parts. parts = self.bubble.parts self.assertEqual(0, len(parts))
def test_naive_plan_no_join(**kwargs): from xoutil.iterators import dict_update_new from xotl.ql.translation.py import naive_translation select_old_entities = these(who for who in Entity if who.name.startswith('Manuel')) dict_update_new(kwargs, dict(only='test_translate.*')) plan = naive_translation(select_old_entities, **kwargs) result = list(plan()) assert manu in result assert manolito in result assert yade not in result
def test_no_custom(): from xotl.ql.translation.py import naive_translation from xotl.ql.expressions import Operator, N_ARITY class myoperator(Operator): arity = N_ARITY _format = 'myoperator({0}{1})' query = these(person for person in Person if myoperator(person)) with pytest.raises(TypeError): plan = naive_translation(query) list(plan())
def test_is_a_partnership_is_not_forgotten(self): from itertools import izip query = these( (person, partner) for person, partner in izip(this('person'), this('partner')) for rel in this('relation') if rel.type == 'partnership' if (rel.subject == person) & (rel.object == partner)) filters = list(query.filters) expected_rel_type = this('relation').type == 'partnership' with context(UNPROXIFING_CONTEXT): self.assertIn(expected_rel_type, filters) self.assertIs(2, len(filters))
def test_right_bindings_for_each_term(): query = these((child, brother) for parent in this for child in parent.children for brother in parent.children if child is not brother) child, brother = query.selection # XXX: This assume the order of the tokens is mantained!!! _this, child_token, brother_token = tuple(query.tokens) assert unboxed(child).binding is child_token assert unboxed(brother).binding is brother_token
def test_is_a_partnership_is_not_forgotten(self): from itertools import izip query = these((person, partner) for person, partner in izip(this('person'), this('partner')) for rel in this('relation') if rel.type == 'partnership' if (rel.subject == person) & (rel.object == partner)) filters = list(query.filters) expected_rel_type = this('relation').type == 'partnership' with context(UNPROXIFING_CONTEXT): self.assertIn(expected_rel_type, filters) self.assertIs(2, len(filters))
def inner(self, *args): from types import GeneratorType from xotl.ql.interfaces import IQueryObject from xotl.ql.core import these query, rest = args[0], args[1:] if rest: raise SyntaxError('%s only accepts query expressions or query objects') if isinstance(query, GeneratorType): query = these(query) elif not IQueryObject.providedBy(query): raise SyntaxError('%s only accepts query expressions or query objects') plan = naive_translation(query, vm=dict(self.vm)) return func(result for result in plan())
def test_theres_a_token_for_partnership(self): from itertools import izip query = these( (person, partner) for person, partner in izip(this('person'), this('partner')) for rel in this('relation') if rel.type == 'partnership' if (rel.subject == person) & (rel.object == partner)) tokens = list(query.tokens) person, partner, rel = this('person'), this('partner'), this( 'relation') with context(UNPROXIFING_CONTEXT): self.assertIs(3, len(tokens)) self.assertIn(rel, tokens) self.assertIn(person, tokens) self.assertIn(partner, tokens)
def test_most_basic_query(self): query = these(parent for parent in this('parent') if parent.age > 40) self.assertTrue(provides_any(query, IQueryObject)) (p, ) = query.selection token_expectation = p_expected = this('parent') filter_expectation = this('parent').age > 40 with context(UNPROXIFING_CONTEXT): self.assertEqual(p, p_expected) filters = query.filters self.assertEqual(1, len(filters)) self.assertIn(filter_expectation, filters) tokens = query.tokens self.assertEqual(1, len(tokens)) self.assertIn(token_expectation, tuple(tokens))
def test_cofind_tokens(self): from itertools import izip from xotl.ql.expressions import is_a from xotl.ql.translate import cofind_tokens @thesefy class Person(object): pass @thesefy class Partnership(object): pass query = these((person, partner) for person, partner in izip(Person, Person) for rel in Partnership if (rel.subject == person) & (rel.obj == partner)) filters = list(query.filters) person, partner = query.selection person_is_a_person = is_a(person, Person) partner_is_a_person = is_a(partner, Person) with context(UNPROXIFING_CONTEXT): self.assertNotEqual(person, partner) self.assertIn(person_is_a_person, filters) self.assertIn(partner_is_a_person, filters) filters.remove(person_is_a_person) filters.remove(partner_is_a_person) # left filter are is_a(rel, Partnership) and the explicit we see in # the query expression self.assertIs(2, len(filters)) rel_is_a = next(f for f in filters if f.operation == is_a) filters.remove(rel_is_a) # there are 4 named instances in the left filter # (rel.subject == person) & (rel.obj == partner) self.assertIs(4, len(list(cofind_tokens(filters[0]))))
def test_20121127_unnamed_this_leaked(self): query = these(parent for parent in this if parent.age > 30) term = query.filters[0].children[0] with context(UNPROXIFING_CONTEXT): self.assertEqual(unboxed(term).parent, query.tokens[0])
birthdate='1950-04-01', lives_in=cotorro) pedro = Person(name='Pedro Piñero', birthdate='1950-04-01', lives_in=cotorro) yade = Person(name='Yadenis Piñero Pérez', birthdate='1979-05-16', mother=denia, father=pedro, lives_in=lisa) manolito = Person(name='Manuel Vázquez Piñero', birthdate='2007-03-22', mother=yade, father=manu, lives_in=lisa) select_manus = these(who for who in Person if who.name.startswith('Manuel ')) select_aged_entities = these(who for who in Entity if who.age) # Three days after I (manu) wrote this query, I started to appear in the # results ;) select_old_entities = these(who for who in Entity if who.age > 34) class TestTranslatorTools(unittest.TestCase): def test_cofind_tokens(self): from itertools import izip from xotl.ql.expressions import is_a from xotl.ql.translate import cofind_tokens @thesefy class Person(object):