自定义PIP包本地模块导入:如何兼顾运行、安装与PyTest测试?
自定义PIP包模块间导入的最优解决方案
项目结构
我的自定义PIP包结构如下:
. ├── setup.py ├── src │ ├── __init__.py │ ├── useful_functions_i.py │ ├── useful_functions_ii.py │ └── useful_strings.py └── tests └── unit_tests.py
其中useful_strings.py内容示例:
USEFUL_STRING_A = "useful-string-a" USEFUL_STRING_B = "useful-string-b" ...
useful_functions_i.py和useful_functions_ii.py中的函数示例:
def a_useful_function(a_string): if a_string == useful_strings.USEFUL_STRING_XYZ: return True return False
导入问题
我需要在useful_functions_i.py和useful_functions_ii.py中导入useful_strings,但遇到了以下矛盾:
- 使用
import useful_strings:本地直接运行src内代码正常,但执行pip install .将包安装后使用会抛出异常。 - 使用
from . import useful_strings:作为PIP包使用时正常,但运行PyTest单元测试时出错。我的pytest.ini配置如下:
测试脚本中的导入语句为[pytest] pythonpath = src testpaths = tests ...from src.useful_functions_i import a_useful_function,此时相对导入语法会抛出异常。
我试过一种临时解决方法,但既繁琐重复,又不符合Python风格,还会触发PyLint报错:
if __package__: from . import useful_strings else: import useful_strings
最优解决方案
方案1:使用绝对导入(推荐)
首先在setup.py中明确你的包名(比如my_useful_package),然后在函数文件中使用基于包名的绝对导入:
# 在useful_functions_i.py中 from my_useful_package import useful_strings
或者更精准地导入所需变量:
from my_useful_package.useful_strings import USEFUL_STRING_XYZ
这种方式无论本地运行、安装为包还是执行单元测试都能正常工作,完全符合Python导入规范,也不会触发Lint工具的报错。
方案2:调整测试配置与导入逻辑
如果不想修改包内的导入语句,可以调整测试相关的配置和操作:
- 先以可编辑模式安装包:
pip install -e . - 修改
pytest.ini,移除pythonpath = src这一行; - 测试脚本中的导入改为直接从包名导入:
from my_useful_package.useful_functions_i import a_useful_function
这样from . import useful_strings的相对导入就能在测试和包安装后的场景下都正常运行。
方案3:统一本地运行的模块加载方式
如果需要保留本地直接运行脚本的能力,不要直接执行python src/useful_functions_i.py,而是用模块方式启动:
python -m src.useful_functions_i
这样本地运行时也会以包模块的方式加载代码,相对导入from . import useful_strings就能正常工作。
内容的提问来源于stack exchange,提问作者Tom Hosker
相关产品推荐
相关产品推荐

