Skip to content

Instantly share code, notes, and snippets.

@dsblank
Created February 13, 2016 16:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsblank/25952531bba2b796922f to your computer and use it in GitHub Desktop.
Save dsblank/25952531bba2b796922f to your computer and use it in GitHub Desktop.
Demonstration of using Python AST to represent WHERE clause in Gramps
from meta.asttools import Visitor
from meta.decompiler import _ast, decompile_func
class ParseFilter(Visitor):
def visitName(self, node):
return node.id
def visitNum(self, node):
return node.n
def visitlong(self, node):
return node
def process_expression(self, expr):
if isinstance(expr, str):
# boolean
return [self.process_field(expr), "=", True]
elif len(expr) == 3:
# (field, op, value)
return [self.process_field(expr[0]), expr[1], expr[2]]
else:
# list of exprs
return [self.process_expression(exp) for
exp in expr]
def process_field(self, field):
if field.startswith(self.parameter + "."):
return field[len(self.parameter) + 1:]
else:
return field
def visitCall(self, node):
"""
Handle LIKE()
"""
return [self.process_field(self.visit(node.args[0])),
self.visit(node.func),
self.visit(node.args[1])]
def visitStr(self, node):
return node.s
def visitlist(self, list):
return [self.visit(node) for node in list]
def visitCompare(self, node):
return [self.process_field(self.visit(node.left)),
" ".join(self.visit(node.ops)),
self.visit(node.comparators[0])]
def visitAttribute(self, node):
return "%s.%s" % (self.visit(node.value), node.attr)
def get_boolean_op(self, node):
if isinstance(node, _ast.And):
return "AND"
elif isinstance(node, _ast.Or):
return "AND"
else:
raise Exception("invalid boolean")
def visitNotEq(self, node):
return "NE"
def visitBoolOp(self, node):
"""
BoolOp: boolean operator
"""
op = self.get_boolean_op(node.op)
values = list(node.values)
return [op, self.process_expression(
[self.visit(value) for value in values])]
def visitLambda(self, node):
self.parameter = self.visit(node.args)[0]
return self.visit(node.body)
def visitarguments(self, node):
return [self.visit(arg) for arg in node.args]
def visitarg(self, node):
return node.arg
##########
# Tests:
test1 = lambda family: (family.private and
family.mother_handle.gramps_id != "I0001")
test2 = lambda person: LIKE(person.gramps_id, "I0001")
tests = [test1, test2]
for test in tests:
ast_top = decompile_func(test)
parser = ParseFilter()
print(parser.visit(ast_top))
@dsblank
Copy link
Author

dsblank commented Feb 13, 2016

Outputs:

['AND', [['private', '=', True], ['mother_handle.gramps_id', 'NE', 'I0001']]]
['gramps_id', 'LIKE', 'I0001']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment