def _detect_class(self, query): '''Detects the class for top-level (i.e has no parent) token. Finds if there is any filter containing an ``is_instance(token, SomeClass)``. If SomeClass has an attribute `this_instances` and it returns an iterable, it is assumed it will yield all objects from this class. ''' token = self.token term = token.expression with context(UNPROXIFING_CONTEXT): parent = term.parent if not parent: from xotl.ql.expressions import is_instance, IExpressionTree def matches(node): with context(UNPROXIFING_CONTEXT): return (IExpressionTree.providedBy(node) and node.operation is is_instance and node.children[0] == term) from xotl.ql.translation import cotraverse_expression found = next(cotraverse_expression(*query.filters, accept=matches), None) if found: self._token_class = found.children[-1] else: self._token_class = None else: self._token_class = None
def test_cotraverse_expression(): from xoutil.compat import zip from xotl.ql.expressions import is_a 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)) filters = list(query.filters) person, partner = query.selection person_is_a_person = is_a(person, Person) partner_is_a_person = is_a(partner, Person) rel_token = query.tokens[-1] rel_subject = rel_token.expression.subject rel_obj = rel_token.expression.obj with context(UNPROXIFING_CONTEXT): assert person != partner assert person_is_a_person in filters assert partner_is_a_person in filters expected_terms_order = [person, partner, rel_token.expression, rel_subject, person, rel_obj, partner] assert expected_terms_order == list(cotraverse_expression(query)) assert UNPROXIFING_CONTEXT not in context
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_cotraverse_expression_reintroduction(): from xotl.ql.translation import cotraverse_expression expr1 = this.a + (this.b + this.c) # To make `+` association from right, # so that traversing gets a, b and then # c. expr2 = this.d + this.e expr3 = this.f * this.g routine = cotraverse_expression(expr1, expr2) result = [] result.append(next(routine)) result.append(routine.send(expr3)) term = next(routine, None) while term: result.append(term) term = next(routine, None) expected = [this.a, this.b, this.c, this.d, this.e, this.f, this.g] with context(UNPROXIFING_CONTEXT): assert result == expected assert UNPROXIFING_CONTEXT not in context