Bug report
Bug description:
TestLoader.discover() saves self._top_level_dir on entry and restores it at the end of the call (gh-59215), but only when discovery succeeds. If discovery raises, for example because the start directory is not importable, the loader keeps the top-level directory of the failed call. A later discover() on the same loader without an explicit top_level_dir then resolves against it and fails:
import os
import tempfile
import unittest
with tempfile.TemporaryDirectory() as tmp:
tests = os.path.join(tmp, "tests")
os.mkdir(tests)
with open(os.path.join(tests, "test_x.py"), "w") as f:
f.write("import unittest\n"
"class T(unittest.TestCase):\n"
" def test_ok(self): pass\n")
loader = unittest.TestLoader()
try:
loader.discover(os.path.join(tmp, "tset")) # typo, no such directory
except ImportError as e:
print(e)
print(loader._top_level_dir) # .../tset, expected None
print(loader.discover(tests).countTestCases()) # ImportError, expected 1
Start directory is not importable: '/tmp/tmpXXXX/tset'
/tmp/tmpXXXX/tset
Traceback (most recent call last):
...
ImportError: Start directory is not importable: '/tmp/tmpXXXX/tests'
The same second call on a fresh TestLoader finds the test. Since unittest.defaultTestLoader is a module-level instance, one failed discovery through it breaks later discoveries that do not pass top_level_dir.
Restoring _top_level_dir in a finally block would fix this.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Bug report
Bug description:
TestLoader.discover()savesself._top_level_diron entry and restores it at the end of the call (gh-59215), but only when discovery succeeds. If discovery raises, for example because the start directory is not importable, the loader keeps the top-level directory of the failed call. A laterdiscover()on the same loader without an explicittop_level_dirthen resolves against it and fails:The same second call on a fresh
TestLoaderfinds the test. Sinceunittest.defaultTestLoaderis a module-level instance, one failed discovery through it breaks later discoveries that do not passtop_level_dir.Restoring
_top_level_dirin afinallyblock would fix this.CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs