88import ast
99from six import string_types
1010from six .moves import builtins
11+ from numbers import Number
1112
1213from bpython import line as line_properties
14+ from bpython ._py3compat import py3
1315
1416class EvaluationError (Exception ):
1517 """Raised if an exception occurred in safe_eval."""
@@ -24,7 +26,7 @@ def safe_eval(expr, namespace):
2426 # raise
2527 raise EvaluationError
2628
27- # taken from Python 2 stdlib ast.literal_eval
29+
2830def simple_eval (node_or_string , namespace = None ):
2931 """
3032 Safely evaluate an expression node or a string containing a Python
@@ -34,6 +36,9 @@ def simple_eval(node_or_string, namespace=None):
3436 * variable names causing lookups in the passed in namespace or builtins
3537 * getitem calls using the [] syntax on objects of the types above
3638
39+ Like the Python 3 (and unlike the Python 2) literal_eval, unary and binary
40+ + and - operations are allowed on all builtin numeric types.
41+
3742 The optional namespace dict-like ought not to cause side effects on lookup
3843 """
3944 # Based heavily on stdlib ast.literal_eval
@@ -43,8 +48,13 @@ def simple_eval(node_or_string, namespace=None):
4348 node_or_string = ast .parse (node_or_string , mode = 'eval' )
4449 if isinstance (node_or_string , ast .Expression ):
4550 node_or_string = node_or_string .body
51+
52+ string_type_nodes = (ast .Str , ast .Bytes ) if py3 else (ast .Str ,)
53+ name_type_nodes = (ast .Name , ast .NameConstant ) if py3 else (ast .Name ,)
54+ numeric_types = (int , float , complex ) + (() if py3 else (long ,))
55+
4656 def _convert (node ):
47- if isinstance (node , ast . Str ):
57+ if isinstance (node , string_type_nodes ):
4858 return node .s
4959 elif isinstance (node , ast .Num ):
5060 return node .n
@@ -55,23 +65,41 @@ def _convert(node):
5565 elif isinstance (node , ast .Dict ):
5666 return dict ((_convert (k ), _convert (v )) for k , v
5767 in zip (node .keys , node .values ))
58- elif isinstance (node , ast .Name ):
68+
69+ # this is a deviation from literal_eval: we allow non-literals
70+ elif isinstance (node , name_type_nodes ):
5971 try :
6072 return namespace [node .id ]
6173 except KeyError :
62- return getattr (builtins , node .id )
74+ try :
75+ return getattr (builtins , node .id )
76+ except AttributeError :
77+ raise EvaluationError ("can't lookup %s" % node .id )
78+
79+ # unary + and - are allowed on any type
80+ elif isinstance (node , ast .UnaryOp ) and \
81+ isinstance (node .op , (ast .UAdd , ast .USub )):
82+ # ast.literal_eval does ast typechecks here, we use type checks
83+ operand = _convert (node .operand )
84+ if not type (operand ) in numeric_types :
85+ raise ValueError ("unary + and - only allowed on builtin nums" )
86+ if isinstance (node .op , ast .UAdd ):
87+ return + operand
88+ else :
89+ return - operand
6390 elif isinstance (node , ast .BinOp ) and \
64- isinstance (node .op , (ast .Add , ast .Sub )) and \
65- isinstance (node .right , ast .Num ) and \
66- isinstance (node .right .n , complex ) and \
67- isinstance (node .left , ast .Num ) and \
68- isinstance (node .left .n , (int , long , float )):
69- left = node .left .n
70- right = node .right .n
91+ isinstance (node .op , (ast .Add , ast .Sub )):
92+ # ast.literal_eval does ast typechecks here, we use type checks
93+ left = _convert (node .left )
94+ right = _convert (node .right )
95+ if not (type (left ) in numeric_types and type (right ) in numeric_types ):
96+ raise ValueError ("binary + and - only allowed on builtin nums" )
7197 if isinstance (node .op , ast .Add ):
7298 return left + right
7399 else :
74100 return left - right
101+
102+ # this is a deviation from literal_eval: we allow indexing
75103 elif isinstance (node , ast .Subscript ) and \
76104 isinstance (node .slice , ast .Index ):
77105 obj = _convert (node .value )
@@ -84,7 +112,10 @@ def _convert(node):
84112
85113def safe_getitem (obj , index ):
86114 if type (obj ) in (list , tuple , dict , bytes ) + string_types :
87- return obj [index ]
115+ try :
116+ return obj [index ]
117+ except (KeyError , IndexError ):
118+ raise EvaluationError ("can't lookup key %r on %r" % (index , obj ))
88119 raise ValueError ('unsafe to lookup on object of type %s' % (type (obj ), ))
89120
90121
@@ -141,5 +172,5 @@ def parse_trees(cursor_offset, line):
141172 raise EvaluationError ("Corresponding ASTs to right of cursor are invalid" )
142173 try :
143174 return simple_eval (largest_ast , namespace )
144- except ( ValueError , KeyError , IndexError , AttributeError ) :
175+ except ValueError :
145176 raise EvaluationError ("Could not safely evaluate" )
0 commit comments