alexmojaki / executing

Get information about what a Python frame is currently doing, particularly the AST node being executed
MIT License
330 stars 32 forks source link

test_main.py::test_global_tester_calls fails with python 3.11.9 #88

Open heirecka opened 2 months ago

heirecka commented 2 months ago

test_global_tester_calls fails with python 3.11.9 here, it works fine with 3.12.5. Not sure what's the difference to github's CI, where it seems to pass, too.

❯ python3.11 -m pytest
=============================================================================== test session starts ===============================================================================
platform linux -- Python 3.11.9, pytest-8.1.1, pluggy-1.5.0
benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /home/heiko/Quelltexte/git-sources/python/executing
configfile: pyproject.toml
plugins: benchmark-4.0.0, expect-1.1.0, dependency-0.5.1, services-2.2.1, forked-1.6.0, pytest_httpserver-1.0.8, cov-4.1.0, flake8-1.1.1, regressions-2.5.0, datadir-1.5.0, pytest_param_files-0.6.0, sphinx_pytest-0.2.0, timeout-2.3.1, flaky-3.8.1, django-4.8.0, jaraco.test-5.4.0, mock-3.14.0, mypy-plugins-3.1.2, xdist-3.6.1, typeguard-4.3.0, xprocess-1.0.2, requests-mock-1.12.1, socket-0.7.0, pyfakefs-5.6.0, anyio-4.4.0, asyncio-0.23.8, subtests-0.13.1, Faker-28.0.0, trio-0.8.0, respx-0.21.1, hypothesis-6.111.0
asyncio: mode=Mode.STRICT
collected 208 items                                                                                                                                                               

tests/test_ipython.py ..                                                                                                                                                    [  0%]
tests/test_main.py ..................ss.................................................................................................................................... [ 74%]
..........................sssssssssssssssF                                                                                                                                  [ 94%]
tests/test_pytest.py ............                                                                                                                                           [100%]

==================================================================================== FAILURES =====================================================================================
____________________________________________________________________________ test_global_tester_calls _____________________________________________________________________________

    def test_global_tester_calls():
        # tester calls should be tested at global scope
>       from . import global_tester_calls

tests/test_main.py:1547: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
<frozen importlib._bootstrap>:1176: in _find_and_load
    ???
<frozen importlib._bootstrap>:1147: in _find_and_load_unlocked
    ???
<frozen importlib._bootstrap>:690: in _load_unlocked
    ???
/usr/host/lib/python3.11/site-packages/_pytest/assertion/rewrite.py:178: in exec_module
    exec(co, module.__dict__)
tests/global_tester_calls.py:5: in <module>
    assert tester([1, 2, 3]) == [1, 2, 3]
tests/utils.py:54: in __call__
    ex = self.get_executing(inspect.currentframe().f_back)
tests/utils.py:42: in get_executing
    return Source.executing(frame)
executing/executing.py:273: in executing
    node_finder = NodeFinder(frame, stmts, tree, lasti, source)
executing/_position_node_finder.py:164: in __init__
    self.known_issues(self.result, instruction)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <executing._position_node_finder.PositionNodeFinder object at 0x7f50d9371010>, node = <ast.Assert object at 0x7f50d937b340>
instruction = Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=0, end_col_offset=37))

    def known_issues(self, node: EnhancedAST, instruction: dis.Instruction) -> None:
        if instruction.opname in ("COMPARE_OP", "IS_OP", "CONTAINS_OP") and isinstance(
            node, types_cmp_issue
        ):
            if isinstance(node, types_cmp_issue_fix):
                # this is a workaround for https://github.com/python/cpython/issues/95921
                # we can fix cases with only on comparison inside the test condition
                #
                # we can not fix cases like:
                # if a<b<c and d<e<f: pass
                # if (a<b<c)!=d!=e: pass
                # because we don't know which comparison caused the problem

                comparisons = [
                    n
                    for n in ast.walk(node.test) # type: ignore[attr-defined]
                    if isinstance(n, ast.Compare) and len(n.ops) > 1
                ]

                assert_(comparisons, "expected at least one comparison")

                if len(comparisons) == 1:
                    node = self.result = cast(EnhancedAST, comparisons[0])
                else:
                    raise KnownIssue(
                        "multiple chain comparison inside %s can not be fixed" % (node)
                    )

            else:
                # Comprehension and generators get not fixed for now.
                raise KnownIssue("chain comparison inside %s can not be fixed" % (node))

        if (
            sys.version_info[:3] == (3, 11, 1)
            and isinstance(node, ast.Compare)
            and instruction.opname == "CALL"
            and any(isinstance(n, ast.Assert) for n in node_and_parents(node))
        ):
            raise KnownIssue(
                "known bug in 3.11.1 https://github.com/python/cpython/issues/95921"
            )

        if isinstance(node, ast.Assert):
            # pytest assigns the position of the assertion to all expressions of the rewritten assertion.
            # All the rewritten expressions get mapped to ast.Assert, which is the wrong ast-node.
            # We don't report this wrong result.
>           raise KnownIssue("assert")
E           executing._exceptions.KnownIssue: assert

executing/_position_node_finder.py:293: KnownIssue
================================================================================ warnings summary =================================================================================
tests/test_main.py::test_small_samples[4851dc1b626a95e97dbe0c53f96099d165b755dd1bd552c6ca771f7bca6d30f5.py]
  /home/heiko/Quelltexte/git-sources/python/executing/tests/small_samples/4851dc1b626a95e97dbe0c53f96099d165b755dd1bd552c6ca771f7bca6d30f5.py:16: SyntaxWarning: "is" with a literal. Did you mean "=="?
    if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in 1 is 1 is not 1:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
============================================================================= short test summary info =============================================================================
FAILED tests/test_main.py::test_global_tester_calls - executing._exceptions.KnownIssue: assert
============================================================== 1 failed, 190 passed, 17 skipped, 1 warning in 6.09s ===============================================================
15r10nk commented 2 months ago

I can not reproduce your issue.

❯ python -m pytest
================================================================================================ test session starts ================================================================================================
platform linux -- Python 3.11.9, pytest-8.1.1, pluggy-1.5.0
rootdir: /home/frank/projects/executing
configfile: pyproject.toml
collected 208 items

tests/test_ipython.py ..                                                                                                                                                                                      [  0%]
tests/test_main.py ..................ss..............................................................................................................................................................ssssssss [ 90%]
sssssss.                                                                                                                                                                                                      [ 94%]
tests/test_pytest.py ............                                                                                                                                                                             [100%]

================================================================================================= warnings summary ==================================================================================================
tests/test_main.py::test_small_samples[4851dc1b626a95e97dbe0c53f96099d165b755dd1bd552c6ca771f7bca6d30f5.py]
  /home/frank/projects/executing/tests/small_samples/4851dc1b626a95e97dbe0c53f96099d165b755dd1bd552c6ca771f7bca6d30f5.py:16: SyntaxWarning: "is" with a literal. Did you mean "=="?
    if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in 1 is 1 is not 1:

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
==================================================================================== 191 passed, 17 skipped, 1 warning in 7.59s =====================================================================================

One reason might be that some of your used plugins performs ast-rewriting or something else which causes this problem.

heirecka commented 2 months ago

Indeed PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 makes the test pass.

15r10nk commented 2 months ago

You can try to find the specific plugin which causes the problems, but we might not be able to solve the issue if the reason is some modified ast.