Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remaining test issues with Python 3.13.0b1: not ki_protected, pathlib.Path.resolve siganture #3004

Closed
hroncok opened this issue May 24, 2024 · 6 comments · Fixed by #3005
Closed

Comments

@hroncok
Copy link
Contributor

hroncok commented May 24, 2024

Hello. After #2959 I still see the following test failures with Python 3.13.0b1:

[trio (master)]$ python3.13 -m venv venv
[trio (master)]$ . venv/bin/activate
(venv) [trio (master)]$ pip install . pytest
...
(venv) [trio (master)]$ pytest --pyargs trio --skip-optional-imports
============================= test session starts ==============================
platform linux -- Python 3.13.0b1, pytest-8.2.1, pluggy-1.5.0
rootdir: .../trio
configfile: pyproject.toml
collected 698 items / 4 skipped

venv/lib64/python3.13/site-packages/trio/_core/_tests/test_asyncgen.py . [  0%]
......                                                                   [  1%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_exceptiongroup_gc.py . [  1%]
.                                                                        [  1%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_guest_mode.py . [  1%]
.............                                                            [  3%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_instrumentation.py . [  3%]
.......                                                                  [  4%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_io.py ....... [  5%]
.....................                                                    [  8%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_ki.py .F..s.. [  9%]
F...                                                                     [ 10%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_local.py .... [ 10%]
                                                                         [ 10%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_mock_clock.py . [ 10%]
....s                                                                    [ 11%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_parking_lot.py . [ 11%]
...                                                                      [ 12%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_run.py ...... [ 12%]
..........................s............................................. [ 23%]
.....................................................................    [ 33%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_thread_cache.py . [ 33%]
.ss..                                                                    [ 33%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_tutil.py .    [ 34%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_unbounded_queue.py . [ 34%]
....                                                                     [ 34%]
venv/lib64/python3.13/site-packages/trio/_core/_tests/test_windows.py ss [ 35%]
sssss                                                                    [ 35%]
venv/lib64/python3.13/site-packages/trio/_tests/test_abc.py ...          [ 36%]
venv/lib64/python3.13/site-packages/trio/_tests/test_channel.py ........ [ 37%]
.....                                                                    [ 38%]
venv/lib64/python3.13/site-packages/trio/_tests/test_contextvars.py ...  [ 38%]
venv/lib64/python3.13/site-packages/trio/_tests/test_deprecate.py ...... [ 39%]
......                                                                   [ 40%]
venv/lib64/python3.13/site-packages/trio/_tests/test_deprecate_strict_exception_groups_false.py . [ 40%]
..                                                                       [ 40%]
venv/lib64/python3.13/site-packages/trio/_tests/test_exports.py .sssssss [ 41%]
sssssssssssssssssssssssssssssssssss..                                    [ 47%]
venv/lib64/python3.13/site-packages/trio/_tests/test_fakenet.py ....s... [ 48%]
.                                                                        [ 48%]
venv/lib64/python3.13/site-packages/trio/_tests/test_file_io.py ........ [ 49%]
.........                                                                [ 50%]
venv/lib64/python3.13/site-packages/trio/_tests/test_highlevel_generic.py . [ 51%]
.                                                                        [ 51%]
venv/lib64/python3.13/site-packages/trio/_tests/test_highlevel_open_tcp_listeners.py . [ 51%]
...................                                                      [ 54%]
venv/lib64/python3.13/site-packages/trio/_tests/test_highlevel_open_tcp_stream.py . [ 54%]
......................                                                   [ 57%]
venv/lib64/python3.13/site-packages/trio/_tests/test_highlevel_open_unix_stream.py . [ 57%]
....s                                                                    [ 58%]
venv/lib64/python3.13/site-packages/trio/_tests/test_highlevel_serve_listeners.py . [ 58%]
...                                                                      [ 58%]
venv/lib64/python3.13/site-packages/trio/_tests/test_highlevel_socket.py . [ 58%]
......                                                                   [ 59%]
venv/lib64/python3.13/site-packages/trio/_tests/test_path.py .s......... [ 61%]
.......F....................                                             [ 65%]
venv/lib64/python3.13/site-packages/trio/_tests/test_repl.py .........   [ 66%]
venv/lib64/python3.13/site-packages/trio/_tests/test_scheduler_determinism.py . [ 66%]
.                                                                        [ 66%]
venv/lib64/python3.13/site-packages/trio/_tests/test_signals.py ........ [ 68%]
                                                                         [ 68%]
venv/lib64/python3.13/site-packages/trio/_tests/test_socket.py .......s. [ 69%]
.........................                                                [ 72%]
venv/lib64/python3.13/site-packages/trio/_tests/test_subprocess.py ..... [ 73%]
...............s........                                                 [ 77%]
venv/lib64/python3.13/site-packages/trio/_tests/test_sync.py ........... [ 78%]
.......................                                                  [ 81%]
venv/lib64/python3.13/site-packages/trio/_tests/test_testing.py ........ [ 83%]
...........                                                              [ 84%]
venv/lib64/python3.13/site-packages/trio/_tests/test_testing_raisesgroup.py . [ 84%]
.............                                                            [ 86%]
venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py F.F..... [ 87%]
.....................................s....                               [ 93%]
venv/lib64/python3.13/site-packages/trio/_tests/test_timeouts.py sss.    [ 94%]
venv/lib64/python3.13/site-packages/trio/_tests/test_tracing.py ..       [ 94%]
venv/lib64/python3.13/site-packages/trio/_tests/test_unix_pipes.py ..... [ 95%]
......                                                                   [ 96%]
venv/lib64/python3.13/site-packages/trio/_tests/test_util.py .........   [ 97%]
venv/lib64/python3.13/site-packages/trio/_tests/test_wait_for_object.py s [ 97%]
sss                                                                      [ 98%]
venv/lib64/python3.13/site-packages/trio/_tests/test_windows_pipes.py ss [ 98%]
ssss                                                                     [ 98%]
venv/lib64/python3.13/site-packages/trio/_tests/tools/test_mypy_annotate.py . [ 99%]
......                                                                   [100%]

=================================== FAILURES ===================================
_______________________________ test_ki_enabled ________________________________

    async def test_ki_enabled() -> None:
        # Regular tasks aren't KI-protected
        assert not _core.currently_ki_protected()
    
        # Low-level call-soon callbacks are KI-protected
        token = _core.current_trio_token()
        record = []
    
        def check() -> None:
            record.append(_core.currently_ki_protected())
    
        token.run_sync_soon(check)
        await wait_all_tasks_blocked()
        assert record == [True]
    
        @_core.enable_ki_protection
        def protected() -> None:
            assert _core.currently_ki_protected()
            unprotected()
    
        @_core.disable_ki_protection
        def unprotected() -> None:
            assert not _core.currently_ki_protected()
    
>       protected()

venv/lib64/python3.13/site-packages/trio/_core/_tests/test_ki.py:62: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
venv/lib64/python3.13/site-packages/trio/_core/_ki.py:182: in wrapper
    return fn(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @_core.enable_ki_protection
    def protected() -> None:
>       assert _core.currently_ki_protected()
E       assert False
E        +  where False = <function currently_ki_protected at 0x7fd1217f2340>()
E        +    where <function currently_ki_protected at 0x7fd1217f2340> = _core.currently_ki_protected

venv/lib64/python3.13/site-packages/trio/_core/_tests/test_ki.py:55: AssertionError
___________________________ test_ki_disabled_in_del ____________________________

    def test_ki_disabled_in_del() -> None:
        def nestedfunction() -> bool:
            return _core.currently_ki_protected()
    
        def __del__() -> None:
            assert _core.currently_ki_protected()
            assert nestedfunction()
    
        @_core.disable_ki_protection
        def outerfunction() -> None:
            assert not _core.currently_ki_protected()
            assert not nestedfunction()
            __del__()
    
        __del__()
>       outerfunction()

venv/lib64/python3.13/site-packages/trio/_core/_tests/test_ki.py:255: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
venv/lib64/python3.13/site-packages/trio/_core/_ki.py:182: in wrapper
    return fn(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    @_core.disable_ki_protection
    def outerfunction() -> None:
>       assert not _core.currently_ki_protected()
E       assert not True
E        +  where True = <function currently_ki_protected at 0x7fd1217f2340>()
E        +    where <function currently_ki_protected at 0x7fd1217f2340> = _core.currently_ki_protected

venv/lib64/python3.13/site-packages/trio/_core/_tests/test_ki.py:250: AssertionError
_________________________ test_async_method_signature __________________________

path = trio.Path('/tmp/pytest-of-churchyard/pytest-6/test_async_method_signature0/test')

    async def test_async_method_signature(path: trio.Path) -> None:
        # use `resolve` as a representative of wrapped methods
    
        assert path.resolve.__name__ == "resolve"
        assert path.resolve.__qualname__ == "Path.resolve"
    
        assert path.resolve.__doc__ is not None
>       assert "pathlib.Path.resolve" in path.resolve.__doc__
E       AssertionError: assert 'pathlib.Path.resolve' in 'Like :meth:`~pathlib._local.Path.resolve`, but async.\n\nMake the path absolute, resolving all symlinks on the way and also\nnormalizing it.\n'
E        +  where 'Like :meth:`~pathlib._local.Path.resolve`, but async.\n\nMake the path absolute, resolving all symlinks on the way and also\nnormalizing it.\n' = <bound method Path.resolve of trio.Path('/tmp/pytest-of-churchyard/pytest-6/test_async_method_signature0/test')>.__doc__
E        +    where <bound method Path.resolve of trio.Path('/tmp/pytest-of-churchyard/pytest-6/test_async_method_signature0/test')> = trio.Path('/tmp/pytest-of-churchyard/pytest-6/test_async_method_signature0/test').resolve

venv/lib64/python3.13/site-packages/trio/_tests/test_path.py:125: AssertionError
____________________________ test_do_in_trio_thread ____________________________

    async def test_do_in_trio_thread() -> None:
        trio_thread = threading.current_thread()
    
        async def check_case(
            do_in_trio_thread: Callable[..., threading.Thread],
            fn: Callable[..., T | Awaitable[T]],
            expected: tuple[str, T],
            trio_token: _core.TrioToken | None = None,
        ) -> None:
            record: RecordType = []
    
            def threadfn() -> None:
                try:
                    record.append(("start", threading.current_thread()))
                    x = do_in_trio_thread(fn, record, trio_token=trio_token)
                    record.append(("got", x))
                except BaseException as exc:
                    print(exc)
                    record.append(("error", type(exc)))
    
            child_thread = threading.Thread(target=threadfn, daemon=True)
            child_thread.start()
            while child_thread.is_alive():
                print("yawn")
                await sleep(0.01)
            assert record == [("start", child_thread), ("f", trio_thread), expected]
    
        token = _core.current_trio_token()
    
        def f1(record: RecordType) -> int:
            assert not _core.currently_ki_protected()
            record.append(("f", threading.current_thread()))
            return 2
    
>       await check_case(from_thread_run_sync, f1, ("got", 2), trio_token=token)

venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py:94: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

do_in_trio_thread = <function run_sync at 0x7fd1216ed3a0>
fn = <function test_do_in_trio_thread.<locals>.f1 at 0x7fd11f520c20>
expected = ('got', 2)
trio_token = TrioToken(_reentry_queue=EntryQueue(queue=deque([]), idempotent_queue={}, wakeup=<trio._core._wakeup_socketpair.WakeupSocketpair object at 0x7fd11eaf3890>, done=True, lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7fd11f4ed2c0>))

    async def check_case(
        do_in_trio_thread: Callable[..., threading.Thread],
        fn: Callable[..., T | Awaitable[T]],
        expected: tuple[str, T],
        trio_token: _core.TrioToken | None = None,
    ) -> None:
        record: RecordType = []
    
        def threadfn() -> None:
            try:
                record.append(("start", threading.current_thread()))
                x = do_in_trio_thread(fn, record, trio_token=trio_token)
                record.append(("got", x))
            except BaseException as exc:
                print(exc)
                record.append(("error", type(exc)))
    
        child_thread = threading.Thread(target=threadfn, daemon=True)
        child_thread.start()
        while child_thread.is_alive():
            print("yawn")
            await sleep(0.01)
>       assert record == [("start", child_thread), ("f", trio_thread), expected]
E       AssertionError: assert [('start', <T...rtionError'>)] == [('start', <T...), ('got', 2)]
E         
E         At index 1 diff: ('error', <class 'AssertionError'>) != ('f', <_MainThread(MainThread, started 140536435861312)>)
E         Right contains one more item: ('got', 2)
E         Use -v to get more diff

venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py:85: AssertionError
----------------------------- Captured stdout call -----------------------------
yawn
assert not True
 +  where True = <function currently_ki_protected at 0x7fd1217f2340>()
 +    where <function currently_ki_protected at 0x7fd1217f2340> = _core.currently_ki_protected
__________________________ test_run_in_trio_thread_ki __________________________

    def test_run_in_trio_thread_ki() -> None:
        # if we get a control-C during a run_in_trio_thread, then it propagates
        # back to the caller (slick!)
        record = set()
    
        async def check_run_in_trio_thread() -> None:
            token = _core.current_trio_token()
    
            def trio_thread_fn() -> None:
                print("in Trio thread")
                assert not _core.currently_ki_protected()
                print("ki_self")
                try:
                    ki_self()
                finally:
                    import sys
    
                    print("finally", sys.exc_info())
    
            async def trio_thread_afn() -> None:
                trio_thread_fn()
    
            def external_thread_fn() -> None:
                try:
                    print("running")
                    from_thread_run_sync(trio_thread_fn, trio_token=token)
                except KeyboardInterrupt:
                    print("ok1")
                    record.add("ok1")
                try:
                    from_thread_run(trio_thread_afn, trio_token=token)
                except KeyboardInterrupt:
                    print("ok2")
                    record.add("ok2")
    
            thread = threading.Thread(target=external_thread_fn)
            thread.start()
            print("waiting")
            while thread.is_alive():
                await sleep(0.01)
            print("waited, joining")
            thread.join()
            print("done")
    
        _core.run(check_run_in_trio_thread)
>       assert record == {"ok1", "ok2"}
E       AssertionError: assert set() == {'ok1', 'ok2'}
E         
E         Extra items in the right set:
E         'ok2'
E         'ok1'
E         Use -v to get more diff

venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py:176: AssertionError

During handling of the above exception, another exception occurred:

cls = <class '_pytest.runner.CallInfo'>
func = <function call_and_report.<locals>.<lambda> at 0x7fd11f690a40>
when = 'call'
reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)

    @classmethod
    def from_call(
        cls,
        func: Callable[[], TResult],
        when: Literal["collect", "setup", "call", "teardown"],
        reraise: Optional[
            Union[Type[BaseException], Tuple[Type[BaseException], ...]]
        ] = None,
    ) -> "CallInfo[TResult]":
        """Call func, wrapping the result in a CallInfo.
    
        :param func:
            The function to call. Called without arguments.
        :param when:
            The phase in which the function is called.
        :param reraise:
            Exception or exceptions that shall propagate if raised by the
            function, instead of being wrapped in the CallInfo.
        """
        excinfo = None
        start = timing.time()
        precise_start = timing.perf_counter()
        try:
>           result: Optional[TResult] = func()

venv/lib64/python3.13/site-packages/_pytest/runner.py:341: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
venv/lib64/python3.13/site-packages/_pytest/runner.py:241: in <lambda>
    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise
venv/lib64/python3.13/site-packages/pluggy/_hooks.py:513: in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
venv/lib64/python3.13/site-packages/pluggy/_manager.py:120: in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
venv/lib64/python3.13/site-packages/_pytest/threadexception.py:87: in pytest_runtest_call
    yield from thread_exception_runtest_hook()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

    def thread_exception_runtest_hook() -> Generator[None, None, None]:
        with catch_threading_exception() as cm:
            try:
                yield
            finally:
                if cm.args:
                    thread_name = (
                        "<unknown>" if cm.args.thread is None else cm.args.thread.name
                    )
                    msg = f"Exception in thread {thread_name}\n\n"
                    msg += "".join(
                        traceback.format_exception(
                            cm.args.exc_type,
                            cm.args.exc_value,
                            cm.args.exc_traceback,
                        )
                    )
>                   warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg))
E                   pytest.PytestUnhandledThreadExceptionWarning: Exception in thread Thread-3 (external_thread_fn)
E                   
E                   Traceback (most recent call last):
E                     File "/usr/lib64/python3.13/threading.py", line 1039, in _bootstrap_inner
E                       self.run()
E                       ~~~~~~~~^^
E                     File "/usr/lib64/python3.13/threading.py", line 990, in run
E                       self._target(*self._args, **self._kwargs)
E                       ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                     File ".../trio/venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py", line 156, in external_thread_fn
E                       from_thread_run_sync(trio_thread_fn, trio_token=token)
E                       ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                     File ".../trio/venv/lib64/python3.13/site-packages/trio/_threads.py", line 632, in from_thread_run_sync
E                       return _send_message_to_trio(trio_token, RunSync(fn, args))
E                     File ".../trio/venv/lib64/python3.13/site-packages/trio/_threads.py", line 550, in _send_message_to_trio
E                       return message_to_trio.queue.get().unwrap()
E                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
E                     File ".../trio/venv/lib64/python3.13/site-packages/outcome/_impl.py", line 213, in unwrap
E                       raise captured_error
E                     File ".../trio/venv/lib64/python3.13/site-packages/trio/_core/_ki.py", line 182, in wrapper
E                       return fn(*args, **kwargs)
E                     File ".../trio/venv/lib64/python3.13/site-packages/trio/_threads.py", line 217, in unprotected_fn
E                       ret = self.context.run(self.fn, *self.args)
E                     File ".../trio/venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py", line 141, in trio_thread_fn
E                       assert not _core.currently_ki_protected()
E                   AssertionError: assert not True
E                    +  where True = <function currently_ki_protected at 0x7fd1217f2340>()
E                    +    where <function currently_ki_protected at 0x7fd1217f2340> = _core.currently_ki_protected

venv/lib64/python3.13/site-packages/_pytest/threadexception.py:77: PytestUnhandledThreadExceptionWarning
----------------------------- Captured stdout call -----------------------------
runningwaiting

in Trio thread
waited, joining
done
=========================== short test summary info ============================
FAILED venv/lib64/python3.13/site-packages/trio/_core/_tests/test_ki.py::test_ki_enabled
FAILED venv/lib64/python3.13/site-packages/trio/_core/_tests/test_ki.py::test_ki_disabled_in_del
FAILED venv/lib64/python3.13/site-packages/trio/_tests/test_path.py::test_async_method_signature
FAILED venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py::test_do_in_trio_thread
FAILED venv/lib64/python3.13/site-packages/trio/_tests/test_threads.py::test_run_in_trio_thread_ki
================== 5 failed, 620 passed, 77 skipped in 3.29s ===================

@hroncok hroncok closed this as completed May 24, 2024
@hroncok hroncok changed the title Remaining test issues with Python Remaining test issues with Python 3.13.0b1 May 24, 2024
@hroncok hroncok changed the title Remaining test issues with Python 3.13.0b1 Remaining test issues with Python 3.13.0b1: not ki_protected, pathlib.Path.resolve siganture May 24, 2024
@hroncok hroncok reopened this May 24, 2024
@hroncok
Copy link
Contributor Author

hroncok commented May 24, 2024

E       AssertionError: assert 'pathlib.Path.resolve' in 'Like :meth:`~pathlib._local.Path.resolve`, but async.\n\nMake the path absolute, resolving all symlinks on the way and also\nnormalizing it.\n'

This failure is easy to understand for me.

The rest, not so much.

@A5rocks
Copy link
Contributor

A5rocks commented May 24, 2024

Interesting, I don't remember the KI changes in the alpha! Maybe worth bisecting to figure out what exactly changed?

@hroncok
Copy link
Contributor Author

hroncok commented May 24, 2024

Let me restest with a6... 625 passed, 77 skipped in 9.85s

Working on git bisest ...

@A5rocks
Copy link
Contributor

A5rocks commented May 24, 2024

I bisected and KI seems to be failing due to PEP 667 (specifically python/cpython#115153). Which kind of makes sense because we stuff KI protection metadata in weird function places, but I'm still surprised.

@hroncok
Copy link
Contributor Author

hroncok commented May 24, 2024

The Pathlib module name thing is python/cpython@d8d9491

@A5rocks
Copy link
Contributor

A5rocks commented May 24, 2024

OK, so KI is cause this no longer works: Before:

>>> import sys
>>> def g():
...   print(sys._getframe(1).f_locals)
...
>>> def f():
...   locals()["name"] = True
...   g()
...
>>> f()
{'name': True}
>>> exit()

Now:

>>> import sys
>>> def g():
...   print(sys._getframe(1).f_locals)
...
>>> def f():
...   locals()["name"] = True
...   g()
...
>>> f()
{}
>>> exit()

This is documented so we just need to fix this. I think one way would be to assign to sys._getframe().f_locals instead of locals().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants