我正在使用 setuptools 制作一个 python 包,但在安装包后无法使源代码中的所有嵌套文件夹可供导入。我正在工作的目录具有如下所示的结构。
├── setup.py
└── src
└── foo
├── a
│ ├── aa
│ │ └── aafile.py
│ └── afile.py
├── b
│ └── bfile.py
└── __init__.py
目前,我无法导入子模块,例如
from foo.a import aa
或 from foo.a.aa import some_method
,除非我明确地将子模块的名称传递给 setuptools。也就是说,setup.py 需要包含类似的内容
from setuptools import setup
setup(
version="0.0.1",
name="foo",
py_modules=["foo", "foo.a", "foo.a.a", "foo.b"],
package_dir={"": "src"},
packages=["foo", "foo.a", "foo.a.a", "foo.b"],
include_package_data=True,
# more arguments go here
)
这使得组织代码变得相当麻烦。有没有一种简单的方法来允许包的用户安装 src/foo 中包含的任何子模块?
setuptools.find_packages()
——尽管总而言之,你可能想考虑完全放弃 setup.py
,转而支持 PEP 517 风格的构建,没有任意的 Python ,而只是 pyproject.toml
(可能还有 setup.cfg
) ).
from setuptools import setup, find_packages
setup(
version="0.0.1",
name="foo",
package_dir={"": "src"},
packages=find_packages(where='src'),
include_package_data=True,
)
每个包/子包必须包含一个(至少为空)
__init__.py
文件才能被视为如此。
如果您希望仅使用一个
import foo
导入整个包和子包树,请考虑使用相关子包的导入来填充您的 __init__.py
文件。
# src/foo/__init__.py
import foo.a
import foo.b
# src/foo/a/__init__.py
import foo.a.aa
# src/foo/b/__init__.py
import foo.b.bb
否则将
__init__.py
文件留空,用户将需要手动加载他想要的子包/子模块。
使用 setup.py 是合法的,并且不被弃用,正如评论中错误建议的那样。
同样,正确的解决方案与提出的答案不同。第一个答案找不到任何东西,因为顶部模块是命名空间包。
正确的方法是正确注释模块、命名空间包、数据文件并使用正确的工具进行包发现或遵守受支持的布局,例如“src”。
考虑这个结构(修复:添加缺失的
__init__.py
来注释 aa
模块)。
📦tmp
┣ 📂src
┃ ┗ 📂foo
┃ ┃ ┣ 📂a
┃ ┃ ┃ ┣ 📂aa
┃ ┃ ┃ ┃ ┣ 📜__init__.py
┃ ┃ ┃ ┃ ┗ 📜aa_file.py
┃ ┃ ┃ ┗ 📜afile.py
┃ ┃ ┗ 📂b
┃ ┃ ┃ ┣ 📜__init__.py
┃ ┃ ┃ ┣ 📜bfile.py
┃ ┃ ┃ ┗ 📜config.yaml
┗ 📜setup.py
请注意,
foo
和foo/a
都是命名空间包,并且不会被find_packages
找到。请注意,我还添加了配置文件作为基本非 Pythonic 文件的示例。这是正确的安装设置:
# setup.py
from setuptools import setup, find_packages, find_namespace_packages
setup(name='proper-package',
version='0.1',
description='A demo showing a proper setup for a complex package.',
packages = find_namespace_packages(where="src"), # NOTE: better than <find_packages> which ignores namespace packages and their nested modules!
package_dir={'':'src'},
include_package_data=True,
package_data={"": ["*.yaml"]}, # NOTE: use this for non-pythonic files needed, such as configs, demo data etc...
)
从
pip install .
目录触发的 project
安装会生成 build
文件夹作为中间步骤,并最终生成 lib/python3.x/site-packages
下的预期内容:
📦foo
┣ 📂a
┃ ┣ 📂__pycache__
┃ ┃ ┗ 📜afile.cpython-310.pyc
┃ ┣ 📂aa
┃ ┃ ┣ 📂__pycache__
┃ ┃ ┃ ┣ 📜__init__.cpython-310.pyc
┃ ┃ ┃ ┗ 📜aa_file.cpython-310.pyc
┃ ┃ ┣ 📜__init__.py
┃ ┃ ┗ 📜aa_file.py
┃ ┗ 📜afile.py
┗ 📂b
┃ ┣ 📂__pycache__
┃ ┃ ┣ 📜__init__.cpython-310.pyc
┃ ┃ ┗ 📜bfile.cpython-310.pyc
┃ ┣ 📜__init__.py
┃ ┣ 📜bfile.py
┃ ┗ 📜config.yaml