From 86a7158f449aee5a4ea72ff30f6ac85bfcbf2f7c Mon Sep 17 00:00:00 2001 From: donBarbos Date: Thu, 14 Aug 2025 09:39:36 +0400 Subject: [PATCH 1/5] gh-131178: Use `support.captured_stdout()` and `support.captured_stderr()` --- Lib/test/test_argparse.py | 2 +- Lib/test/test_ast/test_ast.py | 11 ++--- Lib/test/test_compile.py | 5 +-- Lib/test/test_compileall.py | 10 ++--- .../test_interpreter_pool.py | 11 +++-- Lib/test/test_descr.py | 2 +- Lib/test/test_dis.py | 27 +++++------- .../test_future_multiple_features.py | 2 +- Lib/test/test_itertools.py | 2 +- Lib/test/test_pdb.py | 4 +- Lib/test/test_pickle.py | 7 +-- Lib/test/test_platform.py | 15 ++----- Lib/test/test_pprint.py | 5 +-- Lib/test/test_profile.py | 5 ++- Lib/test/test_pyrepl/test_interact.py | 43 +++++++------------ Lib/test/test_regrtest.py | 4 +- Lib/test/test_sqlite3/util.py | 4 +- Lib/test/test_sys.py | 4 +- Lib/test/test_threading.py | 10 ++--- Lib/test/test_tokenize.py | 6 +-- Lib/test/test_traceback.py | 36 ++++++++-------- Lib/test/test_uuid.py | 15 +++---- Lib/test/test_warnings/__init__.py | 8 ++-- 23 files changed, 93 insertions(+), 145 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index fc73174d98cd6f..4eb0b6311282e5 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -56,7 +56,7 @@ class StdStreamTest(unittest.TestCase): def test_skip_invalid_stderr(self): parser = argparse.ArgumentParser() with ( - contextlib.redirect_stderr(None), + captured_stderr(), mock.patch('argparse._sys.exit') ): parser.exit(status=0, message='foo') diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index 1e6f60074308e2..cedffbb0a2e346 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -1,7 +1,6 @@ import _ast_unparse import ast import builtins -import contextlib import copy import dis import enum @@ -14,7 +13,6 @@ import types import unittest import weakref -from io import StringIO from pathlib import Path from textwrap import dedent try: @@ -3417,11 +3415,9 @@ def set_source(self, content): Path(self.filename).write_text(self.text_normalize(content)) def invoke_ast(self, *flags): - stderr = StringIO() - stdout = StringIO() with ( - contextlib.redirect_stdout(stdout), - contextlib.redirect_stderr(stderr), + support.captured_stdout() as stdout, + support.captured_stderr() as stderr, ): ast.main(args=[*flags, self.filename]) self.assertEqual(stderr.getvalue(), '') @@ -3462,9 +3458,8 @@ def f(x: int) -> int: def test_help_message(self): for flag in ('-h', '--help', '--unknown'): with self.subTest(flag=flag): - output = StringIO() with self.assertRaises(SystemExit): - with contextlib.redirect_stderr(output): + with support.captured_stderr() as output: ast.main(args=flag) self.assertStartsWith(output.getvalue(), 'usage: ') diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 8a66be9b331262..af73346df2a2c9 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1,6 +1,4 @@ -import contextlib import dis -import io import itertools import math import opcode @@ -967,8 +965,7 @@ class C: for mode in ["exec", "single"]: with self.subTest(opt=opt, mode=mode): code = compile(src, "", mode, optimize=opt) - output = io.StringIO() - with contextlib.redirect_stdout(output): + with support.captured_stdout() as output: dis.dis(code) self.assertNotIn('NOP', output.getvalue()) diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index 8384c183dd92dd..53e88744cc341f 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -2,7 +2,6 @@ import contextlib import filecmp import importlib.util -import io import os import py_compile import shutil @@ -89,7 +88,7 @@ def test_year_2038_mtime_compilation(self): os.utime(self.source_path, (2**32 - 1, 2**32 - 1)) except (OverflowError, OSError): self.skipTest("filesystem doesn't support timestamps near 2**32") - with contextlib.redirect_stdout(io.StringIO()): + with support.captured_stdout(): self.assertTrue(compileall.compile_file(self.source_path)) def test_larger_than_32_bit_times(self): @@ -99,7 +98,7 @@ def test_larger_than_32_bit_times(self): os.utime(self.source_path, (2**35, 2**35)) except (OverflowError, OSError): self.skipTest("filesystem doesn't support large timestamps") - with contextlib.redirect_stdout(io.StringIO()): + with support.captured_stdout(): self.assertTrue(compileall.compile_file(self.source_path)) def recreation_check(self, metadata): @@ -206,7 +205,7 @@ def test_no_pycache_in_non_package(self): def test_compile_file_encoding_fallback(self): # Bug 44666 reported that compile_file failed when sys.stdout.encoding is None self.add_bad_source_file() - with contextlib.redirect_stdout(io.StringIO()): + with support.captured_stdout(): self.assertFalse(compileall.compile_file(self.bad_source_path)) @@ -510,8 +509,7 @@ def tearDown(self): shutil.rmtree(self.directory) def test_error(self): - buffer = io.TextIOWrapper(io.BytesIO(), encoding='ascii') - with contextlib.redirect_stdout(buffer): + with support.captured_stdout() as buffer: compiled = compileall.compile_dir(self.directory) self.assertFalse(compiled) # should not be successful buffer.seek(0) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 7241fcc4b1e74d..941bc139ba1ad7 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -1,7 +1,6 @@ import _thread import asyncio import contextlib -import io import os import subprocess import sys @@ -199,14 +198,14 @@ def init2(): nonlocal count count += 1 - with contextlib.redirect_stderr(io.StringIO()) as stderr: + with support.captured_stderr() as stderr: with self.executor_type(initializer=init1) as executor: fut = executor.submit(lambda: None) self.assertIn('NotShareableError', stderr.getvalue()) with self.assertRaises(BrokenInterpreterPool): fut.result() - with contextlib.redirect_stderr(io.StringIO()) as stderr: + with support.captured_stderr() as stderr: with self.executor_type(initializer=init2) as executor: fut = executor.submit(lambda: None) self.assertIn('NotShareableError', stderr.getvalue()) @@ -219,7 +218,7 @@ def initializer(self): raise NotImplementedError spam = Spam() - with contextlib.redirect_stderr(io.StringIO()) as stderr: + with support.captured_stderr() as stderr: with self.executor_type(initializer=spam.initializer) as executor: fut = executor.submit(lambda: None) self.assertIn('NotShareableError', stderr.getvalue()) @@ -230,7 +229,7 @@ def initializer(self): def test_init_exception_in_script(self): executor = self.executor_type(initializer='raise Exception("spam")') with executor: - with contextlib.redirect_stderr(io.StringIO()) as stderr: + with support.captured_stderr() as stderr: fut = executor.submit('pass') with self.assertRaises(BrokenInterpreterPool): fut.result() @@ -244,7 +243,7 @@ def test_init_exception_in_func(self): executor = self.executor_type(initializer=fail, initargs=(Exception, 'spam')) with executor: - with contextlib.redirect_stderr(io.StringIO()) as stderr: + with support.captured_stderr() as stderr: fut = executor.submit(noop) with self.assertRaises(BrokenInterpreterPool): fut.result() diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 8da6647c3f71fc..28f0fe6390bd8b 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1295,7 +1295,7 @@ def __init__(self): def __del__(self_): self.assertEqual(self_.a, 1) self.assertEqual(self_.b, 2) - with support.captured_output('stderr') as s: + with support.captured_stderr() as s: h = H() del h self.assertEqual(s.getvalue(), '') diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 355990ed58ee09..0f9b91d3403793 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1,7 +1,6 @@ # Minimal tests for dis module import ast -import contextlib import dis import functools import io @@ -13,9 +12,9 @@ import textwrap import types import unittest -from test.support import (captured_stdout, requires_debug_ranges, - requires_specialization, cpython_only, - os_helper, import_helper, reset_code) +from test.support import (captured_stderr, captured_stdout, + requires_debug_ranges, requires_specialization, + cpython_only, os_helper, import_helper, reset_code) from test.support.bytecode_helper import BytecodeTestCase @@ -971,8 +970,7 @@ class DisTests(DisTestBase): def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): # We want to test the default printing behaviour, not the file arg - output = io.StringIO() - with contextlib.redirect_stdout(output): + with captured_stdout() as output: if wrapper: dis.dis(func, **kwargs) else: @@ -988,8 +986,7 @@ def do_disassembly_test(self, func, expected, **kwargs): self.do_disassembly_compare(got, expected) # Add checks for dis.disco if hasattr(func, '__code__'): - got_disco = io.StringIO() - with contextlib.redirect_stdout(got_disco): + with captured_stdout() as got_disco: dis.disco(func.__code__, **kwargs) self.do_disassembly_compare(got_disco.getvalue(), expected) @@ -1709,8 +1706,7 @@ def _stringify_instruction(instr): return base + ")," def _prepare_test_cases(): - ignore = io.StringIO() - with contextlib.redirect_stdout(ignore): + with captured_stdout(): f = outer() inner = f() _instructions_outer = dis.get_instructions(outer, first_line=expected_outer_line) @@ -2428,8 +2424,7 @@ def setUp(self) -> None: return super().setUp() def get_disassembly(self, tb): - output = io.StringIO() - with contextlib.redirect_stdout(output): + with captured_stdout() as output: dis.distb(tb) return output.getvalue() @@ -2455,8 +2450,7 @@ def test_distb_explicit_arg(self): class TestDisTracebackWithFile(TestDisTraceback): # Run the `distb` tests again, using the file arg instead of print def get_disassembly(self, tb): - output = io.StringIO() - with contextlib.redirect_stdout(output): + with captured_stdout() as output: dis.distb(tb, file=output) return output.getvalue() @@ -2506,8 +2500,7 @@ def set_source(self, content): fp.write(self.text_normalize(content)) def invoke_dis(self, *flags): - output = io.StringIO() - with contextlib.redirect_stdout(output): + with captured_stdout() as output: dis.main(args=[*flags, self.filename]) return self.text_normalize(output.getvalue()) @@ -2541,7 +2534,7 @@ def f(): with self.assertRaises(SystemExit): # suppress argparse error message - with contextlib.redirect_stderr(io.StringIO()): + with captured_stderr(): _ = self.invoke_dis('--unknown') def test_show_cache(self): diff --git a/Lib/test/test_future_stmt/test_future_multiple_features.py b/Lib/test/test_future_stmt/test_future_multiple_features.py index b44b97e63eea21..6c959469bc4a16 100644 --- a/Lib/test/test_future_stmt/test_future_multiple_features.py +++ b/Lib/test/test_future_stmt/test_future_multiple_features.py @@ -12,7 +12,7 @@ def test_unicode_literals(self): self.assertIsInstance("", str) def test_print_function(self): - with support.captured_output("stderr") as s: + with support.captured_stderr() as s: print("foo", file=sys.stderr) self.assertEqual(s.getvalue(), "foo\n") diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 61bea9dba07fec..4659d5bbfcb5d3 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -879,7 +879,7 @@ def __next__(self): def run(r1, r2): result = [] for i, j in zip_longest(r1, r2, fillvalue=0): - with support.captured_output('stdout'): + with support.captured_stdout(): print((i, j)) result.append((i, j)) return result diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 6b74e21ad73d1a..86ea78bb135b15 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -17,7 +17,7 @@ import zipfile from asyncio.events import _set_event_loop_policy -from contextlib import ExitStack, redirect_stdout +from contextlib import ExitStack from io import StringIO from test import support from test.support import has_socket_support, os_helper @@ -4571,7 +4571,7 @@ def test_checkline_is_not_executable(self): with open(os_helper.TESTFN, "w") as f: f.write(s) num_lines = len(s.splitlines()) + 2 # Test for EOF - with redirect_stdout(StringIO()): + with support.captured_stdout(): db = pdb.Pdb() for lineno in range(num_lines): self.assertFalse(db.checkline(os_helper.TESTFN, lineno)) diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index e2384b33345a45..b24d865b1b8b5c 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -2,7 +2,6 @@ NAME_MAPPING, REVERSE_NAME_MAPPING) import builtins import collections -import contextlib import io import pickle import struct @@ -728,8 +727,7 @@ def set_pickle_data(self, data): pickle.dump(data, f) def invoke_pickle(self, *flags): - output = io.StringIO() - with contextlib.redirect_stdout(output): + with support.captured_stdout() as output: pickle._main(args=[*flags, self.filename]) return self.text_normalize(output.getvalue()) @@ -754,10 +752,9 @@ def test_invocation(self): @support.force_not_colorized def test_unknown_flag(self): - stderr = io.StringIO() with self.assertRaises(SystemExit): # check that the parser help is shown - with contextlib.redirect_stderr(stderr): + with support.captured_stderr() as stderr: _ = self.invoke_pickle('--unknown') self.assertStartsWith(stderr.getvalue(), 'usage: ') diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 479649053abc01..fb7ce2be8eb5ec 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -1,6 +1,4 @@ -import contextlib import copy -import io import itertools import os import pickle @@ -757,18 +755,16 @@ def setUp(self): self.addCleanup(platform.invalidate_caches) def invoke_platform(self, *flags): - output = io.StringIO() - with contextlib.redirect_stdout(output): + with support.captured_stdout() as output: platform._main(args=flags) return output.getvalue() def test_unknown_flag(self): with self.assertRaises(SystemExit): - output = io.StringIO() # suppress argparse error message - with contextlib.redirect_stderr(output): + with support.captured_stderr() as output: _ = self.invoke_platform('--unknown') - self.assertStartsWith(output, "usage: ") + self.assertStartsWith(output.getvalue(), "usage: ") def test_invocation(self): flags = ( @@ -803,12 +799,9 @@ def test_arg_parsing(self): @support.force_not_colorized def test_help(self): - output = io.StringIO() - with self.assertRaises(SystemExit): - with contextlib.redirect_stdout(output): + with support.captured_stdout() as output: platform._main(args=["--help"]) - self.assertStartsWith(output.getvalue(), "usage:") diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 41c337ade7eca1..35f25c0bcbc7b1 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import collections -import contextlib import dataclasses import io import itertools @@ -12,7 +11,7 @@ import unittest from collections.abc import ItemsView, KeysView, Mapping, MappingView, ValuesView -from test.support import cpython_only +from test.support import cpython_only, captured_stdout from test.support.import_helper import ensure_lazy_imports # list, tuple and dict subclasses that do or don't overwrite __repr__ @@ -176,7 +175,7 @@ def test_basic(self): "expected isreadable for %r" % (safe,)) def test_stdout_is_None(self): - with contextlib.redirect_stdout(None): + with captured_stdout(): # smoke test - there is no output to check value = 'this should not fail' pprint.pprint(value) diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index 0f16b92334999c..8f97cc95f65e70 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -7,10 +7,11 @@ from difflib import unified_diff from io import StringIO from test.support.os_helper import TESTFN, unlink, temp_dir, change_cwd -from contextlib import contextmanager, redirect_stdout +from contextlib import contextmanager import profile from test.profilee import testfunc, timer +from test.support import captured_stdout from test.support.script_helper import assert_python_failure, assert_python_ok @@ -93,7 +94,7 @@ def test_run(self): self.assertTrue(os.path.exists(TESTFN)) def test_run_with_sort_by_values(self): - with redirect_stdout(StringIO()) as f: + with captured_stdout() as f: self.profilermodule.run("int('1')", sort=('tottime', 'stdname')) self.assertIn("Ordered by: internal time, standard name", f.getvalue()) diff --git a/Lib/test/test_pyrepl/test_interact.py b/Lib/test/test_pyrepl/test_interact.py index 8c0eeab6dcae96..7702f281aec20f 100644 --- a/Lib/test/test_pyrepl/test_interact.py +++ b/Lib/test/test_pyrepl/test_interact.py @@ -1,11 +1,9 @@ -import contextlib -import io import unittest import warnings from unittest.mock import patch from textwrap import dedent -from test.support import force_not_colorized +from test import support from _pyrepl.console import InteractiveColoredConsole from _pyrepl.simple_interact import _more_lines @@ -28,11 +26,10 @@ def bar(self): a """) console = InteractiveColoredConsole(namespace, filename="") - f = io.StringIO() with ( patch.object(InteractiveColoredConsole, "showsyntaxerror") as showsyntaxerror, patch.object(InteractiveColoredConsole, "runsource", wraps=console.runsource) as runsource, - contextlib.redirect_stdout(f), + support.captured_stdout(), ): more = console.push(code, filename="", _symbol="single") # type: ignore[call-arg] self.assertFalse(more) @@ -48,21 +45,19 @@ def test_multiple_statements_output(self): a """) console = InteractiveColoredConsole(namespace, filename="") - f = io.StringIO() - with contextlib.redirect_stdout(f): + with support.captured_stdout() as f: more = console.push(code, filename="", _symbol="single") # type: ignore[call-arg] self.assertFalse(more) self.assertEqual(f.getvalue(), "1\n") - @force_not_colorized + @support.force_not_colorized def test_multiple_statements_fail_early(self): console = InteractiveColoredConsole() code = dedent("""\ raise Exception('foobar') print('spam', 'eggs', sep='&') """) - f = io.StringIO() - with contextlib.redirect_stderr(f): + with support.captured_stderr() as f: console.runsource(code) self.assertIn('Exception: foobar', f.getvalue()) self.assertNotIn('spam&eggs', f.getvalue()) @@ -71,8 +66,7 @@ def test_empty(self): namespace = {} code = "" console = InteractiveColoredConsole(namespace, filename="") - f = io.StringIO() - with contextlib.redirect_stdout(f): + with support.captured_stdout() as f: more = console.push(code, filename="", _symbol="single") # type: ignore[call-arg] self.assertFalse(more) self.assertEqual(f.getvalue(), "") @@ -87,27 +81,24 @@ def test_runsource_compiles_and_runs_code(self): def test_runsource_returns_false_for_successful_compilation(self): console = InteractiveColoredConsole() source = "print('Hello, world!')" - f = io.StringIO() - with contextlib.redirect_stdout(f): + with support.captured_stdout(): result = console.runsource(source) self.assertFalse(result) - @force_not_colorized + @support.force_not_colorized def test_runsource_returns_false_for_failed_compilation(self): console = InteractiveColoredConsole() source = "print('Hello, world!'" - f = io.StringIO() - with contextlib.redirect_stderr(f): + with support.captured_stderr() as f: result = console.runsource(source) self.assertFalse(result) self.assertIn('SyntaxError', f.getvalue()) - @force_not_colorized + @support.force_not_colorized def test_runsource_show_syntax_error_location(self): console = InteractiveColoredConsole() source = "def f(x, x): ..." - f = io.StringIO() - with contextlib.redirect_stderr(f): + with support.captured_stderr() as f: result = console.runsource(source) self.assertFalse(result) r = """ @@ -134,8 +125,7 @@ def test_runsource_shows_syntax_error_for_failed_compilation(self): def test_runsource_survives_null_bytes(self): console = InteractiveColoredConsole() source = "\x00\n" - f = io.StringIO() - with contextlib.redirect_stdout(f), contextlib.redirect_stderr(f): + with support.captured_stderr() as f: result = console.runsource(source) self.assertFalse(result) self.assertIn("source code string cannot contain null bytes", f.getvalue()) @@ -146,8 +136,7 @@ def test_no_active_future(self): x: int = 1 print(__annotate__(1)) """) - f = io.StringIO() - with contextlib.redirect_stdout(f): + with support.captured_stdout() as f: result = console.runsource(source) self.assertFalse(result) self.assertEqual(f.getvalue(), "{'x': }\n") @@ -159,16 +148,14 @@ def test_future_annotations(self): def g(x: int): ... print(g.__annotations__) """) - f = io.StringIO() - with contextlib.redirect_stdout(f): + with support.captured_stdout() as f: result = console.runsource(source) self.assertFalse(result) self.assertEqual(f.getvalue(), "{'x': 'int'}\n") def test_future_barry_as_flufl(self): console = InteractiveColoredConsole() - f = io.StringIO() - with contextlib.redirect_stdout(f): + with support.captured_stdout() as f: result = console.runsource("from __future__ import barry_as_FLUFL\n") result = console.runsource("""print("black" <> 'blue')\n""") self.assertFalse(result) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 5bc3c5924b07fb..c5af188c22d5d6 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -5,10 +5,8 @@ """ import _colorize -import contextlib import dataclasses import glob -import io import locale import os.path import platform @@ -366,7 +364,7 @@ def test_threshold(self): def test_nowindows(self): for opt in '-n', '--nowindows': with self.subTest(opt=opt): - with contextlib.redirect_stderr(io.StringIO()) as stderr: + with support.captured_stderr() as stderr: ns = self.parse_args([opt]) self.assertTrue(ns.nowindows) err = stderr.getvalue() diff --git a/Lib/test/test_sqlite3/util.py b/Lib/test/test_sqlite3/util.py index cccd062160fd40..3b52a08f9aa1a2 100644 --- a/Lib/test/test_sqlite3/util.py +++ b/Lib/test/test_sqlite3/util.py @@ -1,6 +1,5 @@ import contextlib import functools -import io import re import sqlite3 import test.support @@ -46,8 +45,7 @@ def check_tracebacks(self, cm, exc, exc_regex, msg_regex, obj_name): """Convenience context manager for testing callback tracebacks.""" sqlite3.enable_callback_tracebacks(True) try: - buf = io.StringIO() - with contextlib.redirect_stderr(buf): + with test.support.captured_stderr(): yield self.assertEqual(cm.unraisable.exc_type, exc) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index f89237931b7185..07bee6559a64fb 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -195,7 +195,7 @@ def test_excepthook_bytes_filename(self): self.assertEndsWith(err, "SyntaxError: msg\n") def test_excepthook(self): - with test.support.captured_output("stderr") as stderr: + with test.support.captured_stderr() as stderr: with test.support.catch_unraisable_exception(): sys.excepthook(1, '1', 1) self.assertTrue("TypeError: print_exception(): Exception expected for " \ @@ -1485,7 +1485,7 @@ def test_custom_unraisablehook_fail(self): def hook_func(*args): raise Exception("hook_func failed") - with test.support.captured_output("stderr") as stderr: + with test.support.captured_stderr() as stderr: with test.support.swap_attr(sys, 'unraisablehook', hook_func): err_writeunraisable(ValueError(42), "custom hook fail") diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 0ba78b9a1807d2..d817fa78da1592 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -2072,7 +2072,7 @@ def setUp(self): @force_not_colorized def test_excepthook(self): - with support.captured_output("stderr") as stderr: + with support.captured_stderr() as stderr: thread = ThreadRunFail(name="excepthook thread") thread.start() thread.join() @@ -2088,7 +2088,7 @@ def test_excepthook(self): def test_excepthook_thread_None(self): # threading.excepthook called with thread=None: log the thread # identifier in this case. - with support.captured_output("stderr") as stderr: + with support.captured_stderr() as stderr: try: raise ValueError("bug") except Exception as exc: @@ -2111,7 +2111,7 @@ def run(self): sys.exit(1) # threading.excepthook() silently ignores SystemExit - with support.captured_output("stderr") as stderr: + with support.captured_stderr() as stderr: thread = ThreadExit() thread.start() thread.join() @@ -2151,7 +2151,7 @@ def sys_hook(exc_type, exc_value, exc_traceback): with support.swap_attr(threading, 'excepthook', threading_hook), \ support.swap_attr(sys, 'excepthook', sys_hook), \ - support.captured_output('stderr') as stderr: + support.captured_stderr() as stderr: thread = ThreadRunFail() thread.start() thread.join() @@ -2162,7 +2162,7 @@ def sys_hook(exc_type, exc_value, exc_traceback): def test_original_excepthook(self): def run_thread(): - with support.captured_output("stderr") as output: + with support.captured_stderr() as output: thread = ThreadRunFail(name="excepthook thread") thread.start() thread.join() diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 865e0c5b40ddd3..92a0510ddf0b03 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1,4 +1,3 @@ -import contextlib import itertools import os import re @@ -3181,8 +3180,7 @@ def set_source(self, content): fp.write(content) def invoke_tokenize(self, *flags): - output = StringIO() - with contextlib.redirect_stdout(output): + with support.captured_stdout() as output: tokenize._main(args=[*flags, self.filename]) return self.text_normalize(output.getvalue()) @@ -3209,7 +3207,7 @@ def f(): with self.assertRaises(SystemExit): # suppress argparse error message - with contextlib.redirect_stderr(StringIO()): + with support.captured_stderr(): _ = self.invoke_tokenize('--unknown') def test_without_flag(self): diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 11b7f419bddbe4..b2d01ec9dbbc0f 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -15,7 +15,7 @@ import string from test import support import shutil -from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ, +from test.support import (Error, captured_stderr, cpython_only, ALWAYS_EQ, requires_debug_ranges, has_no_debug_ranges, requires_subprocess) from test.support.os_helper import TESTFN, unlink @@ -597,7 +597,7 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): callable() self.fail("No exception thrown.") except Exception as e: - with captured_output("stderr") as tbstderr: + with captured_stderr() as tbstderr: exception_print(e, self.LEGACY) return tbstderr.getvalue().splitlines()[slice_start:slice_end] @@ -1814,11 +1814,11 @@ def check_traceback_format(self, cleanup_func=None): traceback_print(tb, file_) python_fmt = file_.getvalue() # Call all _tb and _exc functions - with captured_output("stderr") as tbstderr: + with captured_stderr() as tbstderr: traceback.print_tb(tb) tbfile = StringIO() traceback.print_tb(tb, file=tbfile) - with captured_output("stderr") as excstderr: + with captured_stderr() as excstderr: traceback.print_exc() excfmt = traceback.format_exc() excfile = StringIO() @@ -1855,7 +1855,7 @@ def cleanup_tb(tb): def test_stack_format(self): # Verify _stack functions. Note we have to use _getframe(1) to # compare them without this frame appearing in the output - with captured_output("stderr") as ststderr: + with captured_stderr() as ststderr: traceback.print_stack(sys._getframe(1)) stfile = StringIO() traceback.print_stack(sys._getframe(1), file=stfile) @@ -1868,7 +1868,7 @@ def test_stack_format(self): def test_print_stack(self): def prn(): traceback.print_stack() - with captured_output("stderr") as stderr: + with captured_stderr() as stderr: prn() lineno = prn.__code__.co_firstlineno self.assertEqual(stderr.getvalue().splitlines()[-4:], [ @@ -1889,7 +1889,7 @@ def _check_recursive_traceback_display(self, render_exc): def f(): f() - with captured_output("stderr") as stderr_f: + with captured_stderr() as stderr_f: try: f() except RecursionError: @@ -1940,7 +1940,7 @@ def g(count=10): return g(count-1) + 1 raise ValueError - with captured_output("stderr") as stderr_g: + with captured_stderr() as stderr_g: try: g() except ValueError: @@ -1980,7 +1980,7 @@ def h(count=10): return h(count-1) g() - with captured_output("stderr") as stderr_h: + with captured_stderr() as stderr_h: try: h() except ValueError: @@ -2010,7 +2010,7 @@ def h(count=10): self.assertEqual(actual, expected) # Check the boundary conditions. First, test just below the cutoff. - with captured_output("stderr") as stderr_g: + with captured_stderr() as stderr_g: try: g(traceback._RECURSIVE_CUTOFF) except ValueError: @@ -2042,7 +2042,7 @@ def h(count=10): self.assertEqual(actual, expected) # Second, test just above the cutoff. - with captured_output("stderr") as stderr_g: + with captured_stderr() as stderr_g: try: g(traceback._RECURSIVE_CUTOFF + 1) except ValueError: @@ -2114,7 +2114,7 @@ def __eq__(self, other): except UnhashableException as e: exc_val = e - with captured_output("stderr") as stderr_f: + with captured_stderr() as stderr_f: exception_print(exc_val) tb = stderr_f.getvalue().strip().splitlines() @@ -2135,7 +2135,7 @@ def test_exception_group_deep_recursion_capi(self): from _testcapi import exception_print LIMIT = 75 eg = self.deep_eg() - with captured_output("stderr") as stderr_f: + with captured_stderr() as stderr_f: with support.infinite_recursion(max_depth=LIMIT): exception_print(eg) output = stderr_f.getvalue() @@ -2146,7 +2146,7 @@ def test_exception_group_deep_recursion_capi(self): def test_exception_group_deep_recursion_traceback(self): LIMIT = 75 eg = self.deep_eg() - with captured_output("stderr") as stderr_f: + with captured_stderr() as stderr_f: with support.infinite_recursion(max_depth=LIMIT): traceback.print_exception(type(eg), eg, eg.__traceback__) output = stderr_f.getvalue() @@ -2156,7 +2156,7 @@ def test_exception_group_deep_recursion_traceback(self): @cpython_only def test_print_exception_bad_type_capi(self): from _testcapi import exception_print - with captured_output("stderr") as stderr: + with captured_stderr() as stderr: with support.catch_unraisable_exception(): exception_print(42) self.assertEqual( @@ -3013,7 +3013,7 @@ def get_report(self, e): e = self.get_exception(e) s = ''.join( traceback.format_exception(type(e), e, e.__traceback__)) - with captured_output("stderr") as sio: + with captured_stderr() as sio: traceback.print_exception(type(e), e, e.__traceback__) self.assertEqual(sio.getvalue(), s) return s @@ -3029,7 +3029,7 @@ class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): def get_report(self, e): from _testcapi import exception_print e = self.get_exception(e) - with captured_output("stderr") as s: + with captured_stderr() as s: exception_print(e) return s.getvalue() @@ -4833,7 +4833,7 @@ def foo(): foo() self.fail("No exception thrown.") except Exception as e: - with captured_output("stderr") as tbstderr: + with captured_stderr() as tbstderr: with unittest.mock.patch('_colorize.can_colorize', return_value=True): exception_print(e) actual = tbstderr.getvalue().splitlines() diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 0e1a723ce3a151..891131032ad380 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -1145,8 +1145,7 @@ class CommandLineTestCases: uuid = None # to be defined in subclasses def do_test_standalone_uuid(self, version): - stdout = io.StringIO() - with contextlib.redirect_stdout(stdout): + with support.captured_stdout() as stdout: self.uuid.main() output = stdout.getvalue().strip() u = self.uuid.UUID(output) @@ -1178,8 +1177,7 @@ def test_cli_name_required_for_uuid3(self, mock_err): @mock.patch.object(sys, "argv", [""]) def test_cli_uuid4_outputted_with_no_args(self): - stdout = io.StringIO() - with contextlib.redirect_stdout(stdout): + with support.captured_stdout() as stdout: self.uuid.main() output = stdout.getvalue().strip() @@ -1191,8 +1189,7 @@ def test_cli_uuid4_outputted_with_no_args(self): @mock.patch.object(sys, "argv", ["", "-C", "3"]) def test_cli_uuid4_outputted_with_count(self): - stdout = io.StringIO() - with contextlib.redirect_stdout(stdout): + with support.captured_stdout() as stdout: self.uuid.main() output = stdout.getvalue().strip().splitlines() @@ -1206,8 +1203,7 @@ def test_cli_uuid4_outputted_with_count(self): @mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-n", "@dns", "-N", "python.org"]) def test_cli_uuid3_ouputted_with_valid_namespace_and_name(self): - stdout = io.StringIO() - with contextlib.redirect_stdout(stdout): + with support.captured_stdout() as stdout: self.uuid.main() output = stdout.getvalue().strip() @@ -1220,8 +1216,7 @@ def test_cli_uuid3_ouputted_with_valid_namespace_and_name(self): @mock.patch.object(sys, "argv", ["", "-u", "uuid5", "-n", "@dns", "-N", "python.org"]) def test_cli_uuid5_ouputted_with_valid_namespace_and_name(self): - stdout = io.StringIO() - with contextlib.redirect_stdout(stdout): + with support.captured_stdout() as stdout: self.uuid.main() output = stdout.getvalue().strip() diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index f89e94449b3031..b069b50cf12521 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -891,7 +891,7 @@ def test_showwarning_missing(self): with self.module.catch_warnings(): self.module.filterwarnings("always", category=UserWarning) del self.module.showwarning - with support.captured_output('stderr') as stream: + with support.captured_stderr() as stream: self.module.warn(text) result = stream.getvalue() self.assertIn(text, result) @@ -905,7 +905,7 @@ def test_showwarnmsg_missing(self): show = self.module._showwarnmsg try: del self.module._showwarnmsg - with support.captured_output('stderr') as stream: + with support.captured_stderr() as stream: self.module.warn(text) result = stream.getvalue() finally: @@ -918,7 +918,7 @@ def test_showwarning_not_callable(self): with self.module.catch_warnings(): self.module.filterwarnings("always", category=UserWarning) self.module.showwarning = print - with support.captured_output('stdout'): + with support.captured_stdout(): self.module.warn('Warning!') self.module.showwarning = 23 self.assertRaises(TypeError, self.module.warn, "Warning!") @@ -933,7 +933,7 @@ def test_show_warning_output(self): with self.module.catch_warnings(): self.module.filterwarnings("always", category=UserWarning) del self.module.showwarning - with support.captured_output('stderr') as stream: + with support.captured_stderr() as stream: warning_tests.inner(text) result = stream.getvalue() self.assertEqual(result.count('\n'), 2, From 9f3100db9d985d915600cb0184333a7674ac1846 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Thu, 14 Aug 2025 10:04:35 +0400 Subject: [PATCH 2/5] Fix test_unknown_flag for platform --- Lib/test/test_platform.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index fb7ce2be8eb5ec..6f14c4350cfce1 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -759,6 +759,7 @@ def invoke_platform(self, *flags): platform._main(args=flags) return output.getvalue() + @support.force_not_colorized def test_unknown_flag(self): with self.assertRaises(SystemExit): # suppress argparse error message From 0d289d47073a774a264b50643caadf7b5229ec77 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Thu, 14 Aug 2025 12:24:15 +0400 Subject: [PATCH 3/5] Revert changes --- Lib/test/test_argparse.py | 2 +- Lib/test/test_compile.py | 5 ++- Lib/test/test_compileall.py | 10 +++-- .../test_interpreter_pool.py | 11 ++--- Lib/test/test_descr.py | 2 +- Lib/test/test_dis.py | 27 +++++++----- .../test_future_multiple_features.py | 2 +- Lib/test/test_itertools.py | 2 +- Lib/test/test_pdb.py | 4 +- Lib/test/test_platform.py | 13 ++++-- Lib/test/test_pprint.py | 5 ++- Lib/test/test_profile.py | 5 +-- Lib/test/test_pyrepl/test_interact.py | 43 ++++++++++++------- Lib/test/test_sqlite3/util.py | 4 +- Lib/test/test_sys.py | 4 +- Lib/test/test_threading.py | 10 ++--- Lib/test/test_traceback.py | 36 ++++++++-------- Lib/test/test_uuid.py | 15 ++++--- Lib/test/test_warnings/__init__.py | 8 ++-- 19 files changed, 124 insertions(+), 84 deletions(-) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 4eb0b6311282e5..fc73174d98cd6f 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -56,7 +56,7 @@ class StdStreamTest(unittest.TestCase): def test_skip_invalid_stderr(self): parser = argparse.ArgumentParser() with ( - captured_stderr(), + contextlib.redirect_stderr(None), mock.patch('argparse._sys.exit') ): parser.exit(status=0, message='foo') diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index af73346df2a2c9..8a66be9b331262 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1,4 +1,6 @@ +import contextlib import dis +import io import itertools import math import opcode @@ -965,7 +967,8 @@ class C: for mode in ["exec", "single"]: with self.subTest(opt=opt, mode=mode): code = compile(src, "", mode, optimize=opt) - with support.captured_stdout() as output: + output = io.StringIO() + with contextlib.redirect_stdout(output): dis.dis(code) self.assertNotIn('NOP', output.getvalue()) diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index 53e88744cc341f..8384c183dd92dd 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -2,6 +2,7 @@ import contextlib import filecmp import importlib.util +import io import os import py_compile import shutil @@ -88,7 +89,7 @@ def test_year_2038_mtime_compilation(self): os.utime(self.source_path, (2**32 - 1, 2**32 - 1)) except (OverflowError, OSError): self.skipTest("filesystem doesn't support timestamps near 2**32") - with support.captured_stdout(): + with contextlib.redirect_stdout(io.StringIO()): self.assertTrue(compileall.compile_file(self.source_path)) def test_larger_than_32_bit_times(self): @@ -98,7 +99,7 @@ def test_larger_than_32_bit_times(self): os.utime(self.source_path, (2**35, 2**35)) except (OverflowError, OSError): self.skipTest("filesystem doesn't support large timestamps") - with support.captured_stdout(): + with contextlib.redirect_stdout(io.StringIO()): self.assertTrue(compileall.compile_file(self.source_path)) def recreation_check(self, metadata): @@ -205,7 +206,7 @@ def test_no_pycache_in_non_package(self): def test_compile_file_encoding_fallback(self): # Bug 44666 reported that compile_file failed when sys.stdout.encoding is None self.add_bad_source_file() - with support.captured_stdout(): + with contextlib.redirect_stdout(io.StringIO()): self.assertFalse(compileall.compile_file(self.bad_source_path)) @@ -509,7 +510,8 @@ def tearDown(self): shutil.rmtree(self.directory) def test_error(self): - with support.captured_stdout() as buffer: + buffer = io.TextIOWrapper(io.BytesIO(), encoding='ascii') + with contextlib.redirect_stdout(buffer): compiled = compileall.compile_dir(self.directory) self.assertFalse(compiled) # should not be successful buffer.seek(0) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 941bc139ba1ad7..7241fcc4b1e74d 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -1,6 +1,7 @@ import _thread import asyncio import contextlib +import io import os import subprocess import sys @@ -198,14 +199,14 @@ def init2(): nonlocal count count += 1 - with support.captured_stderr() as stderr: + with contextlib.redirect_stderr(io.StringIO()) as stderr: with self.executor_type(initializer=init1) as executor: fut = executor.submit(lambda: None) self.assertIn('NotShareableError', stderr.getvalue()) with self.assertRaises(BrokenInterpreterPool): fut.result() - with support.captured_stderr() as stderr: + with contextlib.redirect_stderr(io.StringIO()) as stderr: with self.executor_type(initializer=init2) as executor: fut = executor.submit(lambda: None) self.assertIn('NotShareableError', stderr.getvalue()) @@ -218,7 +219,7 @@ def initializer(self): raise NotImplementedError spam = Spam() - with support.captured_stderr() as stderr: + with contextlib.redirect_stderr(io.StringIO()) as stderr: with self.executor_type(initializer=spam.initializer) as executor: fut = executor.submit(lambda: None) self.assertIn('NotShareableError', stderr.getvalue()) @@ -229,7 +230,7 @@ def initializer(self): def test_init_exception_in_script(self): executor = self.executor_type(initializer='raise Exception("spam")') with executor: - with support.captured_stderr() as stderr: + with contextlib.redirect_stderr(io.StringIO()) as stderr: fut = executor.submit('pass') with self.assertRaises(BrokenInterpreterPool): fut.result() @@ -243,7 +244,7 @@ def test_init_exception_in_func(self): executor = self.executor_type(initializer=fail, initargs=(Exception, 'spam')) with executor: - with support.captured_stderr() as stderr: + with contextlib.redirect_stderr(io.StringIO()) as stderr: fut = executor.submit(noop) with self.assertRaises(BrokenInterpreterPool): fut.result() diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 28f0fe6390bd8b..8da6647c3f71fc 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1295,7 +1295,7 @@ def __init__(self): def __del__(self_): self.assertEqual(self_.a, 1) self.assertEqual(self_.b, 2) - with support.captured_stderr() as s: + with support.captured_output('stderr') as s: h = H() del h self.assertEqual(s.getvalue(), '') diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 0f9b91d3403793..355990ed58ee09 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1,6 +1,7 @@ # Minimal tests for dis module import ast +import contextlib import dis import functools import io @@ -12,9 +13,9 @@ import textwrap import types import unittest -from test.support import (captured_stderr, captured_stdout, - requires_debug_ranges, requires_specialization, - cpython_only, os_helper, import_helper, reset_code) +from test.support import (captured_stdout, requires_debug_ranges, + requires_specialization, cpython_only, + os_helper, import_helper, reset_code) from test.support.bytecode_helper import BytecodeTestCase @@ -970,7 +971,8 @@ class DisTests(DisTestBase): def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs): # We want to test the default printing behaviour, not the file arg - with captured_stdout() as output: + output = io.StringIO() + with contextlib.redirect_stdout(output): if wrapper: dis.dis(func, **kwargs) else: @@ -986,7 +988,8 @@ def do_disassembly_test(self, func, expected, **kwargs): self.do_disassembly_compare(got, expected) # Add checks for dis.disco if hasattr(func, '__code__'): - with captured_stdout() as got_disco: + got_disco = io.StringIO() + with contextlib.redirect_stdout(got_disco): dis.disco(func.__code__, **kwargs) self.do_disassembly_compare(got_disco.getvalue(), expected) @@ -1706,7 +1709,8 @@ def _stringify_instruction(instr): return base + ")," def _prepare_test_cases(): - with captured_stdout(): + ignore = io.StringIO() + with contextlib.redirect_stdout(ignore): f = outer() inner = f() _instructions_outer = dis.get_instructions(outer, first_line=expected_outer_line) @@ -2424,7 +2428,8 @@ def setUp(self) -> None: return super().setUp() def get_disassembly(self, tb): - with captured_stdout() as output: + output = io.StringIO() + with contextlib.redirect_stdout(output): dis.distb(tb) return output.getvalue() @@ -2450,7 +2455,8 @@ def test_distb_explicit_arg(self): class TestDisTracebackWithFile(TestDisTraceback): # Run the `distb` tests again, using the file arg instead of print def get_disassembly(self, tb): - with captured_stdout() as output: + output = io.StringIO() + with contextlib.redirect_stdout(output): dis.distb(tb, file=output) return output.getvalue() @@ -2500,7 +2506,8 @@ def set_source(self, content): fp.write(self.text_normalize(content)) def invoke_dis(self, *flags): - with captured_stdout() as output: + output = io.StringIO() + with contextlib.redirect_stdout(output): dis.main(args=[*flags, self.filename]) return self.text_normalize(output.getvalue()) @@ -2534,7 +2541,7 @@ def f(): with self.assertRaises(SystemExit): # suppress argparse error message - with captured_stderr(): + with contextlib.redirect_stderr(io.StringIO()): _ = self.invoke_dis('--unknown') def test_show_cache(self): diff --git a/Lib/test/test_future_stmt/test_future_multiple_features.py b/Lib/test/test_future_stmt/test_future_multiple_features.py index 6c959469bc4a16..b44b97e63eea21 100644 --- a/Lib/test/test_future_stmt/test_future_multiple_features.py +++ b/Lib/test/test_future_stmt/test_future_multiple_features.py @@ -12,7 +12,7 @@ def test_unicode_literals(self): self.assertIsInstance("", str) def test_print_function(self): - with support.captured_stderr() as s: + with support.captured_output("stderr") as s: print("foo", file=sys.stderr) self.assertEqual(s.getvalue(), "foo\n") diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 4659d5bbfcb5d3..61bea9dba07fec 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -879,7 +879,7 @@ def __next__(self): def run(r1, r2): result = [] for i, j in zip_longest(r1, r2, fillvalue=0): - with support.captured_stdout(): + with support.captured_output('stdout'): print((i, j)) result.append((i, j)) return result diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 86ea78bb135b15..6b74e21ad73d1a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -17,7 +17,7 @@ import zipfile from asyncio.events import _set_event_loop_policy -from contextlib import ExitStack +from contextlib import ExitStack, redirect_stdout from io import StringIO from test import support from test.support import has_socket_support, os_helper @@ -4571,7 +4571,7 @@ def test_checkline_is_not_executable(self): with open(os_helper.TESTFN, "w") as f: f.write(s) num_lines = len(s.splitlines()) + 2 # Test for EOF - with support.captured_stdout(): + with redirect_stdout(StringIO()): db = pdb.Pdb() for lineno in range(num_lines): self.assertFalse(db.checkline(os_helper.TESTFN, lineno)) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 6f14c4350cfce1..976e540394b4f7 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -1,4 +1,6 @@ +import contextlib import copy +import io import itertools import os import pickle @@ -755,15 +757,17 @@ def setUp(self): self.addCleanup(platform.invalidate_caches) def invoke_platform(self, *flags): - with support.captured_stdout() as output: + output = io.StringIO() + with contextlib.redirect_stdout(output): platform._main(args=flags) return output.getvalue() @support.force_not_colorized def test_unknown_flag(self): + output = io.StringIO() with self.assertRaises(SystemExit): # suppress argparse error message - with support.captured_stderr() as output: + with contextlib.redirect_stderr(output): _ = self.invoke_platform('--unknown') self.assertStartsWith(output.getvalue(), "usage: ") @@ -800,9 +804,12 @@ def test_arg_parsing(self): @support.force_not_colorized def test_help(self): + output = io.StringIO() + with self.assertRaises(SystemExit): - with support.captured_stdout() as output: + with contextlib.redirect_stdout(output): platform._main(args=["--help"]) + self.assertStartsWith(output.getvalue(), "usage:") diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 35f25c0bcbc7b1..41c337ade7eca1 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import collections +import contextlib import dataclasses import io import itertools @@ -11,7 +12,7 @@ import unittest from collections.abc import ItemsView, KeysView, Mapping, MappingView, ValuesView -from test.support import cpython_only, captured_stdout +from test.support import cpython_only from test.support.import_helper import ensure_lazy_imports # list, tuple and dict subclasses that do or don't overwrite __repr__ @@ -175,7 +176,7 @@ def test_basic(self): "expected isreadable for %r" % (safe,)) def test_stdout_is_None(self): - with captured_stdout(): + with contextlib.redirect_stdout(None): # smoke test - there is no output to check value = 'this should not fail' pprint.pprint(value) diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index 8f97cc95f65e70..0f16b92334999c 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -7,11 +7,10 @@ from difflib import unified_diff from io import StringIO from test.support.os_helper import TESTFN, unlink, temp_dir, change_cwd -from contextlib import contextmanager +from contextlib import contextmanager, redirect_stdout import profile from test.profilee import testfunc, timer -from test.support import captured_stdout from test.support.script_helper import assert_python_failure, assert_python_ok @@ -94,7 +93,7 @@ def test_run(self): self.assertTrue(os.path.exists(TESTFN)) def test_run_with_sort_by_values(self): - with captured_stdout() as f: + with redirect_stdout(StringIO()) as f: self.profilermodule.run("int('1')", sort=('tottime', 'stdname')) self.assertIn("Ordered by: internal time, standard name", f.getvalue()) diff --git a/Lib/test/test_pyrepl/test_interact.py b/Lib/test/test_pyrepl/test_interact.py index 7702f281aec20f..8c0eeab6dcae96 100644 --- a/Lib/test/test_pyrepl/test_interact.py +++ b/Lib/test/test_pyrepl/test_interact.py @@ -1,9 +1,11 @@ +import contextlib +import io import unittest import warnings from unittest.mock import patch from textwrap import dedent -from test import support +from test.support import force_not_colorized from _pyrepl.console import InteractiveColoredConsole from _pyrepl.simple_interact import _more_lines @@ -26,10 +28,11 @@ def bar(self): a """) console = InteractiveColoredConsole(namespace, filename="") + f = io.StringIO() with ( patch.object(InteractiveColoredConsole, "showsyntaxerror") as showsyntaxerror, patch.object(InteractiveColoredConsole, "runsource", wraps=console.runsource) as runsource, - support.captured_stdout(), + contextlib.redirect_stdout(f), ): more = console.push(code, filename="", _symbol="single") # type: ignore[call-arg] self.assertFalse(more) @@ -45,19 +48,21 @@ def test_multiple_statements_output(self): a """) console = InteractiveColoredConsole(namespace, filename="") - with support.captured_stdout() as f: + f = io.StringIO() + with contextlib.redirect_stdout(f): more = console.push(code, filename="", _symbol="single") # type: ignore[call-arg] self.assertFalse(more) self.assertEqual(f.getvalue(), "1\n") - @support.force_not_colorized + @force_not_colorized def test_multiple_statements_fail_early(self): console = InteractiveColoredConsole() code = dedent("""\ raise Exception('foobar') print('spam', 'eggs', sep='&') """) - with support.captured_stderr() as f: + f = io.StringIO() + with contextlib.redirect_stderr(f): console.runsource(code) self.assertIn('Exception: foobar', f.getvalue()) self.assertNotIn('spam&eggs', f.getvalue()) @@ -66,7 +71,8 @@ def test_empty(self): namespace = {} code = "" console = InteractiveColoredConsole(namespace, filename="") - with support.captured_stdout() as f: + f = io.StringIO() + with contextlib.redirect_stdout(f): more = console.push(code, filename="", _symbol="single") # type: ignore[call-arg] self.assertFalse(more) self.assertEqual(f.getvalue(), "") @@ -81,24 +87,27 @@ def test_runsource_compiles_and_runs_code(self): def test_runsource_returns_false_for_successful_compilation(self): console = InteractiveColoredConsole() source = "print('Hello, world!')" - with support.captured_stdout(): + f = io.StringIO() + with contextlib.redirect_stdout(f): result = console.runsource(source) self.assertFalse(result) - @support.force_not_colorized + @force_not_colorized def test_runsource_returns_false_for_failed_compilation(self): console = InteractiveColoredConsole() source = "print('Hello, world!'" - with support.captured_stderr() as f: + f = io.StringIO() + with contextlib.redirect_stderr(f): result = console.runsource(source) self.assertFalse(result) self.assertIn('SyntaxError', f.getvalue()) - @support.force_not_colorized + @force_not_colorized def test_runsource_show_syntax_error_location(self): console = InteractiveColoredConsole() source = "def f(x, x): ..." - with support.captured_stderr() as f: + f = io.StringIO() + with contextlib.redirect_stderr(f): result = console.runsource(source) self.assertFalse(result) r = """ @@ -125,7 +134,8 @@ def test_runsource_shows_syntax_error_for_failed_compilation(self): def test_runsource_survives_null_bytes(self): console = InteractiveColoredConsole() source = "\x00\n" - with support.captured_stderr() as f: + f = io.StringIO() + with contextlib.redirect_stdout(f), contextlib.redirect_stderr(f): result = console.runsource(source) self.assertFalse(result) self.assertIn("source code string cannot contain null bytes", f.getvalue()) @@ -136,7 +146,8 @@ def test_no_active_future(self): x: int = 1 print(__annotate__(1)) """) - with support.captured_stdout() as f: + f = io.StringIO() + with contextlib.redirect_stdout(f): result = console.runsource(source) self.assertFalse(result) self.assertEqual(f.getvalue(), "{'x': }\n") @@ -148,14 +159,16 @@ def test_future_annotations(self): def g(x: int): ... print(g.__annotations__) """) - with support.captured_stdout() as f: + f = io.StringIO() + with contextlib.redirect_stdout(f): result = console.runsource(source) self.assertFalse(result) self.assertEqual(f.getvalue(), "{'x': 'int'}\n") def test_future_barry_as_flufl(self): console = InteractiveColoredConsole() - with support.captured_stdout() as f: + f = io.StringIO() + with contextlib.redirect_stdout(f): result = console.runsource("from __future__ import barry_as_FLUFL\n") result = console.runsource("""print("black" <> 'blue')\n""") self.assertFalse(result) diff --git a/Lib/test/test_sqlite3/util.py b/Lib/test/test_sqlite3/util.py index 3b52a08f9aa1a2..cccd062160fd40 100644 --- a/Lib/test/test_sqlite3/util.py +++ b/Lib/test/test_sqlite3/util.py @@ -1,5 +1,6 @@ import contextlib import functools +import io import re import sqlite3 import test.support @@ -45,7 +46,8 @@ def check_tracebacks(self, cm, exc, exc_regex, msg_regex, obj_name): """Convenience context manager for testing callback tracebacks.""" sqlite3.enable_callback_tracebacks(True) try: - with test.support.captured_stderr(): + buf = io.StringIO() + with contextlib.redirect_stderr(buf): yield self.assertEqual(cm.unraisable.exc_type, exc) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 07bee6559a64fb..f89237931b7185 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -195,7 +195,7 @@ def test_excepthook_bytes_filename(self): self.assertEndsWith(err, "SyntaxError: msg\n") def test_excepthook(self): - with test.support.captured_stderr() as stderr: + with test.support.captured_output("stderr") as stderr: with test.support.catch_unraisable_exception(): sys.excepthook(1, '1', 1) self.assertTrue("TypeError: print_exception(): Exception expected for " \ @@ -1485,7 +1485,7 @@ def test_custom_unraisablehook_fail(self): def hook_func(*args): raise Exception("hook_func failed") - with test.support.captured_stderr() as stderr: + with test.support.captured_output("stderr") as stderr: with test.support.swap_attr(sys, 'unraisablehook', hook_func): err_writeunraisable(ValueError(42), "custom hook fail") diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index d817fa78da1592..0ba78b9a1807d2 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -2072,7 +2072,7 @@ def setUp(self): @force_not_colorized def test_excepthook(self): - with support.captured_stderr() as stderr: + with support.captured_output("stderr") as stderr: thread = ThreadRunFail(name="excepthook thread") thread.start() thread.join() @@ -2088,7 +2088,7 @@ def test_excepthook(self): def test_excepthook_thread_None(self): # threading.excepthook called with thread=None: log the thread # identifier in this case. - with support.captured_stderr() as stderr: + with support.captured_output("stderr") as stderr: try: raise ValueError("bug") except Exception as exc: @@ -2111,7 +2111,7 @@ def run(self): sys.exit(1) # threading.excepthook() silently ignores SystemExit - with support.captured_stderr() as stderr: + with support.captured_output("stderr") as stderr: thread = ThreadExit() thread.start() thread.join() @@ -2151,7 +2151,7 @@ def sys_hook(exc_type, exc_value, exc_traceback): with support.swap_attr(threading, 'excepthook', threading_hook), \ support.swap_attr(sys, 'excepthook', sys_hook), \ - support.captured_stderr() as stderr: + support.captured_output('stderr') as stderr: thread = ThreadRunFail() thread.start() thread.join() @@ -2162,7 +2162,7 @@ def sys_hook(exc_type, exc_value, exc_traceback): def test_original_excepthook(self): def run_thread(): - with support.captured_stderr() as output: + with support.captured_output("stderr") as output: thread = ThreadRunFail(name="excepthook thread") thread.start() thread.join() diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index b2d01ec9dbbc0f..11b7f419bddbe4 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -15,7 +15,7 @@ import string from test import support import shutil -from test.support import (Error, captured_stderr, cpython_only, ALWAYS_EQ, +from test.support import (Error, captured_output, cpython_only, ALWAYS_EQ, requires_debug_ranges, has_no_debug_ranges, requires_subprocess) from test.support.os_helper import TESTFN, unlink @@ -597,7 +597,7 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): callable() self.fail("No exception thrown.") except Exception as e: - with captured_stderr() as tbstderr: + with captured_output("stderr") as tbstderr: exception_print(e, self.LEGACY) return tbstderr.getvalue().splitlines()[slice_start:slice_end] @@ -1814,11 +1814,11 @@ def check_traceback_format(self, cleanup_func=None): traceback_print(tb, file_) python_fmt = file_.getvalue() # Call all _tb and _exc functions - with captured_stderr() as tbstderr: + with captured_output("stderr") as tbstderr: traceback.print_tb(tb) tbfile = StringIO() traceback.print_tb(tb, file=tbfile) - with captured_stderr() as excstderr: + with captured_output("stderr") as excstderr: traceback.print_exc() excfmt = traceback.format_exc() excfile = StringIO() @@ -1855,7 +1855,7 @@ def cleanup_tb(tb): def test_stack_format(self): # Verify _stack functions. Note we have to use _getframe(1) to # compare them without this frame appearing in the output - with captured_stderr() as ststderr: + with captured_output("stderr") as ststderr: traceback.print_stack(sys._getframe(1)) stfile = StringIO() traceback.print_stack(sys._getframe(1), file=stfile) @@ -1868,7 +1868,7 @@ def test_stack_format(self): def test_print_stack(self): def prn(): traceback.print_stack() - with captured_stderr() as stderr: + with captured_output("stderr") as stderr: prn() lineno = prn.__code__.co_firstlineno self.assertEqual(stderr.getvalue().splitlines()[-4:], [ @@ -1889,7 +1889,7 @@ def _check_recursive_traceback_display(self, render_exc): def f(): f() - with captured_stderr() as stderr_f: + with captured_output("stderr") as stderr_f: try: f() except RecursionError: @@ -1940,7 +1940,7 @@ def g(count=10): return g(count-1) + 1 raise ValueError - with captured_stderr() as stderr_g: + with captured_output("stderr") as stderr_g: try: g() except ValueError: @@ -1980,7 +1980,7 @@ def h(count=10): return h(count-1) g() - with captured_stderr() as stderr_h: + with captured_output("stderr") as stderr_h: try: h() except ValueError: @@ -2010,7 +2010,7 @@ def h(count=10): self.assertEqual(actual, expected) # Check the boundary conditions. First, test just below the cutoff. - with captured_stderr() as stderr_g: + with captured_output("stderr") as stderr_g: try: g(traceback._RECURSIVE_CUTOFF) except ValueError: @@ -2042,7 +2042,7 @@ def h(count=10): self.assertEqual(actual, expected) # Second, test just above the cutoff. - with captured_stderr() as stderr_g: + with captured_output("stderr") as stderr_g: try: g(traceback._RECURSIVE_CUTOFF + 1) except ValueError: @@ -2114,7 +2114,7 @@ def __eq__(self, other): except UnhashableException as e: exc_val = e - with captured_stderr() as stderr_f: + with captured_output("stderr") as stderr_f: exception_print(exc_val) tb = stderr_f.getvalue().strip().splitlines() @@ -2135,7 +2135,7 @@ def test_exception_group_deep_recursion_capi(self): from _testcapi import exception_print LIMIT = 75 eg = self.deep_eg() - with captured_stderr() as stderr_f: + with captured_output("stderr") as stderr_f: with support.infinite_recursion(max_depth=LIMIT): exception_print(eg) output = stderr_f.getvalue() @@ -2146,7 +2146,7 @@ def test_exception_group_deep_recursion_capi(self): def test_exception_group_deep_recursion_traceback(self): LIMIT = 75 eg = self.deep_eg() - with captured_stderr() as stderr_f: + with captured_output("stderr") as stderr_f: with support.infinite_recursion(max_depth=LIMIT): traceback.print_exception(type(eg), eg, eg.__traceback__) output = stderr_f.getvalue() @@ -2156,7 +2156,7 @@ def test_exception_group_deep_recursion_traceback(self): @cpython_only def test_print_exception_bad_type_capi(self): from _testcapi import exception_print - with captured_stderr() as stderr: + with captured_output("stderr") as stderr: with support.catch_unraisable_exception(): exception_print(42) self.assertEqual( @@ -3013,7 +3013,7 @@ def get_report(self, e): e = self.get_exception(e) s = ''.join( traceback.format_exception(type(e), e, e.__traceback__)) - with captured_stderr() as sio: + with captured_output("stderr") as sio: traceback.print_exception(type(e), e, e.__traceback__) self.assertEqual(sio.getvalue(), s) return s @@ -3029,7 +3029,7 @@ class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): def get_report(self, e): from _testcapi import exception_print e = self.get_exception(e) - with captured_stderr() as s: + with captured_output("stderr") as s: exception_print(e) return s.getvalue() @@ -4833,7 +4833,7 @@ def foo(): foo() self.fail("No exception thrown.") except Exception as e: - with captured_stderr() as tbstderr: + with captured_output("stderr") as tbstderr: with unittest.mock.patch('_colorize.can_colorize', return_value=True): exception_print(e) actual = tbstderr.getvalue().splitlines() diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 891131032ad380..0e1a723ce3a151 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -1145,7 +1145,8 @@ class CommandLineTestCases: uuid = None # to be defined in subclasses def do_test_standalone_uuid(self, version): - with support.captured_stdout() as stdout: + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): self.uuid.main() output = stdout.getvalue().strip() u = self.uuid.UUID(output) @@ -1177,7 +1178,8 @@ def test_cli_name_required_for_uuid3(self, mock_err): @mock.patch.object(sys, "argv", [""]) def test_cli_uuid4_outputted_with_no_args(self): - with support.captured_stdout() as stdout: + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): self.uuid.main() output = stdout.getvalue().strip() @@ -1189,7 +1191,8 @@ def test_cli_uuid4_outputted_with_no_args(self): @mock.patch.object(sys, "argv", ["", "-C", "3"]) def test_cli_uuid4_outputted_with_count(self): - with support.captured_stdout() as stdout: + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): self.uuid.main() output = stdout.getvalue().strip().splitlines() @@ -1203,7 +1206,8 @@ def test_cli_uuid4_outputted_with_count(self): @mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-n", "@dns", "-N", "python.org"]) def test_cli_uuid3_ouputted_with_valid_namespace_and_name(self): - with support.captured_stdout() as stdout: + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): self.uuid.main() output = stdout.getvalue().strip() @@ -1216,7 +1220,8 @@ def test_cli_uuid3_ouputted_with_valid_namespace_and_name(self): @mock.patch.object(sys, "argv", ["", "-u", "uuid5", "-n", "@dns", "-N", "python.org"]) def test_cli_uuid5_ouputted_with_valid_namespace_and_name(self): - with support.captured_stdout() as stdout: + stdout = io.StringIO() + with contextlib.redirect_stdout(stdout): self.uuid.main() output = stdout.getvalue().strip() diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index b069b50cf12521..f89e94449b3031 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -891,7 +891,7 @@ def test_showwarning_missing(self): with self.module.catch_warnings(): self.module.filterwarnings("always", category=UserWarning) del self.module.showwarning - with support.captured_stderr() as stream: + with support.captured_output('stderr') as stream: self.module.warn(text) result = stream.getvalue() self.assertIn(text, result) @@ -905,7 +905,7 @@ def test_showwarnmsg_missing(self): show = self.module._showwarnmsg try: del self.module._showwarnmsg - with support.captured_stderr() as stream: + with support.captured_output('stderr') as stream: self.module.warn(text) result = stream.getvalue() finally: @@ -918,7 +918,7 @@ def test_showwarning_not_callable(self): with self.module.catch_warnings(): self.module.filterwarnings("always", category=UserWarning) self.module.showwarning = print - with support.captured_stdout(): + with support.captured_output('stdout'): self.module.warn('Warning!') self.module.showwarning = 23 self.assertRaises(TypeError, self.module.warn, "Warning!") @@ -933,7 +933,7 @@ def test_show_warning_output(self): with self.module.catch_warnings(): self.module.filterwarnings("always", category=UserWarning) del self.module.showwarning - with support.captured_stderr() as stream: + with support.captured_output('stderr') as stream: warning_tests.inner(text) result = stream.getvalue() self.assertEqual(result.count('\n'), 2, From 092a1c54d163fd160c48915069ab868bada1ab53 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Thu, 14 Aug 2025 12:25:04 +0400 Subject: [PATCH 4/5] Revert missing regrtest --- Lib/test/test_regrtest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index c5af188c22d5d6..5bc3c5924b07fb 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -5,8 +5,10 @@ """ import _colorize +import contextlib import dataclasses import glob +import io import locale import os.path import platform @@ -364,7 +366,7 @@ def test_threshold(self): def test_nowindows(self): for opt in '-n', '--nowindows': with self.subTest(opt=opt): - with support.captured_stderr() as stderr: + with contextlib.redirect_stderr(io.StringIO()) as stderr: ns = self.parse_args([opt]) self.assertTrue(ns.nowindows) err = stderr.getvalue() From 8a538cc1b028e1750abb6f4ee9503c0a8a4b267d Mon Sep 17 00:00:00 2001 From: donBarbos Date: Thu, 14 Aug 2025 14:54:57 +0400 Subject: [PATCH 5/5] Revert platform test fix --- Lib/test/test_platform.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 976e540394b4f7..479649053abc01 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -762,14 +762,13 @@ def invoke_platform(self, *flags): platform._main(args=flags) return output.getvalue() - @support.force_not_colorized def test_unknown_flag(self): - output = io.StringIO() with self.assertRaises(SystemExit): + output = io.StringIO() # suppress argparse error message with contextlib.redirect_stderr(output): _ = self.invoke_platform('--unknown') - self.assertStartsWith(output.getvalue(), "usage: ") + self.assertStartsWith(output, "usage: ") def test_invocation(self): flags = (