Setuptools.setup的name参数值对结果有何影响?

2022-05-27 00:00:00 python pip setuptools

问题描述

我最近收到了一个由学术实验室的一名研究生编写的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.setupname参数值错误会导致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_worldhello-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__.pya.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'
因此,除了发行版名称之外,确保其顶级包不与已安装项目的顶层包冲突也很重要。正是这些顶级包充当了发行版的命名空间。因此,最好选择一个与顶级包的名称类似的分发名称--通常会选择相同的名称。

相关文章