Setuptools.setup的name参数值对结果有何影响?
问题描述
我最近收到了一个由学术实验室的一名研究生编写的Python代码包,它由一个Python脚本和大约六个单文件的Python模块组成,由该脚本使用。所有这些文件(脚本和模块)都位于同一目录中。
我想使用pip
在虚拟环境中安装此代码,所以我尝试为它编写了一个setup.py
文件,这是我以前没有做过的事情。
我使此安装正常工作,并且我对我在setup.py
中输入的大部分内容有一个模糊的理解。
这方面的一个例外是setuptools.setup
函数的name
关键字的值。
根据我找到的文档,这个参数应该是包的名称,但我并没有告诉我它的值最终有多重要。换句话说,此值是仅对人类读者重要,还是实际上影响pip install
或此命令安装的代码的工作方式?
因此,我不知道应该为这个参数赋予什么值,所以我只是想出了一个听起来合理的名称,但没有尝试让它与代码库中的其他名称相匹配。令我惊讶的是,什么也没打破!我的意思是pip
安装完成,没有错误,并且安装的代码在虚拟环境中正确运行。
我做了一些实验,似乎我得出的几乎任何值都是一样的。
为了下面的描述,假设我给name
参数赋值whatever
。那么,据我所知,唯一的效果就是创建了一个名为whatever.egg-info/
的子目录(由pip
创建?)位于与setup.py
文件相同的目录中,并且此子目录包含两个文件,其中包含字符串whatever
。
其中一个文件是whatever.egg-info/PKG-INFO
,它包含行
Name: whatever
另一个是whatever.egg-info/SOURCES.txt
,它列出了几个相对路径,其中包括一些以whatever.egg-info/
开头的路径。
对于name
的值来说,这可能是一个过于简单的打包问题?
问:谁能给我举个简单的例子,setuptools.setup
的name
参数值错误会导致pip install
或安装的代码失败?
解决方案
前言:package将package定义为一个可以包含子模块或递归地包含子程序包的模块。SetupTools等创建的内容通常称为distribution,它可以捆绑一个或多个包(因此参数setup(packages=...)
)。我将在下面的文本中将此含义用于术语包和分发。
参数name
决定如何在整个Python生态系统中标识您的发行版。它与分发的实际布局(即其包)无关,也与这些包中定义的任何模块无关。
The documentation准确指定合法分发名称的定义:
分发的名称。名称字段是分发的主标识符。有效名称仅由ASCII字母和数字、句点、下划线和连字符组成。它必须以字母或数字开头和结尾。分发名称仅限于与以下正则表达式匹配的名称(使用
re.IGNORECASE
运行):^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$
。
(历史:本规范在PEP 566中进行了细化,以与PEP 508中的定义保持一致。在PEP 345之前松散地指定分发名称,不施加任何限制。)
除了上述限制外,还需要考虑其他一些方面:
- 当您打算通过PyPI分发您的分发时,
_
和-
之间没有区别,即hello_world
和hello-world
被视为相同的分发。您还需要确保分发名称尚未在PyPI上使用,否则您将无法上载它(如果它被一个已放弃的项目占用,您可以尝试声明该项目的所有权,以便能够使用该名称;有关详细信息,请参阅PEP 541)。 - 最重要的是,您应该确保发行版名称在您的工作环境中是唯一的,即它不会与其他发行版的名称冲突。假设您已经在虚拟环境中安装了requests项目,并且决定将您的发行版也命名为
requests
。然后,安装您的发行版将删除已有的安装(即相应的包),并且您将无法再访问它。
顶级包名称
上面的第二个要点也适用于您的发行版中顶级包的名称。假设您有以下分布布局:.
├── setup.py
└── testpkg
└── __init__.py
└── a.py
setup.py
包含:
from setuptools import setup
setup(
name='dist-a',
version='1.0',
packages=['testpkg'],
)
__init__.py
和a.py
只是空文件。安装该分发版后,您可以通过导入testpkg
(顶级程序包)来访问它。
name='dist-b'
发行版,但使用相同的packages=['testpkg']
并提供一个模块b.py
(而不是a.py
)。发生的情况是,第二次安装是在已经存在的上执行的,即使用相同的物理目录(即testpkg
,这恰好是两个发行版使用的包),可能会替换已经存在的模块,尽管两个发行版都是实际安装的:
$ pip freeze | grep dist-*
dist-a @ file:///tmp/test-a
dist-b @ file:///tmp/test-b
$ python
>>> import testpkg
>>> import testpkg.a
>>> import testpkg.b
现在卸载第一个发行版(dist-a
)也会删除第二个发行版的内容:
$ pip uninstall dist-a
$ python
>>> import testpkg
ModuleNotFoundError: No module named 'testpkg'
因此,除了发行版名称之外,确保其顶级包不与已安装项目的顶层包冲突也很重要。正是这些顶级包充当了发行版的命名空间。因此,最好选择一个与顶级包的名称类似的分发名称--通常会选择相同的名称。
相关文章