首页 > 解决方案 > 在我的包中导入模块的 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.pypackage1 看起来像这样:

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.pypackage2 看起来像这样:

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 流程:

  1. 我正在pip install .为每个包运行(来自相应的包目录)
  2. 从 package3 目录运行测试:python -m pytest tests -vvv
  3. 从 package2 目录运行测试:python -m pytest tests -vvv
  4. 从 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的不好或项目结构或我正在测试它的方式?

标签: pythonpython-3.xpytest

解决方案


我的问题的解决方案是将 myproject 的路径分配给 PYTHONPATH:

export PYTHONPATH=/Users/yuri/projects/myproject/

当您通过本地安装包pip install .并执行pip freeze时,您会看到您的包已安装,但您还会看到您的包附近的路径,路径是这样的:file:///Users/yuri/projects/myproject/package1作为对原始位置的引用,Python 看不到它。所以你必须手动添加路径。


推荐阅读