1717"""Generic Python Expression Handler
1818"""
1919
20+ import symtable
21+
2022from .TALES import CompilerError
2123from sys import exc_info
2224
@@ -31,7 +33,8 @@ def __init__(self, name, expr, engine):
3133 self .expr = expr = expr .strip ().replace ('\n ' , ' ' )
3234 try :
3335 d = {}
34- exec ('def f():\n return %s\n ' % expr .strip (), d )
36+ self .f_code = 'def f():\n return %s\n ' % expr .strip ()
37+ exec (self .f_code , d )
3538 self ._f = d ['f' ]
3639 except :
3740 raise CompilerError (('Python expression error:\n '
@@ -40,17 +43,38 @@ def __init__(self, name, expr, engine):
4043
4144 def _get_used_names (self ):
4245 self ._f_varnames = vnames = []
43- for vname in self ._f . __code__ . co_names :
44- if vname [0 ] not in '$_' :
46+ for vname in self ._get_from_symtab () :
47+ if vname [0 ] not in '$_. ' :
4548 vnames .append (vname )
4649
50+ def _get_from_symtab (self ):
51+ """
52+ Get the variables used in the 'f' function.
53+ """
54+ variables = set ()
55+ table = symtable .symtable (self .f_code , "<string>" , "exec" )
56+ if table .has_children ():
57+ variables .update (self ._walk_children (table ))
58+ return variables
59+
60+ def _walk_children (self , sym ):
61+ """
62+ Get the variables at this level. Recurse to get them all.
63+ """
64+ variables = set ()
65+ for child in sym .get_children ():
66+ variables .update (set (child .get_identifiers ()))
67+ if child .has_children ():
68+ variables .update (self ._walk_children (child ))
69+ return variables
70+
4771 def _bind_used_names (self , econtext , _marker = []):
4872 # Bind template variables
4973 names = {'CONTEXTS' : econtext .contexts }
50- vars = econtext .vars
74+ variables = econtext .vars
5175 getType = econtext .getCompiler ().getTypes ().get
5276 for vname in self ._f_varnames :
53- val = vars .get (vname , _marker )
77+ val = variables .get (vname , _marker )
5478 if val is _marker :
5579 has = val = getType (vname )
5680 if has :
0 commit comments