[Zope] Re: How to convert string to list without eval or exec
Evan Simpson
evan at 4-am.com
Wed Mar 10 17:15:41 EST 2004
Josef Meile wrote:
> I've seen this question here several times. Even I made it once
> long time ago. I could solve it easily because I didn't have a
> complex list.
Here's another way (in Python 2.3):
from compiler import parse, ast
class LiteralExEval(object):
"""
Evaluate a string as a single expression consisting of literals.
"""
def __call__(self, s):
tree = parse(s)
if tree.doc is not None:
if tree.node.nodes:
raise ValueError, 'Too many expressions.'
return tree.doc
nodes = tree.node.nodes
if len(nodes) < 1:
raise ValueError, 'Empty expression.'
if len(nodes) > 1:
raise ValueError, 'Too many expressions.'
node = nodes[0]
if node.__class__ <> ast.Discard:
raise ValueError, 'String is not an expression.'
return self.dispatch(node.getChildNodes()[0])
def dispatch(self, node):
kind = node.__class__.__name__
f = getattr(self, 'eval' + kind, None)
if f is None:
raise ValueError, '%s not allowed in expression.' % kind
return f(node)
def evalConst(self, node):
return node.value
def evalList(self, node):
e = self.dispatch
return [e(n) for n in node.nodes]
def evalTuple(self, node):
return tuple(self.evalList(node))
def evalDict(self, node):
e = self.dispatch
return dict([(e(k), e(v)) for k, v in node.items])
class NameExEval(LiteralExEval):
"""
Evaluate a string as a single expression that contains literals
and pre-defined names.
"""
def __init__(self,
names={'None': None, 'True': True, 'False': False},
**kwnames):
kwnames.update(names)
self._names = kwnames
def evalName(self, node):
try:
return self._names[node.name]
except KeyError:
raise ValueError, 'Undefined name %s' % `node.name`
class NameCallExEval(NameExEval):
"""
Evaluate a string as a single expression that contains literals
and pre-defined names, including callable names.
"""
def evalCallFunc(self, node):
if node.star_args or node.dstar_args:
raise ValueError, 'Function uses * or **-style arguments.'
e = self.dispatch
f = e(node.node)
args = []
kwargs = {}
for arg in node.args:
if arg.__class__ == ast.Keyword:
kwargs[arg.name] = e(arg.expr)
else:
args.append(e(arg))
return f(*args, **kwargs)
def _debug(Eval, s):
try:
return Eval(s)
except ValueError, e:
print '%s: %s' % (`s`, str(e))
if __name__ == '__main__':
le = LiteralExEval()
for s in (
"'string'",
"42",
"1, 0x2",
"['one', 0.2]",
"{1j: ()}",
):
print _debug(le, s)
ne = NameExEval(x=42)
for s in (
"None",
"[x, 2, True]",
"{False: (2, ['x']),}",
):
print _debug(ne, s)
nc = NameCallExEval(x='42', Int=int, Str=str)
for s in (
"Str(4)",
"Int(x)",
"Str(Int(x,),)",
):
print _debug(nc, s)
More information about the Zope
mailing list