setuptools 问题 -- 排除包,包含数据文件

27 投票
5 回答
15539 浏览
提问于 2025-04-17 08:37

我对setuptools还比较陌生。看到一些类似的问题让我有点抓狂,因为我按照网上的建议去做,但setuptools的表现却和我想的不一样。

这是我项目的结构:

.
..
package1/
    __init__.py
    abc.py
    ...
tests/
    __init__.py
    test_package1.py
LICENSE
README.md
RELEASE
setup.py

这是我的setup.py文件的内容:

#!/usr/bin/env python
import os
#from distutils.core import setup
from setuptools import setup, find_packages

setup(
    name='package1',
    version='1.1',
    test_suite="tests",
    packages=find_packages(exclude=['tests']),    
    include_package_data=True,
    package_data = {
        '': ['LICENSE', 'README.md5', 'RELEASE']
    },   
)

另外,在我的清单文件中,我有:

include LICENSE
include RELEASE
include README.md

我用以下命令构建tar包:

python setup.py sdist

我想要做到:

  1. tests目录从源代码分发中排除掉;
  2. 把LICENSE、README.md和RELEASE文件放到site-packages目录中,可以放在顶层,也可以放在package1目录里(这两种方式我都可以接受)。

但是,实际发生的情况是:

  1. tests目录仍然出现在生成的tar包中,并且被安装到了site-packages里;
  2. 文件被复制到归档中,但没有安装到包的site-packages目录里。

我现在没有头绪了,有人能告诉我我哪里做错了吗?怎么才能解决这个问题?

5 个回答

6

我试了很多方法,但都没有效果,直到我删除了 build 这个文件夹(我看到有个回答提到 *.egg-info/ 文件夹),然后它终于好了。你也可以用 python setup.py clean --all 这个命令来解决问题。

28

find_packages 这个函数用 fnmatchcase 来过滤掉不需要的包。你可以通过下面的方式来测试你的排除模式是否和包名匹配:

>>> from fnmatch import fnmatchcase
>>> fnmatchcase('my.package.name.tests', 'tests')
False

假设你项目中的所有测试都在包名以 tests 结尾的包里,或者是这些包的子包,那么下面的代码就可以用来排除所有的测试代码:

setup(
    name='package1',
    version='1.1',
    packages=find_packages(exclude=['tests', '*.tests', '*.tests.*']),    
)

如果你还想把 tests 文件夹从源代码分发中排除,可以在 MANIFEST.in 文件中添加以下内容:

recursive-exclude tests *
24

你需要在你的包的根目录下创建一个叫做 MANIFEST.in 的新文件,然后按照以下步骤操作:

  1. 为了控制哪些文件会被打包到你的 tar 文件里,你需要在包的根目录下创建一个叫做 MANIFEST.in 的新文件。比如,你可以使用 MANIFEST.in 文件里的 recursive-exclude 来排除整个目录不被打包。在你的情况下,你需要在 MANIFEST.in 文件中包含:

    recursive-exclude tests *
    
  2. 通常情况下,不会把 README 和其他文件放在 site-packages 目录里,但如果你真的想这样做,那么你需要进入 package1 目录,并为你想要包含的文件创建符号链接:

    cd package1
    ln -s ../LICENSE
    ln -s ../README.md
    ln -s ../RELEASE
    

    然后在你的 setup.py 文件中修改以下这一行:

    package_data = {
        '': ['LICENSE', 'README.md', 'RELEASE']
    

    改成:

    package_data = {
        'package1': ['LICENSE', 'README.md', 'RELEASE']
    

撰写回答