cpython icon indicating copy to clipboard operation
cpython copied to clipboard

Flaky test `test_asyncio_repl_is_ok` in `test_repl`

Open colesbury opened this issue 1 year ago • 6 comments

The test fails because the running the asyncio repl exits with:

Fatal Python error: _enter_buffered_busy: could not acquire lock for <_io.BufferedWriter name='<stderr>'> at interpreter shutdown, possibly due to daemon threads

I'm not sure if this is just a flaky test (i.e, _enter_buffered_busy failures are expected), or if it's a bug in the underlying repl.

The exit code -6 means the process crashes due to an abort(), I think.

Example: https://github.com/python/cpython/actions/runs/9331095550/job/25685390386?pr=119908

Test Output
======================================================================
FAIL: test_asyncio_repl_is_ok (test.test_repl.TestInteractiveInterpreter.test_asyncio_repl_is_ok)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/work/cpython/cpython-ro-srcdir/Lib/test/test_repl.py", line 199, in test_asyncio_repl_is_ok
    assert_python_ok("-m", "asyncio")
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/home/runner/work/cpython/cpython-ro-srcdir/Lib/test/support/script_helper.py", line 180, in assert_python_ok
    return _assert_python(True, *args, **env_vars)
  File "/home/runner/work/cpython/cpython-ro-srcdir/Lib/test/support/script_helper.py", line 165, in _assert_python
    res.fail(cmd_line)
    ~~~~~~~~^^^^^^^^^^
  File "/home/runner/work/cpython/cpython-ro-srcdir/Lib/test/support/script_helper.py", line 75, in fail
    raise AssertionError("Process return code is %d\n"
    ...<13 lines>...
                            err))
AssertionError: Process return code is -6
command line: ['/home/runner/work/cpython/cpython-builddir/hypovenv/bin/python', '-X', 'faulthandler', '-I', '-m', 'asyncio']

stdout:
---

---

stderr:
---
asyncio REPL 3.14.0a0 (remotes/pull/119908/merge-dirty:43e023a, Jun  1 2024, 14:47:23) [GCC 11.4.0] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
Exception in thread Interactive thread:
Traceback (most recent call last):
  File "/home/runner/work/cpython/cpython-ro-srcdir/Lib/asyncio/__main__.py", line 109, in run
    raise OSError(errno.ENOTTY, "tty required", "stdin")
OSError: [Errno 25] tty required: 'stdin'

During handling of the above exception, another exception occurred:

exiting asyncio REPL...
Traceback (most recent call last):
Fatal Python error: _enter_buffered_busy: could not acquire lock for <_io.BufferedWriter name='<stderr>'> at interpreter shutdown, possibly due to daemon threads
Python runtime state: finalizing (tstate=0x000055910f31bbf0)

Current thread 0x00007fa49bcdb740 (most recent call first):
  <no Python frame>
---

----------------------------------------------------------------------
Ran 8 tests in 3.[354](https://github.com/python/cpython/actions/runs/9331095550/job/25685390386?pr=119908#step:22:355)s

FAILED (failures=1)
test test_repl failed

Linked PRs

  • gh-121341

colesbury avatar Jun 01 '24 14:06 colesbury

Maybe @ambv or @pablogsal has a clue?

gvanrossum avatar Jun 01 '24 15:06 gvanrossum

It's look related to the 2237946af0981c46dc7d3886477e425ccfb37f28

Eclips4 avatar Jun 01 '24 18:06 Eclips4

The REPL fails to start because of stdin is not a tty:

 stderr:
---
asyncio REPL 3.14.0a0 (remotes/pull/119908/merge-dirty:43e023a, Jun  1 2024, 14:47:23) [GCC 11.4.0] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
Exception in thread Interactive thread:
Traceback (most recent call last):
  File "/home/runner/work/cpython/cpython-ro-srcdir/Lib/asyncio/__main__.py", line 109, in run
    raise OSError(errno.ENOTTY, "tty required", "stdin")
OSError: [Errno 25] tty required: 'stdin'

I'm fixing that case to revert to the classic REPL in this scenario.

ambv avatar Jun 03 '24 12:06 ambv

I will need a better way to reproduce this. Inside asyncio/__main__.py the raised OSError in my code example is being handled by an except: block that indeed runs the old REPL in the case of a missing TTY. So there's nothing to fix there. I can force this path locally with nohup ./python.exe -m asyncio and it does what's expected.

So to see the exception bubble up as in the failing test, this must be a combination of this code running from a secondary daemon thread at interpreter shutdown.

ambv avatar Jun 04 '24 18:06 ambv

Can we skip it for now? I've seen it very often when when I running the test suite in "hunt refleaks" mode

Eclips4 avatar Jun 30 '24 18:06 Eclips4

When _enter_buffered_busy hangs, I also get a different error message if stdin is not a TTY: NameError: name 'exit_message' is not defined.

asyncio REPL 3.14.0a0 (heads/unicode_native-dirty:f3857d87958, Jul  1 2024, 17:40:44) [GCC 14.1.1 20240620 (Red Hat 14.1.1-6)] on linux
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
Exception in thread Interactive thread:
Traceback (most recent call last):
  File "/home/vstinner/python/main/Lib/asyncio/__main__.py", line 110, in run
    raise OSError(errno.ENOTTY, "tty required", "stdin")
OSError: [Errno 25] tty required: 'stdin'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/vstinner/python/main/Lib/threading.py", line 1039, in _bootstrap_inner
    self.run()
    ~~~~~~~~^^
exiting asyncio REPL...
  File "/home/vstinner/python/main/Lib/asyncio/__main__.py", line 120, in run
    console.interact(banner="", exitmsg=exit_message)
                                        ^^^^^^^^^^^^
NameError: name 'exit_message' is not defined
Fatal Python error: _enter_buffered_busy: could not acquire lock for <_io.BufferedWriter name='<stderr>'> at interpreter shutdown, possibly due to daemon threads
Python runtime state: finalizing (tstate=0x0000000000988b28)

Current thread 0x00007fab8fda4740 (most recent call first):
  <no Python frame>

@ambv added console.interact(banner="", exitmsg=exit_message) line in commit 2237946af0981c46dc7d3886477e425ccfb37f28 one month ago.

vstinner avatar Jul 02 '24 07:07 vstinner

Fixed by change https://github.com/python/cpython/commit/114389470ec3db457c589b3991b695258d23ce5a: I can no longer reproduce the bug.

vstinner avatar Jul 06 '24 23:07 vstinner