Python 在我的包中导入模块的最佳实践
Python best practices for Importing module inside my package
我对 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。
所以 package1 的 setup.py
看起来像这样:
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"
)
package2 的 setup.py
如下所示:
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 目录 运行ning 测试:
python -m pytest tests -vvv
- 来自 package2 目录 运行ning 测试:
python -m pytest tests -vvv
- 来自 package1 目录 运行ning 测试:
python -m pytest tests -vvv
package2 和 package3 的测试成功通过,但最后一步 - 当 运行对 package1 进行 pytest 时,它在 package2 中的 ModuleNotFoundError
上抱怨:
module1.py(包 2):
from module2 import AwsService
...
AwsService
只是 module2.py
.
中定义的 class
我将导入更改为:from . import AwsService
,重新安装包并重新运行 package1 再次测试。这次pytest报错import in package3:
module1.py(包 3):
import module2
...
所以我将导入更改为 from . import module2
并开始测试 运行。
但是在 package2 的模块 3 中我有 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 看不到它。所以你必须手动添加路径。
我对 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。
所以 package1 的 setup.py
看起来像这样:
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"
)
package2 的 setup.py
如下所示:
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 目录 运行ning 测试:
python -m pytest tests -vvv
- 来自 package2 目录 运行ning 测试:
python -m pytest tests -vvv
- 来自 package1 目录 运行ning 测试:
python -m pytest tests -vvv
package2 和 package3 的测试成功通过,但最后一步 - 当 运行对 package1 进行 pytest 时,它在 package2 中的 ModuleNotFoundError
上抱怨:
module1.py(包 2):
from module2 import AwsService
...
AwsService
只是 module2.py
.
我将导入更改为:from . import AwsService
,重新安装包并重新运行 package1 再次测试。这次pytest报错import in package3:
module1.py(包 3):
import module2
...
所以我将导入更改为 from . import module2
并开始测试 运行。
但是在 package2 的模块 3 中我有 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 看不到它。所以你必须手动添加路径。