pure_eval
pure_eval copied to clipboard
0.2.3: not ready to to be used with python 3.9 list, tuple (lower case)
Pyton 3.8 just has been EOSed month ago (https://endoflife.date/python) so I've been trying to use pyupgrade --py39-plus to check is current code ready to automatic upgrade. Looks like it is not ready to be automatically updated because it uses (upper case) List, Tuple. Please have look on https://flycoolman.com/coding/python/list-tuple-dict-vs-list-tuple-dict/
Here is the patch generated by `pypgrade --py39-plus`
--- a/pure_eval/core.py
+++ b/pure_eval/core.py
@@ -4,7 +4,8 @@
from collections import ChainMap, OrderedDict, deque
from contextlib import suppress
from types import FrameType
-from typing import Any, Tuple, Iterable, List, Mapping, Dict, Union, Set
+from typing import Any, Tuple, List, Dict, Union, Set
+from collections.abc import Iterable, Mapping
from pure_eval.my_getattr_static import getattr_static
from pure_eval.utils import (
@@ -308,7 +309,7 @@
def _handle_container(
self,
node: Union[ast.List, ast.Tuple, ast.Set, ast.Dict]
- ) -> Union[List, Tuple, Set, Dict]:
+ ) -> Union[list, tuple, set, dict]:
"""Handle container nodes, including List, Set, Tuple and Dict"""
if isinstance(node, ast.Dict):
elts = node.keys
@@ -342,7 +343,7 @@
except TypeError:
raise CannotEval
- def find_expressions(self, root: ast.AST) -> Iterable[Tuple[ast.expr, Any]]:
+ def find_expressions(self, root: ast.AST) -> Iterable[tuple[ast.expr, Any]]:
"""
Find all expressions in the given tree that can be safely evaluated.
This is a low level API, typically you will use `interesting_expressions_grouped`.
@@ -362,7 +363,7 @@
yield node, value
- def interesting_expressions_grouped(self, root: ast.AST) -> List[Tuple[List[ast.expr], Any]]:
+ def interesting_expressions_grouped(self, root: ast.AST) -> list[tuple[list[ast.expr], Any]]:
"""
Find all interesting expressions in the given tree that can be safely evaluated,
grouping equivalent nodes together.
@@ -422,7 +423,7 @@
return True
-def group_expressions(expressions: Iterable[Tuple[ast.expr, Any]]) -> List[Tuple[List[ast.expr], Any]]:
+def group_expressions(expressions: Iterable[tuple[ast.expr, Any]]) -> list[tuple[list[ast.expr], Any]]:
"""
Organise expression nodes and their values such that equivalent nodes are together.
Two nodes are considered equivalent if they have the same structure,
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -73,7 +73,7 @@
foo, Foo, Foo.method, foo.method
)
- check_eval("typing.List", typing, typing.List)
+ check_eval("typing.List", typing, list)
def test_eval_dict():
@@ -445,10 +445,7 @@
def subscript_item(node):
- if sys.version_info < (3, 9):
- return node.slice.value
- else:
- return node.slice
+ return node.slice
def test_evaluator_wrong_getitem():
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -91,7 +91,7 @@
def test_safe_name_direct():
assert safe_name(list) == "list"
- assert safe_name(typing.List) == "List"
+ assert safe_name(list) == "List"
assert safe_name(typing.Union) == "Union"
assert safe_name(typing.Optional) == "Optional"
assert safe_name(3) is None
With that patch pytest fails with
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pure-eval-0.2.3-2.fc37.x86_64/usr/lib64/python3.10/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pure-eval-0.2.3-2.fc37.x86_64/usr/lib/python3.10/site-packages
+ /usr/bin/pytest -ra -m 'not network'
==================================================================================== test session starts ====================================================================================
platform linux -- Python 3.10.14, pytest-8.2.2, pluggy-1.5.0
rootdir: /home/tkloczko/rpmbuild/BUILD/pure_eval-0.2.3
configfile: pyproject.toml
collected 47 items
tests/test_core.py ..F.............. [ 36%]
tests/test_getattr_static.py ....................... [ 85%]
tests/test_utils.py ....F.. [100%]
========================================================================================= FAILURES ==========================================================================================
______________________________________________________________________________________ test_eval_attrs ______________________________________________________________________________________
def test_eval_attrs():
class Foo:
bar = 9
@property
def prop(self):
return 0
def method(self):
pass
foo = Foo()
foo.spam = 44
check_eval(
"foo.bar + foo.spam + Foo.bar",
foo.bar, foo.spam, Foo.bar,
foo.bar + foo.spam,
foo.bar + foo.spam + Foo.bar,
foo, Foo
)
check_eval(
"Foo.spam + Foo.prop + foo.prop + foo.method() + Foo.method",
foo, Foo, Foo.method, foo.method
)
> check_eval("typing.List", typing, list)
tests/test_core.py:76:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
source = 'typing.List', total = True, expected_values = (<module 'typing' from '/usr/lib64/python3.10/typing.py'>, <class 'list'>)
frame = <frame at 0x5562edbec800, file '/home/tkloczko/rpmbuild/BUILD/pure_eval-0.2.3/tests/test_core.py', line 76, code test_eval_attrs>
evaluator = <pure_eval.core.Evaluator object at 0x7f9af4b84a30>
def check_eval(source, *expected_values, total=True):
frame = inspect.currentframe().f_back
evaluator = Evaluator.from_frame(frame)
root = ast.parse(source)
values = []
for node, value in evaluator.find_expressions(root):
expr = ast.Expression(body=node)
ast.copy_location(expr, node)
code = compile(expr, "<expr>", "eval")
expected = eval(code, frame.f_globals, frame.f_locals)
assert value == expected
values.append(value)
if total:
> assert value in expected_values
E AssertionError: assert typing.List in (<module 'typing' from '/usr/lib64/python3.10/typing.py'>, <class 'list'>)
tests/test_core.py:26: AssertionError
___________________________________________________________________________________ test_safe_name_direct ___________________________________________________________________________________
def test_safe_name_direct():
assert safe_name(list) == "list"
> assert safe_name(list) == "List"
E AssertionError: assert 'list' == 'List'
E
E - List
E ? ^
E + list
E ? ^
tests/test_utils.py:94: AssertionError
================================================================================== short test summary info ==================================================================================
FAILED tests/test_core.py::test_eval_attrs - AssertionError: assert typing.List in (<module 'typing' from '/usr/lib64/python3.10/typing.py'>, <class 'list'>)
FAILED tests/test_utils.py::test_safe_name_direct - AssertionError: assert 'list' == 'List'
=============================================================================== 2 failed, 45 passed in 3.11s ================================================================================