Updated the pkgutil + unittest libraries + the pkgutil, unittest and import tests - v.3.13.11 (#6610)

* Updated unittest + tests

* Updated pkgutil + the associated test

* Updated test_import

* Fixed import + unittest test errors

* Updated test_dll_dependency_import with expectedFailure
This commit is contained in:
Terry Tianlin Luan authored and GitHub committed 2026-01-04 09:54:01 +09:00
1 parent eee360822c
commit 4bec6bb6f9
22 files changed
+2374 -268

No files matched your search

+15 -19
View File
@@ -14,7 +14,7 @@ import warnings
__all__ = [
'get_importer', 'iter_importers', 'get_loader', 'find_loader',
'walk_packages', 'iter_modules', 'get_data',
'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
'read_code', 'extend_path',
'ModuleInfo',
]
@@ -23,20 +23,6 @@ ModuleInfo = namedtuple('ModuleInfo', 'module_finder name ispkg')
ModuleInfo.__doc__ = 'A namedtuple with minimal info about a module.'
def _get_spec(finder, name):
"""Return the finder-specific module spec."""
# Works with legacy finders.
try:
find_spec = finder.find_spec
except AttributeError:
loader = finder.find_module(name)
if loader is None:
return None
return importlib.util.spec_from_loader(name, loader)
else:
return find_spec(name)
def read_code(stream):
# This helper is needed in order for the PEP 302 emulation to
# correctly handle compiled files
@@ -184,6 +170,7 @@ def _iter_file_finder_modules(importer, prefix=''):
iter_importer_modules.register(
importlib.machinery.FileFinder, _iter_file_finder_modules)
try:
import zipimport
from zipimport import zipimporter
@@ -231,6 +218,7 @@ def get_importer(path_item):
The cache (or part of it) can be cleared manually if a
rescan of sys.path_hooks is necessary.
"""
path_item = os.fsdecode(path_item)
try:
importer = sys.path_importer_cache[path_item]
except KeyError:
@@ -282,6 +270,10 @@ def get_loader(module_or_name):
If the named module is not already imported, its containing package
(if any) is imported, in order to establish the package __path__.
"""
warnings._deprecated("pkgutil.get_loader",
f"{warnings._DEPRECATED_MSG}; "
"use importlib.util.find_spec() instead",
remove=(3, 14))
if module_or_name in sys.modules:
module_or_name = sys.modules[module_or_name]
if module_or_name is None:
@@ -306,6 +298,10 @@ def find_loader(fullname):
importlib.util.find_spec that converts most failures to ImportError
and only returns the loader rather than the full spec
"""
warnings._deprecated("pkgutil.find_loader",
f"{warnings._DEPRECATED_MSG}; "
"use importlib.util.find_spec() instead",
remove=(3, 14))
if fullname.startswith('.'):
msg = "Relative module name {!r} not supported".format(fullname)
raise ImportError(msg)
@@ -328,10 +324,10 @@ def extend_path(path, name):
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
This will add to the package's __path__ all subdirectories of
directories on sys.path named after the package. This is useful
if one wants to distribute different parts of a single logical
package as multiple directories.
For each directory on sys.path that has a subdirectory that
matches the package name, add the subdirectory to the package's
__path__. This is useful if one wants to distribute different
parts of a single logical package as multiple directories.
It also looks for *.pkg files beginning where * matches the name
argument. This feature is similar to *.pth files (see site.py),
+2059 -71
View File
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,3 @@
import test.test_import.data.circular_imports.import_cycle as m
m.some_attribute
@@ -0,0 +1,13 @@
"""Circular import involving a single-phase-init extension.
This module is imported from the _testsinglephase_circular module from
_testsinglephase, and imports that module again.
"""
import importlib
import _testsinglephase
from test.test_import import import_extension_from_file
name = '_testsinglephase_circular'
filename = _testsinglephase.__file__
mod = import_extension_from_file(name, filename)
+30
View File
@@ -0,0 +1,30 @@
from test.support import TestFailed
# A test for SF bug 422177: manifest float constants varied way too much in
# precision depending on whether Python was loading a module for the first
# time, or reloading it from a precompiled .pyc. The "expected" failure
# mode is that when test_import imports this after all .pyc files have been
# erased, it passes, but when test_import imports this from
# double_const.pyc, it fails. This indicates a woeful loss of precision in
# the marshal format for doubles. It's also possible that repr() doesn't
# produce enough digits to get reasonable precision for this box.
PI = 3.14159265358979324
TWOPI = 6.28318530717958648
PI_str = "3.14159265358979324"
TWOPI_str = "6.28318530717958648"
# Verify that the double x is within a few bits of eval(x_str).
def check_ok(x, x_str):
assert x > 0.0
x2 = eval(x_str)
assert x2 > 0.0
diff = abs(x - x2)
# If diff is no larger than 3 ULP (wrt x2), then diff/8 is no larger
# than 0.375 ULP, so adding diff/8 to x2 should have no effect.
if x2 + (diff / 8.) != x2:
raise TestFailed("Manifest const %s lost too much precision " % x_str)
check_ok(PI, PI_str)
check_ok(TWOPI, TWOPI_str)
+2
View File
@@ -0,0 +1,2 @@
"""Rebinding the package attribute after importing the module."""
from .submodule import submodule
+7
View File
@@ -0,0 +1,7 @@
attr = 'submodule'
class A:
attr = 'submodule'
class submodule:
attr = 'rebound'
class B:
attr = 'rebound'
+5
View File
@@ -0,0 +1,5 @@
"""Binding the package attribute without importing the module."""
class submodule:
attr = 'origin'
class B:
attr = 'origin'
+3
View File
@@ -0,0 +1,3 @@
attr = 'submodule'
class A:
attr = 'submodule'
+159 -20
View File
@@ -1,5 +1,6 @@
from pathlib import Path
from test.support.import_helper import unload, CleanImport
from test.support.warnings_helper import check_warnings
from test.support.warnings_helper import check_warnings, ignore_warnings
import unittest
import sys
import importlib
@@ -11,6 +12,10 @@ import tempfile
import shutil
import zipfile
from test.support.import_helper import DirsOnSysPath
from test.support.os_helper import FakePath
from test.test_importlib.util import uncache
# Note: pkgutil.walk_packages is currently tested in test_runpy. This is
# a hack to get a major issue resolved for 3.3b2. Longer term, it should
# be moved back here, perhaps by factoring out the helper code for
@@ -91,6 +96,45 @@ class PkgutilTests(unittest.TestCase):
del sys.modules[pkg]
def test_issue44061_iter_modules(self):
#see: issue44061
zip = 'test_getdata_zipfile.zip'
pkg = 'test_getdata_zipfile'
# Include a LF and a CRLF, to test that binary data is read back
RESOURCE_DATA = b'Hello, world!\nSecond line\r\nThird line'
# Make a package with some resources
zip_file = os.path.join(self.dirname, zip)
z = zipfile.ZipFile(zip_file, 'w')
# Empty init.py
z.writestr(pkg + '/__init__.py', "")
# Resource files, res.txt
z.writestr(pkg + '/res.txt', RESOURCE_DATA)
z.close()
# Check we can read the resources
sys.path.insert(0, zip_file)
try:
res = pkgutil.get_data(pkg, 'res.txt')
self.assertEqual(res, RESOURCE_DATA)
# make sure iter_modules accepts Path objects
names = []
for moduleinfo in pkgutil.iter_modules([FakePath(zip_file)]):
self.assertIsInstance(moduleinfo, pkgutil.ModuleInfo)
names.append(moduleinfo.name)
self.assertEqual(names, [pkg])
finally:
del sys.path[0]
sys.modules.pop(pkg, None)
# assert path must be None or list of paths
expected_msg = "path must be None or list of paths to look for modules in"
with self.assertRaisesRegex(ValueError, expected_msg):
list(pkgutil.iter_modules("invalid_path"))
def test_unreadable_dir_on_syspath(self):
# issue7367 - walk_packages failed if unreadable dir on sys.path
package_name = "unreadable_package"
@@ -187,8 +231,7 @@ class PkgutilTests(unittest.TestCase):
with self.assertRaises((TypeError, ValueError)):
list(pkgutil.walk_packages(bytes_input))
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_name_resolution(self):
import logging
import logging.handlers
@@ -280,6 +323,38 @@ class PkgutilTests(unittest.TestCase):
with self.assertRaises(exc):
pkgutil.resolve_name(s)
def test_name_resolution_import_rebinding(self):
# The same data is also used for testing import in test_import and
# mock.patch in test_unittest.
path = os.path.join(os.path.dirname(__file__), 'test_import', 'data')
with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package3.submodule.attr'), 'submodule')
with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package3.submodule:attr'), 'submodule')
with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 'rebound')
self.assertEqual(pkgutil.resolve_name('package3.submodule.attr'), 'submodule')
self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 'rebound')
with uncache('package3', 'package3.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 'rebound')
self.assertEqual(pkgutil.resolve_name('package3.submodule:attr'), 'submodule')
self.assertEqual(pkgutil.resolve_name('package3:submodule.attr'), 'rebound')
def test_name_resolution_import_rebinding2(self):
path = os.path.join(os.path.dirname(__file__), 'test_import', 'data')
with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package4.submodule.attr'), 'submodule')
with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package4.submodule:attr'), 'submodule')
with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 'origin')
self.assertEqual(pkgutil.resolve_name('package4.submodule.attr'), 'submodule')
self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 'submodule')
with uncache('package4', 'package4.submodule'), DirsOnSysPath(path):
self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 'origin')
self.assertEqual(pkgutil.resolve_name('package4.submodule:attr'), 'submodule')
self.assertEqual(pkgutil.resolve_name('package4:submodule.attr'), 'submodule')
class PkgutilPEP302Tests(unittest.TestCase):
@@ -391,7 +466,7 @@ class ExtendPathTests(unittest.TestCase):
importers = list(iter_importers(fullname))
expected_importer = get_importer(pathitem)
for finder in importers:
spec = pkgutil._get_spec(finder, fullname)
spec = finder.find_spec(fullname)
loader = spec.loader
try:
loader = loader.loader
@@ -403,7 +478,7 @@ class ExtendPathTests(unittest.TestCase):
self.assertEqual(finder, expected_importer)
self.assertIsInstance(loader,
importlib.machinery.SourceFileLoader)
self.assertIsNone(pkgutil._get_spec(finder, pkgname))
self.assertIsNone(finder.find_spec(pkgname))
with self.assertRaises(ImportError):
list(iter_importers('invalid.module'))
@@ -448,7 +523,43 @@ class ExtendPathTests(unittest.TestCase):
del sys.modules['foo.bar']
del sys.modules['foo.baz']
# XXX: test .pkg files
def test_extend_path_argument_types(self):
pkgname = 'foo'
dirname_0 = self.create_init(pkgname)
# If the input path is not a list it is returned unchanged
self.assertEqual('notalist', pkgutil.extend_path('notalist', 'foo'))
self.assertEqual(('not', 'a', 'list'), pkgutil.extend_path(('not', 'a', 'list'), 'foo'))
self.assertEqual(123, pkgutil.extend_path(123, 'foo'))
self.assertEqual(None, pkgutil.extend_path(None, 'foo'))
# Cleanup
shutil.rmtree(dirname_0)
del sys.path[0]
def test_extend_path_pkg_files(self):
pkgname = 'foo'
dirname_0 = self.create_init(pkgname)
with open(os.path.join(dirname_0, 'bar.pkg'), 'w') as pkg_file:
pkg_file.write('\n'.join([
'baz',
'/foo/bar/baz',
'',
'#comment'
]))
extended_paths = pkgutil.extend_path(sys.path, 'bar')
self.assertEqual(extended_paths[:-2], sys.path)
self.assertEqual(extended_paths[-2], 'baz')
self.assertEqual(extended_paths[-1], '/foo/bar/baz')
# Cleanup
shutil.rmtree(dirname_0)
del sys.path[0]
class NestedNamespacePackageTest(unittest.TestCase):
@@ -491,36 +602,50 @@ class NestedNamespacePackageTest(unittest.TestCase):
self.assertEqual(c, 1)
self.assertEqual(d, 2)
class ImportlibMigrationTests(unittest.TestCase):
# With full PEP 302 support in the standard import machinery, the
# PEP 302 emulation in this module is in the process of being
# deprecated in favour of importlib proper
@unittest.skipIf(__name__ == '__main__', 'not compatible with __main__')
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_missing_loader_attribute(self):
global __loader__
this_loader = __loader__
del __loader__
try:
with check_warnings() as w:
self.assertIsNotNone(pkgutil.get_loader(__name__))
self.assertEqual(len(w.warnings), 0)
self.assertIsNotNone(pkgutil.get_loader(__name__))
finally:
__loader__ = this_loader
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_missing_spec_attribute(self):
name = 'spam'
mod = type(sys)(name)
del mod.__spec__
with CleanImport(name):
sys.modules[name] = mod
loader = pkgutil.get_loader(name)
try:
sys.modules[name] = mod
loader = pkgutil.get_loader(name)
finally:
sys.modules.pop(name, None)
self.assertIsNone(loader)
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_handles_spec_attribute_none(self):
name = 'spam'
mod = type(sys)(name)
mod.__spec__ = None
with CleanImport(name):
sys.modules[name] = mod
loader = pkgutil.get_loader(name)
try:
sys.modules[name] = mod
loader = pkgutil.get_loader(name)
finally:
sys.modules.pop(name, None)
self.assertIsNone(loader)
@ignore_warnings(category=DeprecationWarning)
def test_get_loader_None_in_sys_modules(self):
name = 'totally bogus'
sys.modules[name] = None
@@ -530,24 +655,38 @@ class NestedNamespacePackageTest(unittest.TestCase):
del sys.modules[name]
self.assertIsNone(loader)
def test_get_loader_is_deprecated(self):
with check_warnings(
(r".*\bpkgutil.get_loader\b.*", DeprecationWarning),
):
res = pkgutil.get_loader("sys")
self.assertIsNotNone(res)
def test_find_loader_is_deprecated(self):
with check_warnings(
(r".*\bpkgutil.find_loader\b.*", DeprecationWarning),
):
res = pkgutil.find_loader("sys")
self.assertIsNotNone(res)
@ignore_warnings(category=DeprecationWarning)
def test_find_loader_missing_module(self):
name = 'totally bogus'
loader = pkgutil.find_loader(name)
self.assertIsNone(loader)
def test_find_loader_avoids_emulation(self):
with check_warnings() as w:
self.assertIsNotNone(pkgutil.find_loader("sys"))
self.assertIsNotNone(pkgutil.find_loader("os"))
self.assertIsNotNone(pkgutil.find_loader("test.support"))
self.assertEqual(len(w.warnings), 0)
def test_get_importer_avoids_emulation(self):
# We use an illegal path so *none* of the path hooks should fire
with check_warnings() as w:
self.assertIsNone(pkgutil.get_importer("*??"))
self.assertEqual(len(w.warnings), 0)
def test_issue44061(self):
try:
pkgutil.get_importer(Path("/home"))
except AttributeError:
self.fail("Unexpected AttributeError when calling get_importer")
def test_iter_importers_avoids_emulation(self):
with check_warnings() as w:
for importer in pkgutil.iter_importers(): pass
+3 -6
View File
@@ -48,8 +48,7 @@ class TestAsyncCase(unittest.TestCase):
# starting a new event loop
self.addCleanup(support.gc_collect)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_full_cycle(self):
expected = ['setUp',
'asyncSetUp',
@@ -296,8 +295,7 @@ class TestAsyncCase(unittest.TestCase):
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2', 'cleanup1'])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_deprecation_of_return_val_from_test(self):
# Issue 41322 - deprecate return of value that is not None from a test
class Nothing:
@@ -488,8 +486,7 @@ class TestAsyncCase(unittest.TestCase):
result = test.run()
self.assertTrue(result.wasSuccessful())
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_loop_factory(self):
asyncio.set_event_loop_policy(None)
-4
View File
@@ -364,8 +364,6 @@ class TestDiscovery(unittest.TestCase):
[(loader, [], 'test*.py'),
(loader, [], 'test*.py')])
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_discover(self):
loader = unittest.TestLoader()
@@ -412,8 +410,6 @@ class TestDiscovery(unittest.TestCase):
self.assertEqual(_find_tests_args, [(start_dir, 'pattern')])
self.assertIn(top_level_dir, sys.path)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_discover_should_not_persist_top_level_dir_between_calls(self):
original_isfile = os.path.isfile
original_isdir = os.path.isdir
-6
View File
@@ -90,8 +90,6 @@ class Test_TestLoader(unittest.TestCase):
self.assertIsInstance(suite, loader.suiteClass)
self.assertEqual(list(suite), [])
# TODO: RUSTPYTHON
@unittest.expectedFailure
# "Do not load any tests from `FunctionTestCase` class."
def test_loadTestsFromTestCase__from_FunctionTestCase(self):
loader = unittest.TestLoader()
@@ -121,8 +119,6 @@ class Test_TestLoader(unittest.TestCase):
expected = [loader.suiteClass([MyTestCase('test')])]
self.assertEqual(list(suite), expected)
# TODO: RUSTPYTHON
@unittest.expectedFailure
# "This test ensures that internal `TestCase` subclasses are not loaded"
def test_loadTestsFromModule__TestCase_subclass_internals(self):
# See https://github.com/python/cpython/issues/84867
@@ -187,8 +183,6 @@ class Test_TestLoader(unittest.TestCase):
self.assertEqual(list(suite), reference)
# TODO: RUSTPYTHON
@unittest.expectedFailure
# Check that loadTestsFromModule honors a module
# with a load_tests function.
def test_loadTestsFromModule__load_tests(self):
+22 -2
View File
@@ -75,6 +75,14 @@ class Test_TestProgram(unittest.TestCase):
class Empty(unittest.TestCase):
pass
class SetUpClassFailure(unittest.TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
raise Exception
def testPass(self):
pass
class TestLoader(unittest.TestLoader):
"""Test loader that returns a suite containing the supplied testcase."""
@@ -191,6 +199,18 @@ class Test_TestProgram(unittest.TestCase):
out = stream.getvalue()
self.assertIn('\nNO TESTS RAN\n', out)
def test_ExitSetUpClassFailureSuite(self):
stream = BufferedWriter()
with self.assertRaises(SystemExit) as cm:
unittest.main(
argv=["setup_class_failure"],
testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.TestLoader(self.SetUpClassFailure))
self.assertEqual(cm.exception.code, 1)
out = stream.getvalue()
self.assertIn("ERROR: setUpClass", out)
self.assertIn("SetUpClassFailure", out)
class InitialisableProgram(unittest.TestProgram):
exit = False
@@ -485,8 +505,8 @@ class TestCommandLineArgs(unittest.TestCase):
self.assertEqual(program.testNamePatterns, ['*foo*', '*bar*', '*pat*'])
# TODO: RUSTPYTHON
@unittest.expectedFailureIf(sys.platform != 'win32', "TODO: RUSTPYTHON")
@unittest.expectedFailureIf(sys.platform != 'win32', 'TODO: RUSTPYTHON')
def testSelectedTestNamesFunctionalTest(self):
def run_unittest(args):
# Use -E to ignore PYTHONSAFEPATH env var
+1 -2
View File
@@ -1297,8 +1297,7 @@ class Test_TextTestRunner(unittest.TestCase):
expected = ['startTestRun', 'stopTestRun']
self.assertEqual(events, expected)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_pickle_unpickle(self):
# Issue #7197: a TextTestRunner should be (un)pickleable. This is
# required by test_multiprocessing under Windows (in verbose mode).
+12 -24
View File
@@ -340,8 +340,7 @@ class AsyncSpecTest(unittest.TestCase):
# only the shape of the spec at the time of mock construction matters
self.assertNotIsInstance(mock_async_instance.later_async_func_attr, AsyncMock)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_spec_mock_type_kw(self):
def inner_test(mock_type):
async_mock = mock_type(spec=async_func)
@@ -356,8 +355,7 @@ class AsyncSpecTest(unittest.TestCase):
with self.subTest(f"test spec kwarg with {mock_type}"):
inner_test(mock_type)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_spec_mock_type_positional(self):
def inner_test(mock_type):
async_mock = mock_type(async_func)
@@ -736,8 +734,7 @@ class AsyncIteratorTest(unittest.TestCase):
async def __anext__(self): pass
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_aiter_set_return_value(self):
mock_iter = AsyncMock(name="tester")
mock_iter.__aiter__.return_value = [1, 2, 3]
@@ -763,8 +760,7 @@ class AsyncIteratorTest(unittest.TestCase):
inner_test(mock_type)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_mock_async_for(self):
async def iterate(iterator):
accumulator = []
@@ -810,8 +806,7 @@ class AsyncMockAssert(unittest.TestCase):
async def _await_coroutine(self, coroutine):
return await coroutine
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_assert_called_but_not_awaited(self):
mock = AsyncMock(AsyncClass)
with assertNeverAwaited(self):
@@ -852,8 +847,7 @@ class AsyncMockAssert(unittest.TestCase):
self.mock.assert_called_once()
self.mock.assert_awaited_once()
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_assert_called_twice_and_awaited_once(self):
mock = AsyncMock(AsyncClass)
coroutine = mock.async_method()
@@ -868,8 +862,7 @@ class AsyncMockAssert(unittest.TestCase):
mock.async_method.assert_awaited()
mock.async_method.assert_awaited_once()
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_assert_called_once_and_awaited_twice(self):
mock = AsyncMock(AsyncClass)
coroutine = mock.async_method()
@@ -894,8 +887,7 @@ class AsyncMockAssert(unittest.TestCase):
with self.assertRaises(AssertionError):
self.mock.assert_called()
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_assert_has_calls_not_awaits(self):
kalls = [call('foo')]
with assertNeverAwaited(self):
@@ -904,8 +896,7 @@ class AsyncMockAssert(unittest.TestCase):
with self.assertRaises(AssertionError):
self.mock.assert_has_awaits(kalls)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_assert_has_mock_calls_on_async_mock_no_spec(self):
with assertNeverAwaited(self):
self.mock()
@@ -919,8 +910,7 @@ class AsyncMockAssert(unittest.TestCase):
mock_kalls = ([call(), call('foo'), call('baz')])
self.assertEqual(self.mock.mock_calls, mock_kalls)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_assert_has_mock_calls_on_async_mock_with_spec(self):
a_class_mock = AsyncMock(AsyncClass)
with assertNeverAwaited(self):
@@ -936,8 +926,7 @@ class AsyncMockAssert(unittest.TestCase):
self.assertEqual(a_class_mock.async_method.mock_calls, method_kalls)
self.assertEqual(a_class_mock.mock_calls, mock_kalls)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_async_method_calls_recorded(self):
with assertNeverAwaited(self):
self.mock.something(3, fish=None)
@@ -953,8 +942,7 @@ class AsyncMockAssert(unittest.TestCase):
[("something", (6,), {'cake': sentinel.Cake})],
"method calls not recorded correctly")
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_async_arg_lists(self):
def assert_attrs(mock):
names = ('call_args_list', 'method_calls', 'mock_calls')
+1 -2
View File
@@ -43,8 +43,7 @@ class AnyTest(unittest.TestCase):
mock.assert_called_with(ANY, foo=ANY)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_any_mock_calls_comparison_order(self):
mock = Mock()
class Foo(object):
+1 -6
View File
@@ -1778,8 +1778,6 @@ class PatchTest(unittest.TestCase):
'exception traceback not propagated')
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_name_resolution_import_rebinding(self):
# Currently mock.patch uses pkgutil.resolve_name(), but repeat
# similar tests just for the case.
@@ -1814,8 +1812,6 @@ class PatchTest(unittest.TestCase):
check('package3:submodule.B.attr')
check_error('package3:submodule.A.attr')
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_name_resolution_import_rebinding2(self):
path = os.path.join(os.path.dirname(test.__file__), 'test_import', 'data')
def check(name):
@@ -2016,8 +2012,7 @@ class PatchTest(unittest.TestCase):
self.assertEqual(dic2, origdic2)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_special_attrs(self):
def foo(x=0):
"""TEST"""
+2 -19
View File
@@ -51,10 +51,6 @@ __all__ = ['TestResult', 'TestCase', 'IsolatedAsyncioTestCase', 'TestSuite',
'registerResult', 'removeResult', 'removeHandler',
'addModuleCleanup', 'doModuleCleanups', 'enterModuleContext']
# Expose obsolete functions for backwards compatibility
# bpo-5846: Deprecated in Python 3.11, scheduled for removal in Python 3.13.
__all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])
__unittest = True
from .result import TestResult
@@ -67,20 +63,6 @@ from .main import TestProgram, main
from .runner import TextTestRunner, TextTestResult
from .signals import installHandler, registerResult, removeResult, removeHandler
# IsolatedAsyncioTestCase will be imported lazily.
from .loader import makeSuite, getTestCaseNames, findTestCases
# deprecated
_TextTestResult = TextTestResult
# There are no tests here, so don't try to run anything discovered from
# introspecting the symbols (e.g. FunctionTestCase). Instead, all our
# tests come from within unittest.test.
def load_tests(loader, tests, pattern):
import os.path
# top level directory cached on loader instance
this_dir = os.path.dirname(__file__)
return loader.discover(start_dir=this_dir, pattern=pattern)
# Lazy import of IsolatedAsyncioTestCase from .async_case
@@ -98,6 +80,7 @@ def __getattr__(name):
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
# XXX: RUSTPYTHON
# This is very useful to reduce platform difference boilerplates in tests.
def expectedFailureIf(condition, reason):
@@ -111,4 +94,4 @@ def expectedFailureIf(condition, reason):
# Even more useful because most of them are windows only.
def expectedFailureIfWindows(reason):
import sys
return expectedFailureIf(sys.platform == 'win32', reason)
return expectedFailureIf(sys.platform == 'win32', reason)
+6 -2
View File
@@ -5,6 +5,7 @@ import warnings
from .case import TestCase
__unittest = True
class IsolatedAsyncioTestCase(TestCase):
# Names intentionally have a long prefix
@@ -25,12 +26,15 @@ class IsolatedAsyncioTestCase(TestCase):
# them inside the same task.
# Note: the test case modifies event loop policy if the policy was not instantiated
# yet.
# yet, unless loop_factory=asyncio.EventLoop is set.
# asyncio.get_event_loop_policy() creates a default policy on demand but never
# returns None
# I believe this is not an issue in user level tests but python itself for testing
# should reset a policy in every test module
# by calling asyncio.set_event_loop_policy(None) in tearDownModule()
# or set loop_factory=asyncio.EventLoop
loop_factory = None
def __init__(self, methodName='runTest'):
super().__init__(methodName)
@@ -118,7 +122,7 @@ class IsolatedAsyncioTestCase(TestCase):
def _setupAsyncioRunner(self):
assert self._asyncioRunner is None, 'asyncio runner is already initialized'
runner = asyncio.Runner(debug=True)
runner = asyncio.Runner(debug=True, loop_factory=self.loop_factory)
self._asyncioRunner = runner
def _tearDownAsyncioRunner(self):
+25 -80
View File
@@ -6,7 +6,6 @@ import sys
import traceback
import types
import functools
import warnings
from fnmatch import fnmatch, fnmatchcase
@@ -57,9 +56,7 @@ def _make_skipped_test(methodname, exception, suiteClass):
TestClass = type("ModuleSkipped", (case.TestCase,), attrs)
return suiteClass((TestClass(methodname),))
def _jython_aware_splitext(path):
if path.lower().endswith('$py.class'):
return path[:-9]
def _splitext(path):
return os.path.splitext(path)[0]
@@ -87,40 +84,26 @@ class TestLoader(object):
raise TypeError("Test cases should not be derived from "
"TestSuite. Maybe you meant to derive from "
"TestCase?")
testCaseNames = self.getTestCaseNames(testCaseClass)
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
testCaseNames = ['runTest']
if testCaseClass in (case.TestCase, case.FunctionTestCase):
# We don't load any tests from base types that should not be loaded.
testCaseNames = []
else:
testCaseNames = self.getTestCaseNames(testCaseClass)
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
testCaseNames = ['runTest']
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
return loaded_suite
# XXX After Python 3.5, remove backward compatibility hacks for
# use_load_tests deprecation via *args and **kws. See issue 16662.
def loadTestsFromModule(self, module, *args, pattern=None, **kws):
def loadTestsFromModule(self, module, *, pattern=None):
"""Return a suite of all test cases contained in the given module"""
# This method used to take an undocumented and unofficial
# use_load_tests argument. For backward compatibility, we still
# accept the argument (which can also be the first position) but we
# ignore it and issue a deprecation warning if it's present.
if len(args) > 0 or 'use_load_tests' in kws:
warnings.warn('use_load_tests is deprecated and ignored',
DeprecationWarning)
kws.pop('use_load_tests', None)
if len(args) > 1:
# Complain about the number of arguments, but don't forget the
# required `module` argument.
complaint = len(args) + 1
raise TypeError('loadTestsFromModule() takes 1 positional argument but {} were given'.format(complaint))
if len(kws) != 0:
# Since the keyword arguments are unsorted (see PEP 468), just
# pick the alphabetically sorted first argument to complain about,
# if multiple were given. At least the error message will be
# predictable.
complaint = sorted(kws)[0]
raise TypeError("loadTestsFromModule() got an unexpected keyword argument '{}'".format(complaint))
tests = []
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, type) and issubclass(obj, case.TestCase):
if (
isinstance(obj, type)
and issubclass(obj, case.TestCase)
and obj not in (case.TestCase, case.FunctionTestCase)
):
tests.append(self.loadTestsFromTestCase(obj))
load_tests = getattr(module, 'load_tests', None)
@@ -189,7 +172,11 @@ class TestLoader(object):
if isinstance(obj, types.ModuleType):
return self.loadTestsFromModule(obj)
elif isinstance(obj, type) and issubclass(obj, case.TestCase):
elif (
isinstance(obj, type)
and issubclass(obj, case.TestCase)
and obj not in (case.TestCase, case.FunctionTestCase)
):
return self.loadTestsFromTestCase(obj)
elif (isinstance(obj, types.FunctionType) and
isinstance(parent, type) and
@@ -267,6 +254,7 @@ class TestLoader(object):
Paths are sorted before being imported to ensure reproducible execution
order even on filesystems with non-alphabetical ordering like ext3/4.
"""
original_top_level_dir = self._top_level_dir
set_implicit_top = False
if top_level_dir is None and self._top_level_dir is not None:
# make top_level_dir optional if called from load_tests in a package
@@ -320,6 +308,7 @@ class TestLoader(object):
raise ImportError('Start directory is not importable: %r' % start_dir)
tests = list(self._find_tests(start_dir, pattern))
self._top_level_dir = original_top_level_dir
return self.suiteClass(tests)
def _get_directory_containing_module(self, module_name):
@@ -337,7 +326,7 @@ class TestLoader(object):
def _get_name_from_path(self, path):
if path == self._top_level_dir:
return '.'
path = _jython_aware_splitext(os.path.normpath(path))
path = _splitext(os.path.normpath(path))
_relpath = os.path.relpath(path, self._top_level_dir)
assert not os.path.isabs(_relpath), "Path must be within the project"
@@ -415,13 +404,13 @@ class TestLoader(object):
else:
mod_file = os.path.abspath(
getattr(module, '__file__', full_path))
realpath = _jython_aware_splitext(
realpath = _splitext(
os.path.realpath(mod_file))
fullpath_noext = _jython_aware_splitext(
fullpath_noext = _splitext(
os.path.realpath(full_path))
if realpath.lower() != fullpath_noext.lower():
module_dir = os.path.dirname(realpath)
mod_name = _jython_aware_splitext(
mod_name = _splitext(
os.path.basename(full_path))
expected_dir = os.path.dirname(full_path)
msg = ("%r module incorrectly imported from %r. Expected "
@@ -462,47 +451,3 @@ class TestLoader(object):
defaultTestLoader = TestLoader()
# These functions are considered obsolete for long time.
# They will be removed in Python 3.13.
def _makeLoader(prefix, sortUsing, suiteClass=None, testNamePatterns=None):
loader = TestLoader()
loader.sortTestMethodsUsing = sortUsing
loader.testMethodPrefix = prefix
loader.testNamePatterns = testNamePatterns
if suiteClass:
loader.suiteClass = suiteClass
return loader
def getTestCaseNames(testCaseClass, prefix, sortUsing=util.three_way_cmp, testNamePatterns=None):
import warnings
warnings.warn(
"unittest.getTestCaseNames() is deprecated and will be removed in Python 3.13. "
"Please use unittest.TestLoader.getTestCaseNames() instead.",
DeprecationWarning, stacklevel=2
)
return _makeLoader(prefix, sortUsing, testNamePatterns=testNamePatterns).getTestCaseNames(testCaseClass)
def makeSuite(testCaseClass, prefix='test', sortUsing=util.three_way_cmp,
suiteClass=suite.TestSuite):
import warnings
warnings.warn(
"unittest.makeSuite() is deprecated and will be removed in Python 3.13. "
"Please use unittest.TestLoader.loadTestsFromTestCase() instead.",
DeprecationWarning, stacklevel=2
)
return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(
testCaseClass)
def findTestCases(module, prefix='test', sortUsing=util.three_way_cmp,
suiteClass=suite.TestSuite):
import warnings
warnings.warn(
"unittest.findTestCases() is deprecated and will be removed in Python 3.13. "
"Please use unittest.TestLoader.loadTestsFromModule() instead.",
DeprecationWarning, stacklevel=2
)
return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(\
module)
+5 -5
View File
@@ -269,12 +269,12 @@ class TestProgram(object):
testRunner = self.testRunner
self.result = testRunner.run(self.test)
if self.exit:
if self.result.testsRun == 0 and len(self.result.skipped) == 0:
sys.exit(_NO_TESTS_EXITCODE)
elif self.result.wasSuccessful():
sys.exit(0)
else:
if not self.result.wasSuccessful():
sys.exit(1)
elif self.result.testsRun == 0 and len(self.result.skipped) == 0:
sys.exit(_NO_TESTS_EXITCODE)
else:
sys.exit(0)
main = TestProgram