我正在尝试将一个小型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
文件。即,当我安装到venv
并查看venv
的Lib/site-packages
目录时,我只看到一个名为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
参数并不意味着"除了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
将在源代码发行版中被省略,有效地从tar存档中的PackageA
中删除包属性,现在它将是一个常规目录。运行pip install mydist.tar.gz
将找不到PackageA
,因此PackageA.PackageB
也找不到。因此,不会安装任何东西。setuptools
文档中的自动包发现部分简短地提到了find_packages()
的include
和exclude
参数,但在我看来,更有用的是函数的docstring:
>>> 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'.