diff -r f4c6dab59cd8 Lib/unittest/loader.py --- a/Lib/unittest/loader.py Tue Apr 26 17:04:18 2016 +0200 +++ b/Lib/unittest/loader.py Fri Apr 29 09:48:20 2016 +0200 @@ -35,6 +35,14 @@ return testFailure +def ispackage(path): + """Guess whether a path refers to a package directory.""" + if os.path.isdir(path): + for ext in ('.py', '.pyc'): + if os.path.isfile(os.path.join(path, '__init__' + ext)): + return True + return False + def _make_failed_import_test(name, suiteClass): message = 'Failed to import test module: %s\n%s' % ( name, traceback.format_exc()) @@ -283,7 +291,7 @@ if os.path.isdir(os.path.abspath(start_dir)): start_dir = os.path.abspath(start_dir) if start_dir != top_level_dir: - is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py')) + is_not_importable = not ispackage(start_dir) else: # support for discovery from dotted module names try: @@ -451,8 +459,7 @@ msg % (mod_name, module_dir, expected_dir)) return self.loadTestsFromModule(module, pattern=pattern), False elif os.path.isdir(full_path): - if (not namespace and - not os.path.isfile(os.path.join(full_path, '__init__.py'))): + if not namespace and not ispackage(full_path): return None, False load_tests = None diff -r f4c6dab59cd8 Lib/unittest/test/test_discovery.py --- a/Lib/unittest/test/test_discovery.py Tue Apr 26 17:04:18 2016 +0200 +++ b/Lib/unittest/test/test_discovery.py Fri Apr 29 09:48:20 2016 +0200 @@ -409,23 +409,11 @@ self.assertEqual(_find_tests_args, [(start_dir, 'pattern')]) self.assertIn(top_level_dir, sys.path) - def test_discover_start_dir_is_package_calls_package_load_tests(self): - # This test verifies that the package load_tests in a package is indeed - # invoked when the start_dir is a package (and not the top level). - # http://bugs.python.org/issue22457 - - # Test data: we expect the following: - # an isfile to verify the package, then importing and scanning - # as per _find_tests' normal behaviour. - # We expect to see our load_tests hook called once. - vfs = {abspath('/toplevel'): ['startdir'], - abspath('/toplevel/startdir'): ['__init__.py']} + def _discover_start_dir_is_package_calls_package_load_tests(self, vfs): def list_dir(path): - return list(vfs[path]) + return list(self.vfs[path]) self.addCleanup(setattr, os, 'listdir', os.listdir) os.listdir = list_dir - self.addCleanup(setattr, os.path, 'isfile', os.path.isfile) - os.path.isfile = lambda path: path.endswith('.py') self.addCleanup(setattr, os.path, 'isdir', os.path.isdir) os.path.isdir = lambda path: not path.endswith('.py') self.addCleanup(sys.path.remove, abspath('/toplevel')) @@ -454,6 +442,31 @@ self.assertEqual(suite, [['load_tests called startdir']]) + def test_discover_start_dir_is_package_calls_package_load_tests(self): + # This test verifies that the package load_tests in a package is indeed + # invoked when the start_dir is a package (and not the top level). + # http://bugs.python.org/issue22457 + + # Test data: we expect the following: + # an isfile to verify the package, then importing and scanning + # as per _find_tests' normal behaviour. + # We expect to see our load_tests hook called once. + vfs = {abspath('/toplevel'): ['startdir'], + abspath('/toplevel/startdir'): ['__init__.py']} + self.addCleanup(setattr, os.path, 'isfile', os.path.isfile) + os.path.isfile = lambda path: path.endswith('.py') + self._discover_start_dir_is_package_calls_package_load_tests(vfs) + + def test_discover_start_dir_is_package_with_byte_compiled__init__(self): + # This test verifies that the package load_tests in a package is + # invoked when the start_dir is a package with an __init__.pyc file. + # http://bugs.python.org/issue26859 + vfs = {abspath('/toplevel'): ['startdir'], + abspath('/toplevel/startdir'): ['__init__.pyc']} + self.addCleanup(setattr, os.path, 'isfile', os.path.isfile) + os.path.isfile = lambda path: path.endswith('.pyc') + self._discover_start_dir_is_package_calls_package_load_tests(vfs) + def setup_import_issue_tests(self, fakefile): listdir = os.listdir os.listdir = lambda _: [fakefile]