Skip to content

Commit fbeb99d

Browse files
committed
ENH: initial commit for adding Expr based terms for pytables support
1 parent 995ad57 commit fbeb99d

File tree

6 files changed

+388
-316
lines changed

6 files changed

+388
-316
lines changed

pandas/computation/engines.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,4 @@ def evaluate(self):
7575
def _evaluate(self, env):
7676
pass
7777

78-
79-
_engines = {'numexpr': NumExprEngine, 'python': PythonEngine}
78+
_engines = {'numexpr': NumExprEngine, 'python': PythonEngine }

pandas/computation/expr.py

+30-19
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from pandas.computation.ops import _arith_ops_syms, _unary_ops_syms
99
from pandas.computation.ops import Term, Constant
1010

11-
1211
class Scope(object):
1312
__slots__ = 'globals', 'locals'
1413

@@ -21,7 +20,6 @@ def __init__(self, gbls=None, lcls=None, frame_level=1):
2120
finally:
2221
del frame
2322

24-
2523
class ExprParserError(Exception):
2624
pass
2725

@@ -49,53 +47,66 @@ def __init__(self, env):
4947
lambda node, unary_op=unary_op: partial(UnaryOp, unary_op))
5048
self.env = env
5149

52-
def visit(self, node):
50+
def generic_visit(self, node, **kwargs):
51+
"""Called if no explicit visitor function exists for a node."""
52+
for field, value in iter_fields(node):
53+
if isinstance(value, list):
54+
for item in value:
55+
if isinstance(item, AST):
56+
self.visit(item, **kwargs)
57+
elif isinstance(value, AST):
58+
self.visit(value, **kwargs)
59+
60+
def visit(self, node, **kwargs):
5361
if not (isinstance(node, ast.AST) or isinstance(node, basestring)):
5462
raise TypeError('"node" must be an AST node or a string, you'
5563
' passed a(n) {0}'.format(node.__class__))
5664
if isinstance(node, basestring):
5765
node = ast.fix_missing_locations(ast.parse(node))
58-
return super(ExprVisitor, self).visit(node)
5966

60-
def visit_Module(self, node):
67+
method = 'visit_' + node.__class__.__name__
68+
visitor = getattr(self, method, self.generic_visit)
69+
return visitor(node, **kwargs)
70+
71+
def visit_Module(self, node, **kwargs):
6172
if len(node.body) != 1:
6273
raise ExprParserError('only a single expression is allowed')
6374

6475
expr = node.body[0]
6576
if not isinstance(expr, ast.Expr):
6677
raise SyntaxError('only expressions are allowed')
6778

68-
return self.visit(expr)
79+
return self.visit(expr, **kwargs)
6980

70-
def visit_Expr(self, node):
71-
return self.visit(node.value)
81+
def visit_Expr(self, node, **kwargs):
82+
return self.visit(node.value, **kwargs)
7283

73-
def visit_BinOp(self, node):
84+
def visit_BinOp(self, node, **kwargs):
7485
op = self.visit(node.op)
75-
left = self.visit(node.left)
76-
right = self.visit(node.right)
86+
left = self.visit(node.left,side='left')
87+
right = self.visit(node.right,side='right')
7788
return op(left, right)
7889

79-
def visit_UnaryOp(self, node):
90+
def visit_UnaryOp(self, node, **kwargs):
8091
if isinstance(node.op, ast.Not):
8192
raise NotImplementedError("not operator not yet supported")
8293
op = self.visit(node.op)
8394
return op(self.visit(node.operand))
8495

85-
def visit_Name(self, node):
96+
def visit_Name(self, node, **kwargs):
8697
return Term(node.id, self.env)
8798

88-
def visit_Num(self, node):
99+
def visit_Num(self, node, **kwargs):
89100
return Constant(node.n, self.env)
90101

91-
def visit_Compare(self, node):
102+
def visit_Compare(self, node, **kwargs):
92103
ops = node.ops
93104
comps = node.comparators
94105
if len(ops) != 1:
95106
raise ExprParserError('chained comparisons not supported')
96-
return self.visit(ops[0])(self.visit(node.left), self.visit(comps[0]))
107+
return self.visit(ops[0])(self.visit(node.left,side='left'), self.visit(comps[0],side='right'))
97108

98-
def visit_Call(self, node):
109+
def visit_Call(self, node, **kwargs):
99110
if not isinstance(node.func, ast.Name):
100111
raise TypeError("Only named functions are supported")
101112

@@ -106,10 +117,10 @@ def visit_Call(self, node):
106117

107118
raise NotImplementedError("function calls not yet supported")
108119

109-
def visit_Attribute(self, node):
120+
def visit_Attribute(self, node, **kwargs):
110121
raise NotImplementedError("attribute access is not yet supported")
111122

112-
def visit_BoolOp(self, node):
123+
def visit_BoolOp(self, node, **kwargs):
113124
raise NotImplementedError("boolean operators are not yet supported")
114125

115126

pandas/computation/ops.py

+28-28
Original file line numberDiff line numberDiff line change
@@ -24,43 +24,43 @@ class BinaryOperatorError(OperatorError):
2424
pass
2525

2626

27-
def _resolve_name(env, key):
28-
res = env.locals.get(key, env.globals.get(key))
29-
30-
if res is None:
31-
if not isinstance(key, basestring):
32-
return key
33-
34-
raise NameError('name {0!r} is not defined'.format(key))
35-
36-
return res
37-
38-
39-
def _update_name(env, key, value):
40-
if isinstance(key, basestring):
41-
try:
42-
del env.locals[key]
43-
env.locals[key] = value
44-
except KeyError:
45-
try:
46-
del env.globals[key]
47-
env.globals[key] = value
48-
except KeyError:
49-
raise NameError('{0!r} is undefined'.format(key))
50-
51-
5227
class Term(StringMixin):
53-
def __init__(self, name, env):
28+
def __init__(self, name, env, side=None):
5429
self.name = name
55-
self.value = _resolve_name(env, name)
5630
self.env = env
31+
self.side = side
32+
self.value = self._resolve_name()
5733
self.type = type(self.value)
5834

5935
def __unicode__(self):
6036
return com.pprint_thing(self.name)
6137

38+
def _resolve_name(self):
39+
env = self.env
40+
key = self.name
41+
res = env.locals.get(key, env.globals.get(key))
42+
43+
if res is None:
44+
if not isinstance(key, basestring):
45+
return key
46+
47+
raise NameError('name {0!r} is not defined'.format(key))
48+
return res
49+
6250
def update(self, value):
63-
_update_name(self.env, self.name, value)
51+
env = self.env
52+
key = self.name
53+
if isinstance(key, basestring):
54+
try:
55+
del env.locals[key]
56+
env.locals[key] = value
57+
except KeyError:
58+
try:
59+
del env.globals[key]
60+
env.globals[key] = value
61+
except KeyError:
62+
raise NameError('{0!r} is undefined'.format(key))
63+
6464
self.value = value
6565

6666
@property

0 commit comments

Comments
 (0)