reval builtin
Tim Peters
tim_one at email.msn.com
Wed Apr 14 21:36:38 EDT 1999
[Neil Schemenauer]
> It would be nice to have an "reval" builtin that would only evaluate
> literals. That would make building things like config files safe and
> easy. I have two ideas on how to accomplish this:
>
> 1. Create a new start symbol "reval_input" in the Grammar/Grammar
> and add a "builtin_reval" function in Python/bltinmodule.c. ...
>
> 2. Use something like lex and yacc to create an extension module
> that does the Right Thing(TM). ...
>
> Perhaps some guru can explain an easy way to accomplish this and same me
> some time.
The /F-bot already did -- this is Python, and nothing is *that* hard <wink>.
Even builtins are looked up dynamically at runtime, so all that's required
is to take away eval's normal context. As a one-liner:
def reval(string):
return eval(string, {"__builtins__": {}})
This tells eval to use the dict {"__builtins__": {}} for both local and
global lookups. "__builtins__" is the only key, so is the only name that
*can* be looked up successfully. It's a semi-magical key that Python
accesses internally when all other attempts to resolve a name fail, and in
this case its value is an empty dict, so that makes Python's last-resort
name-lookup fail too.
>>> reval('1+2')
3
>>> reval('int("3")')
Traceback (innermost last):
File "<pyshell#11>", line 1, in ?
reval('int("3")')
File "<pyshell#9>", line 2, in reval
return eval(string, {"__builtins__": {}})
File "<string>", line 0, in ?
NameError: int
>>>
Caution: it does not work to pass eval an empty dict:
>>> eval('int("3")', {})
3
>>>
That may be obscure <snort>. The reason is this:
>>> empty = {}
>>> eval('int("3")', empty)
3
>>> empty.keys()
['__builtins__']
>>>
That is, if the dict you pass to eval (or exec) doesn't have a
"__builtins__" key, Python inserts one for you, with the same value as the
current module's __builtins__. This is to make the normal use of eval/exec
easier. So to stop Python cold, you have to supply your own "__builtins__"
key.
If you're determined to allow only literals (I don't see any harm in
allowing e.g. 1+3), probably easiest to feed the string to the std parser
module, then crawl over the AST looking for things to complain about.
syntactic-cleansing-ly y'rs - tim
More information about the Python-list
mailing list