使用distutils(setup.py)作为包数据的一部分,是否可以包括子目录?

48

我的Python软件包基本上是这样设置的:

module
\_examples
  \_folder1
     \_file1.py
     \_file2.py
  \_folder2
    \_file1.py
    \_file2.py

基本上我只想使用:

package_data  = { 
            'module': ['examples/*'],
  },

因为我的项目总会有人添加示例代码,我希望能够轻松地从我的应用程序中列出它们。我可以让它适用于 examples 文件夹内的任何文件,但无法递归遍历子目录。这是否可能?

9个回答

54

我相信你要找的是类似于这样的setup.py文件,它会递归地查找项目中的任何包,并确保在每个你想要的包的子目录中包含__init__.py文件。

from setuptools import setup, find_packages

setup(name='MySoftware',
      packages=find_packages()
)

2
要小心,在这里,因为你可能会意外地包含测试目录等,除非你明确地使用 exclude=... 来排除它们。 - Arminius

15
在我的软件包根目录下,我有一个名为setup.py的文件。请查看文档
在这个文件中,我有以下代码:
from setuptools import setup

with open("README.md", "r") as fh:
    long_description = fh.read()

setup(
    name='package name',
    version='0.4.1',
    description='short description',
    long_description=long_description,
    long_description_content_type="text/markdown",
    url='repository url',
    author='My name',
    author_email='my@e.mail',
    license='MIT',
    packages=['PackageName','PackageName.SubModule'],
    zip_safe=False,
    install_requires=[
        'dependecy1',
    ],
    classifiers=[
        'Development Status :: 3 - Alpha',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3.7'
    ]
)

回答这个问题的有趣部分在于:

packages=['PackageName','PackageName.SubModule'],

按照这个语法,您可以将子模块包含到主包发行版中。

有关所有其他参数的更多信息,请参阅文档


在所有的答案中,我认为这是最干净的方式。 - Teshan Shanuka J

7

你需要使用一个MANIFEST.in文件来实现这个功能。

我认为你需要像这样:

$ cat MANIFEST.in
recursive-include examples/ *.py

我认为你也可以直接在setup.py中使用Python函数来查找文件和目录,但是我暂时无法找到确切的答案。 - Jeff Tratner
1
嗯,我得试一下,因为我之前是这样写的: recursive-include examples *.py并没有使用 /。不过我看到 MANIFEST.in 已经被弃用了。我想我可能只能按照 Python 函数调用的方法来做了。 - xamox
2
哦...好吧,如果你找出如何用Python做到这一点,请在这里发布。我想知道。 - David Wolever
1
Manifest.in文件的位置在哪里?谢谢。 - vel

4

是的,您可以包括所有子目录。

您只需要将以下参数传递给setup()函数:

packages=find_packages()

include_package_data=True

除此之外,您需要有一个MANIFEST.in文件,并且其内容应如下:
recursive-include examples *

这可以确保所有文件都被递归地包含。
如果您想要特别排除某些扩展名,可以在find_packages()参数中指定排除数组。
例如:要排除.txt文件。
packages=find_packages(exclude=['.txt'])

您可以在这里了解有关include_package_data的更多信息。
此外,这里还有另一个链接,告诉您何时不应使用include_package_data

3

在类似的情况下,没有任何提供的答案适用于我。

我需要创建一个包含多个子模块的分发包,这些子模块位于子目录中,因此这些文件需要放入 sdist 中:

ipyexperiments/*py
ipyexperiments/utils/*py

无论我尝试了什么方法,子目录utils的模块都没有被包含在sdist中。
对我有效的方法是保留config.py的默认设置:
# config.py
from setuptools import setup, find_packages
[...]
setup(
    packages = find_packages(),
    [...]
)

但是需要在MANIFEST.in文件中添加:

# MANIFEST.in
graft ipyexperiments

包括 ipyexperiments 下的所有内容。

如果你还没有 MANIFEST.in 文件,可以在与 config.py 相同的目录下创建它。

我还添加了到 MANIFEST.in 文件中。

prune tests
global-exclude *.py[co]

要排除所有的tests目录以及任何不需要的*pyc*.pyo文件。


你的 MANIFEST.in 文件应该放在哪里?与 setup.py 文件处于同一级别还是位于你正在创建的包的顶层? - Mason Caiby
1
没错。我修改了回复以反映这一点。谢谢你的提问。 - stason

2
您可以使用find_packages()include参数:
...
setup(name="module",
      packages=find_packages(include=('module*',)),
...

0
根据David Wolever所说,为了更清晰明了,如果您想包含子目录文件夹下的所有内容,则必须在MANIFEST.in中显式指定每个文件。
例如:recursive-include examples/ *.py *.png *.sh等等......
如果manifest.in能够理解examples/并包含所有内容,那就太好了。

现在它支持使用 graft some-dir/ 包含某个路径下的所有文件。 - Nick Sweeting

0

所有其他答案似乎都太复杂了。这个方法适用于9.3.15版本:

package_data  = { 
            'module': ['examples/**'],
  },

请注意使用**代替*。在任何文件夹中都不需要__init__.py

-1

我得到的简单答案是,在设置调用的packages=选项中包含所有目录:

 packages=[“examples”, “examples/_folder1”, “examples/_folder2”]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接