如何使用子包正确打包 Python3 应用程序

How to correctly package Python3 app with subpackages

我有一个包 s3_backend,它包含一个模块 api.py,还有一个子包 util,它本身包含 5 个模块。我想将它打包并上传到 PyPI,这样人们就可以 pip install package 并在顶级包中使用脚本 api、api.py。两个包(s3_backend 和 's3_backend.util')都包含 _init__.py 个文件。

整个项目保存在目录名称project中,结构如下

project
    |- s3_backend (package)
        |- __init__.py
        |- util (package)
            |- __init__.py
            |- module1.py
            |...
            |- module5.py
        |- api.py
    |- setup.py

api.py 本身导入 modules1-4.

在本地,在 project 内,我可以做到 导入 api api.func1()... 没有错误。当我将包上传到 TestPyPI,并将包安装在新目录的 virtualenv 中时,我 运行 遇到了问题,这些问题可以追溯到 api.py 中的导入语句,该语句从 modules1-4子包 s3_backend.util

这一行 从 util 导入模块 1、模块 2、模块 3、模块 4 抛出这个错误 没有模块名称 "util" 当我 运行 这个命令 从 s3_backend 导入实用程序

我可以成功

import s3_backend

help(s3_backend)

显示

api.py
util (package)

我的setup.py内容如下图。在我的 setup.py 中处理子包的正确方法是什么?我是否写错了导入语句?

为了修复,我尝试替换

from util import ...

from .util import ... 

from s3_backend.util import ... 

但是那些在本地引起了问题。

setup.py 的源代码:

# project/setup.py
from distutils.core import setup

setup(
  name='s3_backend',
  version='0.1.7',
  license='MIT',
  description='scripting api for file upload to s3',
  author='SkippyElvis',
  author_email='Skippy@Elvis.com',
  url='https://github.com/jackhwolf/s3_backend',
  keywords=['aws', 's3', 'file upload'],
  packages=['s3_backend', 's3_backend.util'],
  classifiers=[
    'Programming Language :: Python :: 3',
  ],
)

在 api.py 中导入语句:

from util import module1, module2, module3, module4

如果您还需要帮助我,请告诉我。谢谢!

SkippyElvis

您可以尝试使用 setuptools 代替吗? find_packages 函数可以很好地工作,只要你在每个要包含的文件夹中都有一个 init.py 文件。

这是您需要在 setup.py

中使用的内容
# project/setup.py
from setuptools import setup, find_packages

setup(
  name='s3_backend',
  version='0.1.7',
  license='MIT',
  description='scripting api for file upload to s3',
  author='SkippyElvis',
  author_email='Skippy@Elvis.com',
  url='https://github.com/jackhwolf/s3_backend',
  keywords=['aws', 's3', 'file upload'],
  packages=find_packages(),
  classifiers=[
    'Programming Language :: Python :: 3',
  ],
)

否则,您可以编写一个函数来模仿 find_packages。我不建议这样做。

至于您的导入,我提倡使用绝对 root-level 导入。这强制执行两件事:它确保您在内部使用您的库的方式与您的用户使用它的方式相同。此外,它还确保您不会尝试从某个文件夹中测试您的代码,而是通过测试调用它。 "enforces" 的方式就是,您的绝对导入在某些文件夹内不起作用。它需要通过外部 file/function 调用来调用。