diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 4e7729c83f49a4..e36496baf4f4b2 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1549,6 +1549,19 @@ expression support in the :mod:`re` module). interpreted as in slice notation. +.. method:: str.dedent() + + Return without any common leading whitespace from every line. + + This can be used to make triple-quoted strings line up with the left edge of the + display, while still presenting them in the source code in indented form. + + Note that tabs and spaces are both treated as whitespace, but they are not + equal: the lines ``" hello"`` and ``"\thello"`` are considered to have no + common leading whitespace. + + .. versionadded:: 3.10 + .. method:: str.removeprefix(prefix, /) If the string starts with the *prefix* string, return diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index c4bff592dc0e71..1853f1396e2517 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -1324,3 +1324,4 @@ def translate(self, *args): return self.__class__(self.data.translate(*args)) def upper(self): return self.__class__(self.data.upper()) def zfill(self, width): return self.__class__(self.data.zfill(width)) + def dedent(self): return self.__class__(self.data.dedent()) diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 5e47e0773a9649..16ff78125cefcc 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -1,7 +1,6 @@ import sys import os from io import StringIO -import textwrap from distutils.core import Distribution from distutils.command.build_ext import build_ext @@ -82,7 +81,7 @@ def test_build_ext(self): else: ALREADY_TESTED = type(self).__name__ - code = textwrap.dedent(f""" + code = f""" tmp_dir = {self.tmp_dir!r} import sys @@ -108,7 +107,7 @@ def test_xx(self): unittest.main() - """) + """.dedent() assert_python_ok('-c', code) def test_solaris_enable_shared(self): @@ -474,7 +473,7 @@ def _try_compile_deployment_target(self, operator, target): deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c') with open(deptarget_c, 'w') as fp: - fp.write(textwrap.dedent('''\ + fp.write(('''\ #include int dummy; @@ -484,7 +483,7 @@ def _try_compile_deployment_target(self, operator, target): #error "Unexpected target" #endif - ''' % operator)) + ''' % operator).dedent()) # get the deployment target that the interpreter was built with target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') diff --git a/Lib/distutils/tests/test_check.py b/Lib/distutils/tests/test_check.py index e534aca1d47637..61d12a7ce387fd 100644 --- a/Lib/distutils/tests/test_check.py +++ b/Lib/distutils/tests/test_check.py @@ -1,6 +1,5 @@ """Tests for distutils.command.check.""" import os -import textwrap import unittest from test.support import run_unittest @@ -118,22 +117,22 @@ def test_check_restructuredtext_with_syntax_highlight(self): # Don't fail if there is a `code` or `code-block` directive example_rst_docs = [] - example_rst_docs.append(textwrap.dedent("""\ + example_rst_docs.append("""\ Here's some code: .. code:: python def foo(): pass - """)) - example_rst_docs.append(textwrap.dedent("""\ + """.dedent()) + example_rst_docs.append("""\ Here's some code: .. code-block:: python def foo(): pass - """)) + """.dedent()) for rest_with_code in example_rst_docs: pkg_info, dist = self.create_dist(long_description=rest_with_code) diff --git a/Lib/distutils/tests/test_dist.py b/Lib/distutils/tests/test_dist.py index cc34725a99efa4..575c8e3c2ea850 100644 --- a/Lib/distutils/tests/test_dist.py +++ b/Lib/distutils/tests/test_dist.py @@ -4,7 +4,6 @@ import sys import unittest import warnings -import textwrap from unittest import mock @@ -421,11 +420,11 @@ def test_download_url(self): self.assertIn('Metadata-Version: 1.1', meta) def test_long_description(self): - long_desc = textwrap.dedent("""\ + long_desc = """\ example:: We start here and continue here - and end here.""") + and end here.""".dedent() attrs = {"name": "package", "version": "1.0", "long_description": long_desc} diff --git a/Lib/distutils/tests/test_sdist.py b/Lib/distutils/tests/test_sdist.py index 23db1269591d66..ce76ee8efc3e0e 100644 --- a/Lib/distutils/tests/test_sdist.py +++ b/Lib/distutils/tests/test_sdist.py @@ -5,7 +5,6 @@ import warnings import zipfile from os.path import join -from textwrap import dedent from test.support import captured_stdout, check_warnings, run_unittest try: @@ -393,11 +392,11 @@ def test_manifest_marker(self): @unittest.skipUnless(ZLIB_SUPPORT, "Need zlib support to run") def test_manifest_comments(self): # make sure comments don't cause exceptions or wrong includes - contents = dedent("""\ + contents = """\ # bad.py #bad.py good.py - """) + """.dedent() dist, cmd = self.get_cmd() cmd.ensure_finalized() self.write_file((self.tmp_dir, cmd.manifest), contents) diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py index 236755d095272f..c73a51ec94b757 100644 --- a/Lib/distutils/tests/test_sysconfig.py +++ b/Lib/distutils/tests/test_sysconfig.py @@ -4,7 +4,6 @@ import shutil import subprocess import sys -import textwrap import unittest from distutils import sysconfig @@ -249,13 +248,13 @@ def test_customize_compiler_before_get_config_vars(self): # instance can be called without an explicit call to # get_config_vars(). with open(TESTFN, 'w') as f: - f.writelines(textwrap.dedent('''\ + f.writelines('''\ from distutils.core import Distribution config = Distribution().get_command_obj('config') # try_compile may pass or it may fail if no compiler # is found but it should not raise an exception. rc = config.try_compile('int x;') - ''')) + '''.dedent()) p = subprocess.Popen([str(sys.executable), TESTFN], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, diff --git a/Lib/idlelib/idle_test/htest.py b/Lib/idlelib/idle_test/htest.py index 1373b7642a6ea9..53711fe4daa62a 100644 --- a/Lib/idlelib/idle_test/htest.py +++ b/Lib/idlelib/idle_test/htest.py @@ -67,7 +67,6 @@ def _wrapper(parent): # htest # import idlelib.pyshell # Set Windows DPI awareness before Tk(). from importlib import import_module -import textwrap import tkinter as tk from tkinter.ttk import Scrollbar tk.NoDefaultRoot() @@ -209,7 +208,7 @@ def _wrapper(parent): # htest # _linenumbers_drag_scrolling_spec = { 'file': 'sidebar', 'kwds': {}, - 'msg': textwrap.dedent("""\ + 'msg': """\ 1. Click on the line numbers and drag down below the edge of the window, moving the mouse a bit and then leaving it there for a while. The text and line numbers should gradually scroll down, with the @@ -223,7 +222,7 @@ def _wrapper(parent): # htest # numbers should gradually scroll up, with the selection updated continuously. - 4. Repeat step #2, clicking a line number below the selection."""), + 4. Repeat step #2, clicking a line number below the selection.""".dedent(), } _multi_call_spec = { diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 5bd84aadcd8011..ccf115d0b0ce61 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -309,7 +309,7 @@ def fix_scaling(root): def fixdoc(fun, text): tem = (fun.__doc__ + '\n\n') if fun.__doc__ is not None else '' - fun.__doc__ = tem + textwrap.fill(textwrap.dedent(text)) + fun.__doc__ = tem + textwrap.fill(text.dedent()) RECURSIONLIMIT_DELTA = 30 diff --git a/Lib/lib2to3/tests/support.py b/Lib/lib2to3/tests/support.py index fe084e8903fc86..5a6390aabd2483 100644 --- a/Lib/lib2to3/tests/support.py +++ b/Lib/lib2to3/tests/support.py @@ -5,7 +5,6 @@ import unittest import os import os.path -from textwrap import dedent # Local imports from lib2to3 import pytree, refactor @@ -32,7 +31,7 @@ def run_all_tests(test_mod=None, tests=None): unittest.TextTestRunner(verbosity=2).run(tests) def reformat(string): - return dedent(string) + "\n\n" + return string.dedent() + "\n\n" def get_refactorer(fixer_pkg="lib2to3", fixers=None, options=None): """ diff --git a/Lib/lib2to3/tests/test_parser.py b/Lib/lib2to3/tests/test_parser.py index ba2bb787332edd..0c3219719e9ccc 100644 --- a/Lib/lib2to3/tests/test_parser.py +++ b/Lib/lib2to3/tests/test_parser.py @@ -599,7 +599,7 @@ def test_extended_unpacking(self): class TestLiterals(GrammarTest): def validate(self, s): - driver.parse_string(support.dedent(s) + "\n\n") + driver.parse_string(s.dedent() + "\n\n") def test_multiline_bytes_literals(self): s = """ diff --git a/Lib/site.py b/Lib/site.py index e981a142088fdf..062a5fbebbda77 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -635,8 +635,7 @@ def _script(): else: sys.exit(3) else: - import textwrap - print(textwrap.dedent(help % (sys.argv[0], os.pathsep))) + print((help % (sys.argv[0], os.pathsep)).dedent()) sys.exit(10) if __name__ == '__main__': diff --git a/Lib/test/mod_generics_cache.py b/Lib/test/mod_generics_cache.py index 6d35c58396d424..c7e915910e68e8 100644 --- a/Lib/test/mod_generics_cache.py +++ b/Lib/test/mod_generics_cache.py @@ -1,12 +1,11 @@ """Module for testing the behavior of generics across different modules.""" import sys -from textwrap import dedent from typing import TypeVar, Generic, Optional if sys.version_info[:2] >= (3, 6): - exec(dedent(""" + exec(""" default_a: Optional['A'] = None default_b: Optional['B'] = None @@ -24,7 +23,7 @@ class A(Generic[T]): my_inner_a1: 'B.A' my_inner_a2: A my_outer_a: 'A' # unless somebody calls get_type_hints with localns=B.__dict__ - """)) + """.dedent()) else: # This should stay in sync with the syntax above. __annotations__ = dict( default_a=Optional['A'], diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 6ef4c8989f55bf..5fa68a6adc2161 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -13,7 +13,6 @@ import threading import unittest import weakref -from textwrap import dedent from http.cookies import SimpleCookie try: @@ -1353,16 +1352,16 @@ def test_truncated_data(self): @reap_threads def test_unpickle_module_race(self): # https://bugs.python.org/issue34572 - locker_module = dedent(""" + locker_module = """ import threading barrier = threading.Barrier(2) - """) - locking_import_module = dedent(""" + """.dedent() + locking_import_module = """ import locker locker.barrier.wait() class ToBeUnpickled(object): pass - """) + """.dedent() os.mkdir(TESTFN) self.addCleanup(shutil.rmtree, TESTFN) diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index 30f8f98acc9dd3..c2f016fa9e148e 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -4,7 +4,6 @@ import os import pickle import sys -from textwrap import dedent import threading import time import unittest @@ -28,12 +27,12 @@ def powerset(*sets): def _captured_script(script): r, w = os.pipe() indented = script.replace('\n', '\n ') - wrapped = dedent(f""" + wrapped = f""" import contextlib with open({w}, 'w') as spipe: with contextlib.redirect_stdout(spipe): {indented} - """) + """.dedent() return wrapped, open(r) @@ -48,11 +47,11 @@ def _run_output(interp, request, shared=None): def _running(interp): r, w = os.pipe() def run(): - interpreters.run_string(interp, dedent(f""" + interpreters.run_string(interp, f""" # wait for "signal" with open({r}) as rpipe: rpipe.read() - """)) + """.dedent()) t = threading.Thread(target=run) t.start() @@ -79,7 +78,7 @@ def run_interp(id, source, **shared): def _run_interp(id, source, shared, _mainns={}): - source = dedent(source) + source = source.dedent() main = interpreters.get_main() if main == id: if interpreters.get_current() != main: @@ -445,12 +444,12 @@ def test_main(self): def test_subinterpreter(self): main = interpreters.get_main() interp = interpreters.create() - out = _run_output(interp, dedent(""" + out = _run_output(interp, """ import _xxsubinterpreters as _interpreters cur = _interpreters.get_current() print(cur) assert isinstance(cur, _interpreters.InterpreterID) - """)) + """.dedent()) cur = int(out.strip()) _, expected = interpreters.list_all() self.assertEqual(cur, expected) @@ -468,12 +467,12 @@ def test_from_main(self): def test_from_subinterpreter(self): [expected] = interpreters.list_all() interp = interpreters.create() - out = _run_output(interp, dedent(""" + out = _run_output(interp, """ import _xxsubinterpreters as _interpreters main = _interpreters.get_main() print(main) assert isinstance(main, _interpreters.InterpreterID) - """)) + """.dedent()) main = int(out.strip()) self.assertEqual(main, expected) @@ -494,13 +493,13 @@ def test_subinterpreter(self): def test_from_subinterpreter(self): interp = interpreters.create() - out = _run_output(interp, dedent(f""" + out = _run_output(interp, f""" import _xxsubinterpreters as _interpreters if _interpreters.is_running({interp}): print(True) else: print(False) - """)) + """.dedent()) self.assertEqual(out.strip(), 'True') def test_already_destroyed(self): @@ -613,12 +612,12 @@ def f(): def test_in_subinterpreter(self): main, = interpreters.list_all() id1 = interpreters.create() - out = _run_output(id1, dedent(""" + out = _run_output(id1, """ import _xxsubinterpreters as _interpreters id = _interpreters.create() print(id) assert isinstance(id, _interpreters.InterpreterID) - """)) + """.dedent()) id2 = int(out.strip()) self.assertEqual(set(interpreters.list_all()), {main, id1, id2}) @@ -629,11 +628,11 @@ def test_in_threaded_subinterpreter(self): id2 = None def f(): nonlocal id2 - out = _run_output(id1, dedent(""" + out = _run_output(id1, """ import _xxsubinterpreters as _interpreters id = _interpreters.create() print(id) - """)) + """.dedent()) id2 = int(out.strip()) t = threading.Thread(target=f) @@ -723,13 +722,13 @@ def test_bad_id(self): def test_from_current(self): main, = interpreters.list_all() id = interpreters.create() - script = dedent(f""" + script = f""" import _xxsubinterpreters as _interpreters try: _interpreters.destroy({id}) except RuntimeError: pass - """) + """.dedent() interpreters.run_string(id, script) self.assertEqual(set(interpreters.list_all()), {main, id}) @@ -738,10 +737,10 @@ def test_from_sibling(self): main, = interpreters.list_all() id1 = interpreters.create() id2 = interpreters.create() - script = dedent(f""" + script = f""" import _xxsubinterpreters as _interpreters _interpreters.destroy({id2}) - """) + """.dedent() interpreters.run_string(id1, script) self.assertEqual(set(interpreters.list_all()), {main, id1}) @@ -770,10 +769,10 @@ def test_still_running(self): class RunStringTests(TestBase): - SCRIPT = dedent(""" + SCRIPT = """ with open('{}', 'w') as out: out.write('{}') - """) + """.dedent() FILENAME = 'spam' def setUp(self): @@ -837,14 +836,14 @@ def test_fork(self): file.flush() expected = 'spam spam spam spam spam' - script = dedent(f""" + script = f""" import os try: os.fork() except RuntimeError: with open('{file.name}', 'w') as out: out.write('{expected}') - """) + """.dedent() interpreters.run_string(self.id, script) file.seek(0) @@ -905,16 +904,16 @@ def test_SystemExit(self): def test_sys_exit(self): with self.assert_run_failed(SystemExit): - interpreters.run_string(self.id, dedent(""" + interpreters.run_string(self.id, """ import sys sys.exit() - """)) + """.dedent()) with self.assert_run_failed(SystemExit, '42'): - interpreters.run_string(self.id, dedent(""" + interpreters.run_string(self.id, """ import sys sys.exit(42) - """)) + """.dedent()) def test_with_shared(self): r, w = os.pipe() @@ -924,7 +923,7 @@ def test_with_shared(self): 'eggs': b'-1', 'cheddar': None, } - script = dedent(f""" + script = f""" eggs = int(eggs) spam = 42 result = spam + eggs @@ -934,7 +933,7 @@ def test_with_shared(self): import pickle with open({w}, 'wb') as chan: pickle.dump(ns, chan) - """) + """.dedent() interpreters.run_string(self.id, script, shared) with open(r, 'rb') as chan: ns = pickle.load(chan) @@ -945,27 +944,27 @@ def test_with_shared(self): self.assertIsNone(ns['cheddar']) def test_shared_overwrites(self): - interpreters.run_string(self.id, dedent(""" + interpreters.run_string(self.id, """ spam = 'eggs' ns1 = dict(vars()) del ns1['__builtins__'] - """)) + """.dedent()) shared = {'spam': b'ham'} - script = dedent(f""" + script = f""" ns2 = dict(vars()) del ns2['__builtins__'] - """) + """.dedent() interpreters.run_string(self.id, script, shared) r, w = os.pipe() - script = dedent(f""" + script = f""" ns = dict(vars()) del ns['__builtins__'] import pickle with open({w}, 'wb') as chan: pickle.dump(ns, chan) - """) + """.dedent() interpreters.run_string(self.id, script) with open(r, 'rb') as chan: ns = pickle.load(chan) @@ -978,7 +977,7 @@ def test_shared_overwrites_default_vars(self): r, w = os.pipe() shared = {'__name__': b'not __main__'} - script = dedent(f""" + script = f""" spam = 42 ns = dict(vars()) @@ -986,7 +985,7 @@ def test_shared_overwrites_default_vars(self): import pickle with open({w}, 'wb') as chan: pickle.dump(ns, chan) - """) + """.dedent() interpreters.run_string(self.id, script, shared) with open(r, 'rb') as chan: ns = pickle.load(chan) @@ -995,7 +994,7 @@ def test_shared_overwrites_default_vars(self): def test_main_reused(self): r, w = os.pipe() - interpreters.run_string(self.id, dedent(f""" + interpreters.run_string(self.id, f""" spam = True ns = dict(vars()) @@ -1004,12 +1003,12 @@ def test_main_reused(self): with open({w}, 'wb') as chan: pickle.dump(ns, chan) del ns, pickle, chan - """)) + """.dedent()) with open(r, 'rb') as chan: ns1 = pickle.load(chan) r, w = os.pipe() - interpreters.run_string(self.id, dedent(f""" + interpreters.run_string(self.id, f""" eggs = False ns = dict(vars()) @@ -1017,7 +1016,7 @@ def test_main_reused(self): import pickle with open({w}, 'wb') as chan: pickle.dump(ns, chan) - """)) + """.dedent()) with open(r, 'rb') as chan: ns2 = pickle.load(chan) @@ -1029,7 +1028,7 @@ def test_main_reused(self): def test_execution_namespace_is_main(self): r, w = os.pipe() - script = dedent(f""" + script = f""" spam = 42 ns = dict(vars()) @@ -1037,7 +1036,7 @@ def test_execution_namespace_is_main(self): import pickle with open({w}, 'wb') as chan: pickle.dump(ns, chan) - """) + """.dedent() interpreters.run_string(self.id, script) with open(r, 'rb') as chan: ns = pickle.load(chan) @@ -1056,21 +1055,20 @@ def test_execution_namespace_is_main(self): # XXX Fix this test! @unittest.skip('blocking forever') def test_still_running_at_exit(self): - script = dedent(f""" - from textwrap import dedent + script = f""" import threading import _xxsubinterpreters as _interpreters id = _interpreters.create() def f(): - _interpreters.run_string(id, dedent(''' + _interpreters.run_string(id, ''' import time # Give plenty of time for the main interpreter to finish. time.sleep(1_000_000) - ''')) + '''.dedent()) t = threading.Thread(target=f) t.start() - """) + """.dedent() with support.temp_dir() as dirname: filename = script_helper.make_script(dirname, 'interp', script) with script_helper.spawn_python(filename) as proc: @@ -1190,19 +1188,19 @@ def test_sequential_ids(self): def test_ids_global(self): id1 = interpreters.create() - out = _run_output(id1, dedent(""" + out = _run_output(id1, """ import _xxsubinterpreters as _interpreters cid = _interpreters.channel_create() print(cid) - """)) + """.dedent()) cid1 = int(out.strip()) id2 = interpreters.create() - out = _run_output(id2, dedent(""" + out = _run_output(id2, """ import _xxsubinterpreters as _interpreters cid = _interpreters.channel_create() print(cid) - """)) + """.dedent()) cid2 = int(out.strip()) self.assertEqual(cid2, int(cid1) + 1) @@ -1220,7 +1218,7 @@ def test_send_recv_main(self): def test_send_recv_same_interpreter(self): id1 = interpreters.create() - out = _run_output(id1, dedent(""" + out = _run_output(id1, """ import _xxsubinterpreters as _interpreters cid = _interpreters.channel_create() orig = b'spam' @@ -1228,15 +1226,15 @@ def test_send_recv_same_interpreter(self): obj = _interpreters.channel_recv(cid) assert obj is not orig assert obj == orig - """)) + """.dedent()) def test_send_recv_different_interpreters(self): cid = interpreters.channel_create() id1 = interpreters.create() - out = _run_output(id1, dedent(f""" + out = _run_output(id1, f""" import _xxsubinterpreters as _interpreters _interpreters.channel_send({cid}, b'spam') - """)) + """.dedent()) obj = interpreters.channel_recv(cid) self.assertEqual(obj, b'spam') @@ -1268,7 +1266,7 @@ def test_send_recv_different_interpreters_and_threads(self): def f(): nonlocal out - out = _run_output(id1, dedent(f""" + out = _run_output(id1, f""" import time import _xxsubinterpreters as _interpreters while True: @@ -1279,7 +1277,7 @@ def f(): time.sleep(0.1) assert(obj == b'spam') _interpreters.channel_send({cid}, b'eggs') - """)) + """.dedent()) t = threading.Thread(target=f) t.start() @@ -1306,11 +1304,11 @@ def test_run_string_arg_unresolved(self): cid = interpreters.channel_create() interp = interpreters.create() - out = _run_output(interp, dedent(""" + out = _run_output(interp, """ import _xxsubinterpreters as _interpreters print(cid.end) _interpreters.channel_send(cid, b'spam') - """), + """.dedent(), dict(cid=cid.send)) obj = interpreters.channel_recv(cid) @@ -1326,11 +1324,11 @@ def test_run_string_arg_resolved(self): cid = interpreters._channel_id(cid, _resolve=True) interp = interpreters.create() - out = _run_output(interp, dedent(""" + out = _run_output(interp, """ import _xxsubinterpreters as _interpreters print(chan.id.end) _interpreters.channel_send(chan.id, b'spam') - """), + """.dedent(), dict(chan=cid.send)) obj = interpreters.channel_recv(cid) @@ -1354,24 +1352,24 @@ def test_close_multiple_users(self): cid = interpreters.channel_create() id1 = interpreters.create() id2 = interpreters.create() - interpreters.run_string(id1, dedent(f""" + interpreters.run_string(id1, f""" import _xxsubinterpreters as _interpreters _interpreters.channel_send({cid}, b'spam') - """)) - interpreters.run_string(id2, dedent(f""" + """.dedent()) + interpreters.run_string(id2, f""" import _xxsubinterpreters as _interpreters _interpreters.channel_recv({cid}) - """)) + """.dedent()) interpreters.channel_close(cid) with self.assertRaises(interpreters.RunFailedError) as cm: - interpreters.run_string(id1, dedent(f""" + interpreters.run_string(id1, f""" _interpreters.channel_send({cid}, b'spam') - """)) + """.dedent()) self.assertIn('ChannelClosedError', str(cm.exception)) with self.assertRaises(interpreters.RunFailedError) as cm: - interpreters.run_string(id2, dedent(f""" + interpreters.run_string(id2, f""" _interpreters.channel_send({cid}, b'spam') - """)) + """.dedent()) self.assertIn('ChannelClosedError', str(cm.exception)) def test_close_multiple_times(self): @@ -1497,10 +1495,10 @@ def test_close_by_unassociated_interp(self): cid = interpreters.channel_create() interpreters.channel_send(cid, b'spam') interp = interpreters.create() - interpreters.run_string(interp, dedent(f""" + interpreters.run_string(interp, f""" import _xxsubinterpreters as _interpreters _interpreters.channel_close({cid}, force=True) - """)) + """.dedent()) with self.assertRaises(interpreters.ChannelClosedError): interpreters.channel_recv(cid) with self.assertRaises(interpreters.ChannelClosedError): @@ -1578,19 +1576,19 @@ def test_multiple_users(self): cid = interpreters.channel_create() id1 = interpreters.create() id2 = interpreters.create() - interpreters.run_string(id1, dedent(f""" + interpreters.run_string(id1, f""" import _xxsubinterpreters as _interpreters _interpreters.channel_send({cid}, b'spam') - """)) - out = _run_output(id2, dedent(f""" + """.dedent()) + out = _run_output(id2, f""" import _xxsubinterpreters as _interpreters obj = _interpreters.channel_recv({cid}) _interpreters.channel_release({cid}) print(repr(obj)) - """)) - interpreters.run_string(id1, dedent(f""" + """.dedent()) + interpreters.run_string(id1, f""" _interpreters.channel_release({cid}) - """)) + """.dedent()) self.assertEqual(out.strip(), "b'spam'") @@ -1636,10 +1634,10 @@ def test_by_unassociated_interp(self): cid = interpreters.channel_create() interpreters.channel_send(cid, b'spam') interp = interpreters.create() - interpreters.run_string(interp, dedent(f""" + interpreters.run_string(interp, f""" import _xxsubinterpreters as _interpreters _interpreters.channel_release({cid}) - """)) + """.dedent()) obj = interpreters.channel_recv(cid) interpreters.channel_release(cid) @@ -1651,11 +1649,11 @@ def test_close_if_unassociated(self): # XXX Something's not right with this test... cid = interpreters.channel_create() interp = interpreters.create() - interpreters.run_string(interp, dedent(f""" + interpreters.run_string(interp, f""" import _xxsubinterpreters as _interpreters obj = _interpreters.channel_send({cid}, b'spam') _interpreters.channel_release({cid}) - """)) + """.dedent()) with self.assertRaises(interpreters.ChannelClosedError): interpreters.channel_recv(cid) diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 9899a53d6d1974..1f285b52dd7aaa 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -5,7 +5,6 @@ import shutil import stat import sys -import textwrap import tempfile import unittest import argparse @@ -2060,7 +2059,7 @@ def test_optional_subparsers(self): def test_help(self): self.assertEqual(self.parser.format_usage(), 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') - self.assertEqual(self.parser.format_help(), textwrap.dedent('''\ + self.assertEqual(self.parser.format_help(), '''\ usage: PROG [-h] [--foo] bar {1,2,3} ... main description @@ -2072,14 +2071,14 @@ def test_help(self): optional arguments: -h, --help show this help message and exit --foo foo help - ''')) + '''.dedent()) def test_help_extra_prefix_chars(self): # Make sure - is still used for help if it is a non-first prefix char parser = self._get_parser(prefix_chars='+:-') self.assertEqual(parser.format_usage(), 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n') - self.assertEqual(parser.format_help(), textwrap.dedent('''\ + self.assertEqual(parser.format_help(), '''\ usage: PROG [-h] [++foo] bar {1,2,3} ... main description @@ -2091,7 +2090,7 @@ def test_help_extra_prefix_chars(self): optional arguments: -h, --help show this help message and exit ++foo foo help - ''')) + '''.dedent()) def test_help_non_breaking_spaces(self): parser = ErrorRaisingArgumentParser( @@ -2100,7 +2099,7 @@ def test_help_non_breaking_spaces(self): "--non-breaking", action='store_false', help='help message containing non-breaking spaces shall not ' 'wrap\N{NO-BREAK SPACE}at non-breaking spaces') - self.assertEqual(parser.format_help(), textwrap.dedent('''\ + self.assertEqual(parser.format_help(), '''\ usage: PROG [-h] [--non-breaking] main description @@ -2109,13 +2108,13 @@ def test_help_non_breaking_spaces(self): -h, --help show this help message and exit --non-breaking help message containing non-breaking spaces shall not wrap\N{NO-BREAK SPACE}at non-breaking spaces - ''')) + '''.dedent()) def test_help_alternate_prefix_chars(self): parser = self._get_parser(prefix_chars='+:/') self.assertEqual(parser.format_usage(), 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n') - self.assertEqual(parser.format_help(), textwrap.dedent('''\ + self.assertEqual(parser.format_help(), '''\ usage: PROG [+h] [++foo] bar {1,2,3} ... main description @@ -2127,13 +2126,13 @@ def test_help_alternate_prefix_chars(self): optional arguments: +h, ++help show this help message and exit ++foo foo help - ''')) + '''.dedent()) def test_parser_command_help(self): self.assertEqual(self.command_help_parser.format_usage(), 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.command_help_parser.format_help(), - textwrap.dedent('''\ + '''\ usage: PROG [-h] [--foo] bar {1,2,3} ... main description @@ -2148,7 +2147,7 @@ def test_parser_command_help(self): optional arguments: -h, --help show this help message and exit --foo foo help - ''')) + '''.dedent()) def test_subparser_title_help(self): parser = ErrorRaisingArgumentParser(prog='PROG', @@ -2162,7 +2161,7 @@ def test_subparser_title_help(self): parser2 = subparsers.add_parser('2') self.assertEqual(parser.format_usage(), 'usage: PROG [-h] [--foo] bar {1,2} ...\n') - self.assertEqual(parser.format_help(), textwrap.dedent('''\ + self.assertEqual(parser.format_help(), '''\ usage: PROG [-h] [--foo] bar {1,2} ... main description @@ -2178,7 +2177,7 @@ def test_subparser_title_help(self): command help {1,2} additional text - ''')) + '''.dedent()) def _test_subparser_help(self, args_str, expected_help): with self.assertRaises(ArgumentParserError) as cm: @@ -2186,7 +2185,7 @@ def _test_subparser_help(self, args_str, expected_help): self.assertEqual(expected_help, cm.exception.stdout) def test_subparser1_help(self): - self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\ + self._test_subparser_help('5.0 1 -h', '''\ usage: PROG bar 1 [-h] [-w W] {a,b,c} 1 description @@ -2197,10 +2196,10 @@ def test_subparser1_help(self): optional arguments: -h, --help show this help message and exit -w W w help - ''')) + '''.dedent()) def test_subparser2_help(self): - self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\ + self._test_subparser_help('5.0 2 -h', '''\ usage: PROG bar 2 [-h] [-y {1,2,3}] [z ...] 2 description @@ -2211,7 +2210,7 @@ def test_subparser2_help(self): optional arguments: -h, --help show this help message and exit -y {1,2,3} y help - ''')) + '''.dedent()) def test_alias_invocation(self): parser = self._get_parser(aliases=True) @@ -2232,7 +2231,7 @@ def test_error_alias_invocation(self): def test_alias_help(self): parser = self._get_parser(aliases=True, subparser_help=True) self.maxDiff = None - self.assertEqual(parser.format_help(), textwrap.dedent("""\ + self.assertEqual(parser.format_help(), """\ usage: PROG [-h] [--foo] bar COMMAND ... main description @@ -2250,7 +2249,7 @@ def test_alias_help(self): 1 help 2 2 help 3 3 help - """)) + """.dedent()) # ============ # Groups tests @@ -2421,7 +2420,7 @@ def test_parent_help(self): parser = ErrorRaisingArgumentParser(parents=parents) parser_help = parser.format_help() progname = self.main_program - self.assertEqual(parser_help, textwrap.dedent('''\ + self.assertEqual(parser_help, '''\ usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z positional arguments: @@ -2438,7 +2437,7 @@ def test_parent_help(self): x: -y Y - '''.format(progname, ' ' if progname else '' ))) + '''.format(progname, ' ' if progname else '' ).dedent()) def test_groups_parents(self): parent = ErrorRaisingArgumentParser(add_help=False) @@ -2455,7 +2454,7 @@ def test_groups_parents(self): parser_help = parser.format_help() progname = self.main_program - self.assertEqual(parser_help, textwrap.dedent('''\ + self.assertEqual(parser_help, '''\ usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z] optional arguments: @@ -2468,7 +2467,7 @@ def test_groups_parents(self): -w W -x X - '''.format(progname, ' ' if progname else '' ))) + '''.format(progname, ' ' if progname else '' ).dedent()) # ============================== # Mutually exclusive group tests @@ -2510,7 +2509,7 @@ def test_help(self): --soup --nuts ''' - self.assertEqual(parser.format_help(), textwrap.dedent(expected)) + self.assertEqual(parser.format_help(), expected.dedent()) class MEMixin(object): @@ -2542,22 +2541,22 @@ def test_successes_when_required(self): def test_usage_when_not_required(self): format_usage = self.get_parser(required=False).format_usage expected_usage = self.usage_when_not_required - self.assertEqual(format_usage(), textwrap.dedent(expected_usage)) + self.assertEqual(format_usage(), expected_usage.dedent()) def test_usage_when_required(self): format_usage = self.get_parser(required=True).format_usage expected_usage = self.usage_when_required - self.assertEqual(format_usage(), textwrap.dedent(expected_usage)) + self.assertEqual(format_usage(), expected_usage.dedent()) def test_help_when_not_required(self): format_help = self.get_parser(required=False).format_help help = self.usage_when_not_required + self.help - self.assertEqual(format_help(), textwrap.dedent(help)) + self.assertEqual(format_help(), help.dedent()) def test_help_when_required(self): format_help = self.get_parser(required=True).format_help help = self.usage_when_required + self.help - self.assertEqual(format_help(), textwrap.dedent(help)) + self.assertEqual(format_help(), help.dedent()) class TestMutuallyExclusiveSimple(MEMixin, TestCase): @@ -3156,7 +3155,7 @@ def _get_parser(self, tester): def _test(self, tester, parser_text): expected_text = getattr(tester, self.func_suffix) - expected_text = textwrap.dedent(expected_text) + expected_text = expected_text.dedent() tester.assertEqual(expected_text, parser_text) def test_format(self, tester): @@ -4584,24 +4583,24 @@ def test_resolve_error(self): parser.add_argument('-x', help='OLD X') parser.add_argument('-x', help='NEW X') - self.assertEqual(parser.format_help(), textwrap.dedent('''\ + self.assertEqual(parser.format_help(), '''\ usage: PROG [-h] [-x X] optional arguments: -h, --help show this help message and exit -x X NEW X - ''')) + '''.dedent()) parser.add_argument('--spam', metavar='OLD_SPAM') parser.add_argument('--spam', metavar='NEW_SPAM') - self.assertEqual(parser.format_help(), textwrap.dedent('''\ + self.assertEqual(parser.format_help(), '''\ usage: PROG [-h] [-x X] [--spam NEW_SPAM] optional arguments: -h, --help show this help message and exit -x X NEW X --spam NEW_SPAM - ''')) + '''.dedent()) # ============================= @@ -5324,14 +5323,14 @@ def setUp(self): def test_help_with_metavar(self): help_text = self.parser.format_help() - self.assertEqual(help_text, textwrap.dedent('''\ + self.assertEqual(help_text, '''\ usage: this_is_spammy_prog_with_a_long_name_sorry_about_the_name [-h] [--proxy ] optional arguments: -h, --help show this help message and exit --proxy - ''')) + '''.dedent()) class TestExitOnError(TestCase): diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 9063b3d2d7b744..9177bf3b96f234 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -5,8 +5,6 @@ import unittest import warnings import weakref -from textwrap import dedent - from test import support def to_tuple(t): @@ -1540,13 +1538,13 @@ def test_lambda(self): self._check_content(s, lam.args.vararg, 'y') def test_func_def(self): - s = dedent(''' + s = ''' def func(x: int, *args: str, z: float = 0, **kwargs: Any) -> bool: return True - ''').strip() + '''.dedent().strip() fdef = ast.parse(s).body[0] self._check_end_pos(fdef, 5, 15) self._check_content(s, fdef.body[0], 'return True') @@ -1569,10 +1567,10 @@ def test_call_noargs(self): self._check_end_pos(call, 1, 6) def test_class_def(self): - s = dedent(''' + s = ''' class C(A, B): x: int = 0 - ''').strip() + '''.dedent().strip() cdef = ast.parse(s).body[0] self._check_end_pos(cdef, 2, 14) self._check_content(s, cdef.bases[1], 'B') @@ -1584,20 +1582,20 @@ def test_class_kw(self): self._check_content(s, cdef.keywords[0].value, 'abc.ABCMeta') def test_multi_line_str(self): - s = dedent(''' + s = ''' x = """Some multi-line text. It goes on starting from same indent.""" - ''').strip() + '''.dedent().strip() assign = ast.parse(s).body[0] self._check_end_pos(assign, 3, 40) self._check_end_pos(assign.value, 3, 40) def test_continued_str(self): - s = dedent(''' + s = ''' x = "first part" \\ "second part" - ''').strip() + '''.dedent().strip() assign = ast.parse(s).body[0] self._check_end_pos(assign, 2, 13) self._check_end_pos(assign.value, 2, 13) @@ -1605,7 +1603,7 @@ def test_continued_str(self): def test_suites(self): # We intentionally put these into the same string to check # that empty lines are not part of the suite. - s = dedent(''' + s = ''' while True: pass @@ -1625,7 +1623,7 @@ def test_suites(self): pass pass - ''').strip() + '''.dedent().strip() mod = ast.parse(s) while_loop = mod.body[0] if_stmt = mod.body[1] @@ -1653,7 +1651,7 @@ def test_fstring(self): self._check_content(s, binop, 'x + y') def test_fstring_multi_line(self): - s = dedent(''' + s = ''' f"""Some multi-line text. { arg_one @@ -1661,7 +1659,7 @@ def test_fstring_multi_line(self): arg_two } It goes on...""" - ''').strip() + '''.dedent().strip() fstr = self._parse_value(s) binop = fstr.values[1].value self._check_end_pos(binop, 5, 7) @@ -1669,22 +1667,22 @@ def test_fstring_multi_line(self): self._check_content(s, binop.right, 'arg_two') def test_import_from_multi_line(self): - s = dedent(''' + s = ''' from x.y.z import ( a, b, c as c ) - ''').strip() + '''.dedent().strip() imp = ast.parse(s).body[0] self._check_end_pos(imp, 3, 1) def test_slices(self): s1 = 'f()[1, 2] [0]' s2 = 'x[ a.b: c.d]' - sm = dedent(''' + sm = ''' x[ a.b: f () , g () : c.d ] - ''').strip() + '''.dedent().strip() i1, i2, im = map(self._parse_value, (s1, s2, sm)) self._check_content(s1, i1.value, 'f()[1, 2]') self._check_content(s1, i1.value.slice, '1, 2') @@ -1695,11 +1693,11 @@ def test_slices(self): self._check_end_pos(im, 3, 3) def test_binop(self): - s = dedent(''' + s = ''' (1 * 2 + (3 ) + 4 ) - ''').strip() + '''.dedent().strip() binop = self._parse_value(s) self._check_end_pos(binop, 2, 6) self._check_content(s, binop.right, '4') @@ -1707,11 +1705,11 @@ def test_binop(self): self._check_content(s, binop.left.right, '3') def test_boolop(self): - s = dedent(''' + s = ''' if (one_condition and (other_condition or yet_another_one)): pass - ''').strip() + '''.dedent().strip() bop = ast.parse(s).body[0].test self._check_end_pos(bop, 2, 44) self._check_content(s, bop.values[1], @@ -1721,11 +1719,11 @@ def test_tuples(self): s1 = 'x = () ;' s2 = 'x = 1 , ;' s3 = 'x = (1 , 2 ) ;' - sm = dedent(''' + sm = ''' x = ( a, b, ) - ''').strip() + '''.dedent().strip() t1, t2, t3, tm = map(self._parse_value, (s1, s2, s3, sm)) self._check_content(s1, t1, '()') self._check_content(s2, t2, '1 ,') @@ -1777,10 +1775,10 @@ def test_displays(self): self._check_content(s2, c2.values[1], 'g ()') def test_comprehensions(self): - s = dedent(''' + s = ''' x = [{x for x, y in stuff if cond.x} for stuff in things] - ''').strip() + '''.dedent().strip() cmp = self._parse_value(s) self._check_end_pos(cmp, 2, 37) self._check_content(s, cmp.generators[0].iter, 'things') @@ -1789,35 +1787,35 @@ def test_comprehensions(self): self._check_content(s, cmp.elt.generators[0].target, 'x, y') def test_yield_await(self): - s = dedent(''' + s = ''' async def f(): yield x await y - ''').strip() + '''.dedent().strip() fdef = ast.parse(s).body[0] self._check_content(s, fdef.body[0].value, 'yield x') self._check_content(s, fdef.body[1].value, 'await y') def test_source_segment_multi(self): - s_orig = dedent(''' + s_orig = ''' x = ( a, b, ) + () - ''').strip() - s_tuple = dedent(''' + '''.dedent().strip() + s_tuple = ''' ( a, b, ) - ''').strip() + '''.dedent().strip() binop = self._parse_value(s_orig) self.assertEqual(ast.get_source_segment(s_orig, binop.left), s_tuple) def test_source_segment_padded(self): - s_orig = dedent(''' + s_orig = ''' class C: def fun(self) -> None: "ЖЖЖЖЖ" - ''').strip() + '''.dedent().strip() s_method = ' def fun(self) -> None:\n' \ ' "ЖЖЖЖЖ"' cdef = ast.parse(s_orig).body[0] @@ -1834,11 +1832,11 @@ def test_source_segment_endings(self): self._check_content(s, z, 'z = 1') def test_source_segment_tabs(self): - s = dedent(''' + s = ''' class C: \t\f def fun(self) -> None: \t\f pass - ''').strip() + '''.dedent().strip() s_method = ' \t\f def fun(self) -> None:\n' \ ' \t\f pass' @@ -1859,7 +1857,7 @@ def visit_NameConstant(self, node): log.append((node.lineno, 'NameConstant', node.value)) def visit_Ellipsis(self, node): log.append((node.lineno, 'Ellipsis', ...)) - mod = ast.parse(dedent('''\ + mod = ast.parse('''\ i = 42 f = 4.25 c = 4.25j @@ -1868,7 +1866,7 @@ def visit_Ellipsis(self, node): t = True n = None e = ... - ''')) + '''.dedent()) visitor = Visitor() log = [] with warnings.catch_warnings(record=True) as wlog: diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 68f3b8cce9f65d..f028535023eaf8 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -9,7 +9,6 @@ import random import re import sys -import textwrap import types import unittest import weakref @@ -3368,7 +3367,7 @@ async def inner(): def test_debug_mode_interop(self): # https://bugs.python.org/issue32636 - code = textwrap.dedent(""" + code = """ import asyncio async def native_coro(): @@ -3379,7 +3378,7 @@ def old_style_coro(): yield from native_coro() asyncio.run(old_style_coro()) - """) + """.dedent() assert_python_ok("-Wignore::DeprecationWarning", "-c", code, PYTHONASYNCIODEBUG="1") diff --git a/Lib/test/test_bdb.py b/Lib/test/test_bdb.py index 6e82cce1f411b7..376836c429f502 100644 --- a/Lib/test/test_bdb.py +++ b/Lib/test/test_bdb.py @@ -52,7 +52,6 @@ import sys import os import unittest -import textwrap import importlib import linecache from contextlib import contextmanager @@ -537,7 +536,7 @@ def create_modules(modules): for m in modules: fname = m + '.py' with open(fname, 'w') as f: - f.write(textwrap.dedent(modules[m])) + f.write(modules[m].dedent()) linecache.checkcache(fname) importlib.invalidate_caches() yield @@ -961,7 +960,7 @@ def test_run_step(self): ('return', 2, ''), ('quit', ), ] with TracerRun(self) as tracer: - tracer.run(compile(textwrap.dedent(code), '', 'exec')) + tracer.run(compile(code.dedent(), '', 'exec')) def test_runeval_step(self): # Test bdb 'runeval'. diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 290ba2cad8e5eb..90c3d593608241 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -22,7 +22,6 @@ from functools import partial from inspect import CO_COROUTINE from itertools import product -from textwrap import dedent from types import AsyncGeneratorType, FunctionType from operator import neg from test import support @@ -403,7 +402,7 @@ async def arange(n): policy = maybe_get_event_loop_policy() try: for mode, code_sample in product(modes, code_samples): - source = dedent(code_sample) + source = code_sample.dedent() with self.assertRaises( SyntaxError, msg=f"source={source} mode={mode}"): compile(source, '?', mode) @@ -452,7 +451,7 @@ async def arange(n): policy = maybe_get_event_loop_policy() try: for mode, code_sample in product(modes, code_samples): - source = dedent(code_sample) + source = code_sample.dedent() with self.assertRaises( SyntaxError, msg=f"source={source} mode={mode}"): compile(source, '?', mode) @@ -473,10 +472,10 @@ def test_compile_async_generator(self): make sure AsyncGenerators are still properly not marked with the CO_COROUTINE flag. """ - code = dedent("""async def ticker(): + code = """async def ticker(): for i in range(10): yield i - await asyncio.sleep(0)""") + await asyncio.sleep(0)""".dedent() co = compile(code, '?', 'exec', flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT) glob = {} diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 770e2c5592cc61..56a2ada548d36a 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -12,7 +12,6 @@ import functools import pickle import tempfile -import textwrap import unittest import test.support @@ -322,7 +321,7 @@ def test_check_encoding_errors(self): # and errors arguments in dev mode invalid = 'Boom, Shaka Laka, Boom!' encodings = ('ascii', 'utf8', 'latin1') - code = textwrap.dedent(f''' + code = f''' import sys type2test = {self.type2test.__name__} encodings = {encodings!r} @@ -369,7 +368,7 @@ def test_check_encoding_errors(self): sys.exit(25) sys.exit(10) - ''') + '''.dedent() proc = assert_python_failure('-X', 'dev', '-c', code) self.assertEqual(proc.rc, 10, proc) diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index f9578d3afa81f3..578e9757f3c7e3 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -8,7 +8,6 @@ import re import subprocess import sys -import textwrap import threading import time import unittest @@ -191,13 +190,13 @@ def test_return_null_without_error(self): # Issue #23571: A function must not return NULL without setting an # error if Py_DEBUG: - code = textwrap.dedent(""" + code = """ import _testcapi from test import support with support.SuppressCrashReport(): _testcapi.return_null_without_error() - """) + """.dedent() rc, out, err = assert_python_failure('-c', code) self.assertRegex(err.replace(b'\r', b''), br'Fatal Python error: _Py_CheckFunctionResult: ' @@ -220,13 +219,13 @@ def test_return_null_without_error(self): def test_return_result_with_error(self): # Issue #23571: A function must not return a result with an error set if Py_DEBUG: - code = textwrap.dedent(""" + code = """ import _testcapi from test import support with support.SuppressCrashReport(): _testcapi.return_result_with_error() - """) + """.dedent() rc, out, err = assert_python_failure('-c', code) self.assertRegex(err.replace(b'\r', b''), br'Fatal Python error: _Py_CheckFunctionResult: ' @@ -335,13 +334,13 @@ def items(self): def test_negative_refcount(self): # bpo-35059: Check that Py_DECREF() reports the correct filename # when calling _Py_NegativeRefcount() to abort Python. - code = textwrap.dedent(""" + code = """ import _testcapi from test import support with support.SuppressCrashReport(): _testcapi.negative_refcount() - """) + """.dedent() rc, out, err = assert_python_failure('-c', code) self.assertRegex(err, br'_testcapimodule\.c:[0-9]+: ' @@ -732,7 +731,7 @@ def test_pyobject_malloc_without_gil(self): self.check_malloc_without_gil(code) def check_pyobject_is_freed(self, func_name): - code = textwrap.dedent(f''' + code = f''' import gc, os, sys, _testcapi # Disable the GC to avoid crash on GC collection gc.disable() @@ -743,7 +742,7 @@ def check_pyobject_is_freed(self, func_name): os._exit(0) except _testcapi.error: os._exit(1) - ''') + '''.dedent() assert_python_ok('-c', code, PYTHONMALLOC=self.PYTHONMALLOC) def test_pyobject_null_is_freed(self): diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index ee96473322dba0..e2fef6cb22f23c 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -6,7 +6,6 @@ import subprocess import sys import tempfile -import textwrap import unittest from test import support from test.support.script_helper import ( @@ -221,13 +220,13 @@ def check_output(text): check_output(text) def test_non_interactive_output_buffering(self): - code = textwrap.dedent(""" + code = """ import sys out = sys.stdout print(out.isatty(), out.write_through, out.line_buffering) err = sys.stderr print(err.isatty(), err.write_through, err.line_buffering) - """) + """.dedent() args = [sys.executable, '-c', code] proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index f0130e376aec4e..e8845a82ce2c5b 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -12,7 +12,6 @@ import subprocess import io -import textwrap from test import support from test.support.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, @@ -536,12 +535,12 @@ def test_dash_m_main_traceback(self): def test_pep_409_verbiage(self): # Make sure PEP 409 syntax properly suppresses # the context of an exception - script = textwrap.dedent("""\ + script = """\ try: raise ValueError except: raise NameError from None - """) + """.dedent() with support.temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'script', script) exitcode, stdout, stderr = assert_python_failure(script_name) @@ -575,7 +574,7 @@ def test_non_ascii(self): self.assertEqual(0, rc) def test_issue20500_exit_with_exception_value(self): - script = textwrap.dedent("""\ + script = """\ import sys error = None try: @@ -585,7 +584,7 @@ def test_issue20500_exit_with_exception_value(self): if error: sys.exit(error) - """) + """.dedent() with support.temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'script', script) exitcode, stdout, stderr = assert_python_failure(script_name) @@ -602,10 +601,10 @@ def test_syntaxerror_unindented_caret_position(self): self.assertIn("\n 1 + 1 = 2\n ^", text) def test_syntaxerror_indented_caret_position(self): - script = textwrap.dedent("""\ + script = """\ if True: 1 + 1 = 2 - """) + """.dedent() with support.temp_dir() as script_dir: script_name = _make_test_script(script_dir, 'script', script) exitcode, stdout, stderr = assert_python_failure(script_name) @@ -660,11 +659,11 @@ def test_consistent_sys_path_for_direct_execution(self): # ./python -s script_dir/__main__.py # ./python -s script_dir # ./python -I script_dir - script = textwrap.dedent("""\ + script = """\ import sys for entry in sys.path: print(entry) - """) + """.dedent() # Always show full path diffs on errors self.maxDiff = None with support.temp_dir() as work_dir, support.temp_dir() as script_dir: @@ -692,11 +691,11 @@ def test_consistent_sys_path_for_module_execution(self): # # And that this fails as unable to find the package: # ./python -Im script_pkg - script = textwrap.dedent("""\ + script = """\ import sys for entry in sys.path: print(entry) - """) + """.dedent() # Always show full path diffs on errors self.maxDiff = None with support.temp_dir() as work_dir: diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index f16da116a745f3..dea5b85896e83c 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -3,7 +3,6 @@ import io import os import pathlib -import textwrap import unittest import warnings @@ -329,31 +328,31 @@ def test_basic(self): self.basic_test(cf) if self.strict: with self.assertRaises(configparser.DuplicateOptionError): - cf.read_string(textwrap.dedent("""\ + cf.read_string("""\ [Duplicate Options Here] option {0[0]} with a value option {0[1]} with another value - """.format(self.delimiters))) + """.dedent().format(self.delimiters)) with self.assertRaises(configparser.DuplicateSectionError): - cf.read_string(textwrap.dedent("""\ + cf.read_string("""\ [And Now For Something] completely different {0[0]} True [And Now For Something] the larch {0[1]} 1 - """.format(self.delimiters))) + """.dedent().format(self.delimiters)) else: - cf.read_string(textwrap.dedent("""\ + cf.read_string("""\ [Duplicate Options Here] option {0[0]} with a value option {0[1]} with another value - """.format(self.delimiters))) + """.dedent().format(self.delimiters)) - cf.read_string(textwrap.dedent("""\ + cf.read_string("""\ [And Now For Something] completely different {0[0]} True [And Now For Something] the larch {0[1]} 1 - """.format(self.delimiters))) + """.dedent().format(self.delimiters)) def test_basic_from_dict(self): config = { @@ -619,14 +618,14 @@ def test_weird_errors(self): if self.strict: with self.assertRaises(configparser.DuplicateSectionError) as cm: - cf.read_string(textwrap.dedent("""\ + cf.read_string("""\ [Foo] will this be added{equals}True [Bar] what about this{equals}True [Foo] oops{equals}this won't - """.format(equals=self.delimiters[0])), source='') + """.dedent().format(equals=self.delimiters[0]), source='') e = cm.exception self.assertEqual(str(e), "While reading from '' " "[line 5]: section 'Foo' already exists") @@ -867,11 +866,10 @@ def test_invalid_multiline_value(self): if self.allow_no_value: self.skipTest('if no_value is allowed, ParsingError is not raised') - invalid = textwrap.dedent("""\ + invalid = """\ [DEFAULT] test {0} test - invalid""".format(self.delimiters[0]) - ) + invalid""".dedent().format(self.delimiters[0]) cf = self.newconfig() with self.assertRaises(configparser.ParsingError): cf.read_string(invalid) @@ -985,7 +983,7 @@ def test_defaults_keyword(self): class ConfigParserTestCaseNoInterpolation(BasicTestCase, unittest.TestCase): config_class = configparser.ConfigParser interpolation = None - ini = textwrap.dedent(""" + ini = """ [numbers] one = 1 two = %(one)s * 2 @@ -993,7 +991,7 @@ class ConfigParserTestCaseNoInterpolation(BasicTestCase, unittest.TestCase): [hexen] sixteen = ${numbers:two} * 8 - """).strip() + """.dedent().strip() def assertMatchesIni(self, cf): self.assertEqual(cf['numbers']['one'], '1') @@ -1170,7 +1168,7 @@ def fromstring(self, string, defaults=None, optionxform=None): return cf def test_extended_interpolation(self): - cf = self.fromstring(textwrap.dedent(""" + cf = self.fromstring(""" [common] favourite Beatle = Paul favourite color = green @@ -1192,7 +1190,7 @@ def test_extended_interpolation(self): favourite state of mind = paranoid favourite movie = soylent ${common:favourite color} favourite song = ${favourite color} sabbath - ${favourite state of mind} - """).strip()) + """.dedent().strip()) eq = self.assertEqual eq(cf['common']['favourite Beatle'], 'Paul') @@ -1215,7 +1213,7 @@ def test_extended_interpolation(self): 'black sabbath - paranoid') def test_endless_loop(self): - cf = self.fromstring(textwrap.dedent(""" + cf = self.fromstring(""" [one for you] ping = ${one for me:pong} @@ -1224,7 +1222,7 @@ def test_endless_loop(self): [selfish] me = ${me} - """).strip()) + """.dedent().strip()) with self.assertRaises(configparser.InterpolationDepthError): cf['one for you']['ping'] @@ -1253,7 +1251,7 @@ def test_strange_options(self): self.assertEqual(cm.exception.args[2], '${dollars:${sick}}') #rawval def test_case_sensitivity_basic(self): - ini = textwrap.dedent(""" + ini = """ [common] optionlower = value OptionUpper = Value @@ -1265,7 +1263,7 @@ def test_case_sensitivity_basic(self): [random] foolower = ${common:optionlower} redefined FooUpper = ${Common:OptionUpper} Redefined - """).strip() + """.dedent().strip() cf = self.fromstring(ini) eq = self.assertEqual @@ -1277,7 +1275,7 @@ def test_case_sensitivity_basic(self): eq(cf['random']['FooUpper'], 'A Better Value Redefined') def test_case_sensitivity_conflicts(self): - ini = textwrap.dedent(""" + ini = """ [common] option = value Option = Value @@ -1289,7 +1287,7 @@ def test_case_sensitivity_conflicts(self): [random] foo = ${common:option} redefined Foo = ${Common:Option} Redefined - """).strip() + """.dedent().strip() with self.assertRaises(configparser.DuplicateOptionError): cf = self.fromstring(ini) @@ -1434,7 +1432,7 @@ class CompatibleTestCase(CfgParserTestCaseClass, unittest.TestCase): inline_comment_prefixes = ';' def test_comment_handling(self): - config_string = textwrap.dedent("""\ + config_string = """\ [Commented Bar] baz=qwe ; a comment foo: bar # not a comment! @@ -1442,7 +1440,7 @@ def test_comment_handling(self): ; another comment quirk: this;is not a comment ; a space must precede an inline comment - """) + """.dedent() cf = self.fromstring(config_string) self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!') @@ -1506,9 +1504,9 @@ def test_file(self): self.assertEqual(parser["Foo Bar"]["foo"], "newbar") def test_iterable(self): - lines = textwrap.dedent(""" + lines = """ [Foo Bar] - foo=newbar""").strip().split('\n') + foo=newbar""".dedent().strip().split('\n') parser = configparser.ConfigParser() parser.read_file(lines) self.assertIn("Foo Bar", parser) @@ -1527,9 +1525,9 @@ def test_readline_generator(self): def test_source_as_bytes(self): """Issue #18260.""" - lines = textwrap.dedent(""" + lines = """ [badbad] - [badbad]""").strip().split('\n') + [badbad]""".dedent().strip().split('\n') parser = configparser.ConfigParser() with self.assertRaises(configparser.DuplicateSectionError) as dse: parser.read_file(lines, source=b"badbad") @@ -1538,10 +1536,10 @@ def test_source_as_bytes(self): "While reading from b'badbad' [line 2]: section 'badbad' " "already exists" ) - lines = textwrap.dedent(""" + lines = """ [badbad] bad = bad - bad = bad""").strip().split('\n') + bad = bad""".dedent().strip().split('\n') parser = configparser.ConfigParser() with self.assertRaises(configparser.DuplicateOptionError) as dse: parser.read_file(lines, source=b"badbad") @@ -1550,9 +1548,9 @@ def test_source_as_bytes(self): "While reading from b'badbad' [line 3]: option 'bad' in section " "'badbad' already exists" ) - lines = textwrap.dedent(""" + lines = """ [badbad] - = bad""").strip().split('\n') + = bad""".dedent().strip().split('\n') parser = configparser.ConfigParser() with self.assertRaises(configparser.ParsingError) as dse: parser.read_file(lines, source=b"badbad") @@ -1560,9 +1558,9 @@ def test_source_as_bytes(self): str(dse.exception), "Source contains parsing errors: b'badbad'\n\t[line 2]: '= bad'" ) - lines = textwrap.dedent(""" + lines = """ [badbad - bad = bad""").strip().split('\n') + bad = bad""".dedent().strip().split('\n') parser = configparser.ConfigParser() with self.assertRaises(configparser.MissingSectionHeaderError) as dse: parser.read_file(lines, source=b"badbad") diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index a16d14019f341f..68fe75bb3c7cc7 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -11,7 +11,6 @@ import pickle from test import support from itertools import permutations -from textwrap import dedent from collections import OrderedDict class Test_Csv(unittest.TestCase): @@ -1163,14 +1162,14 @@ def test_ordering_for_the_dict_reader_and_writer(self): self.assertEqual(len(resultset), 120, "Key ordering: some key permutations not collected (expected 120)") def test_ordered_dict_reader(self): - data = dedent('''\ + data = '''\ FirstName,LastName Eric,Idle Graham,Chapman,Over1,Over2 Under1 John,Cleese - ''').splitlines() + '''.dedent().splitlines() self.assertEqual(list(csv.DictReader(data)), [OrderedDict([('FirstName', 'Eric'), ('LastName', 'Idle')]), diff --git a/Lib/test/test_email/test_contentmanager.py b/Lib/test/test_email/test_contentmanager.py index 169058eac83da3..3c09ffbbc2916b 100644 --- a/Lib/test/test_email/test_contentmanager.py +++ b/Lib/test/test_email/test_contentmanager.py @@ -1,6 +1,5 @@ import unittest from test.test_email import TestEmailBase, parameterize -import textwrap from email import policy from email.message import EmailMessage from email.contentmanager import ContentManager, raw_data_manager @@ -146,120 +145,120 @@ class TestRawDataManager(TestEmailBase): message = EmailMessage def test_get_text_plain(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/plain Basic text. - """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m), "Basic text.\n") def test_get_text_html(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/html

Basic text.

- """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m), "

Basic text.

\n") def test_get_text_plain_latin1(self): - m = self._bytes_msg(textwrap.dedent("""\ + m = self._bytes_msg("""\ Content-Type: text/plain; charset=latin1 Basìc tëxt. - """).encode('latin1')) + """.dedent().encode('latin1')) self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt.\n") def test_get_text_plain_latin1_quoted_printable(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/plain; charset="latin-1" Content-Transfer-Encoding: quoted-printable Bas=ECc t=EBxt. - """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt.\n") def test_get_text_plain_utf8_base64(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/plain; charset="utf8" Content-Transfer-Encoding: base64 QmFzw6xjIHTDq3h0Lgo= - """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt.\n") def test_get_text_plain_bad_utf8_quoted_printable(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/plain; charset="utf8" Content-Transfer-Encoding: quoted-printable Bas=c3=acc t=c3=abxt=fd. - """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt�.\n") def test_get_text_plain_bad_utf8_quoted_printable_ignore_errors(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/plain; charset="utf8" Content-Transfer-Encoding: quoted-printable Bas=c3=acc t=c3=abxt=fd. - """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m, errors='ignore'), "Basìc tëxt.\n") def test_get_text_plain_utf8_base64_recoverable_bad_CTE_data(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/plain; charset="utf8" Content-Transfer-Encoding: base64 QmFzw6xjIHTDq3h0Lgo\xFF= - """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m, errors='ignore'), "Basìc tëxt.\n") def test_get_text_invalid_keyword(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: text/plain Basic text. - """)) + """.dedent()) with self.assertRaises(TypeError): raw_data_manager.get_content(m, foo='ignore') def test_get_non_text(self): - template = textwrap.dedent("""\ + template = """\ Content-Type: {} Content-Transfer-Encoding: base64 Ym9ndXMgZGF0YQ== - """) + """.dedent() for maintype in 'audio image video application'.split(): with self.subTest(maintype=maintype): m = self._str_msg(template.format(maintype+'/foo')) self.assertEqual(raw_data_manager.get_content(m), b"bogus data") def test_get_non_text_invalid_keyword(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: image/jpg Content-Transfer-Encoding: base64 Ym9ndXMgZGF0YQ== - """)) + """.dedent()) with self.assertRaises(TypeError): raw_data_manager.get_content(m, errors='ignore') def test_get_raises_on_multipart(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: multipart/mixed; boundary="===" --=== --===-- - """)) + """.dedent()) with self.assertRaises(KeyError): raw_data_manager.get_content(m) def test_get_message_rfc822_and_external_body(self): - template = textwrap.dedent("""\ + template = """\ Content-Type: message/{} To: foo@example.com @@ -267,7 +266,7 @@ def test_get_message_rfc822_and_external_body(self): Subject: example an example message - """) + """.dedent() for subtype in 'rfc822 external-body'.split(): with self.subTest(subtype=subtype): m = self._str_msg(template.format(subtype)) @@ -279,7 +278,7 @@ def test_get_message_rfc822_and_external_body(self): self.assertEqual(sub_msg['from'].addresses[0].username, 'bar') def test_get_message_non_rfc822_or_external_body_yields_bytes(self): - m = self._str_msg(textwrap.dedent("""\ + m = self._str_msg("""\ Content-Type: message/partial To: foo@example.com @@ -287,19 +286,19 @@ def test_get_message_non_rfc822_or_external_body_yields_bytes(self): Subject: example The real body is in another message. - """)) + """.dedent()) self.assertEqual(raw_data_manager.get_content(m)[:10], b'To: foo@ex') def test_set_text_plain(self): m = self._make_message() content = "Simple message.\n" raw_data_manager.set_content(m, content) - self.assertEqual(str(m), textwrap.dedent("""\ + self.assertEqual(str(m), """\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Simple message. - """)) + """.dedent()) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -307,12 +306,12 @@ def test_set_text_html(self): m = self._make_message() content = "

Simple message.

\n" raw_data_manager.set_content(m, content, subtype='html') - self.assertEqual(str(m), textwrap.dedent("""\ + self.assertEqual(str(m), """\ Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: 7bit

Simple message.

- """)) + """.dedent()) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -320,12 +319,12 @@ def test_set_text_charset_latin_1(self): m = self._make_message() content = "Simple message.\n" raw_data_manager.set_content(m, content, charset='latin-1') - self.assertEqual(str(m), textwrap.dedent("""\ + self.assertEqual(str(m), """\ Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Simple message. - """)) + """.dedent()) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -333,12 +332,12 @@ def test_set_text_short_line_minimal_non_ascii_heuristics(self): m = self._make_message() content = "et là il est monté sur moi et il commence à m'éto.\n" raw_data_manager.set_content(m, content) - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit et là il est monté sur moi et il commence à m'éto. - """).encode('utf-8')) + """.dedent().encode('utf-8')) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -348,14 +347,14 @@ def test_set_text_long_line_minimal_non_ascii_heuristics(self): " vivarium. et là il est monté sur moi et il commence" " à m'éto.\n") raw_data_manager.set_content(m, content) - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable j'ai un probl=C3=A8me de python. il est sorti de son vivari= um. et l=C3=A0 il est mont=C3=A9 sur moi et il commence = =C3=A0 m'=C3=A9to. - """).encode('utf-8')) + """.dedent().encode('utf-8')) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -366,14 +365,14 @@ def test_set_text_11_lines_long_line_minimal_non_ascii_heuristics(self): " vivarium. et là il est monté sur moi et il commence" " à m'éto.\n") raw_data_manager.set_content(m, content) - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), ("""\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable """ + '\n'*10 + """ j'ai un probl=C3=A8me de python. il est sorti de son vivari= um. et l=C3=A0 il est mont=C3=A9 sur moi et il commence = =C3=A0 m'=C3=A9to. - """).encode('utf-8')) + """).dedent().encode('utf-8')) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -381,12 +380,12 @@ def test_set_text_maximal_non_ascii_heuristics(self): m = self._make_message() content = "áàäéèęöő.\n" raw_data_manager.set_content(m, content) - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit áàäéèęöő. - """).encode('utf-8')) + """.dedent().encode('utf-8')) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -394,12 +393,12 @@ def test_set_text_11_lines_maximal_non_ascii_heuristics(self): m = self._make_message() content = '\n'*10 + "áàäéèęöő.\n" raw_data_manager.set_content(m, content) - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), ("""\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit """ + '\n'*10 + """ áàäéèęöő. - """).encode('utf-8')) + """).dedent().encode('utf-8')) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -409,7 +408,7 @@ def test_set_text_long_line_maximal_non_ascii_heuristics(self): "áàäéèęöőáàäéèęöőáàäéèęöőáàäéèęöő" "áàäéèęöőáàäéèęöőáàäéèęöőáàäéèęöő.\n") raw_data_manager.set_content(m, content) - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 @@ -418,7 +417,7 @@ def test_set_text_long_line_maximal_non_ascii_heuristics(self): xJnDtsWRw6HDoMOkw6nDqMSZw7bFkcOhw6DDpMOpw6jEmcO2xZHDocOgw6TD qcOoxJnDtsWRw6HDoMOkw6nDqMSZw7bFkcOhw6DDpMOpw6jEmcO2xZHDocOg w6TDqcOoxJnDtsWRLgo= - """).encode('utf-8')) + """.dedent().encode('utf-8')) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -434,7 +433,7 @@ def test_set_text_11_lines_long_line_maximal_non_ascii_heuristics(self): "áàäéèęöőáàäéèęöőáàäéèęöőáàäéèęöő" "áàäéèęöőáàäéèęöőáàäéèęöőáàäéèęöő" "áàäéèęöőáàäéèęöőáàäéèęöőáàäéèęöő.\n") - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), ("""\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable """ + '\n'*10 + """ @@ -449,7 +448,7 @@ def test_set_text_11_lines_long_line_maximal_non_ascii_heuristics(self): =C3=A8=C4=99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4= =99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4=99=C3=B6= =C5=91. - """).encode('utf-8')) + """).dedent().encode('utf-8')) self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content) self.assertEqual(m.get_content(), content) @@ -477,7 +476,7 @@ def test_set_message(self): content['Subject'] = "get back in your box" content.set_content("Or face the comfy chair.") raw_data_manager.set_content(m, content) - self.assertEqual(str(m), textwrap.dedent("""\ + self.assertEqual(str(m), """\ Subject: Forwarded message Content-Type: message/rfc822 Content-Transfer-Encoding: 8bit @@ -490,7 +489,7 @@ def test_set_message(self): MIME-Version: 1.0 Or face the comfy chair. - """)) + """.dedent()) payload = m.get_payload(0) self.assertIsInstance(payload, self.message) self.assertEqual(str(payload), str(content)) @@ -507,7 +506,7 @@ def test_set_message_with_non_ascii_and_coercion_to_7bit(self): content.set_content("j'ai un problème de python. il est sorti de son" " vivarium.") raw_data_manager.set_content(m, content) - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Subject: Escape report Content-Type: message/rfc822 Content-Transfer-Encoding: 8bit @@ -520,14 +519,14 @@ def test_set_message_with_non_ascii_and_coercion_to_7bit(self): MIME-Version: 1.0 j'ai un problème de python. il est sorti de son vivarium. - """).encode('utf-8')) + """.dedent().encode('utf-8')) # The choice of base64 for the body encoding is because generator # doesn't bother with heuristics and uses it unconditionally for utf-8 # text. # XXX: the first cte should be 7bit, too...that's a generator bug. # XXX: the line length in the body also looks like a generator bug. self.assertEqual(m.as_string(maxheaderlen=self.policy.max_line_length), - textwrap.dedent("""\ + """\ Subject: Escape report Content-Type: message/rfc822 Content-Transfer-Encoding: 8bit @@ -541,7 +540,7 @@ def test_set_message_with_non_ascii_and_coercion_to_7bit(self): aidhaSB1biBwcm9ibMOobWUgZGUgcHl0aG9uLiBpbCBlc3Qgc29ydGkgZGUgc29uIHZpdmFyaXVt Lgo= - """)) + """.dedent()) self.assertIsInstance(m.get_content(), self.message) self.assertEqual(str(m.get_content()), str(content)) @@ -572,12 +571,12 @@ def test_set_image_jpg(self): with self.subTest(content=content): m = self._make_message() raw_data_manager.set_content(m, content, 'image', 'jpeg') - self.assertEqual(str(m), textwrap.dedent("""\ + self.assertEqual(str(m), """\ Content-Type: image/jpeg Content-Transfer-Encoding: base64 Ym9ndXMgY29udGVudA== - """)) + """.dedent()) self.assertEqual(m.get_payload(decode=True), content) self.assertEqual(m.get_content(), content) @@ -593,13 +592,13 @@ def test_set_audio_aif_with_quoted_printable_cte(self): m = self._make_message() content = b'b\xFFgus\tcon\nt\rent ' + b'z'*100 m.set_content(content, 'audio', 'aif', cte='quoted-printable') - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: audio/aif Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 b=FFgus=09con=0At=0Dent=20zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz= - zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz""").encode('latin-1')) + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz""".dedent().encode('latin-1')) self.assertEqual(m.get_payload(decode=True), content) self.assertEqual(m.get_content(), content) @@ -607,12 +606,12 @@ def test_set_video_mpeg_with_binary_cte(self): m = self._make_message() content = b'b\xFFgus\tcon\nt\rent ' + b'z'*100 m.set_content(content, 'video', 'mpeg', cte='binary') - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: video/mpeg Content-Transfer-Encoding: binary MIME-Version: 1.0 - """).encode('ascii') + + """.dedent().encode('ascii') + # XXX: the second \n ought to be a \r, but generator gets it wrong. # THIS MEANS WE DON'T ACTUALLY SUPPORT THE 'binary' CTE. b'b\xFFgus\tcon\nt\nent zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' + @@ -626,12 +625,12 @@ def test_set_application_octet_stream_with_8bit_cte(self): m = self._make_message() content = b'b\xFFgus\tcon\nt\rent\n' + b'z'*60 + b'\n' m.set_content(content, 'application', 'octet-stream', cte='8bit') - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: application/octet-stream Content-Transfer-Encoding: 8bit MIME-Version: 1.0 - """).encode('ascii') + + """.dedent().encode('ascii') + b'b\xFFgus\tcon\nt\nent\n' + b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\n') self.assertEqual(m.get_payload(decode=True), content) @@ -645,7 +644,7 @@ def test_set_headers_from_header_objects(self): header_factory("To", "foo@example.com"), header_factory("From", "foo@example.com"), header_factory("Subject", "I'm talking to myself."))) - self.assertEqual(str(m), textwrap.dedent("""\ + self.assertEqual(str(m), """\ Content-Type: text/plain; charset="utf-8" To: foo@example.com From: foo@example.com @@ -653,7 +652,7 @@ def test_set_headers_from_header_objects(self): Content-Transfer-Encoding: 7bit Simple message. - """)) + """.dedent()) def test_set_headers_from_strings(self): m = self._make_message() @@ -661,14 +660,14 @@ def test_set_headers_from_strings(self): raw_data_manager.set_content(m, content, headers=( "X-Foo-Header: foo", "X-Bar-Header: bar",)) - self.assertEqual(str(m), textwrap.dedent("""\ + self.assertEqual(str(m), """\ Content-Type: text/plain; charset="utf-8" X-Foo-Header: foo X-Bar-Header: bar Content-Transfer-Encoding: 7bit Simple message. - """)) + """.dedent()) def test_set_headers_with_invalid_duplicate_string_header_raises(self): m = self._make_message() @@ -738,7 +737,7 @@ def test_set_filename_and_disposition_inline(self): def test_set_non_ascii_filename(self): m = self._make_message() m.set_content('foo', filename='ábárî.txt') - self.assertEqual(bytes(m), textwrap.dedent("""\ + self.assertEqual(bytes(m), """\ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; @@ -746,7 +745,7 @@ def test_set_non_ascii_filename(self): MIME-Version: 1.0 foo - """).encode('ascii')) + """.dedent().encode('ascii')) content_object_params = { 'text_plain': ('content', ()), diff --git a/Lib/test/test_email/test_defect_handling.py b/Lib/test/test_email/test_defect_handling.py index 781f657418220c..affcabca887dab 100644 --- a/Lib/test/test_email/test_defect_handling.py +++ b/Lib/test/test_email/test_defect_handling.py @@ -1,4 +1,3 @@ -import textwrap import unittest import contextlib from email import policy @@ -16,7 +15,7 @@ def _raise_point(self, defect): yield def test_same_boundary_inner_outer(self): - source = textwrap.dedent("""\ + source = """\ Subject: XX From: xx@xx.dk To: XX @@ -51,7 +50,7 @@ def test_same_boundary_inner_outer(self): --MS_Mac_OE_3071477847_720252_MIME_Part-- - """) + """.dedent() # XXX better would be to actually detect the duplicate. with self._raise_point(errors.StartBoundaryNotFoundDefect): msg = self._str_msg(source) @@ -63,7 +62,7 @@ def test_same_boundary_inner_outer(self): errors.StartBoundaryNotFoundDefect) def test_multipart_no_boundary(self): - source = textwrap.dedent("""\ + source = """\ Date: Fri, 6 Apr 2001 09:23:06 -0800 (GMT-0800) From: foobar Subject: broken mail @@ -80,7 +79,7 @@ def test_multipart_no_boundary(self): Header: Another part --JAB03225.986577786/zinfandel.lacita.com-- - """) + """.dedent() with self._raise_point(errors.NoBoundaryInMultipartDefect): msg = self._str_msg(source) if self.raise_expected: return @@ -91,7 +90,7 @@ def test_multipart_no_boundary(self): self.assertIsInstance(self.get_defects(msg)[1], errors.MultipartInvariantViolationDefect) - multipart_msg = textwrap.dedent("""\ + multipart_msg = """\ Date: Wed, 14 Nov 2007 12:56:23 GMT From: foo@bar.invalid To: foo@bar.invalid @@ -112,7 +111,7 @@ def test_multipart_no_boundary(self): YWJj --===============3344438784458119861==-- - """) + """.dedent() def test_multipart_invalid_cte(self): with self._raise_point( @@ -138,7 +137,7 @@ def test_multipart_valid_cte_no_defect(self): self.assertEqual(len(self.get_defects(msg)), 0, "cte="+cte) def test_lying_multipart(self): - source = textwrap.dedent("""\ + source = """\ From: "Allison Dunlap" To: yyy@example.com Subject: 64423 @@ -147,7 +146,7 @@ def test_lying_multipart(self): Content-Type: multipart/alternative; Blah blah blah - """) + """.dedent() with self._raise_point(errors.NoBoundaryInMultipartDefect): msg = self._str_msg(source) if self.raise_expected: return @@ -159,7 +158,7 @@ def test_lying_multipart(self): errors.MultipartInvariantViolationDefect) def test_missing_start_boundary(self): - source = textwrap.dedent("""\ + source = """\ Content-Type: multipart/mixed; boundary="AAA" From: Mail Delivery Subsystem To: yyy@example.com @@ -179,7 +178,7 @@ def test_missing_start_boundary(self): --AAA-- - """) + """.dedent() # The message structure is: # # multipart/mixed @@ -221,14 +220,14 @@ def test_missing_header_body_separator(self): [errors.MissingHeaderBodySeparatorDefect]) def test_bad_padding_in_base64_payload(self): - source = textwrap.dedent("""\ + source = """\ Subject: test MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 dmk - """) + """.dedent() msg = self._str_msg(source) with self._raise_point(errors.InvalidBase64PaddingDefect): payload = msg.get_payload(decode=True) @@ -238,14 +237,14 @@ def test_bad_padding_in_base64_payload(self): [errors.InvalidBase64PaddingDefect]) def test_invalid_chars_in_base64_payload(self): - source = textwrap.dedent("""\ + source = """\ Subject: test MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 dm\x01k=== - """) + """.dedent() msg = self._str_msg(source) with self._raise_point(errors.InvalidBase64CharactersDefect): payload = msg.get_payload(decode=True) @@ -255,14 +254,14 @@ def test_invalid_chars_in_base64_payload(self): [errors.InvalidBase64CharactersDefect]) def test_invalid_length_of_base64_payload(self): - source = textwrap.dedent("""\ + source = """\ Subject: test MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 abcde - """) + """.dedent() msg = self._str_msg(source) with self._raise_point(errors.InvalidBase64LengthDefect): payload = msg.get_payload(decode=True) @@ -272,7 +271,7 @@ def test_invalid_length_of_base64_payload(self): [errors.InvalidBase64LengthDefect]) def test_missing_ending_boundary(self): - source = textwrap.dedent("""\ + source = """\ To: 1@harrydomain4.com Subject: Fwd: 1 MIME-Version: 1.0 @@ -291,7 +290,7 @@ def test_missing_ending_boundary(self): Alternative 2 - """) + """.dedent() with self._raise_point(errors.CloseBoundaryNotFoundDefect): msg = self._str_msg(source) if self.raise_expected: return diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 59eabb00921942..85139e84516cf3 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -6,7 +6,6 @@ import time import base64 import unittest -import textwrap from io import StringIO, BytesIO from itertools import chain @@ -736,25 +735,25 @@ def test_unicode_header_defaults_to_utf8_encoding(self): # Issue 14291 m = MIMEText('abc\n') m['Subject'] = 'É test' - self.assertEqual(str(m),textwrap.dedent("""\ + self.assertEqual(str(m),"""\ Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: =?utf-8?q?=C3=89_test?= abc - """)) + """.dedent()) def test_unicode_body_defaults_to_utf8_encoding(self): # Issue 14291 m = MIMEText('É testabc\n') - self.assertEqual(str(m),textwrap.dedent("""\ + self.assertEqual(str(m),"""\ Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 w4kgdGVzdGFiYwo= - """)) + """.dedent()) # Test the email.encoders module @@ -794,34 +793,34 @@ def test_encode7or8bit(self): eq = self.assertEqual msg = MIMEText('文\n', _charset='euc-jp') eq(msg['content-transfer-encoding'], '7bit') - eq(msg.as_string(), textwrap.dedent("""\ + eq(msg.as_string(), """\ MIME-Version: 1.0 Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: 7bit \x1b$BJ8\x1b(B - """)) + """.dedent()) def test_qp_encode_latin1(self): msg = MIMEText('\xe1\xf6\n', 'text', 'ISO-8859-1') - self.assertEqual(str(msg), textwrap.dedent("""\ + self.assertEqual(str(msg), """\ MIME-Version: 1.0 Content-Type: text/text; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable =E1=F6 - """)) + """.dedent()) def test_qp_encode_non_latin1(self): # Issue 16948 msg = MIMEText('\u017c\n', 'text', 'ISO-8859-2') - self.assertEqual(str(msg), textwrap.dedent("""\ + self.assertEqual(str(msg), """\ MIME-Version: 1.0 Content-Type: text/text; charset="iso-8859-2" Content-Transfer-Encoding: quoted-printable =BF - """)) + """.dedent()) # Test long header wrapping @@ -1383,17 +1382,17 @@ def test_long_lines_with_different_header(self): """) def test_long_rfc2047_header_with_embedded_fws(self): - h = Header(textwrap.dedent("""\ + h = Header("""\ We're going to pretend this header is in a non-ascii character set \tto see if line wrapping with encoded words and embedded - folding white space works"""), + folding white space works""".dedent(), charset='utf-8', header_name='Test') - self.assertEqual(h.encode()+'\n', textwrap.dedent("""\ + self.assertEqual(h.encode()+'\n', """\ =?utf-8?q?We=27re_going_to_pretend_this_header_is_in_a_non-ascii_chara?= =?utf-8?q?cter_set?= =?utf-8?q?_to_see_if_line_wrapping_with_encoded_words_and_embedded?= - =?utf-8?q?_folding_white_space_works?=""")+'\n') + =?utf-8?q?_folding_white_space_works?=""".dedent()+'\n') @@ -1432,7 +1431,7 @@ def test_dont_mangle_from(self): def test_mangle_from_in_preamble_and_epilog(self): s = StringIO() g = Generator(s, mangle_from_=True) - msg = email.message_from_string(textwrap.dedent("""\ + msg = email.message_from_string("""\ From: foo@bar.com Mime-Version: 1.0 Content-Type: multipart/mixed; boundary=XXX @@ -1447,19 +1446,19 @@ def test_mangle_from_in_preamble_and_epilog(self): --XXX-- From somewhere unknowable - """)) + """.dedent()) g.flatten(msg) self.assertEqual(len([1 for x in s.getvalue().split('\n') if x.startswith('>From ')]), 2) def test_mangled_from_with_bad_bytes(self): - source = textwrap.dedent("""\ + source = """\ Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: aaa@bbb.org - """).encode('utf-8') + """.dedent().encode('utf-8') msg = email.message_from_bytes(source + b'From R\xc3\xb6lli\n') b = BytesIO() g = BytesGenerator(b, mangle_from_=True) @@ -1468,11 +1467,11 @@ def test_mangled_from_with_bad_bytes(self): def test_multipart_with_bad_bytes_in_cte(self): # bpo30835 - source = textwrap.dedent("""\ + source = """\ From: aperson@example.com Content-Type: multipart/mixed; boundary="1" Content-Transfer-Encoding: \xc8 - """).encode('utf-8') + """.dedent().encode('utf-8') msg = email.message_from_bytes(source) @@ -2123,7 +2122,7 @@ def test_multipart_no_boundary(self): self.assertIsInstance(msg.defects[1], errors.MultipartInvariantViolationDefect) - multipart_msg = textwrap.dedent("""\ + multipart_msg = """\ Date: Wed, 14 Nov 2007 12:56:23 GMT From: foo@bar.invalid To: foo@bar.invalid @@ -2144,7 +2143,7 @@ def test_multipart_no_boundary(self): YWJj --===============3344438784458119861==-- - """) + """.dedent() # test_defect_handling def test_multipart_invalid_cte(self): @@ -3767,7 +3766,7 @@ class Test8BitBytesHandling(TestEmailBase): # but it does allow us to parse and preserve them, and to decode body # parts that use an 8bit CTE. - bodytest_msg = textwrap.dedent("""\ + bodytest_msg = """\ From: foo@bar.com To: baz Mime-Version: 1.0 @@ -3775,7 +3774,7 @@ class Test8BitBytesHandling(TestEmailBase): Content-Transfer-Encoding: {cte} {bodyline} - """) + """.dedent() def test_known_8bit_CTE(self): m = self.bodytest_msg.format(charset='utf-8', @@ -3874,14 +3873,14 @@ def test_get_8bit_header(self): def test_print_8bit_headers(self): msg = email.message_from_bytes(self.headertest_msg) self.assertEqual(str(msg), - textwrap.dedent("""\ + """\ From: {} To: {} Subject: {} From: {} Yes, they are flying. - """).format(*[expected[1] for (_, expected) in + """.dedent().format(*[expected[1] for (_, expected) in self.headertest_headers])) def test_values_with_8bit_headers(self): @@ -3914,9 +3913,9 @@ def test_get_all_with_8bit_headers(self): 'g\uFFFD\uFFFDst']) def test_get_content_type_with_8bit(self): - msg = email.message_from_bytes(textwrap.dedent("""\ + msg = email.message_from_bytes("""\ Content-Type: text/pl\xA7in; charset=utf-8 - """).encode('latin-1')) + """.dedent().encode('latin-1')) self.assertEqual(msg.get_content_type(), "text/pl\uFFFDin") self.assertEqual(msg.get_content_maintype(), "text") self.assertEqual(msg.get_content_subtype(), "pl\uFFFDin") @@ -3933,41 +3932,38 @@ def test_get_params_with_8bit(self): # test_headerregistry.TestContentTypeHeader.non_ascii_in_rfc2231_value def test_get_rfc2231_params_with_8bit(self): - msg = email.message_from_bytes(textwrap.dedent("""\ + msg = email.message_from_bytes("""\ Content-Type: text/plain; charset=us-ascii; - title*=us-ascii'en'This%20is%20not%20f\xa7n""" - ).encode('latin-1')) + title*=us-ascii'en'This%20is%20not%20f\xa7n""".dedent().encode('latin-1')) self.assertEqual(msg.get_param('title'), ('us-ascii', 'en', 'This is not f\uFFFDn')) def test_set_rfc2231_params_with_8bit(self): - msg = email.message_from_bytes(textwrap.dedent("""\ + msg = email.message_from_bytes("""\ Content-Type: text/plain; charset=us-ascii; - title*=us-ascii'en'This%20is%20not%20f\xa7n""" - ).encode('latin-1')) + title*=us-ascii'en'This%20is%20not%20f\xa7n""".dedent().encode('latin-1')) msg.set_param('title', 'test') self.assertEqual(msg.get_param('title'), 'test') def test_del_rfc2231_params_with_8bit(self): - msg = email.message_from_bytes(textwrap.dedent("""\ + msg = email.message_from_bytes("""\ Content-Type: text/plain; charset=us-ascii; - title*=us-ascii'en'This%20is%20not%20f\xa7n""" - ).encode('latin-1')) + title*=us-ascii'en'This%20is%20not%20f\xa7n""".dedent().encode('latin-1')) msg.del_param('title') self.assertEqual(msg.get_param('title'), None) self.assertEqual(msg.get_content_maintype(), 'text') def test_get_payload_with_8bit_cte_header(self): - msg = email.message_from_bytes(textwrap.dedent("""\ + msg = email.message_from_bytes("""\ Content-Transfer-Encoding: b\xa7se64 Content-Type: text/plain; charset=latin-1 payload - """).encode('latin-1')) + """.dedent().encode('latin-1')) self.assertEqual(msg.get_payload(), 'payload\n') self.assertEqual(msg.get_payload(decode=True), b'payload\n') - non_latin_bin_msg = textwrap.dedent("""\ + non_latin_bin_msg = """\ From: foo@bar.com To: báz Subject: Maintenant je vous présente mon collègue, le pouf célèbre @@ -3977,7 +3973,7 @@ def test_get_payload_with_8bit_cte_header(self): Content-Transfer-Encoding: 8bit Да, они летят. - """).encode('utf-8') + """.dedent().encode('utf-8') def test_bytes_generator(self): msg = email.message_from_bytes(self.non_latin_bin_msg) @@ -3992,7 +3988,7 @@ def test_bytes_generator_handles_None_body(self): email.generator.BytesGenerator(out).flatten(msg) self.assertEqual(out.getvalue(), b"\n") - non_latin_bin_msg_as7bit_wrapped = textwrap.dedent("""\ + non_latin_bin_msg_as7bit_wrapped = """\ From: foo@bar.com To: =?unknown-8bit?q?b=C3=A1z?= Subject: =?unknown-8bit?q?Maintenant_je_vous_pr=C3=A9sente_mon_coll=C3=A8gue?= @@ -4003,7 +3999,7 @@ def test_bytes_generator_handles_None_body(self): Content-Transfer-Encoding: base64 0JTQsCwg0L7QvdC4INC70LXRgtGP0YIuCg== - """) + """.dedent() def test_generator_handles_8bit(self): msg = email.message_from_bytes(self.non_latin_bin_msg) @@ -4047,7 +4043,7 @@ def test_message_from_binary_file(self): m = email.parser.BytesParser().parse(testfile) self.assertEqual(str(m), self.non_latin_bin_msg_as7bit) - latin_bin_msg = textwrap.dedent("""\ + latin_bin_msg = """\ From: foo@bar.com To: Dinsdale Subject: Nudge nudge, wink, wink @@ -4056,9 +4052,9 @@ def test_message_from_binary_file(self): Content-Transfer-Encoding: 8bit oh là là, know what I mean, know what I mean? - """).encode('latin-1') + """.dedent().encode('latin-1') - latin_bin_msg_as7bit = textwrap.dedent("""\ + latin_bin_msg_as7bit = """\ From: foo@bar.com To: Dinsdale Subject: Nudge nudge, wink, wink @@ -4067,7 +4063,7 @@ def test_message_from_binary_file(self): Content-Transfer-Encoding: quoted-printable oh l=E0 l=E0, know what I mean, know what I mean? - """) + """.dedent() def test_string_generator_reencodes_to_quopri_when_appropriate(self): m = email.message_from_bytes(self.latin_bin_msg) @@ -4101,7 +4097,7 @@ def test_crlf_flatten(self): def test_8bit_multipart(self): # Issue 11605 - source = textwrap.dedent("""\ + source = """\ Date: Fri, 18 Mar 2011 17:15:43 +0100 To: foo@example.com From: foodwatch-Newsletter @@ -4138,7 +4134,7 @@ def test_8bit_multipart(self): --b1_76a486bee62b0d200f33dc2ca08220ad-- - """).encode('utf-8') + """.dedent().encode('utf-8') msg = email.message_from_bytes(source) s = BytesIO() g = email.generator.BytesGenerator(s) @@ -5094,13 +5090,13 @@ def test_rfc2231_get_content_charset(self): # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_no_double_quotes def test_rfc2231_parse_rfc_quoting(self): - m = textwrap.dedent('''\ + m = '''\ Content-Disposition: inline; \tfilename*0*=''This%20is%20even%20more%20; \tfilename*1*=%2A%2A%2Afun%2A%2A%2A%20; \tfilename*2="is it not.pdf" - ''') + '''.dedent() msg = email.message_from_string(m) self.assertEqual(msg.get_filename(), 'This is even more ***fun*** is it not.pdf') @@ -5108,13 +5104,13 @@ def test_rfc2231_parse_rfc_quoting(self): # test_headerregistry.TestContentTypeHeader.rfc2231_encoded_with_double_quotes def test_rfc2231_parse_extra_quoting(self): - m = textwrap.dedent('''\ + m = '''\ Content-Disposition: inline; \tfilename*0*="''This%20is%20even%20more%20"; \tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20"; \tfilename*2="is it not.pdf" - ''') + '''.dedent() msg = email.message_from_string(m) self.assertEqual(msg.get_filename(), 'This is even more ***fun*** is it not.pdf') diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py index 89e7edeb63a892..6bbc5be33bc9e6 100644 --- a/Lib/test/test_email/test_generator.py +++ b/Lib/test/test_email/test_generator.py @@ -1,5 +1,4 @@ import io -import textwrap import unittest from email import message_from_string, message_from_bytes from email.message import EmailMessage @@ -19,7 +18,7 @@ def msgmaker(self, msg, policy=None): return self.msgfunc(msg, policy=policy) refold_long_expected = { - 0: textwrap.dedent("""\ + 0: """\ To: whom_it_may_concern@example.com From: nobody_you_want_to_know@example.com Subject: We the willing led by the unknowing are doing the @@ -27,8 +26,8 @@ def msgmaker(self, msg, policy=None): we are now qualified to do anything with nothing. None - """), - 40: textwrap.dedent("""\ + """.dedent(), + 40: """\ To: whom_it_may_concern@example.com From: nobody_you_want_to_know@example.com @@ -39,8 +38,8 @@ def msgmaker(self, msg, policy=None): qualified to do anything with nothing. None - """), - 20: textwrap.dedent("""\ + """.dedent(), + 20: """\ To: whom_it_may_concern@example.com From: @@ -58,7 +57,7 @@ def msgmaker(self, msg, policy=None): nothing. None - """), + """.dedent(), } refold_long_expected[100] = refold_long_expected[0] @@ -141,12 +140,12 @@ def test_flatten_linesep_overrides_policy(self): self.assertEqual(s.getvalue(), self.typ(expected)) def test_set_mangle_from_via_policy(self): - source = textwrap.dedent("""\ + source = """\ Subject: test that from is mangled in the body! From time to time I write a rhyme. - """) + """.dedent() variants = ( (None, True), (policy.compat32, True), @@ -172,21 +171,21 @@ def test_compat32_max_line_length_does_not_fold_when_none(self): def test_rfc2231_wrapping(self): # This is pretty much just to make sure we don't have an infinite # loop; I don't expect anyone to hit this in the field. - msg = self.msgmaker(self.typ(textwrap.dedent("""\ + msg = self.msgmaker(self.typ("""\ To: nobody Content-Disposition: attachment; filename="afilenamelongenoghtowraphere" None - """))) - expected = textwrap.dedent("""\ + """.dedent())) + expected = """\ To: nobody Content-Disposition: attachment; filename*0*=us-ascii''afilename; filename*1*=longenoghtowraphere None - """) + """.dedent() s = self.ioclass() g = self.genclass(s, policy=self.policy.clone(max_line_length=33)) g.flatten(msg) @@ -196,21 +195,21 @@ def test_rfc2231_wrapping_switches_to_default_len_if_too_narrow(self): # This is just to make sure we don't have an infinite loop; I don't # expect anyone to hit this in the field, so I'm not bothering to make # the result optimal (the encoding isn't needed). - msg = self.msgmaker(self.typ(textwrap.dedent("""\ + msg = self.msgmaker(self.typ("""\ To: nobody Content-Disposition: attachment; filename="afilenamelongenoghtowraphere" None - """))) - expected = textwrap.dedent("""\ + """.dedent())) + expected = """\ To: nobody Content-Disposition: attachment; filename*0*=us-ascii''afilenamelongenoghtowraphere None - """) + """.dedent() s = self.ioclass() g = self.genclass(s, policy=self.policy.clone(max_line_length=20)) g.flatten(msg) @@ -244,7 +243,7 @@ def test_cte_type_7bit_handles_unknown_8bit(self): self.assertEqual(s.getvalue(), expected) def test_cte_type_7bit_transforms_8bit_cte(self): - source = textwrap.dedent("""\ + source = """\ From: foo@bar.com To: Dinsdale Subject: Nudge nudge, wink, wink @@ -253,9 +252,9 @@ def test_cte_type_7bit_transforms_8bit_cte(self): Content-Transfer-Encoding: 8bit oh là là, know what I mean, know what I mean? - """).encode('latin1') + """.dedent().encode('latin1') msg = message_from_bytes(source) - expected = textwrap.dedent("""\ + expected = """\ From: foo@bar.com To: Dinsdale Subject: Nudge nudge, wink, wink @@ -264,7 +263,7 @@ def test_cte_type_7bit_transforms_8bit_cte(self): Content-Transfer-Encoding: quoted-printable oh l=E0 l=E0, know what I mean, know what I mean? - """).encode('ascii') + """.dedent().encode('ascii') s = io.BytesIO() g = BytesGenerator(s, policy=self.policy.clone(cte_type='7bit', linesep='\n')) @@ -277,7 +276,7 @@ def test_smtputf8_policy(self): msg['To'] = 'Dinsdale' msg['Subject'] = 'Nudge nudge, wink, wink \u1F609' msg.set_content("oh là là, know what I mean, know what I mean?") - expected = textwrap.dedent("""\ + expected = """\ From: Páolo To: Dinsdale Subject: Nudge nudge, wink, wink \u1F609 @@ -286,7 +285,7 @@ def test_smtputf8_policy(self): MIME-Version: 1.0 oh là là, know what I mean, know what I mean? - """).encode('utf-8').replace(b'\n', b'\r\n') + """.dedent().encode('utf-8').replace(b'\n', b'\r\n') s = io.BytesIO() g = BytesGenerator(s, policy=policy.SMTPUTF8) g.flatten(msg) @@ -298,7 +297,7 @@ def test_smtp_policy(self): msg["To"] = Address(addr_spec="bar@foo.com", display_name="Dinsdale") msg["Subject"] = "Nudge nudge, wink, wink" msg.set_content("oh boy, know what I mean, know what I mean?") - expected = textwrap.dedent("""\ + expected = """\ From: =?utf-8?q?P=C3=A1olo?= To: Dinsdale Subject: Nudge nudge, wink, wink @@ -307,7 +306,7 @@ def test_smtp_policy(self): MIME-Version: 1.0 oh boy, know what I mean, know what I mean? - """).encode().replace(b"\n", b"\r\n") + """.dedent().encode().replace(b"\n", b"\r\n") s = io.BytesIO() g = BytesGenerator(s, policy=policy.SMTP) g.flatten(msg) diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py index 82e121350ffbf5..86bbe4ad1662bd 100644 --- a/Lib/test/test_email/test_headerregistry.py +++ b/Lib/test/test_email/test_headerregistry.py @@ -1,5 +1,4 @@ import datetime -import textwrap import unittest from email import errors from email import policy @@ -1609,12 +1608,12 @@ def test_unstructured_short_max_line_length(self): 'that will be folded anyway') self.assertEqual( h.fold(policy=policy.default.clone(max_line_length=20)), - textwrap.dedent("""\ + """\ Subject: this is a short header that will be folded anyway - """)) + """.dedent()) def test_fold_unstructured_single_word(self): h = self.make_header('Subject', 'test') @@ -1677,21 +1676,21 @@ def test_fold_unstructured_with_commas(self): "not give a , special treatment in unstructured headers.") self.assertEqual( h.fold(policy=policy.default.clone(max_line_length=60)), - textwrap.dedent("""\ + """\ Subject: This header is intended to demonstrate, in a fairly succinct way, that we now do not give a , special treatment in unstructured headers. - """)) + """.dedent()) def test_fold_address_list(self): h = self.make_header('To', '"Theodore H. Perfect" , ' '"My address is very long because my name is long" , ' '"Only A. Friend" ') - self.assertEqual(h.fold(policy=policy.default), textwrap.dedent("""\ + self.assertEqual(h.fold(policy=policy.default), """\ To: "Theodore H. Perfect" , "My address is very long because my name is long" , "Only A. Friend" - """)) + """.dedent()) def test_fold_date_header(self): h = self.make_header('Date', 'Sat, 2 Feb 2002 17:00:06 -0800') diff --git a/Lib/test/test_email/test_message.py b/Lib/test/test_email/test_message.py index fab97d91882b8b..3dd0baa20a9f84 100644 --- a/Lib/test/test_email/test_message.py +++ b/Lib/test/test_email/test_message.py @@ -1,5 +1,4 @@ import unittest -import textwrap from email import policy, message_from_string from email.message import EmailMessage, MIMEPart from test.test_email import TestEmailBase, parameterize @@ -21,7 +20,7 @@ def test_error_on_setitem_if_max_count_exceeded(self): m['To'] = 'xyz@abc' def test_rfc2043_auto_decoded_and_emailmessage_used(self): - m = message_from_string(textwrap.dedent("""\ + m = message_from_string("""\ Subject: Ayons asperges pour le =?utf-8?q?d=C3=A9jeuner?= From: =?utf-8?q?Pep=C3=A9?= Le Pew To: "Penelope Pussycat" <"penelope@example.com"> @@ -29,7 +28,7 @@ def test_rfc2043_auto_decoded_and_emailmessage_used(self): Content-Type: text/plain; charset="utf-8" sample text - """), policy=policy.default) + """.dedent(), policy=policy.default) self.assertEqual(m['subject'], "Ayons asperges pour le déjeuner") self.assertEqual(m['from'], "Pepé Le Pew ") self.assertIsInstance(m, EmailMessage) @@ -62,29 +61,29 @@ class TestEmailMessageBase: (None, None, 0), (), (), - textwrap.dedent("""\ + """\ To: foo@example.com simple text body - """)), + """.dedent()), 'mime_non_text': ( (None, None, None), (), (), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: image/jpg bogus body. - """)), + """.dedent()), 'plain_html_alternative': ( (None, 2, 1), (), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="===" @@ -101,13 +100,13 @@ class TestEmailMessageBase:

simple body

--===-- - """)), + """.dedent()), 'plain_html_mixed': ( (None, 2, 1), (), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -125,13 +124,13 @@ class TestEmailMessageBase:

simple body

--===-- - """)), + """.dedent()), 'plain_html_attachment_mixed': ( (None, None, 1), (2,), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -148,13 +147,13 @@ class TestEmailMessageBase:

simple body

--===-- - """)), + """.dedent()), 'html_text_attachment_mixed': ( (None, 2, None), (1,), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -171,13 +170,13 @@ class TestEmailMessageBase:

simple body

--===-- - """)), + """.dedent()), 'html_text_attachment_inline_mixed': ( (None, 2, 1), (), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -195,14 +194,14 @@ class TestEmailMessageBase:

simple body

--===-- - """)), + """.dedent()), # RFC 2387 'related': ( (0, 1, None), (2,), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/related; boundary="==="; type=text/html @@ -219,7 +218,7 @@ class TestEmailMessageBase: bogus data --===-- - """)), + """.dedent()), # This message structure will probably never be seen in the wild, but # it proves we distinguish between text parts based on 'start'. The @@ -228,7 +227,7 @@ class TestEmailMessageBase: (0, 2, None), (1,), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/related; boundary="==="; type=text/html; @@ -248,14 +247,14 @@ class TestEmailMessageBase: --===-- - """)), + """.dedent()), 'mixed_alternative_plain_related': ( (3, 4, 2), (6, 7), (1, 6, 7), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -299,7 +298,7 @@ class TestEmailMessageBase: another bogus jpg body --===-- - """)), + """.dedent()), # This structure suggested by Stephen J. Turnbull...may not exist/be # supported in the wild, but we want to support it. @@ -307,7 +306,7 @@ class TestEmailMessageBase: (1, 4, 3), (6, 7), (1, 6, 7), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -351,7 +350,7 @@ class TestEmailMessageBase: another bogus jpg body --===-- - """)), + """.dedent()), # Same thing, but proving we only look at the root part, which is the # first one if there isn't any start parameter. That is, this is a @@ -360,7 +359,7 @@ class TestEmailMessageBase: (1, None, None), (6, 7), (1, 6, 7), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -404,13 +403,13 @@ class TestEmailMessageBase: another bogus jpg body --===-- - """)), + """.dedent()), 'message_rfc822': ( (None, None, None), (), (), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: message/rfc822 @@ -419,13 +418,13 @@ class TestEmailMessageBase: From: robot@examp.com this is a message body. - """)), + """.dedent()), 'mixed_text_message_rfc822': ( (None, None, 1), (2,), (1, 2), - textwrap.dedent("""\ + """\ To: foo@example.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===" @@ -444,7 +443,7 @@ class TestEmailMessageBase: this is a message body. --===-- - """)), + """.dedent()), } @@ -930,11 +929,11 @@ def test_set_content_does_not_add_MIME_Version(self): self.assertNotIn('MIME-Version', m) def test_string_payload_with_multipart_content_type(self): - msg = message_from_string(textwrap.dedent("""\ + msg = message_from_string("""\ Content-Type: multipart/mixed; charset="utf-8" sample text - """), policy=policy.default) + """.dedent(), policy=policy.default) attachments = msg.iter_attachments() self.assertEqual(list(attachments), []) diff --git a/Lib/test/test_email/test_pickleable.py b/Lib/test/test_email/test_pickleable.py index 16b4467114635f..ed5593c2569f3d 100644 --- a/Lib/test/test_email/test_pickleable.py +++ b/Lib/test/test_email/test_pickleable.py @@ -1,5 +1,4 @@ import unittest -import textwrap import copy import pickle import email @@ -45,14 +44,14 @@ class TestPickleCopyMessage(TestEmailBase): msg_params = {} # Note: there will be no custom header objects in the parsed message. - msg_params['parsed'] = (email.message_from_string(textwrap.dedent("""\ + msg_params['parsed'] = (email.message_from_string("""\ Date: Tue, 29 May 2012 09:24:26 +1000 From: frodo@mordor.net To: bilbo@underhill.org Subject: help I think I forgot the ring. - """), policy=policy.default),) + """.dedent(), policy=policy.default),) msg_params['created'] = (email.message.Message(policy=policy.default),) msg_params['created'][0]['Date'] = 'Tue, 29 May 2012 09:24:26 +1000' diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py index e87c275549406d..37313a83bf0ad5 100644 --- a/Lib/test/test_email/test_policy.py +++ b/Lib/test/test_email/test_policy.py @@ -1,6 +1,5 @@ import io import types -import textwrap import unittest import email.errors import email.policy @@ -341,7 +340,7 @@ def test_parser_propagates_policy_to_message(self): self.assertIs(msg.policy, self.policy) def test_parser_propagates_policy_to_sub_messages(self): - msg = self._make_msg(textwrap.dedent("""\ + msg = self._make_msg("""\ Subject: mime test MIME-Version: 1.0 Content-Type: multipart/mixed, boundary="XXX" @@ -355,7 +354,7 @@ def test_parser_propagates_policy_to_sub_messages(self): test2 --XXX-- - """)) + """.dedent()) for part in msg.walk(): self.assertIs(part.policy, self.policy) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 0bdfae1b7e3873..2c3793831aad7c 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -11,7 +11,6 @@ import subprocess import sys import tempfile -import textwrap MS_WINDOWS = (os.name == 'nt') @@ -488,7 +487,7 @@ def main_xoptions(self, xoptions_list): def _get_expected_config_impl(self): env = remove_python_envvars() - code = textwrap.dedent(''' + code = ''' import json import sys import _testinternalcapi @@ -499,7 +498,7 @@ def _get_expected_config_impl(self): data = data.encode('utf-8') sys.stdout.buffer.write(data) sys.stdout.buffer.flush() - ''') + '''.dedent() # Use -S to not import the site module: get the proper configuration # when test_embed is run from a venv (bpo-35313) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index c64afe88c25d6c..21a8f2720d2acc 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -10,7 +10,6 @@ from test.support import script_helper, is_android import tempfile import unittest -from textwrap import dedent try: import _testcapi @@ -64,7 +63,7 @@ def get_output(self, code, filename=None, fd=None): build, and replace "Current thread 0x00007f8d8fbd9700" by "Current thread XXX". """ - code = dedent(code).strip() + code = code.dedent().strip() pass_fds = [] if fd is not None: pass_fds.append(fd) @@ -112,7 +111,7 @@ def check_error(self, code, line_number, fatal_error, *, """ if py_fatal_error: fatal_error += "\nPython runtime state: initialized" - regex = dedent(regex).format( + regex = regex.dedent().format( lineno=line_number, fatal_error=fatal_error, header=header).strip() @@ -528,7 +527,7 @@ def run(self): File "", line {lineno} in dump File "", line 28 in $ """ - regex = dedent(regex.format(lineno=lineno)).strip() + regex = regex.format(lineno=lineno).dedent().strip() self.assertRegex(output, regex) self.assertEqual(exitcode, 0) @@ -778,7 +777,7 @@ def test_ignore_exception(self): faulthandler.enable() faulthandler._raise_exception({exc_code}) """ - code = dedent(code) + code = code.dedent() output, exitcode = self.get_output(code) self.assertEqual(output, []) self.assertEqual(exitcode, exc_code) @@ -813,13 +812,13 @@ def test_raise_nonfatal_exception(self): @unittest.skipUnless(MS_WINDOWS, 'specific to Windows') def test_disable_windows_exc_handler(self): - code = dedent(""" + code = """ import faulthandler faulthandler.enable() faulthandler.disable() code = faulthandler._EXCEPTION_ACCESS_VIOLATION faulthandler._raise_exception(code) - """) + """.dedent() output, exitcode = self.get_output(code) self.assertEqual(output, []) self.assertEqual(exitcode, 0xC0000005) @@ -827,10 +826,10 @@ def test_disable_windows_exc_handler(self): def test_cancel_later_without_dump_traceback_later(self): # bpo-37933: Calling cancel_dump_traceback_later() # without dump_traceback_later() must not segfault. - code = dedent(""" + code = """ import faulthandler faulthandler.cancel_dump_traceback_later() - """) + """.dedent() output, exitcode = self.get_output(code) self.assertEqual(output, []) self.assertEqual(exitcode, 0) diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py index 56b7ac68655594..9dc0b6f8dd31a7 100644 --- a/Lib/test/test_future.py +++ b/Lib/test/test_future.py @@ -4,7 +4,6 @@ import ast import unittest from test import support -from textwrap import dedent import os import re import sys @@ -122,8 +121,7 @@ def test_unicode_literals_exec(self): self.assertIsInstance(scope["x"], str) class AnnotationsFutureTestCase(unittest.TestCase): - template = dedent( - """ + template = """ from __future__ import annotations def f() -> {ann}: ... @@ -135,8 +133,7 @@ async def g2(arg: {ann}) -> None: ... var: {ann} var2: {ann} = None - """ - ) + """.dedent() def getActual(self, annotation): scope = {} diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index acb6391944bc0b..e3627b9087fc76 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -9,7 +9,6 @@ import gc import sys import sysconfig -import textwrap import threading import time import weakref @@ -1171,7 +1170,7 @@ def test_refcount_errors(self): import_module("ctypes") import subprocess - code = textwrap.dedent(''' + code = ''' from test.support import gc_collect, SuppressCrashReport a = [1, 2, 3] @@ -1189,7 +1188,7 @@ def test_refcount_errors(self): # The garbage collector should now have a fatal error # when it reaches the broken object gc_collect() - ''') + '''.dedent() p = subprocess.Popen([sys.executable, "-c", code], stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index d50befc030a484..aae7f35ad996b1 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -12,7 +12,6 @@ import stat import subprocess import sys -import textwrap import threading import time import unittest @@ -351,13 +350,13 @@ def test_import_by_filename(self): def test_import_in_del_does_not_crash(self): # Issue 4236 - testfn = script_helper.make_script('', TESTFN, textwrap.dedent("""\ + testfn = script_helper.make_script('', TESTFN, """\ import sys class C: def __del__(self): import importlib sys.argv.insert(0, C()) - """)) + """.dedent()) script_helper.assert_python_ok(testfn) @skip_if_dont_write_bytecode diff --git a/Lib/test/test_importlib/fixtures.py b/Lib/test/test_importlib/fixtures.py index d923cec26ea8f5..d73d7d78d285c0 100644 --- a/Lib/test/test_importlib/fixtures.py +++ b/Lib/test/test_importlib/fixtures.py @@ -3,7 +3,6 @@ import shutil import pathlib import tempfile -import textwrap import contextlib @@ -197,7 +196,7 @@ def build_files(file_defs, prefix=pathlib.Path()): def DALS(str): "Dedent and left-strip" - return textwrap.dedent(str).lstrip() + return str.dedent().lstrip() class NullFinder: diff --git a/Lib/test/test_importlib/test_main.py b/Lib/test/test_importlib/test_main.py index 42a79992ecc8c0..bb8c4cf9040cbc 100644 --- a/Lib/test/test_importlib/test_main.py +++ b/Lib/test/test_importlib/test_main.py @@ -3,7 +3,6 @@ import re import json import pickle -import textwrap import unittest import importlib.metadata @@ -132,11 +131,11 @@ def pkg_with_non_ascii_description_egg_info(site_dir): metadata_dir.mkdir() metadata = metadata_dir / 'METADATA' with metadata.open('w', encoding='utf-8') as fp: - fp.write(textwrap.dedent(""" + fp.write(""" Name: portend pôrˈtend - """).lstrip()) + """.dedent().lstrip()) return 'portend' def test_metadata_loads(self): diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py index 1d7b29ae05fd10..e6226be2c02382 100644 --- a/Lib/test/test_importlib/test_metadata_api.py +++ b/Lib/test/test_importlib/test_metadata_api.py @@ -1,5 +1,4 @@ import re -import textwrap import unittest from collections.abc import Iterator @@ -112,7 +111,7 @@ def test_requires_dist_info(self): assert "pytest; extra == 'test'" in deps def test_more_complex_deps_requires_text(self): - requires = textwrap.dedent(""" + requires = """ dep1 dep2 @@ -124,7 +123,7 @@ def test_more_complex_deps_requires_text(self): [extra2:python_version < "3"] dep5 - """) + """.dedent() deps = sorted(Distribution._deps_from_requires_text(requires)) expected = [ 'dep1', diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 98a9c0a662a093..801e9a76d5713b 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -13,7 +13,6 @@ import shutil import sys import types -import textwrap import unicodedata import unittest import unittest.mock @@ -3995,15 +3994,15 @@ def test_details(self): class TestReload(unittest.TestCase): - src_before = textwrap.dedent("""\ + src_before = """\ def foo(): print("Bla") - """) + """.dedent() - src_after = textwrap.dedent("""\ + src_after = """\ def foo(): print("Oh no!") - """) + """.dedent() def assertInspectEqual(self, path, source): inspected_src = inspect.getsource(source) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index fe07b56880bbfb..03b9bf8f608b34 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -29,7 +29,6 @@ import signal import sys import sysconfig -import textwrap import threading import time import unittest @@ -4163,7 +4162,7 @@ def test_check_encoding_errors(self): mod = self.io.__name__ filename = __file__ invalid = 'Boom, Shaka Laka, Boom!' - code = textwrap.dedent(f''' + code = f''' import sys from {mod} import open, TextIOWrapper @@ -4198,7 +4197,7 @@ def test_check_encoding_errors(self): sys.exit(24) sys.exit(10) - ''') + '''.dedent() proc = assert_python_failure('-X', 'dev', '-c', code) self.assertEqual(proc.rc, 10, proc) diff --git a/Lib/test/test_json/test_indent.py b/Lib/test/test_json/test_indent.py index e07856f33cbdac..dfc8b58f9e30c0 100644 --- a/Lib/test/test_json/test_indent.py +++ b/Lib/test/test_json/test_indent.py @@ -1,4 +1,3 @@ -import textwrap from io import StringIO from test.test_json import PyTest, CTest @@ -8,7 +7,7 @@ def test_indent(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] - expect = textwrap.dedent("""\ + expect = """\ [ \t[ \t\t"blorpie" @@ -27,7 +26,7 @@ def test_indent(self): \t\t"field": "yes", \t\t"morefield": false \t} - ]""") + ]""".dedent() d1 = self.dumps(h) d2 = self.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) diff --git a/Lib/test/test_json/test_separators.py b/Lib/test/test_json/test_separators.py index 8ca517405179e5..e9beea6d884bf6 100644 --- a/Lib/test/test_json/test_separators.py +++ b/Lib/test/test_json/test_separators.py @@ -1,4 +1,3 @@ -import textwrap from test.test_json import PyTest, CTest @@ -7,7 +6,7 @@ def test_separators(self): h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', {'nifty': 87}, {'field': 'yes', 'morefield': False} ] - expect = textwrap.dedent("""\ + expect = """\ [ [ "blorpie" @@ -26,7 +25,7 @@ def test_separators(self): "field" : "yes" , "morefield" : false } - ]""") + ]""".dedent() d1 = self.dumps(h) diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index fc2a7a4fca3c5a..a72040ff91e470 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -1,7 +1,6 @@ import errno import os import sys -import textwrap import unittest import subprocess @@ -18,7 +17,7 @@ class TestTool(unittest.TestCase): :"yes"} ] """ - expect_without_sort_keys = textwrap.dedent("""\ + expect_without_sort_keys = """\ [ [ "blorpie" @@ -38,9 +37,9 @@ class TestTool(unittest.TestCase): "morefield": false } ] - """) + """.dedent() - expect = textwrap.dedent("""\ + expect = """\ [ [ "blorpie" @@ -60,14 +59,14 @@ class TestTool(unittest.TestCase): "field": "yes" } ] - """) + """.dedent() - jsonlines_raw = textwrap.dedent("""\ + jsonlines_raw = """\ {"ingredients":["frog", "water", "chocolate", "glucose"]} {"ingredients":["chocolate","steel bolts"]} - """) + """.dedent() - jsonlines_expect = textwrap.dedent("""\ + jsonlines_expect = """\ { "ingredients": [ "frog", @@ -82,7 +81,7 @@ class TestTool(unittest.TestCase): "steel bolts" ] } - """) + """.dedent() def test_stdin_stdout(self): args = sys.executable, '-m', 'json.tool' @@ -106,11 +105,11 @@ def test_infile_stdout(self): def test_non_ascii_infile(self): data = '{"msg": "\u3053\u3093\u306b\u3061\u306f"}' - expect = textwrap.dedent('''\ + expect = '''\ { "msg": "\\u3053\\u3093\\u306b\\u3061\\u306f" } - ''').encode() + '''.dedent().encode() infile = self._create_infile(data) rc, out, err = assert_python_ok('-m', 'json.tool', infile) @@ -152,12 +151,12 @@ def test_sort_keys_flag(self): def test_indent(self): input_ = '[1, 2]' - expect = textwrap.dedent('''\ + expect = '''\ [ 1, 2 ] - ''') + '''.dedent() args = sys.executable, '-m', 'json.tool', '--indent', '2' process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) self.assertEqual(process.stdout, expect) diff --git a/Lib/test/test_lltrace.py b/Lib/test/test_lltrace.py index 49fae81eefab9f..051b779ec2a535 100644 --- a/Lib/test/test_lltrace.py +++ b/Lib/test/test_lltrace.py @@ -1,5 +1,4 @@ import os -import textwrap import unittest from test import support @@ -15,7 +14,7 @@ def test_lltrace_does_not_crash_on_subscript_operator(self): # when the interal Python stack was negatively adjusted with open(support.TESTFN, 'w') as fd: self.addCleanup(os.unlink, support.TESTFN) - fd.write(textwrap.dedent("""\ + fd.write("""\ import code console = code.InteractiveConsole() @@ -23,7 +22,7 @@ def test_lltrace_does_not_crash_on_subscript_operator(self): console.push('a = [1, 2, 3]') console.push('a[0] = 1') print('unreachable if bug exists') - """)) + """.dedent()) assert_python_ok(support.TESTFN) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index e1d0eb8145fe23..57cdd4d3176f03 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -45,7 +45,6 @@ from test import support from test.support import socket_helper from test.support.logging_helper import TestHandler -import textwrap import threading import time import unittest @@ -1421,7 +1420,7 @@ class ConfigFileTest(BaseTest): """ def apply_config(self, conf, **kwargs): - file = io.StringIO(textwrap.dedent(conf)) + file = io.StringIO(conf.dedent()) logging.config.fileConfig(file, **kwargs) def test_config0_ok(self): @@ -1442,7 +1441,7 @@ def test_config0_ok(self): def test_config0_using_cp_ok(self): # A simple config file which overrides the default settings. with support.captured_stdout() as output: - file = io.StringIO(textwrap.dedent(self.config0)) + file = io.StringIO(self.config0.dedent()) cp = configparser.ConfigParser() cp.read_file(file) logging.config.fileConfig(cp) @@ -1602,7 +1601,7 @@ def test_config_set_handler_names(self): def test_defaults_do_no_interpolation(self): """bpo-33802 defaults should not get interpolated""" - ini = textwrap.dedent(""" + ini = """ [formatters] keys=default @@ -1621,7 +1620,7 @@ def test_defaults_do_no_interpolation(self): [logger_root] formatter=default handlers=console - """).strip() + """.dedent().strip() fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.ini') try: os.write(fd, ini.encode('ascii')) @@ -3236,7 +3235,7 @@ def test_listen_config_10_ok(self): def test_listen_config_1_ok(self): with support.captured_stdout() as output: - self.setup_via_listener(textwrap.dedent(ConfigFileTest.config1)) + self.setup_via_listener(ConfigFileTest.config1.dedent()) logger = logging.getLogger("compiler.parser") # Both will output a message logger.info(self.next_message()) @@ -3257,7 +3256,7 @@ def verify_reverse(stuff): return stuff[::-1] logger = logging.getLogger("compiler.parser") - to_send = textwrap.dedent(ConfigFileTest.config1) + to_send = ConfigFileTest.config1.dedent() # First, specify a verification function that will fail. # We expect to see no output, since our configuration # never took effect. diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index fdda1d11d3307e..c979e5ed5568e7 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -10,7 +10,6 @@ import tempfile from test import support import unittest -import textwrap import mailbox import glob @@ -82,12 +81,12 @@ def test_add(self): for i in (1, 2, 3, 4, 5, 6): self._check_sample(self._box[keys[i]]) - _nonascii_msg = textwrap.dedent("""\ + _nonascii_msg = """\ From: foo Subject: Falinaptár házhozszállítással. Már rendeltél? 0 - """) + """.dedent() def test_add_invalid_8bit_bytes_header(self): key = self._box.add(self._nonascii_msg.encode('latin-1')) @@ -119,7 +118,7 @@ def raiser(*args, **kw): self._box.close() self.assertMailboxEmpty() - _non_latin_bin_msg = textwrap.dedent("""\ + _non_latin_bin_msg = """\ From: foo@bar.com To: báz Subject: Maintenant je vous présente mon collègue, le pouf célèbre @@ -129,7 +128,7 @@ def raiser(*args, **kw): Content-Transfer-Encoding: 8bit Да, они летят. - """).encode('utf-8') + """.dedent().encode('utf-8') def test_add_8bit_body(self): key = self._box.add(self._non_latin_bin_msg) diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py index 7ce7e565704f74..b653ff159923f8 100644 --- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -1,11 +1,11 @@ -import netrc, os, unittest, sys, tempfile, textwrap +import netrc, os, unittest, sys, tempfile from test import support class NetrcTestCase(unittest.TestCase): def make_nrc(self, test_data): - test_data = textwrap.dedent(test_data) + test_data = test_data.dedent() mode = 'w' if sys.platform != 'cygwin': mode += 't' diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py index 2a5a0b97eea634..095b78a45e5888 100644 --- a/Lib/test/test_nntplib.py +++ b/Lib/test/test_nntplib.py @@ -1,7 +1,6 @@ import io import socket import datetime -import textwrap import unittest import functools import contextlib @@ -502,7 +501,7 @@ def push_data(self, data): def push_lit(self, lit): """Push a string literal""" - lit = textwrap.dedent(lit) + lit = lit.dedent() lit = "\r\n".join(lit.splitlines()) + "\r\n" lit = lit.encode('utf-8') self.push_data(lit) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index fcb7e4e6072cb6..13af4ea5d8c3e2 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -7,7 +7,6 @@ import types import unittest import subprocess -import textwrap from contextlib import ExitStack from io import StringIO @@ -1207,7 +1206,7 @@ def run_pdb_script(self, script, commands): """Run 'script' lines with pdb and the pdb 'commands'.""" filename = 'main.py' with open(filename, 'w') as f: - f.write(textwrap.dedent(script)) + f.write(script.dedent()) self.addCleanup(support.unlink, filename) return self._run_pdb([filename], commands) @@ -1221,12 +1220,12 @@ def run_pdb_module(self, script, commands): with open(init_file, 'w') as f: pass with open(main_file, 'w') as f: - f.write(textwrap.dedent(script)) + f.write(script.dedent()) self.addCleanup(support.rmtree, self.module_name) return self._run_pdb(['-m', self.module_name], commands) def _assert_find_function(self, file_content, func_name, expected): - file_content = textwrap.dedent(file_content) + file_content = file_content.dedent() with open(support.TESTFN, 'w') as f: f.write(file_content) @@ -1299,7 +1298,7 @@ def bar(): pass """ with open('bar.py', 'w') as f: - f.write(textwrap.dedent(bar)) + f.write(bar.dedent()) self.addCleanup(support.unlink, 'bar.py') stdout, stderr = self.run_pdb_script(script, commands) self.assertTrue( @@ -1311,7 +1310,7 @@ def test_issue13120(self): # inside signal.signal. with open(support.TESTFN, 'wb') as f: - f.write(textwrap.dedent(""" + f.write(""" import threading import pdb @@ -1321,7 +1320,7 @@ def start_pdb(): y = 1 t = threading.Thread(target=start_pdb) - t.start()""").encode('ascii')) + t.start()""".dedent().encode('ascii')) cmd = [sys.executable, '-u', support.TESTFN] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, @@ -1336,7 +1335,7 @@ def start_pdb(): def test_issue36250(self): with open(support.TESTFN, 'wb') as f: - f.write(textwrap.dedent(""" + f.write(""" import threading import pdb @@ -1350,7 +1349,7 @@ def start_pdb(): t.start() pdb.Pdb(readrc=False).set_trace() evt.set() - t.join()""").encode('ascii')) + t.join()""".dedent().encode('ascii')) cmd = [sys.executable, '-u', support.TESTFN] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, @@ -1375,11 +1374,11 @@ def test_issue16180(self): def test_readrc_kwarg(self): - script = textwrap.dedent(""" + script = """ import pdb; pdb.Pdb(readrc=False).set_trace() print('hello') - """) + """.dedent() save_home = os.environ.pop('HOME', None) try: @@ -1509,21 +1508,21 @@ def test_relative_imports(self): self.addCleanup(support.rmtree, self.module_name) os.mkdir(self.module_name) with open(init_file, 'w') as f: - f.write(textwrap.dedent(""" + f.write(""" top_var = "VAR from top" - """)) + """.dedent()) with open(main_file, 'w') as f: - f.write(textwrap.dedent(""" + f.write(""" from . import top_var from .module import var from . import module pass # We'll stop here and print the vars - """)) + """.dedent()) with open(module_file, 'w') as f: - f.write(textwrap.dedent(""" + f.write(""" var = "VAR from module" var2 = "second var" - """)) + """.dedent()) commands = """ b 5 c @@ -1547,18 +1546,18 @@ def test_relative_imports_on_plain_module(self): self.addCleanup(support.rmtree, self.module_name) os.mkdir(self.module_name) with open(init_file, 'w') as f: - f.write(textwrap.dedent(""" + f.write(""" top_var = "VAR from top" - """)) + """.dedent()) with open(main_file, 'w') as f: - f.write(textwrap.dedent(""" + f.write(""" from . import module pass # We'll stop here and print the vars - """)) + """.dedent()) with open(module_file, 'w') as f: - f.write(textwrap.dedent(""" + f.write(""" var = "VAR from module" - """)) + """.dedent()) commands = """ b 3 c diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index 8eb66d52795817..0088da398aaaba 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -77,7 +77,7 @@ def build_extension(self, grammar_source): def run_test(self, grammar_source, test_source): self.build_extension(grammar_source) - test_source = textwrap.indent(textwrap.dedent(test_source), 8 * " ") + test_source = textwrap.indent(test_source.dedent(), 8 * " ") assert_python_ok( "-c", TEST_TEMPLATE.format(extension_path=self.tmp_path, test_source=test_source), diff --git a/Lib/test/test_peg_generator/test_pegen.py b/Lib/test/test_peg_generator/test_pegen.py index 0a2a6d4ae16019..fefb4f9079535c 100644 --- a/Lib/test/test_peg_generator/test_pegen.py +++ b/Lib/test/test_peg_generator/test_pegen.py @@ -1,5 +1,4 @@ import io -import textwrap import unittest from test import test_tools @@ -34,7 +33,7 @@ def test_parse_grammar(self) -> None: """ grammar: Grammar = parse_string(grammar_source, GrammarParser) rules = grammar.rules - self.assertEqual(str(grammar), textwrap.dedent(expected).strip()) + self.assertEqual(str(grammar), expected.dedent().strip()) # Check the str() and repr() of a few rules; AST nodes don't support ==. self.assertEqual(str(rules["start"]), "start: sum NEWLINE") self.assertEqual(str(rules["sum"]), "sum: term '+' term | term") @@ -57,7 +56,7 @@ def test_long_rule_str(self) -> None: | one one one """ grammar: Grammar = parse_string(grammar_source, GrammarParser) - self.assertEqual(str(grammar.rules["start"]), textwrap.dedent(expected).strip()) + self.assertEqual(str(grammar.rules["start"]), expected.dedent().strip()) def test_typed_rules(self) -> None: grammar = """ @@ -630,8 +629,7 @@ def test_simple_rule(self) -> None: printer.print_grammar_ast(rules, printer=lines.append) output = "\n".join(lines) - expected_output = textwrap.dedent( - """\ + expected_output = """\ └──Rule └──Rhs └──Alt @@ -639,8 +637,7 @@ def test_simple_rule(self) -> None: │ └──StringLeaf("'a'") └──NamedItem └──StringLeaf("'b'") - """ - ) + """.dedent() self.assertEqual(output, expected_output) @@ -657,8 +654,7 @@ def test_multiple_rules(self) -> None: printer.print_grammar_ast(rules, printer=lines.append) output = "\n".join(lines) - expected_output = textwrap.dedent( - """\ + expected_output = """\ └──Rule └──Rhs └──Alt @@ -678,8 +674,7 @@ def test_multiple_rules(self) -> None: └──Alt └──NamedItem └──StringLeaf("'b'") - """ - ) + """.dedent() self.assertEqual(output, expected_output) @@ -694,8 +689,7 @@ def test_deep_nested_rule(self) -> None: printer.print_grammar_ast(rules, printer=lines.append) output = "\n".join(lines) - expected_output = textwrap.dedent( - """\ + expected_output = """\ └──Rule └──Rhs └──Alt @@ -719,7 +713,6 @@ def test_deep_nested_rule(self) -> None: └──Alt └──NamedItem └──StringLeaf("'d'") - """ - ) + """.dedent() self.assertEqual(output, expected_output) diff --git a/Lib/test/test_peg_parser.py b/Lib/test/test_peg_parser.py index ea4afa6e179732..fbcc6ac777db3d 100644 --- a/Lib/test/test_peg_parser.py +++ b/Lib/test/test_peg_parser.py @@ -5,7 +5,6 @@ import unittest from pathlib import PurePath from typing import Any, Union, Iterable, Tuple -from textwrap import dedent from test import support @@ -661,7 +660,7 @@ def f(): def cleanup_source(source: Any) -> str: if isinstance(source, str): - result = dedent(source) + result = source.dedent() elif not isinstance(source, (list, tuple)): result = "\n".join(source) else: @@ -746,7 +745,7 @@ def test_correct_ast_generation_without_pos_info(self) -> None: def test_fstring_parse_error_tracebacks(self) -> None: for source, error_text in FSTRINGS_TRACEBACKS.values(): with self.assertRaises(SyntaxError) as se: - peg_parser.parse_string(dedent(source)) + peg_parser.parse_string(source.dedent()) self.assertEqual(error_text, se.exception.text) def test_correct_ast_generatrion_eval(self) -> None: diff --git a/Lib/test/test_pkg.py b/Lib/test/test_pkg.py index eed0fd1c6b73fa..9c512d33c8adfd 100644 --- a/Lib/test/test_pkg.py +++ b/Lib/test/test_pkg.py @@ -3,7 +3,6 @@ import sys import os import tempfile -import textwrap import unittest @@ -67,7 +66,7 @@ def tearDown(self): del sys.modules[name] def run_code(self, code): - exec(textwrap.dedent(code), globals(), {"self": self}) + exec(code.dedent(), globals(), {"self": self}) def mkhier(self, descr): root = tempfile.mkdtemp() diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index be121ae463dbb3..7d35275f5c313d 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -17,7 +17,6 @@ import tempfile import unittest import warnings -import textwrap _DUMMY_SYMLINK = os.path.join(tempfile.gettempdir(), support.TESTFN + '-dummy-symlink') @@ -1633,9 +1632,9 @@ def test_setpgroup_wrong_type(self): @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') def test_setsigmask(self): - code = textwrap.dedent("""\ + code = """\ import signal - signal.raise_signal(signal.SIGUSR1)""") + signal.raise_signal(signal.SIGUSR1)""".dedent() pid = self.spawn_func( sys.executable, @@ -1666,12 +1665,12 @@ def test_setsid(self): try: os.set_inheritable(wfd, True) - code = textwrap.dedent(f""" + code = f""" import os fd = {wfd} sid = os.getsid(0) os.write(fd, str(sid).encode()) - """) + """.dedent() try: pid = self.spawn_func(sys.executable, @@ -1695,9 +1694,9 @@ def test_setsid(self): 'need signal.pthread_sigmask()') def test_setsigdef(self): original_handler = signal.signal(signal.SIGUSR1, signal.SIG_IGN) - code = textwrap.dedent("""\ + code = """\ import signal - signal.raise_signal(signal.SIGUSR1)""") + signal.raise_signal(signal.SIGUSR1)""".dedent() try: pid = self.spawn_func( sys.executable, @@ -1730,12 +1729,12 @@ def test_setsigdef_wrong_type(self): def test_setscheduler_only_param(self): policy = os.sched_getscheduler(0) priority = os.sched_get_priority_min(policy) - code = textwrap.dedent(f"""\ + code = f"""\ import os, sys if os.sched_getscheduler(0) != {policy}: sys.exit(101) if os.sched_getparam(0).sched_priority != {priority}: - sys.exit(102)""") + sys.exit(102)""".dedent() pid = self.spawn_func( sys.executable, [sys.executable, '-c', code], @@ -1750,12 +1749,12 @@ def test_setscheduler_only_param(self): def test_setscheduler_with_policy(self): policy = os.sched_getscheduler(0) priority = os.sched_get_priority_min(policy) - code = textwrap.dedent(f"""\ + code = f"""\ import os, sys if os.sched_getscheduler(0) != {policy}: sys.exit(101) if os.sched_getparam(0).sched_priority != {priority}: - sys.exit(102)""") + sys.exit(102)""".dedent() pid = self.spawn_func( sys.executable, [sys.executable, '-c', code], @@ -1888,7 +1887,7 @@ def test_posix_spawnp(self): path = temp_dir # PATH is not set spawn_args = (program, '-I', '-S', '-c', 'pass') - code = textwrap.dedent(""" + code = (""" import os from test import support @@ -1896,7 +1895,7 @@ def test_posix_spawnp(self): pid = os.posix_spawnp(args[0], args, os.environ) support.wait_process(pid, exitcode=0) - """ % (spawn_args,)) + """ % (spawn_args,)).dedent() # Use a subprocess to test os.posix_spawnp() with a modified PATH # environment variable: posix_spawnp() uses the current environment diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 869799cfa9a66b..6d1d0a976f75a7 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -4,7 +4,6 @@ ''' import sys -from textwrap import dedent from types import FunctionType, MethodType, BuiltinFunctionType import pyclbr from unittest import TestCase, main as unittest_main @@ -159,7 +158,7 @@ def test_nested(self): mb = pyclbr # Set arguments for descriptor creation and _creat_tree call. m, p, f, t, i = 'test', '', 'test.py', {}, None - source = dedent("""\ + source = """\ def f0: def f1(a,b,c): def f2(a=1, b=2, c=3): pass @@ -175,7 +174,7 @@ class C2: "Class nested within nested class." def F3(): return 1+1 - """) + """.dedent() actual = mb._create_tree(m, p, f, source, t, i) # Create descriptors, linked together, and expected dict. diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index ffabb7f1b94072..ae4840150f7d6f 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -668,7 +668,7 @@ def test_help_output_redirect(self): Help on module test.pydoc_mod in test: """.lstrip() - help_header = textwrap.dedent(help_header) + help_header = help_header.dedent() expected_help_pattern = help_header + expected_text_pattern pydoc.getpager = getpager_new diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 93f8d44ec69380..1c3b72ae00334c 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -15,7 +15,6 @@ import sys import sysconfig import tempfile -import textwrap import unittest from test import libregrtest from test import support @@ -27,14 +26,14 @@ ROOT_DIR = os.path.abspath(os.path.normpath(ROOT_DIR)) LOG_PREFIX = r'[0-9]+:[0-9]+:[0-9]+ (?:load avg: [0-9]+\.[0-9]{2} )?' -TEST_INTERRUPTED = textwrap.dedent(""" +TEST_INTERRUPTED = """ from signal import SIGINT, raise_signal try: raise_signal(SIGINT) except ImportError: import os os.kill(os.getpid(), SIGINT) - """) + """.dedent() class ParseArgsTestCase(unittest.TestCase): @@ -372,13 +371,13 @@ def create_test(self, name=None, code=None): BaseTestCase.TEST_UNIQUE_ID += 1 if code is None: - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): def test_empty_test(self): pass - """) + """.dedent() # test_regrtest cannot be run twice in parallel because # of setUp() and create_test() @@ -698,13 +697,13 @@ def run_tests(self, *testargs, **kw): def test_failing_test(self): # test a failing test - code = textwrap.dedent(""" + code = """ import unittest class FailingTest(unittest.TestCase): def test_failing(self): self.fail("bug") - """) + """.dedent() test_ok = self.create_test('ok') test_failing = self.create_test('failing', code=code) tests = [test_ok, test_failing] @@ -716,13 +715,13 @@ def test_resources(self): # test -u command line option tests = {} for resource in ('audio', 'network'): - code = textwrap.dedent(""" + code = (""" from test import support; support.requires(%r) import unittest class PassingTest(unittest.TestCase): def test_pass(self): pass - """ % resource) + """ % resource).dedent() tests[resource] = self.create_test(resource, code) test_names = sorted(tests.values()) @@ -743,10 +742,10 @@ def test_pass(self): def test_random(self): # test -r and --randseed command line option - code = textwrap.dedent(""" + code = """ import random print("TESTRANDOM: %s" % random.randint(1, 1000)) - """) + """.dedent() test = self.create_test('random', code) # first run to get the output with the random seed @@ -864,7 +863,7 @@ def test_wait(self): def test_forever(self): # test --forever - code = textwrap.dedent(""" + code = """ import builtins import unittest @@ -878,7 +877,7 @@ def test_run(self): self.fail("fail at the 3rd runs") else: builtins.__dict__['RUN'] = 1 - """) + """.dedent() test = self.create_test('forever', code=code) output = self.run_tests('--forever', test, exitcode=2) self.check_executed_tests(output, [test]*3, failed=test) @@ -906,7 +905,7 @@ def check_leak(self, code, what): @unittest.skipUnless(Py_DEBUG, 'need a debug build') def test_huntrleaks(self): # test --huntrleaks - code = textwrap.dedent(""" + code = """ import unittest GLOBAL_LIST = [] @@ -914,13 +913,13 @@ def test_huntrleaks(self): class RefLeakTest(unittest.TestCase): def test_leak(self): GLOBAL_LIST.append(object()) - """) + """.dedent() self.check_leak(code, 'references') @unittest.skipUnless(Py_DEBUG, 'need a debug build') def test_huntrleaks_fd_leak(self): # test --huntrleaks for file descriptor leak - code = textwrap.dedent(""" + code = """ import os import unittest @@ -928,7 +927,7 @@ class FDLeakTest(unittest.TestCase): def test_leak(self): fd = os.open(__file__, os.O_RDONLY) # bug: never close the file descriptor - """) + """.dedent() self.check_leak(code, 'file descriptors') def test_list_tests(self): @@ -940,7 +939,7 @@ def test_list_tests(self): def test_list_cases(self): # test --list-cases - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): @@ -948,7 +947,7 @@ def test_method1(self): pass def test_method2(self): pass - """) + """.dedent() testname = self.create_test(code=code) # Test --list-cases @@ -980,7 +979,7 @@ def parse_methods(self, output): return [match.group(1) for match in regex.finditer(output)] def test_ignorefile(self): - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): @@ -992,7 +991,7 @@ def test_method3(self): pass def test_method4(self): pass - """) + """.dedent() all_methods = ['test_method1', 'test_method2', 'test_method3', 'test_method4'] testname = self.create_test(code=code) @@ -1016,7 +1015,7 @@ def test_method4(self): self.assertEqual(methods, subset) def test_matchfile(self): - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): @@ -1028,7 +1027,7 @@ def test_method3(self): pass def test_method4(self): pass - """) + """.dedent() all_methods = ['test_method1', 'test_method2', 'test_method3', 'test_method4'] testname = self.create_test(code=code) @@ -1057,13 +1056,13 @@ def test_method4(self): self.assertEqual(methods, subset) def test_env_changed(self): - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): def test_env_changed(self): open("env_changed", "w").close() - """) + """.dedent() testname = self.create_test(code=code) # don't fail by default @@ -1077,14 +1076,14 @@ def test_env_changed(self): def test_rerun_fail(self): # FAILURE then FAILURE - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): def test_bug(self): # test always fail self.fail("bug") - """) + """.dedent() testname = self.create_test(code=code) output = self.run_tests("-w", testname, exitcode=2) @@ -1093,7 +1092,7 @@ def test_bug(self): def test_rerun_success(self): # FAILURE then SUCCESS - code = textwrap.dedent(""" + code = """ import builtins import unittest @@ -1104,7 +1103,7 @@ def test_fail_once(self): if not hasattr(builtins, '_test_failed'): builtins._test_failed = True self.fail("bug") - """) + """.dedent() testname = self.create_test(code=code) output = self.run_tests("-w", testname, exitcode=0) @@ -1112,39 +1111,39 @@ def test_fail_once(self): rerun=testname) def test_no_tests_ran(self): - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): def test_bug(self): pass - """) + """.dedent() testname = self.create_test(code=code) output = self.run_tests(testname, "-m", "nosuchtest", exitcode=0) self.check_executed_tests(output, [testname], no_test_ran=testname) def test_no_tests_ran_skip(self): - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): def test_skipped(self): self.skipTest("because") - """) + """.dedent() testname = self.create_test(code=code) output = self.run_tests(testname, exitcode=0) self.check_executed_tests(output, [testname]) def test_no_tests_ran_multiple_tests_nonexistent(self): - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): def test_bug(self): pass - """) + """.dedent() testname = self.create_test(code=code) testname2 = self.create_test(code=code) @@ -1153,21 +1152,21 @@ def test_bug(self): no_test_ran=[testname, testname2]) def test_no_test_ran_some_test_exist_some_not(self): - code = textwrap.dedent(""" + code = """ import unittest class Tests(unittest.TestCase): def test_bug(self): pass - """) + """.dedent() testname = self.create_test(code=code) - other_code = textwrap.dedent(""" + other_code = """ import unittest class Tests(unittest.TestCase): def test_other_bug(self): pass - """) + """.dedent() testname2 = self.create_test(code=other_code) output = self.run_tests(testname, testname2, "-m", "nosuchtest", @@ -1177,7 +1176,7 @@ def test_other_bug(self): @support.cpython_only def test_findleaks(self): - code = textwrap.dedent(r""" + code = r""" import _testcapi import gc import unittest @@ -1193,7 +1192,7 @@ def test_garbage(self): obj = Garbage() obj.ref_cycle = obj obj = None - """) + """.dedent() testname = self.create_test(code=code) output = self.run_tests("--fail-env-changed", testname, exitcode=3) @@ -1208,7 +1207,7 @@ def test_garbage(self): fail_env_changed=True) def test_multiprocessing_timeout(self): - code = textwrap.dedent(r""" + code = r""" import time import unittest try: @@ -1225,7 +1224,7 @@ def test_sleep(self): faulthandler.cancel_dump_traceback_later() time.sleep(60 * 5) - """) + """.dedent() testname = self.create_test(code=code) output = self.run_tests("-j2", "--timeout=1.0", testname, exitcode=2) @@ -1236,7 +1235,7 @@ def test_sleep(self): def test_unraisable_exc(self): # --fail-env-changed must catch unraisable exception - code = textwrap.dedent(r""" + code = r""" import unittest import weakref @@ -1253,7 +1252,7 @@ def test_unraisable_exc(self): # call weakref_callback() which logs # an unraisable exception obj = None - """) + """.dedent() testname = self.create_test(code=code) output = self.run_tests("--fail-env-changed", "-v", testname, exitcode=3) diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 71f192f90d9a1d..dc3666840166b3 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -4,7 +4,6 @@ import os import unittest import subprocess -from textwrap import dedent from test.support import cpython_only, SuppressCrashReport from test.support.script_helper import kill_python @@ -48,7 +47,7 @@ def test_no_memory(self): _testcapi.set_nomemory(0) sys.exit(0) """ - user_input = dedent(user_input) + user_input = user_input.dedent() user_input = user_input.encode() p = spawn_repl() with SuppressCrashReport(): @@ -85,7 +84,7 @@ def test_multiline_string_parsing(self): """ ''' - user_input = dedent(user_input) + user_input = user_input.dedent() user_input = user_input.encode() p = spawn_repl() with SuppressCrashReport(): diff --git a/Lib/test/test_smtpd.py b/Lib/test/test_smtpd.py index 3be7739743940e..b8da12be7152ae 100644 --- a/Lib/test/test_smtpd.py +++ b/Lib/test/test_smtpd.py @@ -1,5 +1,4 @@ import unittest -import textwrap from test import support, mock_socket from test.support import socket_helper import socket @@ -95,14 +94,14 @@ def test_process_message_with_decode_data_true(self): with support.captured_stdout() as s: self.send_data(channel, b'From: test\n\nhello\n') stdout = s.getvalue() - self.assertEqual(stdout, textwrap.dedent("""\ + self.assertEqual(stdout, """\ ---------- MESSAGE FOLLOWS ---------- From: test X-Peer: peer-address hello ------------ END MESSAGE ------------ - """)) + """.dedent()) def test_process_message_with_decode_data_false(self): server = smtpd.DebuggingServer((socket_helper.HOST, 0), ('b', 0)) @@ -111,14 +110,14 @@ def test_process_message_with_decode_data_false(self): with support.captured_stdout() as s: self.send_data(channel, b'From: test\n\nh\xc3\xa9llo\xff\n') stdout = s.getvalue() - self.assertEqual(stdout, textwrap.dedent("""\ + self.assertEqual(stdout, """\ ---------- MESSAGE FOLLOWS ---------- b'From: test' b'X-Peer: peer-address' b'' b'h\\xc3\\xa9llo\\xff' ------------ END MESSAGE ------------ - """)) + """.dedent()) def test_process_message_with_enable_SMTPUTF8_true(self): server = smtpd.DebuggingServer((socket_helper.HOST, 0), ('b', 0), @@ -128,14 +127,14 @@ def test_process_message_with_enable_SMTPUTF8_true(self): with support.captured_stdout() as s: self.send_data(channel, b'From: test\n\nh\xc3\xa9llo\xff\n') stdout = s.getvalue() - self.assertEqual(stdout, textwrap.dedent("""\ + self.assertEqual(stdout, """\ ---------- MESSAGE FOLLOWS ---------- b'From: test' b'X-Peer: peer-address' b'' b'h\\xc3\\xa9llo\\xff' ------------ END MESSAGE ------------ - """)) + """.dedent()) def test_process_SMTPUTF8_message_with_enable_SMTPUTF8_true(self): server = smtpd.DebuggingServer((socket_helper.HOST, 0), ('b', 0), @@ -146,7 +145,7 @@ def test_process_SMTPUTF8_message_with_enable_SMTPUTF8_true(self): self.send_data(channel, b'From: test\n\nh\xc3\xa9llo\xff\n', enable_SMTPUTF8=True) stdout = s.getvalue() - self.assertEqual(stdout, textwrap.dedent("""\ + self.assertEqual(stdout, """\ ---------- MESSAGE FOLLOWS ---------- mail options: ['BODY=8BITMIME', 'SMTPUTF8'] b'From: test' @@ -154,7 +153,7 @@ def test_process_SMTPUTF8_message_with_enable_SMTPUTF8_true(self): b'' b'h\\xc3\\xa9llo\\xff' ------------ END MESSAGE ------------ - """)) + """.dedent()) def tearDown(self): asyncore.close_all() diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index d1ffb368a4f6f6..3436c93402fe27 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -15,7 +15,6 @@ import time import select import errno -import textwrap import threading import unittest @@ -1350,7 +1349,7 @@ def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): msg.set_content("oh là là, know what I mean, know what I mean?\n\n") # XXX smtpd converts received /r/n to /n, so we can't easily test that # we are successfully sending /r/n :(. - expected = textwrap.dedent("""\ + expected = """\ From: Páolo To: Dinsdale Subject: Nudge nudge, wink, wink \u1F609 @@ -1359,7 +1358,7 @@ def test_send_message_uses_smtputf8_if_addrs_non_ascii(self): MIME-Version: 1.0 oh là là, know what I mean, know what I mean? - """) + """.dedent() smtp = smtplib.SMTP( HOST, self.port, local_hostname='localhost', timeout=support.LOOPBACK_TIMEOUT) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index aced87694cf7b6..d298648e873de6 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -18,7 +18,6 @@ import shutil import threading import gc -import textwrap import json from test.support import FakePath @@ -947,12 +946,12 @@ def test_universal_newlines_communicate(self): def test_universal_newlines_communicate_stdin(self): # universal newlines through communicate(), with only stdin p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' + SETBINARY + textwrap.dedent(''' + 'import sys,os;' + SETBINARY + ''' s = sys.stdin.readline() assert s == "line1\\n", repr(s) s = sys.stdin.read() assert s == "line3\\n", repr(s) - ''')], + '''.dedent()], stdin=subprocess.PIPE, universal_newlines=1) (stdout, stderr) = p.communicate("line1\nline3\n") @@ -973,7 +972,7 @@ def test_universal_newlines_communicate_input_none(self): def test_universal_newlines_communicate_stdin_stdout_stderr(self): # universal newlines through communicate(), with stdin, stdout, stderr p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' + SETBINARY + textwrap.dedent(''' + 'import sys,os;' + SETBINARY + ''' s = sys.stdin.buffer.readline() sys.stdout.buffer.write(s) sys.stdout.buffer.write(b"line2\\r") @@ -984,7 +983,7 @@ def test_universal_newlines_communicate_stdin_stdout_stderr(self): sys.stdout.buffer.write(b"line5\\r\\n") sys.stderr.buffer.write(b"eline6\\r") sys.stderr.buffer.write(b"eline7\\r\\nz") - ''')], + '''.dedent()], stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, @@ -1197,7 +1196,7 @@ def test_nonexisting_with_pipes(self): except (AttributeError, ImportError): self.skipTest("need msvcrt.CrtSetReportMode") - code = textwrap.dedent(f""" + code = f""" import msvcrt import subprocess @@ -1215,7 +1214,7 @@ def test_nonexisting_with_pipes(self): stderr=subprocess.PIPE) except OSError: pass - """) + """.dedent() cmd = [sys.executable, "-c", code] proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, @@ -2455,13 +2454,13 @@ def _check_swap_std_fds_with_one_closed(self, from_fds, to_fds): for from_fd, to_fd in zip(from_fds, to_fds): kwargs[arg_names[to_fd]] = from_fd - code = textwrap.dedent(r''' + code = r''' import os, sys skipped_fd = int(sys.argv[1]) for fd in range(3): if fd != skipped_fd: os.write(fd, str(fd).encode('ascii')) - ''') + '''.dedent() skipped_fd = (set(range(3)) - set(to_fds)).pop() @@ -2473,11 +2472,11 @@ def _check_swap_std_fds_with_one_closed(self, from_fds, to_fds): os.lseek(from_fd, 0, os.SEEK_SET) read_bytes = os.read(from_fd, 1024) read_fds = list(map(int, read_bytes.decode('ascii'))) - msg = textwrap.dedent(f""" + msg = f""" When testing {from_fds} to {to_fds} redirection, parent descriptor {from_fd} got redirected to descriptor(s) {read_fds} instead of descriptor {to_fd}. - """) + """.dedent() self.assertEqual([to_fd], read_fds, msg) finally: self._restore_fds(saved_fds) @@ -2694,8 +2693,7 @@ def test_close_fds_when_max_fd_is_lowered(self): # +--> The TEST: This one launches a fd_status.py # subprocess with close_fds=True so we can find out if # any of the fds above the lowered rlimit are still open. - p = subprocess.Popen([sys.executable, '-c', textwrap.dedent( - ''' + p = subprocess.Popen([sys.executable, '-c', (''' import os, resource, subprocess, sys, textwrap open_fds = set() # Add a bunch more fds to pass down. @@ -2742,7 +2740,7 @@ def test_close_fds_when_max_fd_is_lowered(self): close_fds=False).wait() finally: resource.setrlimit(resource.RLIMIT_NOFILE, (rlim_cur, rlim_max)) - ''' % fd_status)], stdout=subprocess.PIPE) + ''' % fd_status).dedent()], stdout=subprocess.PIPE) output, unused_stderr = p.communicate() output_lines = output.splitlines() diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 606e57003ed711..75d12004647a5e 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -9,7 +9,6 @@ import subprocess import sys import tempfile -import textwrap import time import unittest from test import support @@ -171,7 +170,7 @@ def test_temp_dir__forked_child(self): """Test that a forked child process does not remove the directory.""" # See bpo-30028 for details. # Run the test as an external script, because it uses fork. - script_helper.assert_python_ok("-c", textwrap.dedent(""" + script_helper.assert_python_ok("-c", """ import os from test import support with support.temp_cwd() as temp_path: @@ -188,7 +187,7 @@ def test_temp_dir__forked_child(self): # directory. if not os.path.isdir(temp_path): raise AssertionError("Child removed temp_path.") - """)) + """.dedent()) # Tests for change_cwd() diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 91a645b460ec02..40ee8914585cc8 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -11,7 +11,6 @@ import sys import sysconfig import test.support -import textwrap import unittest import warnings @@ -274,7 +273,7 @@ def set_recursion_limit_at_depth(depth, limit): def test_recursionlimit_fatalerror(self): # A fatal error occurs if a second recursion limit is hit when recovering # from a first one. - code = textwrap.dedent(""" + code = """ import sys def f(): @@ -284,7 +283,7 @@ def f(): f() sys.setrecursionlimit(%d) - f()""") + f()""".dedent() with test.support.SuppressCrashReport(): for i in (50, 1000): sub = subprocess.Popen([sys.executable, '-c', code % i], diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index 95840d6ac0c5f4..3354b986e7b9cb 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -10,7 +10,6 @@ import tabnanny import tokenize import tempfile -import textwrap from test.support import (captured_stderr, captured_stdout, script_helper, findfile, unlink) @@ -332,15 +331,11 @@ def test_quiet_flag(self): def test_verbose_mode(self): """Should display more error information if verbose mode is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: - stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" - ).strip() + stdout = "offending line: '\\tprint(\"world\")\\n'".dedent().strip() self.validate_cmd("-v", path, stdout=stdout, partial=True) def test_double_verbose_mode(self): """Should display detailed error information if double verbose is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: - stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" - ).strip() + stdout = "offending line: '\\tprint(\"world\")\\n'".dedent().strip() self.validate_cmd("-vv", path, stdout=stdout, partial=True) diff --git a/Lib/test/test_textwrap.py b/Lib/test/test_textwrap.py index ed97f70ba1fa40..6e0f25e02095c6 100644 --- a/Lib/test/test_textwrap.py +++ b/Lib/test/test_textwrap.py @@ -9,6 +9,7 @@ # import unittest +import warnings from textwrap import TextWrapper, wrap, fill, dedent, indent, shorten @@ -693,6 +694,20 @@ def test_subsequent_indent(self): # of IndentTestCase! class DedentTestCase(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls._warning_catcher = warnings.catch_warnings() + cls._warning_catcher.__enter__() + warnings.filterwarnings( + "ignore", + # "textwrap.dedent is pending deprecation", + category=PendingDeprecationWarning + ) + + @classmethod + def tearDownClass(cls): + cls._warning_catcher.__exit__() + def assertUnchanged(self, text): """assert that dedent() has no effect on 'text'""" self.assertEqual(text, dedent(text)) @@ -833,6 +848,20 @@ class IndentTestCase(unittest.TestCase): "\nHi.\r\nThis is a test.\n\r\nTesting.\r\n\n", ) + @classmethod + def setUpClass(cls): + cls._warning_catcher = warnings.catch_warnings() + cls._warning_catcher.__enter__() + warnings.filterwarnings( + "ignore", + # "textwrap.dedent is pending deprecation", + category=PendingDeprecationWarning + ) + + @classmethod + def tearDownClass(cls): + cls._warning_catcher.__exit__() + def test_indent_nomargin_default(self): # indent should do nothing if 'prefix' is empty. for text in self.CASES: diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 81e5f70d6d6aea..2e91af6ad3077e 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -16,7 +16,6 @@ import os import subprocess import signal -import textwrap from test import lock_tests from test import support @@ -961,7 +960,7 @@ def test_threads_join(self): # Non-daemon threads should be joined at subinterpreter shutdown # (issue #18808) r, w = self.pipe() - code = textwrap.dedent(r""" + code = (r""" import os import random import threading @@ -979,7 +978,7 @@ def f(): threading.Thread(target=f).start() random_sleep() - """ % (w,)) + """ % (w,)).dedent() ret = test.support.run_in_subinterp(code) self.assertEqual(ret, 0) # The thread was joined properly. @@ -991,7 +990,7 @@ def test_threads_join_2(self): # To achieve this, we register a thread-local object which sleeps # a bit when deallocated. r, w = self.pipe() - code = textwrap.dedent(r""" + code = (r""" import os import random import threading @@ -1016,7 +1015,7 @@ def f(): threading.Thread(target=f).start() random_sleep() - """ % (w,)) + """ % (w,)).dedent() ret = test.support.run_in_subinterp(code) self.assertEqual(ret, 0) # The thread was joined properly. diff --git a/Lib/test/test_timeit.py b/Lib/test/test_timeit.py index e02d4a71a9ba7c..71b5add25f8fa9 100644 --- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -2,8 +2,6 @@ import unittest import sys import io -from textwrap import dedent - from test.support import captured_stdout from test.support import captured_stderr @@ -244,10 +242,10 @@ def run_main(self, seconds_per_increment=1.0, switches=None, timer=None): def test_main_bad_switch(self): s = self.run_main(switches=['--bad-switch']) - self.assertEqual(s, dedent("""\ + self.assertEqual(s, """\ option --bad-switch not recognized use -h/--help for command line help - """)) + """.dedent()) def test_main_seconds(self): s = self.run_main(seconds_per_increment=5.5) @@ -294,17 +292,17 @@ def test_main_help(self): def test_main_verbose(self): s = self.run_main(switches=['-v']) - self.assertEqual(s, dedent("""\ + self.assertEqual(s, """\ 1 loop -> 1 secs raw times: 1 sec, 1 sec, 1 sec, 1 sec, 1 sec 1 loop, best of 5: 1 sec per loop - """)) + """.dedent()) def test_main_very_verbose(self): s = self.run_main(seconds_per_increment=0.000_030, switches=['-vv']) - self.assertEqual(s, dedent("""\ + self.assertEqual(s, """\ 1 loop -> 3e-05 secs 2 loops -> 6e-05 secs 5 loops -> 0.00015 secs @@ -322,7 +320,7 @@ def test_main_very_verbose(self): raw times: 300 msec, 300 msec, 300 msec, 300 msec, 300 msec 10000 loops, best of 5: 30 usec per loop - """)) + """.dedent()) def test_main_with_time_unit(self): unit_sec = self.run_main(seconds_per_increment=0.003, diff --git a/Lib/test/test_tools/test_c_analyzer/test_cpython/test_supported.py b/Lib/test/test_tools/test_c_analyzer/test_cpython/test_supported.py index a244b97e1fc7c7..b67814512c8b55 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_cpython/test_supported.py +++ b/Lib/test/test_tools/test_c_analyzer/test_cpython/test_supported.py @@ -1,5 +1,4 @@ import re -import textwrap import unittest from .. import tool_imports_for_tests @@ -57,14 +56,14 @@ def _read_tsv(self, *args): return self._return_read_tsv def test_typical(self): - lines = textwrap.dedent(''' + lines = ''' filename funcname name kind reason file1.c - var1 variable ... file1.c func1 local1 variable | file1.c - var2 variable ??? file1.c func2 local2 variable | file2.c - var1 variable reasons - ''').strip().splitlines() + '''.dedent().strip().splitlines() lines = [re.sub(r'\s{1,8}', '\t', line, 4).replace('|', '') for line in lines] self._return_read_tsv = [tuple(v.strip() for v in line.split('\t')) diff --git a/Lib/test/test_tools/test_c_analyzer/test_parser/test_declarations.py b/Lib/test/test_tools/test_c_analyzer/test_parser/test_declarations.py index 674fcb1af1c7ad..9716fff192b509 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_parser/test_declarations.py +++ b/Lib/test/test_tools/test_c_analyzer/test_parser/test_declarations.py @@ -1,4 +1,3 @@ -import textwrap import unittest from .. import tool_imports_for_tests @@ -27,18 +26,18 @@ class IterGlobalDeclarationsTests(TestCaseBase): def test_functions(self): tests = [ - (textwrap.dedent(''' + (''' void func1() { return; } - '''), - textwrap.dedent(''' + '''.dedent(), + ''' void func1() { return; } - ''').strip(), + '''.dedent().strip(), ), - (textwrap.dedent(''' + (''' static unsigned int * _func1( const char *arg1, int *arg2 @@ -47,14 +46,14 @@ def test_functions(self): { return _do_something(arg1, arg2, arg3); } - '''), - textwrap.dedent(''' + '''.dedent(), + ''' static unsigned int * _func1( const char *arg1, int *arg2 long long arg3 ) { return _do_something(arg1, arg2, arg3); } - ''').strip(), + '''.dedent().strip(), ), - (textwrap.dedent(''' + (''' static PyObject * _func1(const char *arg1, PyObject *arg2) { @@ -68,8 +67,8 @@ def test_functions(self): Py_INCREF(result); return result; } - '''), - textwrap.dedent(''' + '''.dedent(), + ''' static PyObject * _func1(const char *arg1, PyObject *arg2) { static int initialized = 0; if (!initialized) { @@ -80,13 +79,11 @@ def test_functions(self): Py_INCREF(result); return result; } - ''').strip(), + '''.dedent().strip(), ), ] for lines, expected in tests: - body = textwrap.dedent( - expected.partition('{')[2].rpartition('}')[0] - ).strip() + body = expected.partition('{')[2].rpartition('}')[0].dedent().strip() expected = (expected, body) with self.subTest(lines): lines = lines.splitlines() @@ -132,7 +129,7 @@ def test_declaration_multiple_vars(self): ]) def test_mixed(self): - lines = textwrap.dedent(''' + lines = ''' int spam; static const char const *eggs; @@ -151,9 +148,9 @@ def test_mixed(self): ham = reason; return _stop(); } - ''').splitlines() + '''.dedent().splitlines() expected = [ - (textwrap.dedent(''' + (''' PyObject * start(void) { static int initialized = 0; if (initialized) { @@ -162,26 +159,26 @@ def test_mixed(self): } return _start(); } - ''').strip(), - textwrap.dedent(''' + '''.dedent().strip(), + ''' static int initialized = 0; if (initialized) { initialized = 1; init(); } return _start(); - ''').strip(), + '''.dedent().strip(), ), - (textwrap.dedent(''' + (''' static int stop(char *reason) { ham = reason; return _stop(); } - ''').strip(), - textwrap.dedent(''' + '''.dedent().strip(), + ''' ham = reason; return _stop(); - ''').strip(), + '''.dedent().strip(), ), ] @@ -202,7 +199,7 @@ def test_no_statements(self): def test_bogus(self): tests = [ - (textwrap.dedent(''' + (''' int spam; static const char const *eggs; @@ -224,8 +221,8 @@ def test_bogus(self): ham = reason; return _stop(); } - '''), - [(textwrap.dedent(''' + '''.dedent(), + [(''' PyObject * start(void) { static int initialized = 0; if (initialized) { @@ -234,15 +231,15 @@ def test_bogus(self): } return _start(); } - ''').strip(), - textwrap.dedent(''' + '''.dedent().strip(), + ''' static int initialized = 0; if (initialized) { initialized = 1; init(); } return _start(); - ''').strip(), + '''.dedent().strip(), ), # Neither "stop()" nor "_stop()" are here. ], @@ -355,11 +352,11 @@ def test_vars(self): @unittest.expectedFailure def test_vars_multiline_var(self): - lines = textwrap.dedent(''' + lines = ''' PyObject * spam = NULL; - ''').splitlines() + '''.dedent().splitlines() expected = 'PyObject * spam = NULL;' stmts = list(iter_local_statements(lines)) @@ -607,9 +604,9 @@ def test_empty_file(self): ]) def test_no_statements(self): - content = textwrap.dedent(''' + content = ''' ... - ''') + '''.dedent() self._return_iter_source_lines = content self._return_iter_global = [ [], @@ -634,9 +631,9 @@ def test_no_statements(self): ]) def test_typical(self): - content = textwrap.dedent(''' + content = ''' ... - ''') + '''.dedent() self._return_iter_source_lines = content self._return_iter_global = [ [('', None), # var1 @@ -718,9 +715,9 @@ def test_typical(self): ]) def test_no_locals(self): - content = textwrap.dedent(''' + content = ''' ... - ''') + '''.dedent() self._return_iter_source_lines = content self._return_iter_global = [ [('', None), # var1 diff --git a/Lib/test/test_tools/test_c_analyzer/test_parser/test_preprocessor.py b/Lib/test/test_tools/test_c_analyzer/test_parser/test_preprocessor.py index 56a1c9c612f726..7f1f2d5e07e0c5 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_parser/test_preprocessor.py +++ b/Lib/test/test_tools/test_c_analyzer/test_parser/test_preprocessor.py @@ -1,5 +1,4 @@ import itertools -import textwrap import unittest import sys @@ -67,7 +66,7 @@ def test_no_lines(self): self.check_calls() def test_no_directives(self): - lines = textwrap.dedent(''' + lines = ''' // xyz typedef enum { @@ -101,7 +100,7 @@ def test_no_directives(self): return 0; } - ''')[1:-1].splitlines() + '''.dedent()[1:-1].splitlines() expected = [(lno, line, None, ()) for lno, line in enumerate(lines, 1)] expected[1] = (2, ' ', None, ()) @@ -141,11 +140,11 @@ def test_single_directives(self): self.parsed = [ directive, ] - text = textwrap.dedent(''' + text = ''' static int spam = 0; {} static char buffer[256]; - ''').strip().format(line) + '''.dedent().strip().format(line) lines = text.strip().splitlines() results = list( @@ -188,14 +187,14 @@ def test_split_lines(self): self.parsed = [ directive, ] - text = textwrap.dedent(r''' + text = r''' static int spam = 0; #define eggs(a, b) \ { \ a = b; \ } static char buffer[256]; - ''').strip() + '''.dedent().strip() lines = [line + '\n' for line in text.splitlines()] lines[-1] = lines[-1][:-1] @@ -221,7 +220,7 @@ def test_nested_conditions(self): OtherDirective('endif', None), ] self.parsed = list(directives) - text = textwrap.dedent(r''' + text = r''' static int spam = 0; #ifdef SPAM @@ -237,7 +236,7 @@ def test_nested_conditions(self): #endif static int eggs = 0; - ''').strip() + '''.dedent().strip() lines = [line for line in text.splitlines() if line.strip()] results = list( @@ -274,7 +273,7 @@ def test_split_blocks(self): OtherDirective('endif', None), ] self.parsed = list(directives) - text = textwrap.dedent(r''' + text = r''' void str_copy(char *buffer, *orig); int init(char *name) { @@ -302,7 +301,7 @@ def test_split_blocks(self): } #endif - ''').strip() + '''.dedent().strip() lines = [line for line in text.splitlines() if line.strip()] results = list( @@ -362,7 +361,7 @@ def test_basic(self): OtherDirective('endif', None), ] self.parsed = list(directives) - text = textwrap.dedent(r''' + text = r''' #include print("begin"); #ifdef SPAM @@ -386,7 +385,7 @@ def test_basic(self): print("no ham"); #endif print("end"); - ''')[1:-1] + '''.dedent()[1:-1] lines = [line + '\n' for line in text.splitlines()] lines[-1] = lines[-1][:-1] @@ -513,7 +512,7 @@ def test_typical(self): OtherDirective('endif', None), # ifndef Py_COMPILE_H ] self.parsed = list(directives) - text = textwrap.dedent(r''' + text = r''' #ifndef Py_COMPILE_H #define Py_COMPILE_H @@ -611,7 +610,7 @@ def test_typical(self): #define Py_func_type_input 345 #endif /* !Py_COMPILE_H */ - ''').strip() + '''.dedent().strip() lines = [line + '\n' for line in text.splitlines()] lines[-1] = lines[-1][:-1] diff --git a/Lib/test/test_tools/test_c_analyzer/test_variables/test_known.py b/Lib/test/test_tools/test_c_analyzer/test_variables/test_known.py index 49ff45c6d1b2cf..dbce6742439bd7 100644 --- a/Lib/test/test_tools/test_c_analyzer/test_variables/test_known.py +++ b/Lib/test/test_tools/test_c_analyzer/test_variables/test_known.py @@ -1,5 +1,4 @@ import re -import textwrap import unittest from .. import tool_imports_for_tests @@ -33,14 +32,14 @@ def _read_tsv(self, *args): return self._return_read_tsv def test_typical(self): - lines = textwrap.dedent(''' + lines = ''' filename funcname name kind declaration file1.c - var1 variable static int file1.c func1 local1 variable static int file1.c - var2 variable int file1.c func2 local2 variable char * file2.c - var1 variable char * - ''').strip().splitlines() + '''.dedent().strip().splitlines() lines = [re.sub(r'\s+', '\t', line, 4) for line in lines] self._return_read_tsv = [tuple(v.strip() for v in line.split('\t')) for line in lines[1:]] diff --git a/Lib/test/test_tools/test_i18n.py b/Lib/test/test_tools/test_i18n.py index 42e20f8f7716db..88669918184c7c 100644 --- a/Lib/test/test_tools/test_i18n.py +++ b/Lib/test/test_tools/test_i18n.py @@ -3,7 +3,6 @@ import os import sys import unittest -from textwrap import dedent from test.support.script_helper import assert_python_ok from test.test_tools import skip_if_missing, toolsdir @@ -112,47 +111,47 @@ def test_POT_Creation_Date(self): def test_funcdocstring(self): for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'): with self.subTest(doc): - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str(('''\ def foo(bar): %s - ''' % doc)) + ''' % doc).dedent()) self.assertIn('doc', msgids) def test_funcdocstring_bytes(self): - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ def foo(bar): b"""doc""" - ''')) + '''.dedent()) self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) def test_funcdocstring_fstring(self): - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ def foo(bar): f"""doc""" - ''')) + '''.dedent()) self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) def test_classdocstring(self): for doc in ('"""doc"""', "r'''doc'''", "R'doc'", 'u"doc"'): with self.subTest(doc): - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str(('''\ class C: %s - ''' % doc)) + ''' % doc).dedent()) self.assertIn('doc', msgids) def test_classdocstring_bytes(self): - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ class C: b"""doc""" - ''')) + '''.dedent()) self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) def test_classdocstring_fstring(self): - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ class C: f"""doc""" - ''')) + '''.dedent()) self.assertFalse([msgid for msgid in msgids if 'doc' in msgid]) def test_msgid(self): @@ -170,33 +169,33 @@ def test_msgid_fstring(self): def test_funcdocstring_annotated_args(self): """ Test docstrings for functions with annotated args """ - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ def foo(bar: str): """doc""" - ''')) + '''.dedent()) self.assertIn('doc', msgids) def test_funcdocstring_annotated_return(self): """ Test docstrings for functions with annotated return type """ - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ def foo(bar) -> str: """doc""" - ''')) + '''.dedent()) self.assertIn('doc', msgids) def test_funcdocstring_defvalue_args(self): """ Test docstring for functions with default arg values """ - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ def foo(bar=()): """doc""" - ''')) + '''.dedent()) self.assertIn('doc', msgids) def test_funcdocstring_multiple_funcs(self): """ Test docstring extraction for multiple functions combining annotated args, annotated return types and default arg values """ - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ def foo1(bar: tuple=()) -> str: """doc1""" @@ -205,7 +204,7 @@ def foo2(bar: List[1:2]) -> (lambda x: x): def foo3(bar: 'func'=lambda x: x) -> {1: 2}: """doc3""" - ''')) + '''.dedent()) self.assertIn('doc1', msgids) self.assertIn('doc2', msgids) self.assertIn('doc3', msgids) @@ -214,10 +213,10 @@ def test_classdocstring_early_colon(self): """ Test docstring extraction for a class with colons occurring within the parentheses. """ - msgids = self.extract_docstrings_from_str(dedent('''\ + msgids = self.extract_docstrings_from_str('''\ class D(L[1:2], F({1: 2}), metaclass=M(lambda x: x)): """doc""" - ''')) + '''.dedent()) self.assertIn('doc', msgids) def test_files_list(self): diff --git a/Lib/test/test_tools/test_pindent.py b/Lib/test/test_tools/test_pindent.py index e293bc872ce51e..fb6735fca04e6a 100644 --- a/Lib/test/test_tools/test_pindent.py +++ b/Lib/test/test_tools/test_pindent.py @@ -4,7 +4,6 @@ import sys import unittest import subprocess -import textwrap from test import support from test.support.script_helper import assert_python_ok @@ -82,7 +81,7 @@ def pindent_test(self, clean, closed): self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '4'), closed) def test_statements(self): - clean = textwrap.dedent("""\ + clean = """\ if a: pass @@ -145,9 +144,9 @@ class A: def f(): pass - """) + """.dedent() - closed = textwrap.dedent("""\ + closed = """\ if a: pass # end if @@ -223,11 +222,11 @@ class A: def f(): pass # end def f - """) + """.dedent() self.pindent_test(clean, closed) def test_multilevel(self): - clean = textwrap.dedent("""\ + clean = """\ def foobar(a, b): if a == b: a = a+1 @@ -236,8 +235,8 @@ def foobar(a, b): if b > a: a = a-1 else: print 'oops!' - """) - closed = textwrap.dedent("""\ + """.dedent() + closed = """\ def foobar(a, b): if a == b: a = a+1 @@ -249,45 +248,45 @@ def foobar(a, b): print 'oops!' # end if # end def foobar - """) + """.dedent() self.pindent_test(clean, closed) def test_preserve_indents(self): - clean = textwrap.dedent("""\ + clean = """\ if a: if b: pass - """) - closed = textwrap.dedent("""\ + """.dedent() + closed = """\ if a: if b: pass # end if # end if - """) + """.dedent() self.assertEqual(self.pindent(clean, '-c'), closed) self.assertEqual(self.pindent(closed, '-d'), clean) broken = self.lstriplines(closed) self.assertEqual(self.pindent(broken, '-r', '-e', '-s', '9'), closed) - clean = textwrap.dedent("""\ + clean = """\ if a: \tif b: \t\tpass - """) - closed = textwrap.dedent("""\ + """.dedent() + closed = """\ if a: \tif b: \t\tpass \t# end if # end if - """) + """.dedent() self.assertEqual(self.pindent(clean, '-c'), closed) self.assertEqual(self.pindent(closed, '-d'), clean) broken = self.lstriplines(closed) self.assertEqual(self.pindent(broken, '-r'), closed) def test_escaped_newline(self): - clean = textwrap.dedent("""\ + clean = """\ class\\ \\ A: @@ -295,8 +294,8 @@ def test_escaped_newline(self): \\ f: pass - """) - closed = textwrap.dedent("""\ + """.dedent() + closed = """\ class\\ \\ A: @@ -306,32 +305,32 @@ def test_escaped_newline(self): pass # end def f # end class A - """) + """.dedent() self.assertEqual(self.pindent(clean, '-c'), closed) self.assertEqual(self.pindent(closed, '-d'), clean) def test_empty_line(self): - clean = textwrap.dedent("""\ + clean = """\ if a: pass - """) - closed = textwrap.dedent("""\ + """.dedent() + closed = """\ if a: pass # end if - """) + """.dedent() self.pindent_test(clean, closed) def test_oneline(self): - clean = textwrap.dedent("""\ + clean = """\ if a: pass - """) - closed = textwrap.dedent("""\ + """.dedent() + closed = """\ if a: pass # end if - """) + """.dedent() self.pindent_test(clean, closed) diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index 7cda546b8b9853..dbf3a3e8d52841 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -2,7 +2,6 @@ import sys from test.support import TESTFN, rmtree, unlink, captured_stdout from test.support.script_helper import assert_python_ok, assert_python_failure -import textwrap import unittest import trace @@ -429,11 +428,11 @@ class TestCoverageCommandLineOutput(unittest.TestCase): def setUp(self): with open(self.codefile, 'w') as f: - f.write(textwrap.dedent('''\ + f.write('''\ x = 42 if []: print('unreachable') - ''')) + '''.dedent()) def tearDown(self): unlink(self.codefile) @@ -463,11 +462,11 @@ def test_cover_files_written_with_highlight(self): status, stdout, stderr = assert_python_ok(*argv) self.assertTrue(os.path.exists(self.coverfile)) with open(self.coverfile) as f: - self.assertEqual(f.read(), textwrap.dedent('''\ + self.assertEqual(f.read(), '''\ 1: x = 42 1: if []: >>>>>> print('unreachable') - ''')) + '''.dedent()) class TestCommandLine(unittest.TestCase): @@ -507,7 +506,7 @@ def test_count_and_summary(self): with open(filename, 'w') as fd: self.addCleanup(unlink, filename) self.addCleanup(unlink, coverfilename) - fd.write(textwrap.dedent("""\ + fd.write("""\ x = 1 y = 2 @@ -516,7 +515,7 @@ def f(): for i in range(10): f() - """)) + """.dedent()) status, stdout, _ = assert_python_ok('-m', 'trace', '-cs', filename) stdout = stdout.decode() self.assertEqual(status, 0) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7361d091cfbbef..fdc785cc54b3f1 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -9,7 +9,6 @@ from test import support from test.support import TESTFN, Error, captured_output, unlink, cpython_only, ALWAYS_EQ from test.support.script_helper import assert_python_ok -import textwrap import traceback @@ -177,7 +176,7 @@ def do_test(firstlines, message, charset, lineno): def test_print_traceback_at_exit(self): # Issue #22599: Ensure that it is possible to use the traceback module # to display an exception at Python exit - code = textwrap.dedent(""" + code = """ import sys import traceback @@ -198,7 +197,7 @@ def __del__(self): # Keep a reference in the module namespace to call the destructor # when the module is unloaded obj = PrintExceptionAtExit() - """) + """.dedent() rc, stdout, stderr = assert_python_ok('-c', code) expected = [b'Traceback (most recent call last):', b' File "", line 8, in __init__', diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 28398896467898..95e2e749c36b34 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -11,7 +11,6 @@ import operator import struct import sys -import textwrap import unicodedata import unittest import warnings @@ -2449,12 +2448,130 @@ def test_free_after_iterating(self): support.check_free_after_iterating(self, iter, str) support.check_free_after_iterating(self, reversed, str) + def dedent_and_assert_unchanged(self, text): + """assert that dedent() has no effect on 'text'""" + self.assertEqual(text, text.dedent()) + + def test_dedent_nomargin(self): + # No lines indented. + text = "Hello there.\nHow are you?\nOh good, I'm glad." + self.dedent_and_assert_unchanged(text) + + # Similar, with a blank line. + text = "Hello there.\n\nBoo!" + self.dedent_and_assert_unchanged(text) + + # Some lines indented, but overall margin is still zero. + text = "Hello there.\n This is indented." + self.dedent_and_assert_unchanged(text) + + # Again, add a blank line. + text = "Hello there.\n\n Boo!\n" + self.dedent_and_assert_unchanged(text) + + def test_dedent_even(self): + # All lines indented by two spaces. + text = " Hello there.\n How are ya?\n Oh good." + expect = "Hello there.\nHow are ya?\nOh good." + self.assertEqual(expect, text.dedent()) + + # Same, with blank lines. + text = " Hello there.\n\n How are ya?\n Oh good.\n" + expect = "Hello there.\n\nHow are ya?\nOh good.\n" + self.assertEqual(expect, text.dedent()) + + # Now indent one of the blank lines. + text = " Hello there.\n \n How are ya?\n Oh good.\n" + expect = "Hello there.\n\nHow are ya?\nOh good.\n" + self.assertEqual(expect, text.dedent()) + + def test_dedent_uneven(self): + # Lines indented unevenly. + text = '''\ + def foo(): + while 1: + return foo + ''' + expect = '''\ +def foo(): + while 1: + return foo +''' + self.assertEqual(expect, text.dedent()) + + # Uneven indentation with a blank line. + text = " Foo\n Bar\n\n Baz\n" + expect = "Foo\n Bar\n\n Baz\n" + self.assertEqual(expect, text.dedent()) + + # Uneven indentation with a whitespace-only line. + text = " Foo\n Bar\n \n Baz\n" + expect = "Foo\n Bar\n\n Baz\n" + self.assertEqual(expect, text.dedent()) + + def test_dedent_declining(self): + # Uneven indentation with declining indent level. + text = " Foo\n Bar\n" # 5 spaces, then 4 + expect = " Foo\nBar\n" + self.assertEqual(expect, text.dedent()) + + # Declining indent level with blank line. + text = " Foo\n\n Bar\n" # 5 spaces, blank, then 4 + expect = " Foo\n\nBar\n" + self.assertEqual(expect, text.dedent()) + + # Declining indent level with whitespace only line. + text = " Foo\n \n Bar\n" # 5 spaces, then 4, then 4 + expect = " Foo\n\nBar\n" + self.assertEqual(expect, text.dedent()) + + # dedent() should not mangle internal tabs + def test_dedent_preserve_internal_tabs(self): + text = " hello\tthere\n how are\tyou?" + expect = "hello\tthere\nhow are\tyou?" + self.assertEqual(expect, text.dedent()) + + # make sure that it preserves tabs when it's not making any + # changes at all + self.assertEqual(expect, expect.dedent()) + + # dedent() should not mangle tabs in the margin (i.e. + # tabs and spaces both count as margin, but are *not* + # considered equivalent) + def test_dedent_preserve_margin_tabs(self): + text = " hello there\n\thow are you?" + self.dedent_and_assert_unchanged(text) + + # same effect even if we have 8 spaces + text = " hello there\n\thow are you?" + self.dedent_and_assert_unchanged(text) + + # dedent() only removes whitespace that can be uniformly removed! + text = "\thello there\n\thow are you?" + expect = "hello there\nhow are you?" + self.assertEqual(expect, text.dedent()) + + text = " \thello there\n \thow are you?" + self.assertEqual(expect, text.dedent()) + + text = " \t hello there\n \t how are you?" + self.assertEqual(expect, text.dedent()) + + text = " \thello there\n \t how are you?" + expect = "hello there\n how are you?" + self.assertEqual(expect, text.dedent()) + + # test margin is smaller than smallest indent + text = " \thello there\n \thow are you?\n \tI'm fine, thanks" + expect = " \thello there\n \thow are you?\n\tI'm fine, thanks" + self.assertEqual(expect, text.dedent()) + def test_check_encoding_errors(self): # bpo-37388: str(bytes) and str.decode() must check encoding and errors # arguments in dev mode encodings = ('ascii', 'utf8', 'latin1') invalid = 'Boom, Shaka Laka, Boom!' - code = textwrap.dedent(f''' + code = f''' import sys encodings = {encodings!r} @@ -2505,7 +2622,7 @@ def test_check_encoding_errors(self): sys.exit(24) sys.exit(10) - ''') + '''.dedent() proc = assert_python_failure('-X', 'dev', '-c', code) self.assertEqual(proc.rc, 10, proc) diff --git a/Lib/test/test_utf8_mode.py b/Lib/test/test_utf8_mode.py index bdb93457cfc405..2b252e062c376c 100644 --- a/Lib/test/test_utf8_mode.py +++ b/Lib/test/test_utf8_mode.py @@ -4,7 +4,6 @@ import locale import sys -import textwrap import unittest from test import support from test.support.script_helper import assert_python_ok, assert_python_failure @@ -97,11 +96,11 @@ def test_env_var(self): out.rstrip()) def test_filesystemencoding(self): - code = textwrap.dedent(''' + code = ''' import sys print("{}/{}".format(sys.getfilesystemencoding(), sys.getfilesystemencodeerrors())) - ''') + '''.dedent() if MS_WINDOWS: expected = 'utf-8/surrogatepass' @@ -120,12 +119,12 @@ def test_filesystemencoding(self): self.assertEqual(out, 'mbcs/replace') def test_stdio(self): - code = textwrap.dedent(''' + code = ''' import sys print(f"stdin: {sys.stdin.encoding}/{sys.stdin.errors}") print(f"stdout: {sys.stdout.encoding}/{sys.stdout.errors}") print(f"stderr: {sys.stderr.encoding}/{sys.stderr.errors}") - ''') + '''.dedent() out = self.get_output('-X', 'utf8', '-c', code, PYTHONIOENCODING='') @@ -150,12 +149,12 @@ def test_stdio(self): 'stderr: utf-8/backslashreplace']) def test_io(self): - code = textwrap.dedent(''' + code = ''' import sys filename = sys.argv[1] with open(filename) as fp: print(f"{fp.encoding}/{fp.errors}") - ''') + '''.dedent() filename = __file__ out = self.get_output('-c', code, filename, PYTHONUTF8='1') @@ -170,13 +169,13 @@ def _check_io_encoding(self, module, encoding=None, errors=None): args.append(f'encoding={encoding!r}') if errors: args.append(f'errors={errors!r}') - code = textwrap.dedent(''' + code = (''' import sys from %s import open filename = sys.argv[1] with open(filename, %s) as fp: print(f"{fp.encoding}/{fp.errors}") - ''') % (module, ', '.join(args)) + ''' % (module, ', '.join(args))).dedent() out = self.get_output('-c', code, filename, PYTHONUTF8='1') diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index b2794cd992a06a..44d43825a3519d 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py @@ -484,8 +484,8 @@ def do_test_with_pip(self, system_site_packages): # Ensure pip is available in the virtual environment envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe) # Ignore DeprecationWarning since pip code is not part of Python - out, err = check_output([envpy, '-W', 'ignore::DeprecationWarning', '-I', - '-m', 'pip', '--version']) + out, err = check_output([envpy, '-W', 'ignore::DeprecationWarning', + '-W', 'ignore::PendingDeprecationWarning', '-I', '-m', 'pip', '--version']) # We force everything to text, so unittest gives the detailed diff # if we get unexpected results err = err.decode("latin-1") # Force to text, prevent decoding errors @@ -501,7 +501,8 @@ def do_test_with_pip(self, system_site_packages): # installers works (at least in a virtual environment) with EnvironmentVarGuard() as envvars: out, err = check_output([envpy, - '-W', 'ignore::DeprecationWarning', '-I', + '-W', 'ignore::DeprecationWarning', + '-W', 'ignore::PendingDeprecationWarning','-I', '-m', 'ensurepip._uninstall']) # We force everything to text, so unittest gives the detailed diff # if we get unexpected results diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 268ecb03f4dc65..f851a6f7d0449d 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -4,7 +4,6 @@ from io import StringIO import re import sys -import textwrap import unittest from test import support from test.support.script_helper import assert_python_ok, assert_python_failure @@ -930,14 +929,14 @@ def test_tracemalloc(self): self.addCleanup(support.unlink, support.TESTFN) with open(support.TESTFN, 'w') as fp: - fp.write(textwrap.dedent(""" + fp.write(""" def func(): f = open(__file__) # Emit ResourceWarning f = None func() - """)) + """.dedent()) def run(*args): res = assert_python_ok(*args) @@ -951,16 +950,16 @@ def run(*args): # tracemalloc disabled filename = os.path.abspath(support.TESTFN) stderr = run('-Wd', support.TESTFN) - expected = textwrap.dedent(f''' + expected = f''' {filename}:5: ResourceWarning: unclosed file <...> f = None ResourceWarning: Enable tracemalloc to get the object allocation traceback - ''').strip() + '''.dedent().strip() self.assertEqual(stderr, expected) # tracemalloc enabled stderr = run('-Wd', '-X', 'tracemalloc=2', support.TESTFN) - expected = textwrap.dedent(f''' + expected = f''' {filename}:5: ResourceWarning: unclosed file <...> f = None Object allocated at (most recent call last): @@ -968,7 +967,7 @@ def run(*args): func() File "{filename}", lineno 3 f = open(__file__) - ''').strip() + '''.dedent().strip() self.assertEqual(stderr, expected) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index d01649d1c31b26..33eef1c5ece6e9 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -15,7 +15,6 @@ import os import pickle import sys -import textwrap import types import unittest import warnings @@ -725,7 +724,7 @@ def end_ns(self, prefix): builder = Builder() parser = ET.XMLParser(target=builder) - parser.feed(textwrap.dedent("""\ + parser.feed("""\ @@ -733,7 +732,7 @@ def end_ns(self, prefix): texttail - """)) + """.dedent()) self.assertEqual(builder, [ ('end-ns', 'a'), ('end-ns', 'p'), @@ -3895,7 +3894,7 @@ def test_simple_roundtrip(self): #'') def test_c14n_exclusion(self): - xml = textwrap.dedent("""\ + xml = """\ abtext @@ -3905,7 +3904,7 @@ def test_c14n_exclusion(self): dtext - """) + """.dedent() self.assertEqual( c14n_roundtrip(xml, strip_text=True), '' diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py index 88561017503ff8..f98bb7fc4f54c8 100644 --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -6,7 +6,6 @@ import os import os.path import sys -import textwrap import zipfile import zipimport import doctest @@ -183,14 +182,14 @@ def test_doctest_issue4197(self): del sys.modules["test_zipped_doctest"] def test_doctest_main_issue4197(self): - test_src = textwrap.dedent("""\ + test_src = """\ class Test: ">>> 'line 2'" pass import doctest doctest.testmod() - """) + """.dedent() pattern = 'File "%s", line 2, in %s' with test.support.temp_dir() as d: script_name = make_script(d, 'script', test_src) @@ -212,13 +211,13 @@ class Test: self.assertIn(expected.encode('utf-8'), out) def test_pdb_issue4201(self): - test_src = textwrap.dedent("""\ + test_src = """\ def f(): pass import pdb pdb.Pdb(nosigint=True).runcall(f) - """) + """.dedent() with test.support.temp_dir() as d: script_name = make_script(d, 'script', test_src) p = spawn_python(script_name) diff --git a/Lib/textwrap.py b/Lib/textwrap.py index 30e693c8de0354..0ea26ff8d8739d 100644 --- a/Lib/textwrap.py +++ b/Lib/textwrap.py @@ -6,6 +6,7 @@ # Written by Greg Ward import re +import warnings __all__ = ['TextWrapper', 'wrap', 'fill', 'dedent', 'indent', 'shorten'] @@ -411,19 +412,8 @@ def shorten(text, width, **kwargs): _whitespace_only_re = re.compile('^[ \t]+$', re.MULTILINE) _leading_whitespace_re = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE) -def dedent(text): - """Remove any common leading whitespace from every line in `text`. - - This can be used to make triple-quoted strings line up with the left - edge of the display, while still presenting them in the source code - in indented form. - - Note that tabs and spaces are both treated as whitespace, but they - are not equal: the lines " hello" and "\\thello" are - considered to have no common leading whitespace. - Entirely blank lines are normalized to a newline character. - """ +def _dedent(text): # Look for the longest leading string of spaces and tabs common to # all lines. margin = None @@ -462,6 +452,27 @@ def dedent(text): return text +def dedent(text): + """Remove any common leading whitespace from every line in `text`. + + This can be used to make triple-quoted strings line up with the left + edge of the display, while still presenting them in the source code + in indented form. + + Note that tabs and spaces are both treated as whitespace, but they + are not equal: the lines " hello" and "\\thello" are + considered to have no common leading whitespace. + + Entirely blank lines are normalized to a newline character. + """ + warnings.warn( + "textwrap.dedent is pending deprecation, use the str.dedent method instead", + PendingDeprecationWarning, + stacklevel=2 + ) + return _dedent(text) + + def indent(text, prefix, predicate=None): """Adds 'prefix' to the beginning of selected lines in 'text'. diff --git a/Lib/unittest/test/test_result.py b/Lib/unittest/test/test_result.py index 0ffb87b40256cf..0bb8f7029389b6 100644 --- a/Lib/unittest/test/test_result.py +++ b/Lib/unittest/test/test_result.py @@ -1,6 +1,5 @@ import io import sys -import textwrap from test import support @@ -615,16 +614,16 @@ def testBufferOutputAddErrorOrFailure(self): self.assertEqual(len(result_list), 1) test, message = result_list[0] - expectedOutMessage = textwrap.dedent(""" + expectedOutMessage = """ Stdout: foo - """) + """.dedent() expectedErrMessage = '' if include_error: - expectedErrMessage = textwrap.dedent(""" + expectedErrMessage = """ Stderr: bar - """) + """.dedent() expectedFullMessage = 'A traceback%s%s' % (expectedOutMessage, expectedErrMessage) diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-05-21-12-08-40.bpo-36906.5_cnlN.rst b/Misc/NEWS.d/next/Core and Builtins/2019-05-21-12-08-40.bpo-36906.5_cnlN.rst new file mode 100644 index 00000000000000..edeaf90823d0ac --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-05-21-12-08-40.bpo-36906.5_cnlN.rst @@ -0,0 +1,2 @@ +Add new method `str.dedent()` that is equivalent to ``textwrap.dedent`` but +cached at compile time. Patch contributed by Rémi Lapeyre. diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index cf81df4af67b2c..cf832511851a46 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -1303,4 +1303,21 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return unicode_sizeof_impl(self); } -/*[clinic end generated code: output=b91233f3722643be input=a9049054013a1b77]*/ + +PyDoc_STRVAR(unicode_dedent__doc__, +"dedent($self, /)\n" +"--\n" +"\n"); + +#define UNICODE_DEDENT_METHODDEF \ + {"dedent", (PyCFunction)unicode_dedent, METH_NOARGS, unicode_dedent__doc__}, + +static PyObject * +unicode_dedent_impl(PyObject *self); + +static PyObject * +unicode_dedent(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_dedent_impl(self); +} +/*[clinic end generated code: output=5b5f4334bbe82619 input=a9049054013a1b77]*/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index aba7407533c4ed..09b35795768f8f 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -230,6 +230,7 @@ static PyObject *unicode_empty = NULL; return unicode_empty; \ } while (0) + static inline void unicode_fill(enum PyUnicode_Kind kind, void *data, Py_UCS4 value, Py_ssize_t start, Py_ssize_t length) @@ -14121,6 +14122,31 @@ unicode_sizeof_impl(PyObject *self) return PyLong_FromSsize_t(size); } +/*[clinic input] +str.dedent as unicode_dedent + +[clinic start generated code]*/ + +static PyObject * +unicode_dedent_impl(PyObject *self) +/*[clinic end generated code: output=4d41f65b94304b63 input=032d062ea6d3d9f3]*/ +{ + _Py_IDENTIFIER(_dedent); + PyObject *textwrap = PyImport_ImportModule("textwrap"); + if (!textwrap) { + return NULL; + } + PyObject *dedent = _PyObject_GetAttrId(textwrap, &PyId__dedent); + if (!dedent) { + Py_DECREF(textwrap); + return NULL; + } + PyObject *result = PyObject_CallFunction(dedent, "O", self); + Py_DECREF(textwrap); + Py_DECREF(dedent); + return result; +} + static PyObject * unicode_getnewargs(PyObject *v, PyObject *Py_UNUSED(ignored)) { @@ -14180,6 +14206,7 @@ static PyMethodDef unicode_methods[] = { UNICODE___FORMAT___METHODDEF UNICODE_MAKETRANS_METHODDEF UNICODE_SIZEOF_METHODDEF + UNICODE_DEDENT_METHODDEF #if 0 /* These methods are just used for debugging the implementation. */ {"_decimal2ascii", (PyCFunction) unicode__decimal2ascii, METH_NOARGS}, diff --git a/Python/ast_opt.c b/Python/ast_opt.c index ff786d6f8d63ef..80ca7c7e4d736a 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -464,6 +464,39 @@ astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) return 1; } +static int +astfold_dedent(expr_ty node_, PyArena *arena, _PyASTOptimizeState *state) +{ + if (asdl_seq_LEN(node_->v.Call.args) != 0 || + asdl_seq_LEN(node_->v.Call.keywords) != 0 || + node_->v.Call.func->kind != Attribute_kind) { + return 1; + } + _Py_IDENTIFIER(dedent); + PyObject *dedent = PyUnicode_FromString("dedent"); + if (!dedent) { + return 0; + } + expr_ty attr = node_->v.Call.func; + if (attr->v.Attribute.value->kind != Constant_kind || + attr->v.Attribute.value->v.Constant.kind != NULL || + !PyUnicode_CheckExact(attr->v.Attribute.value->v.Constant.value) || + !PyObject_RichCompareBool(attr->v.Attribute.attr, dedent, Py_EQ)) { + + return 1; + } + + PyObject *value = attr->v.Attribute.value->v.Constant.value; + PyObject *newval = _PyObject_CallMethodId(value, &PyId_dedent, "", NULL); + if (!newval) { + Py_DECREF(dedent); + return 0; + } + + Py_DECREF(dedent); + return make_const(node_, newval, arena); +} + static int astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { @@ -531,6 +564,7 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) CALL(astfold_expr, expr_ty, node_->v.Call.func); CALL_SEQ(astfold_expr, expr_ty, node_->v.Call.args); CALL_SEQ(astfold_keyword, keyword_ty, node_->v.Call.keywords); + CALL(astfold_dedent, expr_ty, node_); break; case FormattedValue_kind: CALL(astfold_expr, expr_ty, node_->v.FormattedValue.value); diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 382e29a28ab48e..25ad8aac913bdf 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -526,8 +526,7 @@ def normalize_snippet(s, *, indent=0): * ensures that it does not end with a newline * dedents so the first nonwhite character on any line is at column "indent" """ - s = strip_leading_and_trailing_blank_lines(s) - s = textwrap.dedent(s) + s = strip_leading_and_trailing_blank_lines(s).dedent() if indent: s = textwrap.indent(s, ' ' * indent) return s diff --git a/Tools/peg_generator/pegen/testutil.py b/Tools/peg_generator/pegen/testutil.py index 5a91862be1273f..da076039a994a2 100644 --- a/Tools/peg_generator/pegen/testutil.py +++ b/Tools/peg_generator/pegen/testutil.py @@ -3,7 +3,6 @@ import os import pathlib import sys -import textwrap import tokenize from typing import Any, cast, Dict, IO, Type, Final @@ -44,7 +43,7 @@ def parse_string( ) -> Any: # Run the parser on a string. if dedent: - source = textwrap.dedent(source) + source = source.dedent() file = io.StringIO(source) return run_parser(file, parser_class, verbose=verbose) # type: ignore # typeshed issue #3515