pytest场景下目录名含连字符Python相对导入报错如何解决?
根本原因
Python的包名必须是合法的标识符,仅支持字母、数字、下划线,且不能以数字开头,含连字符的目录无法被识别为标准Python包,因此相对导入机制会触发attempted relative import with no known parent package报错。
解决方案1:动态加载配置文件(无需调整运行参数)
直接通过文件路径加载同目录下的settings.py,绕过包导入规则,代码示例:
import importlib.util from pathlib import Path # 加载同目录下的settings.py spec = importlib.util.spec_from_file_location("settings", Path(__file__).parent / "settings.py") settings = importlib.util.module_from_spec(spec) spec.loader.exec_module(settings) # 把配置变量导入当前命名空间,等效于from settings import * globals().update(vars(settings)) def test_port(host): assert host.socket(f"tcp://127.0.0.1:{ PORT }").is_listening
解决方案2:将当前测试目录加入Python导入路径
在测试文件开头先把当前文件所在目录加入sys.path,之后直接导入settings即可,无需使用相对导入:
import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.resolve())) from settings import * def test_port(host): assert host.socket(f"tcp://127.0.0.1:{ PORT }").is_listening
如果要全局生效,无需修改每个测试文件,可以在pytest配置文件pytest.ini中添加如下配置:
[pytest] pythonpath = .
解决方案3:使用pytest conftest共享配置(最推荐)
pytest会自动加载测试目录下的conftest.py文件,不受目录名格式限制,你可以把配置都放到conftest中,不需要任何导入操作:
- 在测试目录下新建
conftest.py,写入配置:
import pytest # 用fixture方式共享配置 @pytest.fixture(scope="session") def app_port(): return 8080 # 也可以直接定义全局变量 PORT = 8080
- 测试用例直接引用即可:
# 用法1:直接使用fixture def test_port(host, app_port): assert host.socket(f"tcp://127.0.0.1:{ app_port }").is_listening # 用法2:直接从conftest导入变量 from conftest import PORT def test_port(host): assert host.socket(f"tcp://127.0.0.1:{ PORT }").is_listening
内容的提问来源于stack exchange,提问作者George Shuklin
相关产品推荐
相关产品推荐

