blob: d936a96e73fbc77a8e0e9108ce898010aae3aa6d [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
Jonas Haag5b48dc62017-11-25 16:23:52 +010011from fnmatch import fnmatch, fnmatchcase
Benjamin Petersonbed7d042009-07-19 21:01:52 +000012
13from . import case, suite, util
14
Benjamin Petersondccc1fc2010-03-22 00:15:53 +000015__unittest = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +000016
Brett Cannonf299abd2015-04-13 14:21:02 -040017# what about .pyc (etc)
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000018# we would need to avoid loading the same tests multiple times
Brett Cannonf299abd2015-04-13 14:21:02 -040019# from '.py', *and* '.pyc'
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000020VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE)
21
22
Antoine Pitroud8337792015-03-18 23:56:46 +010023class _FailedTest(case.TestCase):
24 _testMethodName = None
25
26 def __init__(self, method_name, exception):
27 self._exception = exception
28 super(_FailedTest, self).__init__(method_name)
29
30 def __getattr__(self, name):
31 if name != self._testMethodName:
32 return super(_FailedTest, self).__getattr__(name)
33 def testFailure():
34 raise self._exception
35 return testFailure
36
37
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000038def _make_failed_import_test(name, suiteClass):
Robert Collinsf920c212014-10-20 13:24:05 +130039 message = 'Failed to import test module: %s\n%s' % (
40 name, traceback.format_exc())
Antoine Pitrou8eef6a92015-03-19 00:01:37 +010041 return _make_failed_test(name, ImportError(message), suiteClass, message)
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000042
Benjamin Peterson886af962010-03-21 23:13:07 +000043def _make_failed_load_tests(name, exception, suiteClass):
Robert Collinsf920c212014-10-20 13:24:05 +130044 message = 'Failed to call load_tests:\n%s' % (traceback.format_exc(),)
45 return _make_failed_test(
Antoine Pitrou8eef6a92015-03-19 00:01:37 +010046 name, exception, suiteClass, message)
Benjamin Peterson886af962010-03-21 23:13:07 +000047
Antoine Pitrou8eef6a92015-03-19 00:01:37 +010048def _make_failed_test(methodname, exception, suiteClass, message):
Antoine Pitroud8337792015-03-18 23:56:46 +010049 test = _FailedTest(methodname, exception)
Antoine Pitrou8eef6a92015-03-19 00:01:37 +010050 return suiteClass((test,)), message
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000051
Ezio Melottieae2b382013-03-01 14:47:50 +020052def _make_skipped_test(methodname, exception, suiteClass):
53 @case.skip(str(exception))
54 def testSkipped(self):
55 pass
56 attrs = {methodname: testSkipped}
57 TestClass = type("ModuleSkipped", (case.TestCase,), attrs)
58 return suiteClass((TestClass(methodname),))
59
Michael Foorde01c62c2012-03-13 00:09:54 -070060def _jython_aware_splitext(path):
61 if path.lower().endswith('$py.class'):
62 return path[:-9]
63 return os.path.splitext(path)[0]
64
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000065
Benjamin Petersonbed7d042009-07-19 21:01:52 +000066class TestLoader(object):
67 """
68 This class is responsible for loading tests according to various criteria
69 and returning them wrapped in a TestSuite
70 """
71 testMethodPrefix = 'test'
72 sortTestMethodsUsing = staticmethod(util.three_way_cmp)
Jonas Haag5b48dc62017-11-25 16:23:52 +010073 testNamePatterns = None
Benjamin Petersonbed7d042009-07-19 21:01:52 +000074 suiteClass = suite.TestSuite
75 _top_level_dir = None
76
Robert Collinsf920c212014-10-20 13:24:05 +130077 def __init__(self):
78 super(TestLoader, self).__init__()
79 self.errors = []
Robert Collinsbf2bda32014-11-05 03:09:01 +130080 # Tracks packages which we have called into via load_tests, to
81 # avoid infinite re-entrancy.
82 self._loading_packages = set()
Robert Collinsf920c212014-10-20 13:24:05 +130083
Benjamin Petersonbed7d042009-07-19 21:01:52 +000084 def loadTestsFromTestCase(self, testCaseClass):
Martin Panter37f183d2017-01-18 12:06:38 +000085 """Return a suite of all test cases contained in testCaseClass"""
Benjamin Petersonbed7d042009-07-19 21:01:52 +000086 if issubclass(testCaseClass, suite.TestSuite):
Michael Foorde28bb152013-11-23 13:29:23 +000087 raise TypeError("Test cases should not be derived from "
88 "TestSuite. Maybe you meant to derive from "
89 "TestCase?")
Benjamin Petersonbed7d042009-07-19 21:01:52 +000090 testCaseNames = self.getTestCaseNames(testCaseClass)
91 if not testCaseNames and hasattr(testCaseClass, 'runTest'):
92 testCaseNames = ['runTest']
93 loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
94 return loaded_suite
95
Barry Warsawd78742a2014-09-08 14:21:37 -040096 # XXX After Python 3.5, remove backward compatibility hacks for
97 # use_load_tests deprecation via *args and **kws. See issue 16662.
98 def loadTestsFromModule(self, module, *args, pattern=None, **kws):
Martin Panter37f183d2017-01-18 12:06:38 +000099 """Return a suite of all test cases contained in the given module"""
Barry Warsawd78742a2014-09-08 14:21:37 -0400100 # This method used to take an undocumented and unofficial
101 # use_load_tests argument. For backward compatibility, we still
102 # accept the argument (which can also be the first position) but we
103 # ignore it and issue a deprecation warning if it's present.
Barry Warsawbb1e3f12014-09-08 17:29:02 -0400104 if len(args) > 0 or 'use_load_tests' in kws:
Barry Warsawd78742a2014-09-08 14:21:37 -0400105 warnings.warn('use_load_tests is deprecated and ignored',
106 DeprecationWarning)
107 kws.pop('use_load_tests', None)
108 if len(args) > 1:
Barry Warsawbb1e3f12014-09-08 17:29:02 -0400109 # Complain about the number of arguments, but don't forget the
110 # required `module` argument.
111 complaint = len(args) + 1
112 raise TypeError('loadTestsFromModule() takes 1 positional argument but {} were given'.format(complaint))
Barry Warsawd78742a2014-09-08 14:21:37 -0400113 if len(kws) != 0:
114 # Since the keyword arguments are unsorted (see PEP 468), just
115 # pick the alphabetically sorted first argument to complain about,
116 # if multiple were given. At least the error message will be
117 # predictable.
118 complaint = sorted(kws)[0]
119 raise TypeError("loadTestsFromModule() got an unexpected keyword argument '{}'".format(complaint))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000120 tests = []
121 for name in dir(module):
122 obj = getattr(module, name)
123 if isinstance(obj, type) and issubclass(obj, case.TestCase):
124 tests.append(self.loadTestsFromTestCase(obj))
125
126 load_tests = getattr(module, 'load_tests', None)
Michael Foord41647d62010-02-06 00:26:13 +0000127 tests = self.suiteClass(tests)
Barry Warsawd78742a2014-09-08 14:21:37 -0400128 if load_tests is not None:
Benjamin Peterson886af962010-03-21 23:13:07 +0000129 try:
Barry Warsawd78742a2014-09-08 14:21:37 -0400130 return load_tests(self, tests, pattern)
Benjamin Peterson886af962010-03-21 23:13:07 +0000131 except Exception as e:
Robert Collinsf920c212014-10-20 13:24:05 +1300132 error_case, error_message = _make_failed_load_tests(
133 module.__name__, e, self.suiteClass)
134 self.errors.append(error_message)
135 return error_case
Michael Foord41647d62010-02-06 00:26:13 +0000136 return tests
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000137
138 def loadTestsFromName(self, name, module=None):
Martin Panter37f183d2017-01-18 12:06:38 +0000139 """Return a suite of all test cases given a string specifier.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000140
141 The name may resolve either to a module, a test case class, a
142 test method within a test case class, or a callable object which
143 returns a TestCase or TestSuite instance.
144
145 The method optionally resolves the names relative to a given module.
146 """
147 parts = name.split('.')
Robert Collins659dd622014-10-30 08:27:27 +1300148 error_case, error_message = None, None
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000149 if module is None:
150 parts_copy = parts[:]
151 while parts_copy:
152 try:
Robert Collins659dd622014-10-30 08:27:27 +1300153 module_name = '.'.join(parts_copy)
154 module = __import__(module_name)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000155 break
156 except ImportError:
Robert Collins659dd622014-10-30 08:27:27 +1300157 next_attribute = parts_copy.pop()
158 # Last error so we can give it to the user if needed.
159 error_case, error_message = _make_failed_import_test(
160 next_attribute, self.suiteClass)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000161 if not parts_copy:
Robert Collins659dd622014-10-30 08:27:27 +1300162 # Even the top level import failed: report that error.
163 self.errors.append(error_message)
164 return error_case
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000165 parts = parts[1:]
166 obj = module
167 for part in parts:
Robert Collins659dd622014-10-30 08:27:27 +1300168 try:
169 parent, obj = obj, getattr(obj, part)
170 except AttributeError as e:
171 # We can't traverse some part of the name.
172 if (getattr(obj, '__path__', None) is not None
173 and error_case is not None):
174 # This is a package (no __path__ per importlib docs), and we
175 # encountered an error importing something. We cannot tell
176 # the difference between package.WrongNameTestClass and
177 # package.wrong_module_name so we just report the
178 # ImportError - it is more informative.
179 self.errors.append(error_message)
180 return error_case
181 else:
182 # Otherwise, we signal that an AttributeError has occurred.
183 error_case, error_message = _make_failed_test(
Antoine Pitrou8eef6a92015-03-19 00:01:37 +0100184 part, e, self.suiteClass,
Robert Collins659dd622014-10-30 08:27:27 +1300185 'Failed to access attribute:\n%s' % (
186 traceback.format_exc(),))
187 self.errors.append(error_message)
188 return error_case
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000189
190 if isinstance(obj, types.ModuleType):
191 return self.loadTestsFromModule(obj)
192 elif isinstance(obj, type) and issubclass(obj, case.TestCase):
193 return self.loadTestsFromTestCase(obj)
194 elif (isinstance(obj, types.FunctionType) and
195 isinstance(parent, type) and
196 issubclass(parent, case.TestCase)):
R David Murray5e2f5932013-04-11 08:55:45 -0400197 name = parts[-1]
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000198 inst = parent(name)
199 # static methods follow a different path
200 if not isinstance(getattr(inst, name), types.FunctionType):
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000201 return self.suiteClass([inst])
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000202 elif isinstance(obj, suite.TestSuite):
203 return obj
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200204 if callable(obj):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000205 test = obj()
206 if isinstance(test, suite.TestSuite):
207 return test
208 elif isinstance(test, case.TestCase):
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000209 return self.suiteClass([test])
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000210 else:
211 raise TypeError("calling %s returned %s, not a test" %
212 (obj, test))
213 else:
214 raise TypeError("don't know how to make test from: %s" % obj)
215
216 def loadTestsFromNames(self, names, module=None):
Martin Panter37f183d2017-01-18 12:06:38 +0000217 """Return a suite of all test cases found using the given sequence
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000218 of string specifiers. See 'loadTestsFromName()'.
219 """
220 suites = [self.loadTestsFromName(name, module) for name in names]
221 return self.suiteClass(suites)
222
223 def getTestCaseNames(self, testCaseClass):
224 """Return a sorted sequence of method names found within testCaseClass
225 """
Jonas Haag5b48dc62017-11-25 16:23:52 +0100226 def shouldIncludeMethod(attrname):
Jonas Haag4d193bc2017-11-28 20:40:44 +0100227 if not attrname.startswith(self.testMethodPrefix):
228 return False
Jonas Haag5b48dc62017-11-25 16:23:52 +0100229 testFunc = getattr(testCaseClass, attrname)
Jonas Haag4d193bc2017-11-28 20:40:44 +0100230 if not callable(testFunc):
Jonas Haag5b48dc62017-11-25 16:23:52 +0100231 return False
232 fullName = '%s.%s' % (testCaseClass.__module__, testFunc.__qualname__)
233 return self.testNamePatterns is None or \
234 any(fnmatchcase(fullName, pattern) for pattern in self.testNamePatterns)
235 testFnNames = list(filter(shouldIncludeMethod, dir(testCaseClass)))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000236 if self.sortTestMethodsUsing:
Raymond Hettingerc50846a2010-04-05 18:56:31 +0000237 testFnNames.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000238 return testFnNames
239
240 def discover(self, start_dir, pattern='test*.py', top_level_dir=None):
241 """Find and return all test modules from the specified start
Michael Foord6bcfade2010-11-20 17:22:21 +0000242 directory, recursing into subdirectories to find them and return all
243 tests found within them. Only test files that match the pattern will
244 be loaded. (Using shell style pattern matching.)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000245
246 All test modules must be importable from the top level of the project.
247 If the start directory is not the top level directory then the top
248 level directory must be specified separately.
249
250 If a test package name (directory with '__init__.py') matches the
251 pattern then the package will be checked for a 'load_tests' function. If
Robert Collinsbf2bda32014-11-05 03:09:01 +1300252 this exists then it will be called with (loader, tests, pattern) unless
253 the package has already had load_tests called from the same discovery
254 invocation, in which case the package module object is not scanned for
255 tests - this ensures that when a package uses discover to further
256 discover child tests that infinite recursion does not happen.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000257
Robert Collinsbf2bda32014-11-05 03:09:01 +1300258 If load_tests exists then discovery does *not* recurse into the package,
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000259 load_tests is responsible for loading all tests in the package.
260
261 The pattern is deliberately not stored as a loader attribute so that
262 packages can continue discovery themselves. top_level_dir is stored so
263 load_tests does not need to pass this argument in to loader.discover().
Michael Foord80cbc9e2013-03-18 17:50:12 -0700264
265 Paths are sorted before being imported to ensure reproducible execution
266 order even on filesystems with non-alphabetical ordering like ext3/4.
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000267 """
Benjamin Petersonb48af542010-04-11 20:43:16 +0000268 set_implicit_top = False
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000269 if top_level_dir is None and self._top_level_dir is not None:
270 # make top_level_dir optional if called from load_tests in a package
271 top_level_dir = self._top_level_dir
272 elif top_level_dir is None:
Benjamin Petersonb48af542010-04-11 20:43:16 +0000273 set_implicit_top = True
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000274 top_level_dir = start_dir
275
Benjamin Petersonb48af542010-04-11 20:43:16 +0000276 top_level_dir = os.path.abspath(top_level_dir)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000277
278 if not top_level_dir in sys.path:
279 # all test modules must be importable from the top level directory
Michael Foord3b2494f2010-05-07 23:42:40 +0000280 # should we *unconditionally* put the start directory in first
281 # in sys.path to minimise likelihood of conflicts between installed
282 # modules and development versions?
283 sys.path.insert(0, top_level_dir)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000284 self._top_level_dir = top_level_dir
285
Benjamin Petersonb48af542010-04-11 20:43:16 +0000286 is_not_importable = False
Michael Foorde28bb152013-11-23 13:29:23 +0000287 is_namespace = False
288 tests = []
Benjamin Petersonb48af542010-04-11 20:43:16 +0000289 if os.path.isdir(os.path.abspath(start_dir)):
290 start_dir = os.path.abspath(start_dir)
291 if start_dir != top_level_dir:
292 is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py'))
293 else:
294 # support for discovery from dotted module names
295 try:
296 __import__(start_dir)
297 except ImportError:
298 is_not_importable = True
299 else:
300 the_module = sys.modules[start_dir]
301 top_part = start_dir.split('.')[0]
Michael Foorde28bb152013-11-23 13:29:23 +0000302 try:
303 start_dir = os.path.abspath(
304 os.path.dirname((the_module.__file__)))
305 except AttributeError:
306 # look for namespace packages
307 try:
308 spec = the_module.__spec__
309 except AttributeError:
310 spec = None
311
312 if spec and spec.loader is None:
313 if spec.submodule_search_locations is not None:
314 is_namespace = True
315
316 for path in the_module.__path__:
317 if (not set_implicit_top and
318 not path.startswith(top_level_dir)):
319 continue
320 self._top_level_dir = \
321 (path.split(the_module.__name__
322 .replace(".", os.path.sep))[0])
323 tests.extend(self._find_tests(path,
324 pattern,
325 namespace=True))
326 elif the_module.__name__ in sys.builtin_module_names:
327 # builtin module
328 raise TypeError('Can not use builtin modules '
329 'as dotted module names') from None
330 else:
331 raise TypeError(
332 'don\'t know how to discover from {!r}'
333 .format(the_module)) from None
334
Benjamin Petersonb48af542010-04-11 20:43:16 +0000335 if set_implicit_top:
Michael Foorde28bb152013-11-23 13:29:23 +0000336 if not is_namespace:
337 self._top_level_dir = \
338 self._get_directory_containing_module(top_part)
339 sys.path.remove(top_level_dir)
340 else:
341 sys.path.remove(top_level_dir)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000342
343 if is_not_importable:
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000344 raise ImportError('Start directory is not importable: %r' % start_dir)
345
Michael Foorde28bb152013-11-23 13:29:23 +0000346 if not is_namespace:
347 tests = list(self._find_tests(start_dir, pattern))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000348 return self.suiteClass(tests)
349
Benjamin Petersonb48af542010-04-11 20:43:16 +0000350 def _get_directory_containing_module(self, module_name):
351 module = sys.modules[module_name]
352 full_path = os.path.abspath(module.__file__)
353
354 if os.path.basename(full_path).lower().startswith('__init__.py'):
355 return os.path.dirname(os.path.dirname(full_path))
356 else:
357 # here we have been given a module rather than a package - so
358 # all we can do is search the *same* directory the module is in
359 # should an exception be raised instead
360 return os.path.dirname(full_path)
361
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000362 def _get_name_from_path(self, path):
Robert Collins68b11d12014-11-05 03:43:36 +1300363 if path == self._top_level_dir:
364 return '.'
Michael Foorde01c62c2012-03-13 00:09:54 -0700365 path = _jython_aware_splitext(os.path.normpath(path))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000366
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000367 _relpath = os.path.relpath(path, self._top_level_dir)
368 assert not os.path.isabs(_relpath), "Path must be within the project"
369 assert not _relpath.startswith('..'), "Path must be within the project"
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000370
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +0000371 name = _relpath.replace(os.path.sep, '.')
372 return name
373
374 def _get_module_from_name(self, name):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000375 __import__(name)
376 return sys.modules[name]
377
Michael Foord4107d312010-06-05 10:45:41 +0000378 def _match_path(self, path, full_path, pattern):
379 # override this method to use alternative matching strategy
380 return fnmatch(path, pattern)
381
Michael Foorde28bb152013-11-23 13:29:23 +0000382 def _find_tests(self, start_dir, pattern, namespace=False):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000383 """Used by discovery. Yields test suites it loads."""
Robert Collinsbf2bda32014-11-05 03:09:01 +1300384 # Handle the __init__ in this package
385 name = self._get_name_from_path(start_dir)
386 # name is '.' when start_dir == top_level_dir (and top_level_dir is by
387 # definition not a package).
388 if name != '.' and name not in self._loading_packages:
389 # name is in self._loading_packages while we have called into
390 # loadTestsFromModule with name.
391 tests, should_recurse = self._find_test_path(
392 start_dir, pattern, namespace)
393 if tests is not None:
394 yield tests
395 if not should_recurse:
Martin Panter46f50722016-05-26 05:35:26 +0000396 # Either an error occurred, or load_tests was used by the
Robert Collinsbf2bda32014-11-05 03:09:01 +1300397 # package.
398 return
399 # Handle the contents.
Michael Foord80cbc9e2013-03-18 17:50:12 -0700400 paths = sorted(os.listdir(start_dir))
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000401 for path in paths:
402 full_path = os.path.join(start_dir, path)
Robert Collinsbf2bda32014-11-05 03:09:01 +1300403 tests, should_recurse = self._find_test_path(
404 full_path, pattern, namespace)
405 if tests is not None:
406 yield tests
407 if should_recurse:
408 # we found a package that didn't use load_tests.
Michael Foord4107d312010-06-05 10:45:41 +0000409 name = self._get_name_from_path(full_path)
Robert Collinsbf2bda32014-11-05 03:09:01 +1300410 self._loading_packages.add(name)
Michael Foord4107d312010-06-05 10:45:41 +0000411 try:
Robert Collinsbf2bda32014-11-05 03:09:01 +1300412 yield from self._find_tests(full_path, pattern, namespace)
413 finally:
414 self._loading_packages.discard(name)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000415
Robert Collinsbf2bda32014-11-05 03:09:01 +1300416 def _find_test_path(self, full_path, pattern, namespace=False):
417 """Used by discovery.
418
419 Loads tests from a single file, or a directories' __init__.py when
420 passed the directory.
421
422 Returns a tuple (None_or_tests_from_file, should_recurse).
423 """
424 basename = os.path.basename(full_path)
425 if os.path.isfile(full_path):
426 if not VALID_MODULE_NAME.match(basename):
427 # valid Python identifiers only
428 return None, False
429 if not self._match_path(basename, full_path, pattern):
430 return None, False
431 # if the test file matches, load it
432 name = self._get_name_from_path(full_path)
433 try:
434 module = self._get_module_from_name(name)
435 except case.SkipTest as e:
436 return _make_skipped_test(name, e, self.suiteClass), False
437 except:
438 error_case, error_message = \
439 _make_failed_import_test(name, self.suiteClass)
440 self.errors.append(error_message)
441 return error_case, False
442 else:
443 mod_file = os.path.abspath(
444 getattr(module, '__file__', full_path))
445 realpath = _jython_aware_splitext(
446 os.path.realpath(mod_file))
447 fullpath_noext = _jython_aware_splitext(
448 os.path.realpath(full_path))
449 if realpath.lower() != fullpath_noext.lower():
450 module_dir = os.path.dirname(realpath)
451 mod_name = _jython_aware_splitext(
452 os.path.basename(full_path))
453 expected_dir = os.path.dirname(full_path)
454 msg = ("%r module incorrectly imported from %r. Expected "
455 "%r. Is this module globally installed?")
456 raise ImportError(
457 msg % (mod_name, module_dir, expected_dir))
458 return self.loadTestsFromModule(module, pattern=pattern), False
459 elif os.path.isdir(full_path):
460 if (not namespace and
461 not os.path.isfile(os.path.join(full_path, '__init__.py'))):
462 return None, False
463
464 load_tests = None
465 tests = None
466 name = self._get_name_from_path(full_path)
467 try:
468 package = self._get_module_from_name(name)
469 except case.SkipTest as e:
470 return _make_skipped_test(name, e, self.suiteClass), False
471 except:
472 error_case, error_message = \
473 _make_failed_import_test(name, self.suiteClass)
474 self.errors.append(error_message)
475 return error_case, False
476 else:
477 load_tests = getattr(package, 'load_tests', None)
478 # Mark this package as being in load_tests (possibly ;))
479 self._loading_packages.add(name)
Barry Warsawd78742a2014-09-08 14:21:37 -0400480 try:
Barry Warsawd78742a2014-09-08 14:21:37 -0400481 tests = self.loadTestsFromModule(package, pattern=pattern)
Barry Warsawd78742a2014-09-08 14:21:37 -0400482 if load_tests is not None:
Robert Collinsbf2bda32014-11-05 03:09:01 +1300483 # loadTestsFromModule(package) has loaded tests for us.
484 return tests, False
485 return tests, True
486 finally:
487 self._loading_packages.discard(name)
Robert Collinsecd53832016-03-15 13:29:17 +1300488 else:
489 return None, False
Barry Warsawd78742a2014-09-08 14:21:37 -0400490
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000491
492defaultTestLoader = TestLoader()
493
494
Jonas Haag5b48dc62017-11-25 16:23:52 +0100495def _makeLoader(prefix, sortUsing, suiteClass=None, testNamePatterns=None):
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000496 loader = TestLoader()
497 loader.sortTestMethodsUsing = sortUsing
498 loader.testMethodPrefix = prefix
Jonas Haag5b48dc62017-11-25 16:23:52 +0100499 loader.testNamePatterns = testNamePatterns
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000500 if suiteClass:
501 loader.suiteClass = suiteClass
502 return loader
503
Jonas Haag5b48dc62017-11-25 16:23:52 +0100504def getTestCaseNames(testCaseClass, prefix, sortUsing=util.three_way_cmp, testNamePatterns=None):
505 return _makeLoader(prefix, sortUsing, testNamePatterns=testNamePatterns).getTestCaseNames(testCaseClass)
Benjamin Petersonbed7d042009-07-19 21:01:52 +0000506
507def makeSuite(testCaseClass, prefix='test', sortUsing=util.three_way_cmp,
508 suiteClass=suite.TestSuite):
509 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(
510 testCaseClass)
511
512def findTestCases(module, prefix='test', sortUsing=util.three_way_cmp,
513 suiteClass=suite.TestSuite):
514 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(\
515 module)