Last active
February 21, 2016 06:15
-
-
Save keturn/9dba29c7d0b4e00863fe to your computer and use it in GitHub Desktop.
Can we force something like Cypher syntax in to Python? In the tradition of [Sugared DOM](https://gist.github.com/neilj/1532562) and [plumbum](https://pypi.python.org/pypi/plumbum).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
"""THIS IS PROBABLY NOT A GOOD IDEA. | |
""" | |
def test_cases(): | |
cases = [ | |
(N(), "()"), | |
(E, "[]"), | |
(E[:], "[]"), | |
(N('Person'), "(:Person)"), | |
(E[:'Person'], "[:Person]"), | |
(N() - E[:], "()-[]"), | |
(E[:] - N(), "[]-()"), | |
(N('Person')--N('Club'), "(:Person)--(:Club)"), | |
(E[:'MemberOf'] > N('Club'), "[:MemberOf]->(:Club)"), | |
(N('Person') - E[:'MemberOf'] - N('Club'), "(:Person)-[:MemberOf]-(:Club)"), | |
(N('Person') - E[:'MemberOf'] > N('Club'), "(:Person)-[:MemberOf]->(:Club)"), | |
(N('Person') < E[:'HasMember'], "(:Person)<-[:HasMember]"), | |
(N('Person') < E[:'HasMember'] - N('Club'), "(:Person)<-[:HasMember]-(:Club)") | |
] | |
return cases | |
class N(object): | |
def __init__(self, *labels): | |
self.labels = labels | |
def __sub__(self, other): | |
return Path(self, other) | |
def __neg__(self): | |
return self | |
def __lt__(self, other): | |
return Path(self, other.as_direction(Edge.LEFT)) | |
def __unicode__(self): | |
if self.labels: | |
label = ':' + self.labels[0] | |
else: | |
label = '' | |
return u"(%(label)s)" % dict( | |
label=label, | |
) | |
class Edge(object): | |
direction = None | |
RIGHT = "RIGHT" | |
LEFT = "LEFT" | |
def __init__(self, *labels): | |
self.labels = labels | |
def __sub__(self, other): | |
return Path(self, other) | |
def __gt__(self, other): | |
new = self.as_direction(self.RIGHT) | |
return Path(new, other) | |
def as_direction(self, direction): | |
new = self.__class__(*self.labels) | |
new.direction = direction | |
return new | |
def __unicode__(self): | |
if self.labels: | |
label = ':' + self.labels[0] | |
else: | |
label = '' | |
return u"[%(label)s]" % dict( | |
label=label | |
) | |
class EdgeFactory(object): | |
def __getitem__(self, item): | |
if item.stop: | |
edge = Edge(item.stop) | |
else: | |
edge = Edge() | |
return edge | |
def __unicode__(self): | |
return unicode(Edge()) | |
class Path(object): | |
edge_separators = { | |
Edge.LEFT: '<-', | |
Edge.RIGHT: '->', | |
None: '-' | |
} | |
def __init__(self, *elements): | |
self.elements = elements | |
def __sub__(self, other): | |
return self.__class__(*(self.elements + (other,))) | |
def __gt__(self, other): | |
lead_elements, rightmost = self.elements[:-1], self.elements[-1] | |
tail = rightmost.__gt__(other) | |
return Path(*(lead_elements + tail.elements)) | |
def as_direction(self, direction): | |
if direction == Edge.LEFT: | |
left_edge, tail = self.elements[0], self.elements[1:] | |
left_edge = left_edge.as_direction(direction) | |
return self.__class__(left_edge, *tail) | |
raise NotImplementedError(direction) | |
def __iter__(self): | |
for element in self.elements: | |
if isinstance(element, Path): | |
for subpath_element in element: | |
yield subpath_element | |
else: | |
yield element | |
def __unicode__(self): | |
elements = iter(self) | |
left_element = next(elements) | |
parts = [left_element] | |
for right_element in elements: | |
if isinstance(left_element, N) and isinstance(right_element, N): | |
separator = u'--' | |
elif isinstance(left_element, Edge) and isinstance(right_element, N): | |
if left_element.direction == Edge.RIGHT: | |
separator = self.edge_separators[Edge.RIGHT] | |
else: | |
separator = '-' | |
elif isinstance(left_element, N) and isinstance(right_element, Edge): | |
if right_element.direction == Edge.LEFT: | |
separator = self.edge_separators[Edge.LEFT] | |
else: | |
separator = '-' | |
else: | |
separator = u'-' | |
parts.append(separator) | |
parts.append(right_element) | |
left_element = right_element | |
return u"".join(unicode(p) for p in parts) | |
E = EdgeFactory() | |
def run_tests(): | |
for val, expected in test_cases(): | |
assert unicode(val) == expected, u"%s != %s" % (unicode(val), expected) | |
print expected | |
if __name__ == '__main__': | |
run_tests() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I just realized, Python doesn't have an
->
operator, but it does have>>