Python跨多层目录导入模块失败,寻求优雅解决方案
问题描述
项目文件结构
- scraper_backend - jobs - bronze - extract_bronze.py - tests - jobs - bronze - extract_bronze_test.py
导入错误信息
运行测试时触发以下导入错误:
ImportError while importing test module 'D:\School\Academiejaar 3\Semester 2\internship2023-solarstreaming\tests\unit_tests\jobs\bronze\test_extract_bronze.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: C:\Users\david\AppData\Local\Programs\Python\Python310\lib\importlib\__init__.py:126: in import_module return _bootstrap._gcd_import(name[level:], package, level) tests\unit_tests\jobs\bronze\test_extract_bronze.py:4: in <module> from .....scraper_backend.jobs.bronze import extract_bronze E ImportError: attempted relative import with no known parent package ===================================================================================== short test summary info ===================================================================================== ERROR tests/unit_tests/jobs/bronze/test_extract_bronze.py !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ======================================================================================== 1 error in 0.13s =========================================================================================
测试文件导入代码
测试文件中的导入写法如下,两种方式都尝试过但报错:
from datetime import datetime from .....scraper_backend.jobs.bronze import extract_bronze # 出错的相对导入 # 也试过绝对导入 # from scraper_backend.jobs.bronze import extract_bronze def test_extract_energy_happy(): energy_type = "solar" params = { "datetime": datetime.now(), "province": "Antwerp" } date_time = datetime.now() result = extract_bronze.extract_energy(energy_type, params, date_time) assert type(result) != str assert type(result) == float
已知现象
将测试文件移至tests根目录时可正常运行,推测问题源于目录嵌套过深。曾尝试用sys.path手动添加路径,但希望找到更优雅的解决方式。
优雅解决方案
1. 把项目转为可安装包(推荐)
在项目根目录创建pyproject.toml文件,将scraper_backend声明为可安装的Python包:
[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "scraper_backend" version = "0.1.0" packages = ["scraper_backend"]
然后在项目根目录执行命令,以开发模式安装包:
pip install -e .
安装完成后,测试文件里直接使用绝对导入即可:
from scraper_backend.jobs.bronze import extract_bronze
2. 为所有目录添加__init__.py
在scraper_backend、scraper_backend/jobs、scraper_backend/jobs/bronze、tests、tests/jobs、tests/jobs/bronze这些目录下,都创建一个空的__init__.py文件,将它们标记为Python包。
之后从项目根目录运行pytest,此时测试文件中的绝对导入就能正常生效。
3. 配置pytest根目录
在项目根目录创建pytest.ini文件,指定测试路径并将根目录加入Python路径:
[pytest] testpaths = tests pythonpath = .
配置完成后,运行pytest时会自动识别项目根目录,测试文件里的绝对导入from scraper_backend.jobs.bronze import extract_bronze就能正常工作。
内容的提问来源于stack exchange,提问作者david backx
相关产品推荐
相关产品推荐

