Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d78742a

Browse filesBrowse files
committed
- Issue python#16662: load_tests() is now unconditionally run when it is present in
a package's __init__.py. TestLoader.loadTestsFromModule() still accepts use_load_tests, but it is deprecated and ignored. A new keyword-only attribute `pattern` is added and documented. Patch given by Robert Collins, tweaked by Barry Warsaw.
1 parent 238f5aa commit d78742a
Copy full SHA for d78742a

File tree

5 files changed

+472
-61
lines changed
Filter options

5 files changed

+472
-61
lines changed

‎Doc/library/unittest.rst

Copy file name to clipboardExpand all lines: Doc/library/unittest.rst
+39-28Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,7 @@ Loading and running tests
15611561
:class:`testCaseClass`.
15621562

15631563

1564-
.. method:: loadTestsFromModule(module)
1564+
.. method:: loadTestsFromModule(module, pattern=None)
15651565

15661566
Return a suite of all tests cases contained in the given module. This
15671567
method searches *module* for classes derived from :class:`TestCase` and
@@ -1578,11 +1578,18 @@ Loading and running tests
15781578

15791579
If a module provides a ``load_tests`` function it will be called to
15801580
load the tests. This allows modules to customize test loading.
1581-
This is the `load_tests protocol`_.
1581+
This is the `load_tests protocol`_. The *pattern* argument is passed as
1582+
the third argument to ``load_tests``.
15821583

15831584
.. versionchanged:: 3.2
15841585
Support for ``load_tests`` added.
15851586

1587+
.. versionchanged:: 3.5
1588+
The undocumented and unofficial *use_load_tests* default argument is
1589+
deprecated and ignored, although it is still accepted for backward
1590+
compatibility. The method also now accepts a keyword-only argument
1591+
*pattern* which is passed to ``load_tests`` as the third argument.
1592+
15861593

15871594
.. method:: loadTestsFromName(name, module=None)
15881595

@@ -1634,18 +1641,18 @@ Loading and running tests
16341641
the start directory is not the top level directory then the top level
16351642
directory must be specified separately.
16361643

1637-
If importing a module fails, for example due to a syntax error, then this
1638-
will be recorded as a single error and discovery will continue. If the
1639-
import failure is due to :exc:`SkipTest` being raised, it will be recorded
1640-
as a skip instead of an error.
1644+
If importing a module fails, for example due to a syntax error, then
1645+
this will be recorded as a single error and discovery will continue. If
1646+
the import failure is due to :exc:`SkipTest` being raised, it will be
1647+
recorded as a skip instead of an error.
16411648

1642-
If a test package name (directory with :file:`__init__.py`) matches the
1643-
pattern then the package will be checked for a ``load_tests``
1644-
function. If this exists then it will be called with *loader*, *tests*,
1645-
*pattern*.
1649+
If a package (a directory containing a file named :file:`__init__.py`) is
1650+
found, the package will be checked for a ``load_tests`` function. If this
1651+
exists then it will be called with *loader*, *tests*, *pattern*.
16461652

1647-
If load_tests exists then discovery does *not* recurse into the package,
1648-
``load_tests`` is responsible for loading all tests in the package.
1653+
If ``load_tests`` exists then discovery does *not* recurse into the
1654+
package, ``load_tests`` is responsible for loading all tests in the
1655+
package.
16491656

16501657
The pattern is deliberately not stored as a loader attribute so that
16511658
packages can continue discovery themselves. *top_level_dir* is stored so
@@ -1664,6 +1671,11 @@ Loading and running tests
16641671
the same even if the underlying file system's ordering is not
16651672
dependent on file name.
16661673

1674+
.. versionchanged:: 3.5
1675+
Found packages are now checked for ``load_tests`` regardless of
1676+
whether their path matches *pattern*, because it is impossible for
1677+
a package name to match the default pattern.
1678+
16671679

16681680
The following attributes of a :class:`TestLoader` can be configured either by
16691681
subclassing or assignment on an instance:
@@ -2032,7 +2044,10 @@ test runs or test discovery by implementing a function called ``load_tests``.
20322044
If a test module defines ``load_tests`` it will be called by
20332045
:meth:`TestLoader.loadTestsFromModule` with the following arguments::
20342046

2035-
load_tests(loader, standard_tests, None)
2047+
load_tests(loader, standard_tests, pattern)
2048+
2049+
where *pattern* is passed straight through from ``loadTestsFromModule``. It
2050+
defaults to ``None``.
20362051

20372052
It should return a :class:`TestSuite`.
20382053

@@ -2054,21 +2069,12 @@ A typical ``load_tests`` function that loads tests from a specific set of
20542069
suite.addTests(tests)
20552070
return suite
20562071

2057-
If discovery is started, either from the command line or by calling
2058-
:meth:`TestLoader.discover`, with a pattern that matches a package
2059-
name then the package :file:`__init__.py` will be checked for ``load_tests``.
2060-
2061-
.. note::
2062-
2063-
The default pattern is ``'test*.py'``. This matches all Python files
2064-
that start with ``'test'`` but *won't* match any test directories.
2065-
2066-
A pattern like ``'test*'`` will match test packages as well as
2067-
modules.
2068-
2069-
If the package :file:`__init__.py` defines ``load_tests`` then it will be
2070-
called and discovery not continued into the package. ``load_tests``
2071-
is called with the following arguments::
2072+
If discovery is started in a directory containing a package, either from the
2073+
command line or by calling :meth:`TestLoader.discover`, then the package
2074+
:file:`__init__.py` will be checked for ``load_tests``. If that function does
2075+
not exist, discovery will recurse into the package as though it were just
2076+
another directory. Otherwise, discovery of the package's tests will be left up
2077+
to ``load_tests`` which is called with the following arguments::
20722078

