Safely evaluate an expression node or a string containing a Python expression without triggering any user code. The string or node provided may only consist of: * the following Python literal structures: strings, numbers, tuples, lists, dicts, and sets * variable names
(node_or_string, namespace=None)
| 60 | # * indexing syntax is allowed |
| 61 | # * evaluates tuple() and list() |
| 62 | def simple_eval(node_or_string, namespace=None): |
| 63 | """ |
| 64 | Safely evaluate an expression node or a string containing a Python |
| 65 | expression without triggering any user code. |
| 66 | |
| 67 | The string or node provided may only consist of: |
| 68 | * the following Python literal structures: strings, numbers, tuples, |
| 69 | lists, dicts, and sets |
| 70 | * variable names causing lookups in the passed in namespace or builtins |
| 71 | * getitem calls using the [] syntax on objects of the types above |
| 72 | |
| 73 | Like Python 3's literal_eval, unary and binary + and - operations are |
| 74 | allowed on all builtin numeric types. |
| 75 | |
| 76 | The optional namespace dict-like ought not to cause side effects on lookup. |
| 77 | """ |
| 78 | if namespace is None: |
| 79 | namespace = {} |
| 80 | if isinstance(node_or_string, str): |
| 81 | node_or_string = ast.parse(node_or_string, mode="eval") |
| 82 | if isinstance(node_or_string, ast.Expression): |
| 83 | node_or_string = node_or_string.body |
| 84 | |
| 85 | def _convert(node): |
| 86 | if isinstance(node, ast.Constant): |
| 87 | return node.value |
| 88 | elif isinstance(node, ast.Tuple): |
| 89 | return tuple(map(_convert, node.elts)) |
| 90 | elif isinstance(node, ast.List): |
| 91 | return list(map(_convert, node.elts)) |
| 92 | elif isinstance(node, ast.Dict): |
| 93 | return { |
| 94 | _convert(k): _convert(v) for k, v in zip(node.keys, node.values) |
| 95 | } |
| 96 | elif isinstance(node, ast.Set): |
| 97 | return set(map(_convert, node.elts)) |
| 98 | elif ( |
| 99 | isinstance(node, ast.Call) |
| 100 | and isinstance(node.func, ast.Name) |
| 101 | and node.func.id == "set" |
| 102 | and node.args == node.keywords == [] |
| 103 | ): |
| 104 | return set() |
| 105 | |
| 106 | # this is a deviation from literal_eval: we evaluate tuple() and list() |
| 107 | elif ( |
| 108 | isinstance(node, ast.Call) |
| 109 | and isinstance(node.func, ast.Name) |
| 110 | and node.func.id == "tuple" |
| 111 | and node.args == node.keywords == [] |
| 112 | ): |
| 113 | return tuple() |
| 114 | elif ( |
| 115 | isinstance(node, ast.Call) |
| 116 | and isinstance(node.func, ast.Name) |
| 117 | and node.func.id == "list" |
| 118 | and node.args == node.keywords == [] |
| 119 | ): |