pure_eval icon indicating copy to clipboard operation
pure_eval copied to clipboard

0.2.3: not ready to to be used with python 3.9 list, tuple (lower case)

Open kloczek opened this issue 11 months ago • 1 comments

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 ================================================================================

kloczek avatar Nov 09 '24 16:11 kloczek