From dbda02e85a3b2a38b83c5238ae779ef35b910047 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 23 Jul 2026 10:44:26 +0300 Subject: [PATCH] gh-139445: Skip pyrepl tests if the terminal is not supported (GH-154497) They were only skipped if TERM was unset or "dumb", but pyrepl also needs the terminal to have several capabilities. (cherry picked from commit 7745710bec7f6de899e97d6f87528035e8977d85) Co-authored-by: Serhiy Storchaka Co-authored-by: Claude Opus 4.8 --- Lib/test/test_pyrepl/test_pyrepl.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index 4240a3c3174959..04a7a1b7f56751 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -13,7 +13,7 @@ import tempfile from functools import partial from pkgutil import ModuleInfo -from unittest import TestCase, skipUnless, skipIf, SkipTest +from unittest import TestCase, skipUnless, SkipTest from unittest.mock import Mock, patch import warnings from test.support import ( @@ -37,6 +37,7 @@ code_to_events, ) from _colorize import ANSIColors, get_theme +from _pyrepl import terminfo from _pyrepl.console import Event from _pyrepl.completing_reader import stripcolor from _pyrepl._module_completer import ( @@ -1998,8 +1999,20 @@ def test_dumb_terminal_exits_cleanly(self): self.assertNotIn("Traceback", output) +def supports_pyrepl(): + # pyrepl falls back to the basic REPL if the terminal lacks any of the + # capabilities which UnixConsole requires. This covers an unset or + # "dumb" TERM as well, they are resolved to the "dumb" capabilities. + try: + info = terminfo.TermInfo(None) + except Exception: + return False + return all(info.get(cap) is not None + for cap in ("bel", "clear", "cup", "el")) + + @skipUnless(pty, "requires pty") -@skipIf((os.environ.get("TERM") or "dumb") == "dumb", "can't use pyrepl in dumb terminal") +@skipUnless(supports_pyrepl(), "can't use pyrepl in this terminal") class TestMain(ReplTestCase): def setUp(self): # Cleanup from PYTHON* variables to isolate from local