文章目录
源码地址:
https://github.com/pypa/setuptools
Setuptools 是Python开发中用于打包、安装和分发软件的核心工具。它扩展了 Distutils ,增加了元数据定义和依赖处理等高级功能,并引入了 .EGG 格式和相关的打包工具。Setuptools 简化了软件包的安装过程,支持依赖管理,使得创建自包含的发行版成为可能。此外,它与 easy_install 命令、虚拟环境工具如 pip 和 virtualenv 良好集成,对于Python生态系统的繁荣至关重要。
安装方法
使用如下命令可以安装最新的版本:
uv add --upgrade setuptools[core]
然而,大多数时候,在创建新的Python包时,建议使用名为 build 的命令行工具。此工具将自动下载 setuptools 和项目需要用到的其他构建时依赖项。您只需要在项目根目录下的 pyproject.toml 文件中指定它们。如下:
uv add --upgrade build
完成后,将运行使用如下的命令行:
python -m build
每个python包都必须提供一个 pyproject.toml 文件并指定它要使用的后端(构建系统)。然后,可以使用任何提供象 build sdist 功能的工具生成该发行版。
配置概览
基础配置
在创建了一个 Python 项目之后,在项目根目录下必须包含一个 pyproject.toml 文件,并在该文件下的 build-system 节如下代码所示指定他要使用的后端。
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
build-system 声明了构建系统依赖项是什么,以及将实际使用哪个库进行打包。
⚠️ 注意
包维护者可能会将
setuptools[core]作为一个个必要条件尝试使用;但最好避免这样做,因为extra目前被认为是内部实现细节且将来可能会消失,Setuptools团队将不再支持对声明了这个extra的包所产生的问题的兼容性。供应商提供的包会满足最常见的独立构建场景中的依赖关系。本文档不再在
requires列表中列出wheel,但现在许多项目仍然列出。不建议这样做,因为后端不再需要wheel包,显式列出它会导致源代码发行版构建时会把它构建进去。如果你需要在构建期间显式地访问wheel,你应该只在require中包含wheel(例如,如果你的项目需要导入wheel的setup.py脚本)。
除了指定构建系统之外,您还需要添加一些包信息,例如元数据、内容、依赖项等。这可以在pyproject.toml 文件中配置,或者通过在单独的setup.cfg 或 setup.py文件配置。
下面的例子演示了一个最小配置(假设项目依赖于 requests 和 importlib-metadata才能运行):
-
在
pyproject.toml中配置:[project] name = "mypackage" version = "0.0.1" dependencies = [ "requests", 'importlib-metadata; python_version<"3.10"', ] -
或在
setup.cfg中配置[metadata] name = mypackage version = 0.0.1 [options] install_requires = requests importlib-metadata; python_version<"3.10" -
或在
setup.py中配置from setuptools import setup setup( name='mypackage', version='0.0.1', install_requires=[ 'requests', 'importlib-metadata; python_version<"3.10"', ], )
最后,你需要组织你的Python代码,使其准备好分发成如下所示的内容(带有#标记的可选文件):
mypackage
├── pyproject.toml # and/or setup.cfg/setup.py (depending on the configuration method)
| # README.rst or README.md (a nice description of your package)
| # LICENCE (properly chosen license information, e.g. MIT, BSD-3, GPL-3, MPL-2, etc...)
└── mypackage
├── __init__.py
└── ... (other Python files)
如果已经安装 build 工具,运行以下命令:
python -m build
现在您已经准备好了您的发行版(例如,dist 目录中的 tar.gz 文件和 .whl 文件),您可以将其上传到 PyPI !
当然,在将项目发布到PyPI之前,您需要添加更多信息,以帮助人们查找或了解您的项目。也许到那时您的项目已经发展到包含一些依赖项,也许还包括一些数据文件和脚本。
包发现
对于遵循简单目录结构的项目,setuptools 应该能够自动检测所有包和命名空间。然而,复杂的项目可能包括非必须分发的额外文件夹和支持文件,这些资源可能会混淆 setuptools 自动发现算法。
因此,setuptools 提供了一种方便的方法来定制应该分发哪些包以及应该在哪个目录中找到它们,如下面的示例所示:
-
在
pyproject.toml中配置# ... [tool.setuptools.packages] find = {} # 使用默认参数查找项目目录 # 或者 [tool.setuptools.packages.find] # 以下所有配置都是可选的: where = ["src"] # 默认是 ["."] include = ["mypackage*"] # 默认是 ["*"] exclude = ["mypackage.tests*"] # 默认是 空 namespaces = false # true by default -
或在
setup.cfg中配置[options] packages = find: # 如果想使用命名空间,使用 `find_namespace:` [options.packages.find] # (上面设置使用命名空间,则将 `find` 写成 `find_namespace`) # 本节中以下所有参数都是可选的: where=src # 默认是 '.' include=mypackage* # 默认是 '*' exclude=mypackage.tests* # 默认是空 -
或在
setup.py中配置from setuptools import setup, find_packages # or find_namespace_packages setup( # ... packages=find_packages( # 下面所有配置选项都是可选的: where='src', # 默认是 '.' include=['mypackage*'], # 默认是 ['*'] exclude=['mypackage.tests'], # 默认是空 ), # ... )当您传递上述信息以及其他必要信息时,
setuptools遍历where(默认为.)中指定的目录,并加入与include模式(默认为*)匹配的包,然后删除与exclude匹配的包(默认为空),然后返回Python包列表。
配置自动执行脚本
Setuptools 支持在安装时自动创建脚本,如果在入口点(entry_points)中指定这些脚本,这些脚本将在包中被执行。比如通过 pip 来执行:它允许您像运行 pip install 一样运行这些命令,而不必输入 python -m pip install。
下面的配置示例展示了如何完成此操作:
-
在
pyproject.toml中配置[project.scripts] cli-name = "mypkg.mymodule:some_func" -
或在
setup.cfg中配置[options.entry_points] console_scripts = cli-name = mypkg.mymodule:some_func -
或在
setup.py中配置setup( # ... entry_points={ 'console_scripts': [ 'cli-name = mypkg.mymodule:some_func', ] } )安装此项目时,将创建一个
cli-name可执行项。cli-name在用户调用时调用mypkg/mymodule.py中的some_func函数。另外,您还可以使用入口点在安装包和插件之间发布组件。依赖管理
使用 setuptools 构建的包可以指定需要自动安装的依赖项。下面的例子展示了如何配置这种依赖:
-
在
pyproject.toml中配置[project] # ... dependencies = [ "docutils", "requests <= 0.4", ] # ... -
或在
setup.cfg中配置[options] install_requires = docutils requests <= 0.4 -
或在
setup.py中配置setup( # ... install_requires=["docutils", "requests <= 0.4"], # ... )
每个依赖都由一个字符串表示,该字符串可以包含版本(如操作符<、>、<=、>=、==或 != 之一,后跟一个版本标识符),和(或)条件环境表示(如 sys_platform == "win32")。
在安装项目时,所有未安装的依赖项将会查找定位、下载、构建(如果需要)和安装。当然,这是一个简化的场景。您还可以指定一组额外的依赖项,这些依赖项不是包工作所严格要求的,但它们将提供额外的功能。
包含数据文件
Setuptools 提供了三种方法来指定要包含在包中的数据文件。对于最简单的使用,您可以简单地使用 include_package_data 关键字:
-
在
pyproject.toml中配置[tool.setuptools] include-package-data = true # This is already the default behaviour if you are using # pyproject.toml to configure your build. # You can deactivate that with `include-package-data = false` -
或在
setup.cfg中配置[options] include_package_data = True -
或在
setup.py中配置setup( # ... include_package_data=True, # ... )启用安装数据文件后,
setuptools将在项目中查找所能找到的数据文件并安装。数据文件必须通过MANIFEST.in指定或者通过Revision Control System plugin自动添加的资源。
开发模式
setuptools 允许你安装一个包,而不需要将任何文件复制到你的环境目录(例如 site-packages 目录)。这允许您修改源代码并使更改生效,而无需重新构建和重新安装。以下示例展示如何做到这一点:
uv add --editable .
配置元数据
以下所列是 setuptools.setup() 接受的关键字,用来指示 Python 发行版的构建过程,或者通过放在项目根目录下的 setup.py 脚本添加元数据。所有这些都是可选的;您不必手动配置这些参数,除非您需要相关的 setuptools 特性。
setup() 提供的元数据和配置是对 setup.cfg 和 pyproject.toml 的信息重新设置并且可能覆盖掉原值。如果没有指定,可能有一些重要的元数据(如 name 和 version)会被设定为无意义的值。
强烈建议用户通过 setup.cfg 或 pyproject.toml 使用声明性配置。只有当他们需要利用需要脚本的特殊行为(比如构建C扩展)时才依赖 setup.py。
| 参数名 | 类型 | 说明 |
|---|---|---|
name |
str |
指定包的名称。 |
version |
str |
指定包的版本号。 |
description |
str |
在单行中描述包。 |
long_description |
str |
提供更长的包描述。 |
long_description_content_type |
str |
指定用于long_description(例如 text/markdown)的内容类型 |
author |
str |
指定包的作者。 |
author_email |
str |
指定包作者的电子邮件地址。 |
maintainer |
str |
如果当前维护者与作者不同,则指定其名称。注意,如果指定了维护者,setuptools 将把它作为 PKG-INFO 中的作者使用。` |
maintainer_email |
str |
如果当前维护者与作者不同,则指定其电子邮件地址。 |
url |
str |
指定包主页的URL。 |
download_url |
str |
指定下载包的URL。 |
packages |
list[str] |
指定 setuptools 要操作的包列表。 |
py_modules |
list[str] |
指定 setuptools 要操作的模块列表。 |
scripts |
list[str] |
指定要构建和安装的独立脚本文件列表。 |
ext_package |
str |
指定此包提供的扩展的基本包名。 |
ext_modules |
list[str] |
提供要构建的Python扩展列表。列表的每一项都是 setuptools.Extension 的实例 |
classifiers |
list[str] |
描述包的类别的列表。 |
distclass |
Distribution |
要使用的Distribution 的子类 |
script_name |
str |
指定 setup.py 脚本的名称。默认为 sys.argv[0] |
script_args |
list[str] |
定义要提供给 setup 脚本的参数列表。 |
options |
dict |
为安装脚本提供默认选项的字典。 |
license |
str |
指定包的 license。 |
license_files |
list[str] |
应该包含的与证书相关文件的全局通配符列表。如果 license_file 和 license_files 都未指定,则默认为 LICEN[CS]E*、copy *、NOTICE* 和 AUTHORS*。 |
keywords |
str,list[str] |
提供描述性元数据的字符串列表或逗号分隔的字符串。 |
platforms |
str,list[str] |
字符串或逗号分隔字符串。 |
cmdclass |
dict |
一个字典,提供命令名称与 Command 子类的映射。 |
data_files |
str |
指定要安装的数据文件的 (directory, files)序列,directory 是一个str, files是一个 str 序列。序列中的每个 (directory, files) 对指定安装目录和要在其中安装的文件。 |
package_dir |
str |
一个将包名(最终用户将导入它们)映射到目录路径(实际存在于项目的代码树中)的字典。 |
obsoletes |
list[str] |
描述此包之前的包的字符串列表,适用于当包修改过名称 |
provides |
list[str] |
指定可以为哪些模块提供依赖 |
include_package_data |
bool |
安装包是否包含的数据文件 |
exclude_package_data |
dict |
排除的安装包中的数据文件 |
package_data |
dict[str, list] |
将包名称映射到全局匹配模式列表的字典。以获取完整的描述和示例 |
zip_safe |
bool |
指定项目是否可以安全地从 zip 文件安装和运行。如果没有提供这个参数,bdist_egg 命令将不得不在每次构建一个 egg 时分析项目的所有内容,以找出可能存在的问题。 |
install_requires |
str, list[str] |
指定在安装此发行版时需要安装的其他发行版名称或者名称列表。 |
entry_points |
dict |
将入口点组名称映射到定义入口点的字符串或字符串列表的字典。入口点用于支持动态发现项目提供的服务或插件。 |
extras_require |
str |
字典将 extras(项目的可选功能)的名称映射到字符串或字符串列表,指定必须安装哪些其他发行版才能支持这些功能。 |
python_requires |
str |
对应于Python版本的版本说明符(如PEP 440中定义的) |
setup_requires |
str, list[str] |
指定需要哪些其他发行版才能运行安装脚本。setuptools 将在处理其余的安装脚本或命令之前尝试获取这些信息。如果您在构建过程中使用 distutils 扩展,则需要此参数; |
dependency_links |
list[str] |
在满足依赖关系时命名要搜索的 url。如果需要安装由 setup_require 或tests_require 指定的包,将使用这些链接。它们也将被写入到 egg 的元数据中,以便在安装期间由支持它们的工具使用。 |
namespace_packages |
list[str] |
命名项目的 namespace packages。名称空间包是一个可以跨多个项目发行版分割的包。 |
test_suite |
str |
unittest.TestCase 子类民(或包含一个或多个此类子类的包或模块,或此类子类的方法),或者命名一个不带参数调用并返回 unittest.TestSuite 的函数。 |
tests_require |
str, list[str] |
如果项目的测试除了安装所需的包之外还需要一个或多个附加包,则可以使用此选项来指定它们。它指定运行包的测试需要提供哪些其他发行版。当您运行 test 命令时,setuptools 将尝试获取这些信息。 |
test_loader |
str |
如果您希望使用与 setuptools 通常使用的不同的方式来查找要运行的测试,您可以在此参数中指定模块名称和类名称。类必须是无参并可实例化的,并且它的实例必须支持 loadTestsFromNames()方法,该方法定义在Python unittest模块的 TestLoader 类中。 |
eager_resources |
list[str] |
如果需要,或者项目中包含的任何C扩展被导入,则应该一起提取命名资源。只有当项目作为 zip 文件安装,并且需要将列出的所有资源作为一个单元提取到文件系统中时,该参数才有效。 |
project_urls |
map |
URL 名称到超链接的任意映射,比简单的 url 和 download_url 选项提供更多可扩展的文档,说明在哪里可以找到各种资源。 |
入口点 entry_points
入口点是一种元数据,可以在安装时由包公开。它们是Python生态系统中非常有用的功能,在以下两种情况下特别方便:
-
这个包想要提供在终端上运行的命令。这个功能被称为控制台脚本。该命令还可以打开
GUI,在这种情况下,它被称为GUI脚本。一个控制台脚本的示例是由pip包提供的脚本,它允许您在终端中运行像pip install这样的命令。 -
一个包希望能够通过插件来定制它的功能。例如,测试框架
pytest允许通过pytest11入口点进行定制,语法高亮显示工具pyements允许使用入口点pygments.styles指定额外的样式。