From 6cac1136665b70f72db291b95876d7affcf1d2db Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 8 Dec 2019 08:38:16 +0100 Subject: [PATCH] bpo-38991: Remove test.support.strip_python_stderr() (GH-17490) test.support: run_python_until_end(), assert_python_ok() and assert_python_failure() functions no longer strip whitespaces from stderr. --- Doc/library/test.rst | 16 +++--- Lib/test/support/__init__.py | 10 ---- Lib/test/support/script_helper.py | 3 +- Lib/test/test_cmd_line.py | 6 +-- Lib/test/test_cmd_line_script.py | 4 +- Lib/test/test_faulthandler.py | 3 +- Lib/test/test_gc.py | 6 +-- Lib/test/test_subprocess.py | 50 ++++++++----------- Lib/test/test_support.py | 1 - Lib/test/test_warnings/__init__.py | 3 +- .../2019-12-07-00-52-09.bpo-38991.JE3_o-.rst | 5 ++ 11 files changed, 46 insertions(+), 61 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2019-12-07-00-52-09.bpo-38991.JE3_o-.rst diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 4a61566c2239a1..73b3fe5cf06f86 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -686,13 +686,6 @@ The :mod:`test.support` module defines the following functions: ``sys.stdout`` if it's not set. -.. function:: strip_python_strerr(stderr) - - Strip the *stderr* of a Python process from potential debug output - emitted by the interpreter. This will typically be run on the result of - :meth:`subprocess.Popen.communicate`. - - .. function:: args_from_interpreter_flags() Return a list of command line arguments reproducing the current settings @@ -1499,6 +1492,9 @@ script execution tests. in a subprocess. The values can include ``__isolated``, ``__cleanenv``, ``__cwd``, and ``TERM``. + .. versionchanged:: 3.9 + The function no longer strips whitespaces from *stderr*. + .. function:: assert_python_ok(*args, **env_vars) @@ -1512,6 +1508,9 @@ script execution tests. Python is started in isolated mode (command line option ``-I``), except if the ``__isolated`` keyword is set to ``False``. + .. versionchanged:: 3.9 + The function no longer strips whitespaces from *stderr*. + .. function:: assert_python_failure(*args, **env_vars) @@ -1521,6 +1520,9 @@ script execution tests. See :func:`assert_python_ok` for more options. + .. versionchanged:: 3.9 + The function no longer strips whitespaces from *stderr*. + .. function:: spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 7e1b30cc160cae..215bab8131a044 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2512,16 +2512,6 @@ def swap_item(obj, item, new_val): if item in obj: del obj[item] -def strip_python_stderr(stderr): - """Strip the stderr of a Python process from potential debug output - emitted by the interpreter. - - This will typically be run on the result of the communicate() method - of a subprocess.Popen object. - """ - stderr = re.sub(br"\[\d+ refs, \d+ blocks\]\r?\n?", b"", stderr).strip() - return stderr - requires_type_collecting = unittest.skipIf(hasattr(sys, 'getcounts'), 'types are immortal if COUNT_ALLOCS is defined') diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py index 83519988e39478..37e576d4a770e0 100644 --- a/Lib/test/support/script_helper.py +++ b/Lib/test/support/script_helper.py @@ -11,7 +11,7 @@ import zipfile from importlib.util import source_from_cache -from test.support import make_legacy_pyc, strip_python_stderr +from test.support import make_legacy_pyc # Cached result of the expensive test performed in the function below. @@ -134,7 +134,6 @@ def run_python_until_end(*args, **env_vars): proc.kill() subprocess._cleanup() rc = proc.returncode - err = strip_python_stderr(err) return _PythonRunResult(rc, out, err), cmd_line def _assert_python(expected_success, /, *args, **env_vars): diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 497bfa9eb89de4..47810020dd353c 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -332,10 +332,10 @@ def test_output_newline(self): if sys.platform == 'win32': self.assertEqual(b'1\r\n2\r\n', out) - self.assertEqual(b'3\r\n4', err) + self.assertEqual(b'3\r\n4\r\n', err) else: self.assertEqual(b'1\n2\n', out) - self.assertEqual(b'3\n4', err) + self.assertEqual(b'3\n4\n', err) def test_unmached_quote(self): # Issue #10206: python program starting with unmatched quote @@ -391,7 +391,7 @@ def preexec(): stderr=subprocess.PIPE, preexec_fn=preexec) out, err = p.communicate() - self.assertEqual(support.strip_python_stderr(err), b'') + self.assertEqual(err, b'') self.assertEqual(p.returncode, 42) def test_no_stdin(self): diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 60723078efc6b2..2ac926deac4850 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -535,7 +535,7 @@ def test_pep_409_verbiage(self): script_name = _make_test_script(script_dir, 'script', script) exitcode, stdout, stderr = assert_python_failure(script_name) text = stderr.decode('ascii').split('\n') - self.assertEqual(len(text), 4) + self.assertEqual(len(text), 5) self.assertTrue(text[0].startswith('Traceback')) self.assertTrue(text[1].startswith(' File ')) self.assertTrue(text[3].startswith('NameError')) @@ -579,7 +579,7 @@ def test_issue20500_exit_with_exception_value(self): script_name = _make_test_script(script_dir, 'script', script) exitcode, stdout, stderr = assert_python_failure(script_name) text = stderr.decode('ascii') - self.assertEqual(text, "some text") + self.assertEqual(text.rstrip(), "some text") def test_syntaxerror_unindented_caret_position(self): script = "1 + 1 = 2\n" diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index a4427a537d1f86..ac8cf4686bf8ca 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -71,9 +71,8 @@ def get_output(self, code, filename=None, fd=None): with support.SuppressCrashReport(): process = script_helper.spawn_python('-c', code, pass_fds=pass_fds) with process: - stdout, stderr = process.communicate() + output, stderr = process.communicate() exitcode = process.wait() - output = support.strip_python_stderr(stdout) output = output.decode('ascii', 'backslashreplace') if filename: self.assertEqual(output, '') diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index fdb8752b66817d..c0d4a7507ae0d3 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -1,7 +1,7 @@ import unittest import unittest.mock from test.support import (verbose, refcount_test, run_unittest, - strip_python_stderr, cpython_only, start_threads, + cpython_only, start_threads, temp_dir, requires_type_collecting, TESTFN, unlink, import_module) from test.support.script_helper import assert_python_ok, make_script @@ -671,8 +671,8 @@ def run_command(code): p.stdout.close() p.stderr.close() self.assertEqual(p.returncode, 0) - self.assertEqual(stdout.strip(), b"") - return strip_python_stderr(stderr) + self.assertEqual(stdout, b"") + return stderr stderr = run_command(code % "0") self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at " diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 97dc09c564965a..f806be817b55bd 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -85,15 +85,6 @@ def tearDown(self): self.doCleanups() support.reap_children() - def assertStderrEqual(self, stderr, expected, msg=None): - # In a debug build, stuff like "[6580 refs]" is printed to stderr at - # shutdown time. That frustrates tests trying to check stderr produced - # from a spawned Python process. - actual = support.strip_python_stderr(stderr) - # strip_python_stderr also strips whitespace, so we do too. - expected = expected.strip() - self.assertEqual(actual, expected, msg) - class PopenTestException(Exception): pass @@ -547,7 +538,7 @@ def test_stderr_pipe(self): 'import sys; sys.stderr.write("strawberry")'], stderr=subprocess.PIPE) with p: - self.assertStderrEqual(p.stderr.read(), b"strawberry") + self.assertEqual(p.stderr.read(), b"strawberry") def test_stderr_filedes(self): # stderr is set to open file descriptor @@ -559,7 +550,7 @@ def test_stderr_filedes(self): stderr=d) p.wait() os.lseek(d, 0, 0) - self.assertStderrEqual(os.read(d, 1024), b"strawberry") + self.assertEqual(os.read(d, 1024), b"strawberry") def test_stderr_fileobj(self): # stderr is set to open file object @@ -570,7 +561,7 @@ def test_stderr_fileobj(self): stderr=tf) p.wait() tf.seek(0) - self.assertStderrEqual(tf.read(), b"strawberry") + self.assertEqual(tf.read(), b"strawberry") def test_stderr_redirect_with_no_stdout_redirect(self): # test stderr=STDOUT while stdout=None (not set) @@ -589,8 +580,8 @@ def test_stderr_redirect_with_no_stdout_redirect(self): stderr=subprocess.PIPE) stdout, stderr = p.communicate() #NOTE: stdout should get stderr from grandchild - self.assertStderrEqual(stdout, b'42') - self.assertStderrEqual(stderr, b'') # should be empty + self.assertEqual(stdout, b'42') + self.assertEqual(stderr, b'') # should be empty self.assertEqual(p.returncode, 0) def test_stdout_stderr_pipe(self): @@ -603,7 +594,7 @@ def test_stdout_stderr_pipe(self): stdout=subprocess.PIPE, stderr=subprocess.STDOUT) with p: - self.assertStderrEqual(p.stdout.read(), b"appleorange") + self.assertEqual(p.stdout.read(), b"appleorange") def test_stdout_stderr_file(self): # capture stdout and stderr to the same open file @@ -618,7 +609,7 @@ def test_stdout_stderr_file(self): stderr=tf) p.wait() tf.seek(0) - self.assertStderrEqual(tf.read(), b"appleorange") + self.assertEqual(tf.read(), b"appleorange") def test_stdout_filedes_of_stdout(self): # stdout is set to 1 (#1531862). @@ -767,7 +758,7 @@ def test_communicate_stderr(self): stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() self.assertEqual(stdout, None) - self.assertStderrEqual(stderr, b"pineapple") + self.assertEqual(stderr, b"pineapple") def test_communicate(self): p = subprocess.Popen([sys.executable, "-c", @@ -782,7 +773,7 @@ def test_communicate(self): self.addCleanup(p.stdin.close) (stdout, stderr) = p.communicate(b"banana") self.assertEqual(stdout, b"banana") - self.assertStderrEqual(stderr, b"pineapple") + self.assertEqual(stderr, b"pineapple") def test_communicate_timeout(self): p = subprocess.Popen([sys.executable, "-c", @@ -801,7 +792,7 @@ def test_communicate_timeout(self): # after it completes. (stdout, stderr) = p.communicate() self.assertEqual(stdout, "banana") - self.assertStderrEqual(stderr.encode(), b"pineapple\npear\n") + self.assertEqual(stderr.encode(), b"pineapple\npear\n") def test_communicate_timeout_large_output(self): # Test an expiring timeout while the child is outputting lots of data. @@ -887,7 +878,7 @@ def test_writes_before_communicate(self): p.stdin.write(b"banana") (stdout, stderr) = p.communicate(b"split") self.assertEqual(stdout, b"bananasplit") - self.assertStderrEqual(stderr, b"") + self.assertEqual(stderr, b"") def test_universal_newlines_and_text(self): args = [ @@ -1005,7 +996,6 @@ def test_universal_newlines_communicate_stdin_stdout_stderr(self): self.assertEqual("line1\nline2\nline3\nline4\nline5\n", stdout) # Python debug build push something like "[42442 refs]\n" # to stderr at exit of subprocess. - # Don't use assertStderrEqual because it strips CR and LF from output. self.assertTrue(stderr.startswith("eline2\neline6\neline7\n")) def test_universal_newlines_communicate_encodings(self): @@ -2240,13 +2230,13 @@ def test_send_signal(self): def test_kill(self): p = self._kill_process('kill') _, stderr = p.communicate() - self.assertStderrEqual(stderr, b'') + self.assertEqual(stderr, b'') self.assertEqual(p.wait(), -signal.SIGKILL) def test_terminate(self): p = self._kill_process('terminate') _, stderr = p.communicate() - self.assertStderrEqual(stderr, b'') + self.assertEqual(stderr, b'') self.assertEqual(p.wait(), -signal.SIGTERM) def test_send_signal_dead(self): @@ -2294,8 +2284,8 @@ def check_close_std_fds(self, fds): stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() - err = support.strip_python_stderr(err) - self.assertEqual((out, err), (b'apple', b'orange')) + self.assertEqual(out, b'apple') + self.assertEqual(err, b'orange') finally: self._restore_fds(saved_fds) @@ -2380,7 +2370,7 @@ def test_remapping_std_fds(self): os.lseek(fd, 0, 0) out = os.read(temp_fds[2], 1024) - err = support.strip_python_stderr(os.read(temp_fds[0], 1024)) + err = os.read(temp_fds[0], 1024).strip() self.assertEqual(out, b"got STDIN") self.assertEqual(err, b"err") @@ -2422,7 +2412,7 @@ def check_swap_fds(self, stdin_no, stdout_no, stderr_no): os.lseek(fd, 0, 0) out = os.read(stdout_no, 1024) - err = support.strip_python_stderr(os.read(stderr_no, 1024)) + err = os.read(stderr_no, 1024).strip() finally: self._restore_fds(saved_fds) @@ -3338,7 +3328,7 @@ def _kill_process(self, method, *args): p.stdout.read(1) getattr(p, method)(*args) _, stderr = p.communicate() - self.assertStderrEqual(stderr, b'') + self.assertEqual(stderr, b'') returncode = p.wait() self.assertNotEqual(returncode, 0) @@ -3361,7 +3351,7 @@ def _kill_dead_process(self, method, *args): # This shouldn't raise even though the child is now dead getattr(p, method)(*args) _, stderr = p.communicate() - self.assertStderrEqual(stderr, b'') + self.assertEqual(stderr, b'') rc = p.wait() self.assertEqual(rc, 42) @@ -3550,7 +3540,7 @@ def test_pipe(self): stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc: self.assertEqual(proc.stdout.read(), b"stdout") - self.assertStderrEqual(proc.stderr.read(), b"stderr") + self.assertEqual(proc.stderr.read(), b"stderr") self.assertTrue(proc.stdout.closed) self.assertTrue(proc.stderr.closed) diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index e3ce670b8437f9..eb27c0cf866b53 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -653,7 +653,6 @@ def test_fd_count(self): # run_doctest # threading_cleanup # reap_threads - # strip_python_stderr # can_symlink # skip_unless_symlink # SuppressCrashReport diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index d1031829514b25..3a6d64eaad1f89 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1219,7 +1219,8 @@ def __del__(self): a=A() """ rc, out, err = assert_python_ok("-c", code) - self.assertEqual(err.decode(), ':7: UserWarning: test') + self.assertEqual(err.decode().rstrip(), + ':7: UserWarning: test') def test_late_resource_warning(self): # Issue #21925: Emitting a ResourceWarning late during the Python diff --git a/Misc/NEWS.d/next/Tests/2019-12-07-00-52-09.bpo-38991.JE3_o-.rst b/Misc/NEWS.d/next/Tests/2019-12-07-00-52-09.bpo-38991.JE3_o-.rst new file mode 100644 index 00000000000000..cff5a65646551b --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2019-12-07-00-52-09.bpo-38991.JE3_o-.rst @@ -0,0 +1,5 @@ +:mod:`test.support`: :func:`~test.support.run_python_until_end`, +:func:`~test.support.assert_python_ok` and +:func:`~test.support.assert_python_failure` functions no longer strip +whitespaces from stderr. Remove ``test.support.strip_python_stderr()`` +function.