20732079
load_tests(loader, standard_tests, pattern)
20742080

@@ -2087,6 +2093,11 @@ continue (and potentially modify) test discovery. A 'do nothing'
20872093
standard_tests.addTests(package_tests)
20882094
return standard_tests
20892095

2096+
.. versionchanged:: 3.5
2097+
Discovery no longer checks package names for matching *pattern* due to the
2098+
impossibility of package names matching the default pattern.
2099+
2100+
20902101

20912102
Class and Module Fixtures
20922103
-------------------------

‎Lib/unittest/loader.py

Copy file name to clipboardExpand all lines: Lib/unittest/loader.py
+37-16Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import traceback
77
import types
88
import functools
9+
import warnings
910

1011
from fnmatch import fnmatch
1112

@@ -70,8 +71,27 @@ def loadTestsFromTestCase(self, testCaseClass):
7071
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
7172
return loaded_suite
7273

73-
def loadTestsFromModule(self, module, use_load_tests=True):
74+
# XXX After Python 3.5, remove backward compatibility hacks for
75+
# use_load_tests deprecation via *args and **kws. See issue 16662.
76+
def loadTestsFromModule(self, module, *args, pattern=None, **kws):
7477
"""Return a suite of all tests cases contained in the given module"""
78+
# This method used to take an undocumented and unofficial
79+
# use_load_tests argument. For backward compatibility, we still
80+
# accept the argument (which can also be the first position) but we
81+
# ignore it and issue a deprecation warning if it's present.
82+
if len(args) == 1 or 'use_load_tests' in kws:
83+
warnings.warn('use_load_tests is deprecated and ignored',
84+
DeprecationWarning)
85+
kws.pop('use_load_tests', None)
86+
if len(args) > 1:
87+
raise TypeError('loadTestsFromModule() takes 1 positional argument but {} were given'.format(len(args)))
88+
if len(kws) != 0:
89+
# Since the keyword arguments are unsorted (see PEP 468), just
90+
# pick the alphabetically sorted first argument to complain about,
91+
# if multiple were given. At least the error message will be
92+
# predictable.
93+
complaint = sorted(kws)[0]
94+
raise TypeError("loadTestsFromModule() got an unexpected keyword argument '{}'".format(complaint))
7595
tests = []
7696
for name in dir(module):
7797
obj = getattr(module, name)
@@ -80,9 +100,9 @@ def loadTestsFromModule(self, module, use_load_tests=True):
80100

81101
load_tests = getattr(module, 'load_tests', None)
82102
tests = self.suiteClass(tests)
83-
if use_load_tests and load_tests is not None:
103+
if load_tests is not None:
84104
try:
85-
return load_tests(self, tests, None)
105+
return load_tests(self, tests, pattern)
86106
except Exception as e:
87107
return _make_failed_load_tests(module.__name__, e,
88108
self.suiteClass)
@@ -325,34 +345,35 @@ def _find_tests(self, start_dir, pattern, namespace=False):
325345
msg = ("%r module incorrectly imported from %r. Expected %r. "
326346
"Is this module globally installed?")
327347
raise ImportError(msg % (mod_name, module_dir, expected_dir))
328-
yield self.loadTestsFromModule(module)
348+
yield self.loadTestsFromModule(module, pattern=pattern)
329349
elif os.path.isdir(full_path):
330350
if (not namespace and
331351
not os.path.isfile(os.path.join(full_path, '__init__.py'))):
332352
continue
333353

334354
load_tests = None
335355
tests = None
336-
if fnmatch(path, pattern):
337-
# only check load_tests if the package directory itself matches the filter
338-
name = self._get_name_from_path(full_path)
356+
name = self._get_name_from_path(full_path)
357+
try:
339358
package = self._get_module_from_name(name)
359+
except case.SkipTest as e:
360+
yield _make_skipped_test(name, e, self.suiteClass)
361+
except:
362+
yield _make_failed_import_test(name, self.suiteClass)
363+
else:
340364
load_tests = getattr(package, 'load_tests', None)
341-
tests = self.loadTestsFromModule(package, use_load_tests=False)
342-
343-
if load_tests is None:
365+
tests = self.loadTestsFromModule(package, pattern=pattern)
344366
if tests is not None:
345367
# tests loaded from package file
346368
yield tests
369+
370+
if load_tests is not None:
371+
# loadTestsFromModule(package) has load_tests for us.
372+
continue
347373
# recurse into the package
348374
yield from self._find_tests(full_path, pattern,
349375
namespace=namespace)
350-
else:
351-
try:
352-
yield load_tests(self, tests, pattern)
353-
except Exception as e:
354-
yield _make_failed_load_tests(package.__name__, e,
355-
self.suiteClass)
376+
356377

357378
defaultTestLoader = TestLoader()
358379

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.