Skip to content

bpo-41718: Reduce test.libregrtest imports #22089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 1 addition & 41 deletions Lib/test/libregrtest/save_env.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import asyncio
import builtins
import locale
import logging
Expand All @@ -7,15 +6,10 @@
import sys
import sysconfig
import threading
import urllib.request
import warnings
from test import support
from test.support import os_helper
from test.libregrtest.utils import print_warning
try:
import _multiprocessing, multiprocessing.process
except ImportError:
multiprocessing = None


# Unit tests are supposed to leave the execution environment unchanged
Expand Down Expand Up @@ -63,32 +57,12 @@ def __init__(self, testname, verbose=0, quiet=False, *, pgo=False):
'warnings.filters', 'asyncore.socket_map',
'logging._handlers', 'logging._handlerList', 'sys.gettrace',
'sys.warnoptions',
# multiprocessing.process._cleanup() may release ref
# to a thread, so check processes first.
'multiprocessing.process._dangling', 'threading._dangling',
'threading._dangling',
'sysconfig._CONFIG_VARS', 'sysconfig._INSTALL_SCHEMES',
'files', 'locale', 'warnings.showwarning',
'shutil_archive_formats', 'shutil_unpack_formats',
'asyncio.events._event_loop_policy',
'urllib.requests._url_tempfiles', 'urllib.requests._opener',
)

def get_urllib_requests__url_tempfiles(self):
return list(urllib.request._url_tempfiles)
def restore_urllib_requests__url_tempfiles(self, tempfiles):
for filename in tempfiles:
os_helper.unlink(filename)

def get_urllib_requests__opener(self):
return urllib.request._opener
def restore_urllib_requests__opener(self, opener):
urllib.request._opener = opener

def get_asyncio_events__event_loop_policy(self):
return support.maybe_get_event_loop_policy()
def restore_asyncio_events__event_loop_policy(self, policy):
asyncio.set_event_loop_policy(policy)

def get_sys_argv(self):
return id(sys.argv), sys.argv, sys.argv[:]
def restore_sys_argv(self, saved_argv):
Expand Down Expand Up @@ -206,20 +180,6 @@ def restore_threading__dangling(self, saved):
threading._dangling.clear()
threading._dangling.update(saved)

# Same for Process objects
def get_multiprocessing_process__dangling(self):
if not multiprocessing:
return None
# Unjoined process objects can survive after process exits
multiprocessing.process._cleanup()
# This copies the weakrefs without making any strong reference
return multiprocessing.process._dangling.copy()
def restore_multiprocessing_process__dangling(self, saved):
if not multiprocessing:
return
multiprocessing.process._dangling.clear()
multiprocessing.process._dangling.update(saved)

def get_sysconfig__CONFIG_VARS(self):
# make sure the dict is initialized
sysconfig.get_config_var('prefix')
Expand Down
18 changes: 17 additions & 1 deletion Lib/test/test_regrtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ def run_command(self, args, input=None, exitcode=0, **kw):
if 'stderr' not in kw:
kw['stderr'] = subprocess.STDOUT
proc = subprocess.run(args,
universal_newlines=True,
text=True,
input=input,
stdout=subprocess.PIPE,
**kw)
Expand Down Expand Up @@ -1307,5 +1307,21 @@ def test_format_duration(self):
'3 hour 1 sec')


class MiscTestCase(BaseTestCase):
def test_num_imports(self):
# bpo-41718: "import test.libregrtest" must not import too many
# modules.
code = textwrap.dedent("""
import sys
import test.libregrtest
print(len(sys.modules))
""")
proc = self.run_command([sys.executable, '-I', '-c', code])
out = proc.stdout.strip()
nmodules = int(out)
# Python 3.10 on Linux imports 149 modules
self.assertLess(nmodules, 155)


if __name__ == '__main__':
unittest.main()
16 changes: 15 additions & 1 deletion Lib/test/test_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ def check_options(self, args, func, expected=None):
proc = subprocess.run(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
universal_newlines=True,
text=True,
env=env)
if expected is None:
expected = args
Expand Down Expand Up @@ -656,6 +656,20 @@ def test_print_warning(self):
self.check_print_warning("a\nb",
'Warning -- a\nWarning -- b\n')

def test_num_imports(self):
# bpo-41718: "import test.support" must not import too many modules.
code = textwrap.dedent("""
import sys
import test.support
print(len(sys.modules))
""")
cmd = [sys.executable, '-I', '-c', code]
proc = subprocess.run(cmd, stdout=subprocess.PIPE, text=True, check=True)
out = proc.stdout.strip()
nmodules = int(out)
# Python 3.10 on Linux imports 96 modules
self.assertLess(nmodules, 100)

# XXX -follows a list of untested API
# make_legacy_pyc
# is_resource_enabled
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test.libregrtest.save_env no longer imports asyncio, multiprocessing nor
urllib to reduce the number of imports, to better isolate unit tests.