Вот мой макет проекта:
project
+-- package_1
| +-- __init__.py
| +-- module_1.py tests
+-- package_2
| +-- __init__.py
| +-- module_2.py tests
+-- tests
+-- package_1
| +-- __init__.py
| +-- test_module_1.py
+-- package_2
+-- __init__.py
+-- test_module_2.py
test_module_1.py начинается с:
import package_1.module_1
test_module_2.py начинается с:
import package_2.module_2
Запуск python -m unittest discover tests
из каталога проекта выдает ошибки:
EE
======================================================================
ERROR: package_1.test_module_1 (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: package_1.test_module_1
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 434, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 375, in _get_module_from_name
__import__(name)
File "/Users/maggyero/project/tests/package_1/test_module_1.py", line 1, in <module>
import package_1.module_1
ModuleNotFoundError: No module named 'package_1.module_1'
======================================================================
ERROR: package_2.test_module_2 (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: package_2.test_module_2
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 434, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/loader.py", line 375, in _get_module_from_name
__import__(name)
File "/Users/maggyero/project/tests/package_2/test_module_2.py", line 1, in <module>
import package_2.module_2
ModuleNotFoundError: No module named 'package_2.module_2'
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (errors=2)
Добавление import sys; print(sys.modules['package_1'])
в начале test_module_1.py и import sys; print(sys.modules['package_2'])
в начале test_module_2.py, чтобы увидеть, что находится в sys.modules
cache показывает, что package_1 и package_2 из каталога тестов уже были импортированы во время обнаружения теста:
<module 'package_1' from '/Users/maggyero/project/tests/package_1/__init__.py'>
<module 'package_2' from '/Users/maggyero/project/tests/package_2/__init__.py'>
При импорте ранее импортированного пакета повторно используйте тот же кэшированный пакет из sys.modules
, даже еслиsys.path
с тех пор были обновлены.Таким образом, когда выполняются import package_1.module_1
и import package_2.module_2
, сначала package_1 и package_2 из каталога тестов (которые содержат test_module_1 и test_module_2) повторно импортируются вместо package_1 и package_2 из каталога проекта (которые содержат module_1 и module_2), затем module_1 и module_2импортируются, вызывая ModuleNotFoundError
.
Есть ли обходной путь, чтобы избежать того, что пакеты из каталога тестов затеняют пакеты из каталога проекта, кроме переименования?
Обновление (после ответа)
Альтернативное решение для нижеприведенного Лорана Лапорта (он избегает иметь 'package_1'
и 'package_2'
уже в sys.modules
при выполнении import package_1.module_1
и import package_2.module_2
, имея вместо этого 'tests.package_1'
и 'tests.package_2'
, спасибодля изменения каталога верхнего уровня) это обновить sys.path
и перезагрузить пакеты в test_module_1.py:
import importlib
import pathlib
import sys
sys.path.insert(0, pathlib.Path(__file__).resolve().parents[2])
import package_1
importlib.reload(package_1)
import package_1.module_1
и test_module_2.py:
import importlib
import pathlib
import sys
sys.path.insert(0, pathlib.Path(__file__).resolve().parents[2])
import package_2
importlib.reload(package_2)
import package_2.module_2
ЕдинственноеПреимущество этого решения заключается в том, что каталог tests не обязательно должен быть обычным пакетом (то есть с файлом __init__.py).Таким образом, не будет никакого преимущества, когда Unittest разрешит рекурсивное обнаружение пакета пространства имен (на данный момент билет еще открыт: https://bugs.python.org/issue23882).
Предпочтение должно отдаваться решению Лорана Лапорта, как квалификация пакета Лучше различать пакеты с одинаковыми именами, чем , перезагрузка пакета . Другим хорошим решением является переименование пакета (например, переименование package_1 и package_2 из каталога test в test_package_1 и test_package_2).