| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b0951cd commit c16c2f2
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,8 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | 6 | """ | |
| 7 | 7 | ||
| 8 | - from ast import * | ||
| 8 | + import ast | ||
| 9 | 9 | from six import string_types | |
| 10 | + from six.moves import builtins | ||
| 10 | 11 | ||
| 11 | 12 | from bpython import line as line_properties | |
| 12 | 13 | ||
@@ -23,6 +24,7 @@ def safe_eval(expr, namespace): | |||
| 23 | 24 | # raise | |
| 24 | 25 | raise EvaluationError | |
| 25 | 26 | ||
| 27 | + # taken from Python 2 stdlib ast.literal_eval | ||
| 26 | 28 | def simple_eval(node_or_string, namespace=None): | |
| 27 | 29 | """ | |
| 28 | 30 | Safely evaluate an expression node or a string containing a Python | |
@@ -37,43 +39,44 @@ def simple_eval(node_or_string, namespace=None): | |||
| 37 | 39 | ||
| 38 | 40 | The optional namespace dict-like ought not to cause side effects on lookup | |
| 39 | 41 | """ | |
| 42 | + # Based heavily on stdlib ast.literal_eval | ||
| 40 | 43 | if namespace is None: | |
| 41 | 44 | namespace = {} | |
| 42 | 45 | if isinstance(node_or_string, string_types): | |
| 43 | - node_or_string = parse(node_or_string, mode='eval') | ||
| 44 | - if isinstance(node_or_string, Expression): | ||
| 46 | + node_or_string = ast.parse(node_or_string, mode='eval') | ||
| 47 | + if isinstance(node_or_string, ast.Expression): | ||
| 45 | 48 | node_or_string = node_or_string.body | |
| 46 | 49 | def _convert(node): | |
| 47 | - if isinstance(node, Str): | ||
| 50 | + if isinstance(node, ast.Str): | ||
| 48 | 51 | return node.s | |
| 49 | - elif isinstance(node, Num): | ||
| 52 | + elif isinstance(node, ast.Num): | ||
| 50 | 53 | return node.n | |
| 51 | - elif isinstance(node, Tuple): | ||
| 54 | + elif isinstance(node, ast.Tuple): | ||
| 52 | 55 | return tuple(map(_convert, node.elts)) | |
| 53 | - elif isinstance(node, List): | ||
| 56 | + elif isinstance(node, ast.List): | ||
| 54 | 57 | return list(map(_convert, node.elts)) | |
| 55 | - elif isinstance(node, Dict): | ||
| 58 | + elif isinstance(node, ast.Dict): | ||
| 56 | 59 | return dict((_convert(k), _convert(v)) for k, v | |
| 57 | 60 | in zip(node.keys, node.values)) | |
| 58 | - elif isinstance(node, Name): | ||
| 61 | + elif isinstance(node, ast.Name): | ||
| 59 | 62 | try: | |
| 60 | 63 | return namespace[node.id] | |
| 61 | 64 | except KeyError: | |
| 62 | - return __builtins__[node.id] | ||
| 63 | - elif isinstance(node, BinOp) and \ | ||
| 64 | - isinstance(node.op, (Add, Sub)) and \ | ||
| 65 | - isinstance(node.right, Num) and \ | ||
| 65 | + return getattr(builtins, node.id) | ||
| 66 | + elif isinstance(node, ast.BinOp) and \ | ||
| 67 | + isinstance(node.op, (ast.Add, ast.Sub)) and \ | ||
| 68 | + isinstance(node.right, ast.Num) and \ | ||
| 66 | 69 | isinstance(node.right.n, complex) and \ | |
| 67 | - isinstance(node.left, Num) and \ | ||
| 70 | + isinstance(node.left, ast.Num) and \ | ||
| 68 | 71 | isinstance(node.left.n, (int, long, float)): | |
| 69 | 72 | left = node.left.n | |
| 70 | 73 | right = node.right.n | |
| 71 | - if isinstance(node.op, Add): | ||
| 74 | + if isinstance(node.op, ast.Add): | ||
| 72 | 75 | return left + right | |
| 73 | 76 | else: | |
| 74 | 77 | return left - right | |
| 75 | - elif isinstance(node, Subscript) and \ | ||
| 76 | - isinstance(node.slice, Index): | ||
| 78 | + elif isinstance(node, ast.Subscript) and \ | ||
| 79 | + isinstance(node.slice, ast.Index): | ||
| 77 | 80 | obj = _convert(node.value) | |
| 78 | 81 | index = _convert(node.slice.value) | |
| 79 | 82 | return safe_getitem(obj, index) | |
@@ -90,16 +93,16 @@ def safe_getitem(obj, index): | |||
| 90 | 93 | ||
| 91 | 94 | def find_attribute_with_name(node, name): | |
| 92 | 95 | """Based on ast.NodeVisitor""" | |
| 93 | - if isinstance(node, Attribute) and node.attr == name: | ||
| 96 | + if isinstance(node, ast.Attribute) and node.attr == name: | ||
| 94 | 97 | return node | |
| 95 | - for field, value in iter_fields(node): | ||
| 98 | + for field, value in ast.iter_fields(node): | ||
| 96 | 99 | if isinstance(value, list): | |
| 97 | 100 | for item in value: | |
| 98 | - if isinstance(item, AST): | ||
| 101 | + if isinstance(item, ast.AST): | ||
| 99 | 102 | r = find_attribute_with_name(item, name) | |
| 100 | 103 | if r: | |
| 101 | 104 | return r | |
| 102 | - elif isinstance(value, AST): | ||
| 105 | + elif isinstance(value, ast.AST): | ||
| 103 | 106 | r = find_attribute_with_name(value, name) | |
| 104 | 107 | if r: | |
| 105 | 108 | return r | |
@@ -126,8 +129,8 @@ def evaluate_current_expression(cursor_offset, line, namespace={}): | |||
| 126 | 129 | def parse_trees(cursor_offset, line): | |
| 127 | 130 | for i in range(cursor_offset-1, -1, -1): | |
| 128 | 131 | try: | |
| 129 | - ast = parse(line[i:cursor_offset]) | ||
| 130 | - yield ast | ||
| 132 | + tree = ast.parse(line[i:cursor_offset]) | ||
| 133 | + yield tree | ||
| 131 | 134 | except SyntaxError: | |
| 132 | 135 | continue | |
| 133 | 136 | ||
@@ -141,5 +144,5 @@ def parse_trees(cursor_offset, line): | |||
| 141 | 144 | raise EvaluationError("Corresponding ASTs to right of cursor are invalid") | |
| 142 | 145 | try: | |
| 143 | 146 | return simple_eval(largest_ast, namespace) | |
| 144 | - except (ValueError, KeyError, IndexError): | ||
| 147 | + except (ValueError, KeyError, IndexError, AttributeError): | ||
| 145 | 148 | raise EvaluationError("Could not safely evaluate") | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -65,7 +65,7 @@ def test_function_calls_raise(self): | |||
| 65 | 65 | simple_eval('1()') | |
| 66 | 66 | ||
| 67 | 67 | def test_nonexistant_names_raise(self): | |
| 68 | - with self.assertRaises(KeyError): | ||
| 68 | + with self.assertRaises((KeyError, AttributeError)): | ||
| 69 | 69 | simple_eval('a') | |
| 70 | 70 | ||
| 71 | 71 | class TestEvaluateCurrentExpression(unittest.TestCase): | |
| Back | FazBrowse Home | New Git URL |
0 commit comments