python-pexpect fails to build with Python 3.13.0b1. =================================== FAILURES =================================== _______________________ PerformanceTestCase.test_100000 ________________________ self = <tests.test_performance.PerformanceTestCase testMethod=test_100000> def test_100000(self): if platform.python_implementation() == 'PyPy': raise unittest.SkipTest("This test fails on PyPy because of REPL differences") print() start_time = time.time() self.plain_range (100000) print("100000 calls to plain_range:", (time.time() - start_time)) start_time = time.time() > self.window_range(100000) tests/test_performance.py:93: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_performance.py:61: in window_range self.assertEqual(e.expect([b'inquisition', '%d' % n], searchwindowsize=20), 1) pexpect/spawnbase.py:354: in expect return self.expect_list(compiled_pattern_list, pexpect/spawnbase.py:383: in expect_list return exp.expect_loop(timeout) pexpect/expect.py:181: in expect_loop return self.timeout(e) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <pexpect.expect.Expecter object at 0x7f09369af380> err = TIMEOUT('Timeout exceeded.') def timeout(self, err=None): spawn = self.spawn spawn.before = spawn._before.getvalue() spawn.after = TIMEOUT index = self.searcher.timeout_index if index >= 0: spawn.match = TIMEOUT spawn.match_index = index return index else: spawn.match = None spawn.match_index = None msg = str(spawn) msg += '\nsearcher: %s' % self.searcher if err is not None: msg = str(err) + '\n' + msg exc = TIMEOUT(msg) exc.__cause__ = None # in Python 3.x we can use "raise exc from None" > raise exc E pexpect.exceptions.TIMEOUT: Timeout exceeded. E <pexpect.pty_spawn.spawn object at 0x7f0936ad7b10> E command: /usr/bin/python3 E args: ['/usr/bin/python3'] E buffer (last 100 chars): b';35m>>> \x1b[0m\x1b[4D\x1b[4C' E before (last 100 chars): b'99993\r\n99994\r\n99995\r\n99996\r\n99997\r\n99998\r\n99999\r\n100000\r\n\x1b[?2004h\x1b[?1h\x1b=\x1b[1A\n\x1b[1;35m>>> \x1b[0m\x1b[4D\x1b[4C' E after: <class 'pexpect.exceptions.TIMEOUT'> E match: None E match_index: None E exitstatus: None E flag_eof: False E pid: 596 E child_fd: 18 E closed: False E timeout: 100 E delimiter: <class 'pexpect.exceptions.EOF'> E logfile: None E logfile_read: None E logfile_send: None E maxread: 2000 E ignorecase: False E searchwindowsize: None E delaybeforesend: 0.05 E delayafterclose: 0.1 E delayafterterminate: 0.1 E searcher: searcher_re: E 0: re.compile(b'inquisition') E 1: re.compile(b'100000') pexpect/expect.py:144: TIMEOUT ----------------------------- Captured stdout call ----------------------------- tests.test_performance.PerformanceTestCase.test_100000 100000 calls to plain_range: 0.9722907543182373 ____________________ REPLWrapTestCase.test_no_change_prompt ____________________ self = <tests.test_replwrap.REPLWrapTestCase testMethod=test_no_change_prompt> def test_no_change_prompt(self): if platform.python_implementation() == 'PyPy': raise unittest.SkipTest(skip_pypy) child = pexpect.spawn(sys.executable, echo=False, timeout=5, encoding='utf-8') # prompt_change=None should mean no prompt change py = replwrap.REPLWrapper(child, u">>> ", prompt_change=None, continuation_prompt=u"... ") assert py.prompt == ">>> " res = py.run_command("for a in range(3): print(a)\n") > assert res.strip().splitlines() == ['0', '1', '2'] E AssertionError: assert ['\x1b[0m\x1b...5D\x1b[1;35m'] == ['0', '1', '2'] E At index 0 diff: '\x1b[0m\x1b[4D\x1b[4C\x1b[4D\x1b[1;35m\x1b[0mf\x1b[5D\x1b[5C\x1b[5D\x1b[1;35m' != '0' E Right contains 2 more items, first extra item: '1' E Full diff: E - ['0', '1', '2'] E + ['\x1b[0m\x1b[4D\x1b[4C\x1b[4D\x1b[1;35m\x1b[0mf\x1b[5D\x1b[5C\x1b[5D\x1b[1;35m'] /builddir/build/BUILD/pexpect-4.9.0/tests/test_replwrap.py:134: AssertionError _________________________ REPLWrapTestCase.test_python _________________________ self = <tests.test_replwrap.REPLWrapTestCase testMethod=test_python> def test_python(self): if platform.python_implementation() == 'PyPy': raise unittest.SkipTest(skip_pypy) p = replwrap.python() res = p.run_command('4+7') > assert res.strip() == '11' E assert "\x1b[41D\x1b...ys; sys.ps1='" == '11' E - 11 E + >>> import sys; sys.ps1=' /builddir/build/BUILD/pexpect-4.9.0/tests/test_replwrap.py:118: AssertionError =========================== short test summary info ============================ FAILED tests/test_performance.py::PerformanceTestCase::test_100000 - pexpect.exceptions.TIMEOUT: Timeout exceeded. <pexpect.pty_spawn.spawn object at 0x7f0936ad7b10> command: /usr/bin/python3 args: ['/usr/bin/python3'] buffer (last 100 chars): b';35m>>> \x1b[0m\x1b[4D\x1b[4C' before (last 100 chars): b'99993\r\n99994\r\n99995\r\n99996\r\n99997\r\n99998\r\n99999\r\n100000\r\n\x1b[?2004h\x1b[?1h\x1b=\x1b[1A\n\x1b[1;35m>>> \x1b[0m\x1b[4D\x1b[4C' after: <class 'pexpect.exceptions.TIMEOUT'> match: None match_index: None exitstatus: None flag_eof: False pid: 596 child_fd: 18 closed: False timeout: 100 delimiter: <class 'pexpect.exceptions.EOF'> logfile: None logfile_read: None logfile_send: None maxread: 2000 ignorecase: False searchwindowsize: None delaybeforesend: 0.05 delayafterclose: 0.1 delayafterterminate: 0.1 searcher: searcher_re: 0: re.compile(b'inquisition') 1: re.compile(b'100000') FAILED tests/test_replwrap.py::REPLWrapTestCase::test_no_change_prompt - AssertionError: assert ['\x1b[0m\x1b...5D\x1b[1;35m'] == ['0', '1', '2'] At index 0 diff: '\x1b[0m\x1b[4D\x1b[4C\x1b[4D\x1b[1;35m\x1b[0mf\x1b[5D\x1b[5C\x1b[5D\x1b[1;35m' != '0' Right contains 2 more items, first extra item: '1' Full diff: - ['0', '1', '2'] + ['\x1b[0m\x1b[4D\x1b[4C\x1b[4D\x1b[1;35m\x1b[0mf\x1b[5D\x1b[5C\x1b[5D\x1b[1;35m'] FAILED tests/test_replwrap.py::REPLWrapTestCase::test_python - assert "\x1b[41D\x1b...ys; sys.ps1='" == '11' - 11 + >>> import sys; sys.ps1=' ============ 3 failed, 254 passed, 85 warnings in 339.06s (0:05:39) ============ https://docs.python.org/3.13/whatsnew/3.13.html For the build logs, see: https://copr-be.cloud.fedoraproject.org/results/@python/python3.13/fedora-rawhide-x86_64/07495770-python-pexpect/ For all our attempts to build python-pexpect with Python 3.13, see: https://copr.fedorainfracloud.org/coprs/g/python/python3.13/package/python-pexpect/ Testing and mass rebuild of packages is happening in copr. You can follow these instructions to test locally in mock if your package builds with Python 3.13: https://copr.fedorainfracloud.org/coprs/g/python/python3.13/ Let us know here if you have any questions. Python 3.13 is planned to be included in Fedora 41. To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.13. A build failure prevents us from testing all dependent packages (transitive [Build]Requires), so if this package is required a lot, it's important for us to get it fixed soon. We'd appreciate help from the people who know this package best, but if you don't want to work on this now, let us know so we can try to work around it on our side.
Confirmed, I can reproduce the second two failures and see what the problem is - it seems Python 3.13 introduced color support in the interactive interpreter, which causes some problems. Not entirely sure how to fix yet but doesn't seem too bad.
Perhaps setting NO_COLOR=1 in %check might help. Anyway, this is blocking pytest-xdist so we need to solve this problem this week.
This makes one of the failures go away: diff --git a/tests/test_replwrap.py b/tests/test_replwrap.py index ddafa5d..5ac782a 100644 --- a/tests/test_replwrap.py +++ b/tests/test_replwrap.py @@ -124,7 +124,7 @@ class REPLWrapTestCase(unittest.TestCase): if platform.python_implementation() == 'PyPy': raise unittest.SkipTest(skip_pypy) - child = pexpect.spawn(sys.executable, echo=False, timeout=5, encoding='utf-8') + child = pexpect.spawn(sys.executable, echo=False, timeout=5, encoding='utf-8', env={'NO_COLOR': '1'}) # prompt_change=None should mean no prompt change py = replwrap.REPLWrapper(child, u">>> ", prompt_change=None, continuation_prompt=u"... ")
This helps with the other test: diff --git a/pexpect/replwrap.py b/pexpect/replwrap.py index 08dbd5e..c8714a2 100644 --- a/pexpect/replwrap.py +++ b/pexpect/replwrap.py @@ -35,7 +35,7 @@ class REPLWrapper(object): continuation_prompt=PEXPECT_CONTINUATION_PROMPT, extra_init_cmd=None): if isinstance(cmd_or_spawn, basestring): - self.child = pexpect.spawn(cmd_or_spawn, echo=False, encoding='utf-8') + self.child = pexpect.spawn(cmd_or_spawn, echo=False, encoding='utf-8', env={'NO_COLOR': '1'}) else: self.child = cmd_or_spawn if self.child.echo:
https://github.com/pexpect/pexpect/pull/794
https://src.fedoraproject.org/rpms/python-pexpect/pull-request/11
It seems test_100000 from test_performance.py is just flaky in copr. The test has a hardcoded timeout and we might need to increase it a bit but there is no simple way (rather than a sed/patch).