blob: 8ee6c56153122f23498f7a94a757f782f357ef52 [file] [log] [blame]
Benjamin Petersonbed7d042009-07-19 21:01:52 +00001"""Loading unittests."""
2
3import os
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +00004import re
Benjamin Petersonbed7d042009-07-19 21:01:52 +00005import sys
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +00006import traceback
Benjamin Petersonbed7d042009-07-19 21:01:52 +00007import types
Raymond Hettingerc50846a2010-04-05 18:56:31 +00008import functools
Barry Warsawd78742a2014-09-08 14:21:37 -04009import warnings
Benjamin Petersonbed7d042009-07-19 21:01:52 +000010
11from fnmatch import fnmatch
12
13from . import case, suite, util
14
Benjamin Petersondccc1fc2010-03-22 00:15:53 +000015__unittest = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +000016
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000017# what about .pyc or .pyo (etc)
18# we would need to avoid loading the same tests multiple times
19# from '.py', '.pyc' *and* '.pyo'
20VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE)
21
22
23def _make_failed_import_test(name, suiteClass):
Robert Collinsf920c212014-10-20 13:24:05 +130024 message = 'Failed to import test module: %s\n%s' % (
25 name, traceback.format_exc())
Benjamin Peterson886af962010-03-21 23:13:07 +000026 return _make_failed_test('ModuleImportFailure', name, ImportError(message),
Robert Collinsf920c212014-10-20 13:24:05 +130027 suiteClass, message)
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000028
Benjamin Peterson886af962010-03-21 23:13:07 +000029def _make_failed_load_tests(name, exception, suiteClass):
Robert Collinsf920c212014-10-20 13:24:05 +130030 message = 'Failed to call load_tests:\n%s' % (traceback.format_exc(),)
31 return _make_failed_test(
32 'LoadTestsFailure', name, exception, suiteClass, message)
Benjamin Peterson886af962010-03-21 23:13:07 +000033
Robert Collinsf920c212014-10-20 13:24:05 +130034def _make_failed_test(classname, methodname, exception, suiteClass, message):
Benjamin Peterson886af962010-03-21 23:13:07 +000035 def testFailure(self):
36 raise exception
37 attrs = {methodname: testFailure}
38 TestClass = type(classname, (case.TestCase,), attrs)
Robert Collinsf920c212014-10-20 13:24:05 +130039 return suiteClass((TestClass(methodname),)), message
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000040
Ezio Melottieae2b382013-03-01 14:47:50 +020041def _make_skipped_test(methodname, exception, suiteClass):
42 @case.skip(str(exception))
43 def testSkipped(self):
44 pass
45 attrs = {methodname: testSkipped}
46 TestClass = type("ModuleSkipped", (case.TestCase,), attrs)
47 return suiteClass((TestClass(methodname),))
48
Michael Foorde01c62c2012-03-13 00:09:54 -070049def _jython_aware_splitext(path):
50 if path.lower().endswith('$py.class'):
51 return path[:-9]
52 return os.path.splitext(path)[0]
53
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000054
Benjamin Petersonbed7d042009-07-19 21:01:52 +000055class TestLoader(object):
56 """
57 This class is responsible for loading tests according to various criteria
58 and returning them wrapped in a TestSuite
59 """
60 testMethodPrefix = 'test'
61 sortTestMethodsUsing = staticmethod(util.three_way_cmp)
62 suiteClass = suite.TestSuite
63 _top_level_dir = None
64
Robert Collinsf920c212014-10-20 13:24:05 +130065 def __init__(self):
66 super(TestLoader, self).__init__()
67 self.errors = []
Robert Collinsbf2bda32014-11-05 03:09:01 +130068 # Tracks packages which we have called into via load_tests, to
69 # avoid infinite re-entrancy.
70 self._loading_packages = set()
Robert Collinsf920c212014-10-20 13:24:05 +130071
Benjamin Petersonbed7d042009-07-19 21:01:52 +000072 def loadTestsFromTestCase(self, testCaseClass):
73 """Return a suite of all tests cases contained in testCaseClass"""
74 if issubclass(testCaseClass, suite.TestSuite):
Michael Foorde28bb152013-11-23 13:29:23 +000075 raise TypeError("Test cases should not be derived from "
76 "TestSuite. Maybe you meant to derive from "
77 "TestCase?")
Benjamin Petersonbed7d042009-07-19 21:01:52 +000078 testCaseNames = self.getTestCaseNames(testCaseClass)
79 if not testCaseNames and hasattr(testCaseClass, 'runTest'):
80 testCaseNames = ['runTest']
81 loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
82 return loaded_suite
83
Barry Warsawd78742a2014-09-08 14:21:37 -040084 # XXX After Python 3.5, remove backward compatibility hacks for
85 # use_load_tests deprecation via *args and **kws. See issue 16662.
86 def loadTestsFromModule(self, module, *args, pattern=None, **kws):
Benjamin Petersonbed7d042009-07-19 21:01:52 +000087 """Return a suite of all tests cases contained in the given module"""
Barry Warsawd78742a2014-09-08 14:21:37 -040088 # This method used to take an undocumented and unofficial
89 # use_load_tests argument. For backward compatibility, we still
90 # accept the argument (which can also be the first position) but we
91 # ignore it and issue a deprecation warning if it's present.
Barry Warsawbb1e3f12014-09-08 17:29:02 -040092 if len(args) > 0 or 'use_load_tests' in kws:
Barry Warsawd78742a2014-09-08 14:21:37 -040093 warnings.warn('use_load_tests is deprecated and ignored',
94 DeprecationWarning)
95 kws.pop('use_load_tests', None)
96 if len(args) > 1:
Barry Warsawbb1e3f12014-09-08 17:29:02 -040097 # Complain about the number of arguments, but don't forget the
98 # required `module` argument.
99 complaint = len(args) + 1
100 raise TypeError('loadTestsFromModule() takes 1 positional argument but {} were given'.format(complaint))
Barry Warsawd78742a2014-09-08 14:21:37 -0400101 if len(kws) != 0:
102 # Since the keyword arguments are unsorted (see PEP 468), just
103 # pick the alphabetically sorted first argument to complain about,
104 # if multiple were given. At least the error message will be
105 # predictable.
106 complaint = sorted(kws)[0]
107 raise TypeError("loadTestsFromModule() got an unexpected keyword argument '{}'".format(complaint))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000108 tests = []
109 for name in dir(module):
110 obj = getattr(module, name)
111 if isinstance(obj, type) and issubclass(obj, case.TestCase):
112 tests.append(self.loadTestsFromTestCase(obj))
113
114 load_tests = getattr(module, 'load_tests', None)
Michael Foord41647d62010-02-06 00:26:13 +0000115 tests = self.suiteClass(tests)
Barry Warsawd78742a2014-09-08 14:21:37 -0400116 if load_tests is not None:
Benjamin Peterson886af962010-03-21 23:13:07 +0000117 try:
Barry Warsawd78742a2014-09-08 14:21:37 -0400118 return load_tests(self, tests, pattern)
Benjamin Peterson886af962010-03-21 23:13:07 +0000119 except Exception as e:
Robert Collinsf920c212014-10-20 13:24:05 +1300120 error_case, error_message = _make_failed_load_tests(
121 module.__name__, e, self.suiteClass)
122 self.errors.append(error_message)
123 return error_case
Michael Foord41647d62010-02-06 00:26:13 +0000124 return tests
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000125
126 def loadTestsFromName(self, name, module=None):
127 """Return a suite of all tests cases given a string specifier.
128
129 The name may resolve either to a module, a test case class, a
130 test method within a test case class, or a callable object which
131 returns a TestCase or TestSuite instance.
132
133 The method optionally resolves the names relative to a given module.
134 """
135 parts = name.split('.')
Robert Collins659dd622014-10-30 08:27:27 +1300136 error_case, error_message = None, None
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000137 if module is None:
138 parts_copy = parts[:]
139 while parts_copy:
140 try:
Robert Collins659dd622014-10-30 08:27:27 +1300141 module_name = '.'.join(parts_copy)
142 module = __import__(module_name)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000143 break
144 except ImportError:
Robert Collins659dd622014-10-30 08:27:27 +1300145 next_attribute = parts_copy.pop()
146 # Last error so we can give it to the user if needed.
147 error_case, error_message = _make_failed_import_test(
148 next_attribute, self.suiteClass)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000149 if not parts_copy:
Robert Collins659dd622014-10-30 08:27:27 +1300150 # Even the top level import failed: report that error.
151 self.errors.append(error_message)
152 return error_case
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000153 parts = parts[1:]
154 obj = module
155 for part in parts:
Robert Collins659dd622014-10-30 08:27:27 +1300156 try:
157 parent, obj = obj, getattr(obj, part)
158 except AttributeError as e:
159 # We can't traverse some part of the name.
160 if (getattr(obj, '__path__', None) is not None
161 and error_case is not None):
162 # This is a package (no __path__ per importlib docs), and we
163 # encountered an error importing something. We cannot tell
164 # the difference between package.WrongNameTestClass and
165 # package.wrong_module_name so we just report the
166 # ImportError - it is more informative.
167 self.errors.append(error_message)
168 return error_case
169 else:
170 # Otherwise, we signal that an AttributeError has occurred.
171 error_case, error_message = _make_failed_test(
172 'AttributeError', part, e, self.suiteClass,
173 'Failed to access attribute:\n%s' % (
174 traceback.format_exc(),))
175 self.errors.append(error_message)
176 return error_case
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000177
178 if isinstance(obj, types.ModuleType):
179 return self.loadTestsFromModule(obj)
180 elif isinstance(obj, type) and issubclass(obj, case.TestCase):
181 return self.loadTestsFromTestCase(obj)
182 elif (isinstance(obj, types.FunctionType) and
183 isinstance(parent, type) and
184 issubclass(parent, case.TestCase)):
R David Murray5e2f5932013-04-11 08:55:45 -0400185 name = parts[-1]
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000186 inst = parent(name)
187 # static methods follow a different path
188 if not isinstance(getattr(inst, name), types.FunctionType):
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000189 return self.suiteClass([inst])
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000190 elif isinstance(obj, suite.TestSuite):
191 return obj
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200192 if callable(obj):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000193 test = obj()
194 if isinstance(test, suite.TestSuite):
195 return test
196 elif isinstance(test, case.TestCase):
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000197 return self.suiteClass([test])
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000198 else:
199 raise TypeError("calling %s returned %s, not a test" %
200 (obj, test))
201 else:
202 raise TypeError("don't know how to make test from: %s" % obj)
203
204 def loadTestsFromNames(self, names, module=None):
205 """Return a suite of all tests cases found using the given sequence
206 of string specifiers. See 'loadTestsFromName()'.
207 """
208 suites = [self.loadTestsFromName(name, module) for name in names]
209 return self.suiteClass(suites)
210
211 def getTestCaseNames(self, testCaseClass):
212 """Return a sorted sequence of method names found within testCaseClass
213 """
214 def isTestMethod(attrname, testCaseClass=testCaseClass,
215 prefix=self.testMethodPrefix):
216 return attrname.startswith(prefix) and \
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200217 callable(getattr(testCaseClass, attrname))
Senthil Kumaranf27be5c2011-11-25 02:08:39 +0800218 testFnNames = list(filter(isTestMethod, dir(testCaseClass)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000219 if self.sortTestMethodsUsing:
Raymond Hettingerc50846a2010-04-05 18:56:31 +0000220 testFnNames.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000221 return testFnNames
222
223 def discover(self, start_dir, pattern='test*.py', top_level_dir=None):
224 """Find and return all test modules from the specified start
Michael Foord6bcfade2010-11-20 17:22:21 +0000225 directory, recursing into subdirectories to find them and return all
226 tests found within them. Only test files that match the pattern will
227 be loaded. (Using shell style pattern matching.)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000228
229 All test modules must be importable from the top level of the project.
230 If the start directory is not the top level directory then the top
231 level directory must be specified separately.
232
233 If a test package name (directory with '__init__.py') matches the
234 pattern then the package will be checked for a 'load_tests' function. If
Robert Collinsbf2bda32014-11-05 03:09:01 +1300235 this exists then it will be called with (loader, tests, pattern) unless
236 the package has already had load_tests called from the same discovery
237 invocation, in which case the package module object is not scanned for
238 tests - this ensures that when a package uses discover to further
239 discover child tests that infinite recursion does not happen.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000240
Robert Collinsbf2bda32014-11-05 03:09:01 +1300241 If load_tests exists then discovery does *not* recurse into the package,
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000242 load_tests is responsible for loading all tests in the package.
243
244 The pattern is deliberately not stored as a loader attribute so that
245 packages can continue discovery themselves. top_level_dir is stored so
246 load_tests does not need to pass this argument in to loader.discover().
Michael Foord80cbc9e2013-03-18 17:50:12 -0700247
248 Paths are sorted before being imported to ensure reproducible execution
249 order even on filesystems with non-alphabetical ordering like ext3/4.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000250 """
Benjamin Petersonb48af542010-04-11 20:43:16 +0000251 set_implicit_top = False
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000252 if top_level_dir is None and self._top_level_dir is not None:
253 # make top_level_dir optional if called from load_tests in a package
254 top_level_dir = self._top_level_dir
255 elif top_level_dir is None:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000256 set_implicit_top = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000257 top_level_dir = start_dir
258
Benjamin Petersonb48af542010-04-11 20:43:16 +0000259 top_level_dir = os.path.abspath(top_level_dir)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000260
261 if not top_level_dir in sys.path:
262 # all test modules must be importable from the top level directory
Michael Foord3b2494f2010-05-07 23:42:40 +0000263 # should we *unconditionally* put the start directory in first
264 # in sys.path to minimise likelihood of conflicts between installed
265 # modules and development versions?
266 sys.path.insert(0, top_level_dir)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000267 self._top_level_dir = top_level_dir
268
Benjamin Petersonb48af542010-04-11 20:43:16 +0000269 is_not_importable = False
Michael Foorde28bb152013-11-23 13:29:23 +0000270 is_namespace = False
271 tests = []
Benjamin Petersonb48af542010-04-11 20:43:16 +0000272 if os.path.isdir(os.path.abspath(start_dir)):
273 start_dir = os.path.abspath(start_dir)
274 if start_dir != top_level_dir:
275 is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py'))
276 else:
277 # support for discovery from dotted module names
278 try:
279 __import__(start_dir)
280 except ImportError:
281 is_not_importable = True
282 else:
283 the_module = sys.modules[start_dir]
284 top_part = start_dir.split('.')[0]
Michael Foorde28bb152013-11-23 13:29:23 +0000285 try:
286 start_dir = os.path.abspath(
287 os.path.dirname((the_module.__file__)))
288 except AttributeError:
289 # look for namespace packages
290 try:
291 spec = the_module.__spec__
292 except AttributeError:
293 spec = None
294
295 if spec and spec.loader is None:
296 if spec.submodule_search_locations is not None:
297 is_namespace = True
298
299 for path in the_module.__path__:
300 if (not set_implicit_top and
301 not path.startswith(top_level_dir)):
302 continue
303 self._top_level_dir = \
304 (path.split(the_module.__name__
305 .replace(".", os.path.sep))[0])
306 tests.extend(self._find_tests(path,
307 pattern,
308 namespace=True))
309 elif the_module.__name__ in sys.builtin_module_names:
310 # builtin module
311 raise TypeError('Can not use builtin modules '
312 'as dotted module names') from None
313 else:
314 raise TypeError(
315 'don\'t know how to discover from {!r}'
316 .format(the_module)) from None
317
Benjamin Petersonb48af542010-04-11 20:43:16 +0000318 if set_implicit_top:
Michael Foorde28bb152013-11-23 13:29:23 +0000319 if not is_namespace:
320 self._top_level_dir = \
321 self._get_directory_containing_module(top_part)
322 sys.path.remove(top_level_dir)
323 else:
324 sys.path.remove(top_level_dir)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000325
326 if is_not_importable:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000327 raise ImportError('Start directory is not importable: %r' % start_dir)
328
Michael Foorde28bb152013-11-23 13:29:23 +0000329 if not is_namespace:
330 tests = list(self._find_tests(start_dir, pattern))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000331 return self.suiteClass(tests)
332
Benjamin Petersonb48af542010-04-11 20:43:16 +0000333 def _get_directory_containing_module(self, module_name):
334 module = sys.modules[module_name]
335 full_path = os.path.abspath(module.__file__)
336
337 if os.path.basename(full_path).lower().startswith('__init__.py'):
338 return os.path.dirname(os.path.dirname(full_path))
339 else:
340 # here we have been given a module rather than a package - so
341 # all we can do is search the *same* directory the module is in
342 # should an exception be raised instead
343 return os.path.dirname(full_path)
344
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000345 def _get_name_from_path(self, path):
Robert Collins68b11d12014-11-05 03:43:36 +1300346 if path == self._top_level_dir:
347 return '.'
Michael Foorde01c62c2012-03-13 00:09:54 -0700348 path = _jython_aware_splitext(os.path.normpath(path))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000349
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000350 _relpath = os.path.relpath(path, self._top_level_dir)
351 assert not os.path.isabs(_relpath), "Path must be within the project"
352 assert not _relpath.startswith('..'), "Path must be within the project"
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000353
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000354 name = _relpath.replace(os.path.sep, '.')
355 return name
356
357 def _get_module_from_name(self, name):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000358 __import__(name)
359 return sys.modules[name]
360
Michael Foord4107d312010-06-05 10:45:41 +0000361 def _match_path(self, path, full_path, pattern):
362 # override this method to use alternative matching strategy
363 return fnmatch(path, pattern)
364
Michael Foorde28bb152013-11-23 13:29:23 +0000365 def _find_tests(self, start_dir, pattern, namespace=False):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000366 """Used by discovery. Yields test suites it loads."""
Robert Collinsbf2bda32014-11-05 03:09:01 +1300367 # Handle the __init__ in this package
368 name = self._get_name_from_path(start_dir)
369 # name is '.' when start_dir == top_level_dir (and top_level_dir is by
370 # definition not a package).
371 if name != '.' and name not in self._loading_packages:
372 # name is in self._loading_packages while we have called into
373 # loadTestsFromModule with name.
374 tests, should_recurse = self._find_test_path(
375 start_dir, pattern, namespace)
376 if tests is not None:
377 yield tests
378 if not should_recurse:
379 # Either an error occured, or load_tests was used by the
380 # package.
381 return
382 # Handle the contents.
Michael Foord80cbc9e2013-03-18 17:50:12 -0700383 paths = sorted(os.listdir(start_dir))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000384 for path in paths:
385 full_path = os.path.join(start_dir, path)
Robert Collinsbf2bda32014-11-05 03:09:01 +1300386 tests, should_recurse = self._find_test_path(
387 full_path, pattern, namespace)
388 if tests is not None:
389 yield tests
390 if should_recurse:
391 # we found a package that didn't use load_tests.
Michael Foord4107d312010-06-05 10:45:41 +0000392 name = self._get_name_from_path(full_path)
Robert Collinsbf2bda32014-11-05 03:09:01 +1300393 self._loading_packages.add(name)
Michael Foord4107d312010-06-05 10:45:41 +0000394 try:
Robert Collinsbf2bda32014-11-05 03:09:01 +1300395 yield from self._find_tests(full_path, pattern, namespace)
396 finally:
397 self._loading_packages.discard(name)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000398
Robert Collinsbf2bda32014-11-05 03:09:01 +1300399 def _find_test_path(self, full_path, pattern, namespace=False):
400 """Used by discovery.
401
402 Loads tests from a single file, or a directories' __init__.py when
403 passed the directory.
404
405 Returns a tuple (None_or_tests_from_file, should_recurse).
406 """
407 basename = os.path.basename(full_path)
408 if os.path.isfile(full_path):
409 if not VALID_MODULE_NAME.match(basename):
410 # valid Python identifiers only
411 return None, False
412 if not self._match_path(basename, full_path, pattern):
413 return None, False
414 # if the test file matches, load it
415 name = self._get_name_from_path(full_path)
416 try:
417 module = self._get_module_from_name(name)
418 except case.SkipTest as e:
419 return _make_skipped_test(name, e, self.suiteClass), False
420 except:
421 error_case, error_message = \
422 _make_failed_import_test(name, self.suiteClass)
423 self.errors.append(error_message)
424 return error_case, False
425 else:
426 mod_file = os.path.abspath(
427 getattr(module, '__file__', full_path))
428 realpath = _jython_aware_splitext(
429 os.path.realpath(mod_file))
430 fullpath_noext = _jython_aware_splitext(
431 os.path.realpath(full_path))
432 if realpath.lower() != fullpath_noext.lower():
433 module_dir = os.path.dirname(realpath)
434 mod_name = _jython_aware_splitext(
435 os.path.basename(full_path))
436 expected_dir = os.path.dirname(full_path)
437 msg = ("%r module incorrectly imported from %r. Expected "
438 "%r. Is this module globally installed?")
439 raise ImportError(
440 msg % (mod_name, module_dir, expected_dir))
441 return self.loadTestsFromModule(module, pattern=pattern), False
442 elif os.path.isdir(full_path):
443 if (not namespace and
444 not os.path.isfile(os.path.join(full_path, '__init__.py'))):
445 return None, False
446
447 load_tests = None
448 tests = None
449 name = self._get_name_from_path(full_path)
450 try:
451 package = self._get_module_from_name(name)
452 except case.SkipTest as e:
453 return _make_skipped_test(name, e, self.suiteClass), False
454 except:
455 error_case, error_message = \
456 _make_failed_import_test(name, self.suiteClass)
457 self.errors.append(error_message)
458 return error_case, False
459 else:
460 load_tests = getattr(package, 'load_tests', None)
461 # Mark this package as being in load_tests (possibly ;))
462 self._loading_packages.add(name)
Barry Warsawd78742a2014-09-08 14:21:37 -0400463 try:
Barry Warsawd78742a2014-09-08 14:21:37 -0400464 tests = self.loadTestsFromModule(package, pattern=pattern)
Barry Warsawd78742a2014-09-08 14:21:37 -0400465 if load_tests is not None:
Robert Collinsbf2bda32014-11-05 03:09:01 +1300466 # loadTestsFromModule(package) has loaded tests for us.
467 return tests, False
468 return tests, True
469 finally:
470 self._loading_packages.discard(name)
Barry Warsawd78742a2014-09-08 14:21:37 -0400471
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000472
473defaultTestLoader = TestLoader()
474
475
476def _makeLoader(prefix, sortUsing, suiteClass=None):
477 loader = TestLoader()
478 loader.sortTestMethodsUsing = sortUsing
479 loader.testMethodPrefix = prefix
480 if suiteClass:
481 loader.suiteClass = suiteClass
482 return loader
483
484def getTestCaseNames(testCaseClass, prefix, sortUsing=util.three_way_cmp):
485 return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
486
487def makeSuite(testCaseClass, prefix='test', sortUsing=util.three_way_cmp,
488 suiteClass=suite.TestSuite):
489 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(
490 testCaseClass)
491
492def findTestCases(module, prefix='test', sortUsing=util.three_way_cmp,
493 suiteClass=suite.TestSuite):
494 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(\
495 module)