python - 在我的包中导入模块的 Python 最佳实践
问题描述
我对 Python 打包路径系统有点困惑(实际上很多)。
我有这个项目:
myproject/
package1/
setup.py
src/
__init__.py
module1.py
module2.py
module3.py
tests/
__init__.py
test_package1.py
package2/
setup.py
src/
__init__.py
module1.py
module2.py
module3.py
tests/
test_package2.py
package3/
setup.py
src/
__init__.py
module1.py
module2.py
module3.py
tests/
test_package3.py
这些包应该在 CI 过程之后发布在私有存储库中(如果测试通过)。
重要提示: Package1 使用 package2,而 package2 使用 package3。
所以setup.py
package1 看起来像这样:
setuptools.setup(
name='package1',
version='1.4.0.dev1',
install_requires=['setuptools~=50.3.2',
'boto3~=1.17.0',
'pandas~=1.3.4',
'package2~=1.4.0.dev1'],
package_dir={"package1": "src"},
packages=["package1"],
include_package_data=True,
setup_requires=['pytest-runner'],
tests_require=['pytest'],
python_requires=">=3.6"
)
setup.py
package2 看起来像这样:
setuptools.setup(
name='package2',
version='1.4.0.dev1',
install_requires=['PyYAML~=5.3.1'
'package3~=1.4.0.dev1'],
package_dir={"package2": "src"},
packages=["package2"],
include_package_data=True,
setup_requires=['pytest-runner'],
tests_require=['pytest'],
python_requires=">=3.6"
)
CI 流程:
- 我正在
pip install .
为每个包运行(来自相应的包目录) - 从 package3 目录运行测试:
python -m pytest tests -vvv
- 从 package2 目录运行测试:
python -m pytest tests -vvv
- 从 package1 目录运行测试:
python -m pytest tests -vvv
package2 和 package3 的测试成功通过,但最后一步 - 为 package1 运行 pytest 时,它ModuleNotFoundError
在 package2 中抱怨:
module1.py(package2):
from module2 import AwsService
...
AwsService
只是一个定义在module2.py
.
我将导入更改为:from . import AwsService
,重新安装包并再次重新运行 package1 测试。这次pytest抱怨package3中的import:
module1.py(package3):
import module2
...
所以我将导入更改为from . import module2
并开始运行测试。
但是在 package2 的 module3 中我有from module2 import AwsService
并且没关系,那么我怎么知道什么时候必须进行相对导入,什么时候不需要呢?!。
我对所有这些路径行为感到完全困惑。
也许我setup.py
的不好或项目结构或我正在测试它的方式?
解决方案
我的问题的解决方案是将 myproject 的路径分配给 PYTHONPATH:
export PYTHONPATH=/Users/yuri/projects/myproject/
当您通过本地安装包pip install .
并执行pip freeze
时,您会看到您的包已安装,但您还会看到您的包附近的路径,路径是这样的:file:///Users/yuri/projects/myproject/package1
作为对原始位置的引用,Python 看不到它。所以你必须手动添加路径。
推荐阅读
- interrupt - STM32 MCU 上 DSP 的中断安全“FIFO”
- javascript - 使用带有 nextjs 的外部 scss 文件
- android - 防止应用覆盖 Android 通知栏
- coordinates - 如何将足球场上的位置转换为矩形上的坐标?
- jquery - 如何使用 font-awesome 类而不是 unicodes 或 .svg 图像进行切换
- c# - 尝试捕获 FormatException
- ibm-odm - IBM ODM 启动错误无法查找名为“jdbc/ilogDataSource”的数据源
- java - 如何将 Listview 中收到的 url 播放到 youtube webview 中?
- react-native - android RN 0.57.1 的 React 本机构建失败
- python - Keras 架构对于保存和加载的模型是不一样的