Python: 为什么 pip install 不从 sdist 部署我的代码?

Python: Why does pip install not deploy my code from sdist?

我正在尝试将小型 Python 3.9 应用程序打包到 .tar.gz 软件分发文件(又名“sdist”)中。

我的代码有这样的结构:

my-code
  PackageA
    PackageB
      Module1.py
      __init__.py 
    __init__.py
  setup.py

我的 setup.py 文件如下所示:

from setuptools import find_packages, setup

setup(
    name="my-code",
    version="0.1",
    install_requires=[],
    packages=find_packages(include=["PackageA.PackageB"]),
    include_package_data=True,
    description="My Code"
)


当我 运行 python setup.py sdist --formats=gztar 我成功地得到一个 my-code-0.1.tar.gz 文件,我可以看到它包含我的 .py 个文件。

但是,当我 运行 pip install my-code-0.1.tar.gz 时,似乎 pip 没有编译和部署我的 .py 文件。 IE。当我安装到 venv 并查看 Lib/site-packages 目录中的 venv 时,我只看到一个名为 my_code-0.1-py3.9.egg-info 的目录,而我的代码不在其中。尝试导入或 运行 我在 PackageA.PackageB 中的模块失败。

我的问题是 - 为什么 pip install 没有构建和安装我的代码,我该如何解决这个问题?

TL;DR 因为 find_packages(include=["PackageA.PackageB"]) 会过滤掉父 PackageA,所以它不包含在安装中。只需使用

setup(
    packages=find_packages(),
    ...
)

会好的。

更长的解释是 include arg 并不意味着“除了 find_packages() 发现的内容之外还包含”。它的意思是“只包括 find_packages()include 过滤器列表中找到的包”,所以它只能缩小包的选择范围。比较

的输出
$ python -c "from setuptools import find_packages as f; print(f())"
['PackageA', 'PackageA.PackageB']

$ python -c "from setuptools import find_packages as f; print(f(include=['PackageA.PackageB']))"
['PackageA.PackageB']

由于 PackageA 不包含,PackageA/__init__.py 将在源代码分发中省略,有效地从 PackageA 中删除包 属性 - 在 tar 存档,现在它将是一个常规目录。 运行 pip install mydist.tar.gz 不会再找到 PackageA,因此 PackageA.PackageB 也找不到。因此,不会安装任何东西。 setuptools 文档中的 Automatic package discovery 部分包含对 find_packages()includeexclude 参数的简短提及,但 IMO 更有帮助的是函数的文档字符串:

>>> from setuptools import find_packages
>>> help(find_packages)
find(where='.', exclude=(), include=('*',)) method of builtins.type instance
    Return a list all Python packages found within directory 'where'

    ...

    'include' is a sequence of package names to include.  If it's
    specified, only the named packages will be included.  If it's not
    specified, all found packages will be included.  'include' can contain
    shell style wildcard patterns just like 'exclude'.