Evaluate an expression node or a string containing only a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. Caution: A complex expression can over
(node_or_string)
| 48 | |
| 49 | |
| 50 | def literal_eval(node_or_string): |
| 51 | """ |
| 52 | Evaluate an expression node or a string containing only a Python |
| 53 | expression. The string or node provided may only consist of the following |
| 54 | Python literal structures: strings, bytes, numbers, tuples, lists, dicts, |
| 55 | sets, booleans, and None. |
| 56 | |
| 57 | Caution: A complex expression can overflow the C stack and cause a crash. |
| 58 | """ |
| 59 | if isinstance(node_or_string, str): |
| 60 | node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval') |
| 61 | if isinstance(node_or_string, Expression): |
| 62 | node_or_string = node_or_string.body |
| 63 | def _raise_malformed_node(node): |
| 64 | msg = "malformed node or string" |
| 65 | if lno := getattr(node, 'lineno', None): |
| 66 | msg += f' on line {lno}' |
| 67 | raise ValueError(msg + f': {node!r}') |
| 68 | def _convert_num(node): |
| 69 | if not isinstance(node, Constant) or type(node.value) not in (int, float, complex): |
| 70 | _raise_malformed_node(node) |
| 71 | return node.value |
| 72 | def _convert_signed_num(node): |
| 73 | if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)): |
| 74 | operand = _convert_num(node.operand) |
| 75 | if isinstance(node.op, UAdd): |
| 76 | return + operand |
| 77 | else: |
| 78 | return - operand |
| 79 | return _convert_num(node) |
| 80 | def _convert(node): |
| 81 | if isinstance(node, Constant): |
| 82 | return node.value |
| 83 | elif isinstance(node, Tuple): |
| 84 | return tuple(map(_convert, node.elts)) |
| 85 | elif isinstance(node, List): |
| 86 | return list(map(_convert, node.elts)) |
| 87 | elif isinstance(node, Set): |
| 88 | return set(map(_convert, node.elts)) |
| 89 | elif (isinstance(node, Call) and isinstance(node.func, Name) and |
| 90 | node.func.id == 'set' and node.args == node.keywords == []): |
| 91 | return set() |
| 92 | elif isinstance(node, Dict): |
| 93 | if len(node.keys) != len(node.values): |
| 94 | _raise_malformed_node(node) |
| 95 | return dict(zip(map(_convert, node.keys), |
| 96 | map(_convert, node.values))) |
| 97 | elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)): |
| 98 | left = _convert_signed_num(node.left) |
| 99 | right = _convert_num(node.right) |
| 100 | if isinstance(left, (int, float)) and isinstance(right, complex): |
| 101 | if isinstance(node.op, Add): |
| 102 | return left + right |
| 103 | else: |
| 104 | return left - right |
| 105 | return _convert_signed_num(node) |
| 106 | return _convert(node_or_string) |
| 107 |
no test coverage detected