深入了解Python的setup.py文件

深入了解Python的setup.py文件

技术背景

在Python开发中,经常需要安装和管理各种包和模块。setup.py文件是Python的一个重要工具,它是使用Distutils(Python标准库中用于分发Python模块的工具)打包和分发Python模块的标志。通过setup.py,可以方便地安装、打包和发布Python包,实现包的自动化管理。

实现步骤

安装Python包

如果你下载的Python包的根目录下有setup.py文件,可以使用以下命令进行安装:

1
python setup.py install

不过,现在更推荐使用pip来安装,因为直接调用setup.py有一些潜在问题,使用pip安装时,它会自动使用setup.py来完成安装:

1
pip install .

创建Python包

如果要创建自己的Python包,需要编写setup.py文件。以下是不同复杂度的包对应的setup.py编写示例:

简单包结构

假设包结构如下:

1
2
3
4
5
6
7
8
foo
├── foo
│ ├── data_struct.py
│ ├── __init__.py
│ └── internals.py
├── README
├── requirements.txt
└── setup.py

对应的setup.py文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
from setuptools import setup

setup(
name='foo',
version='1.0',
description='A useful module',
author='Man Foo',
author_email='[email protected]',
packages=['foo'], # 与包名相同
install_requires=['wheel', 'bar', 'greek'], # 外部依赖包
)

复杂包结构

当包结构更复杂,包含脚本文件时,例如:

1
2
3
4
5
6
7
8
9
10
11
foo
├── foo
│ ├── data_struct.py
│ ├── __init__.py
│ └── internals.py
├── README
├── requirements.txt
├── scripts
│ ├── cool
│ └── skype
└── setup.py

setup.py文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from setuptools import setup

setup(
name='foo',
version='1.0',
description='A useful module',
author='Man Foo',
author_email='[email protected]',
packages=['foo'], # 与包名相同
install_requires=['wheel', 'bar', 'greek'], # 外部依赖包
scripts=[
'scripts/cool',
'scripts/skype',
]
)

发布Python包到PyPI

如果要将包发布到PyPI供他人使用,可以按照以下步骤操作:

  1. 首先,在本地构建分发文件:
1
2
3
# 前提:安装wheel
pip install wheel
python setup.py sdist bdist_wheel
  1. 然后,使用twine上传到测试服务器test.pypi.org进行测试:
1
twine upload --repository testpypi dist/*

输入用户名和密码后,等待几分钟,包就会出现在test.pypi.org上。
3. 若测试通过,将包上传到正式的pypi.org

1
twine upload dist/*

还可以选择使用GPG对包中的文件进行签名:

1
twine upload dist/* --sign

核心代码

以下是一个较为完整的setup.py示例,包含读取README文件作为长描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from setuptools import setup

with open("README", 'r') as f:
long_description = f.read()

setup(
name='foo',
version='1.0',
description='A useful module',
license="MIT",
long_description=long_description,
author='Man Foo',
author_email='[email protected]',
url="http://www.foopackage.example/",
packages=['foo'], # 与包名相同
install_requires=['wheel', 'bar', 'greek'], # 外部依赖包
scripts=[
'scripts/cool',
'scripts/skype',
]
)

最佳实践

  • 使用pip安装:避免直接调用setup.py进行安装,因为pip能更好地处理依赖和版本管理。
  • 读取requirements.txt:可以解析requirements.txt文件并将其内容赋值给install_requires,使依赖管理更清晰。
1
2
3
4
5
6
7
8
with open('requirements.txt') as f:
requirements = f.read().splitlines()

setup(
# ...
install_requires=requirements,
# ...
)
  • 使用setuptoolssetuptoolsDistutils的增强版本,提供了更多功能,如自动发现包和子包。
1
2
3
4
5
6
7
from setuptools import setup, find_packages

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

常见问题

1. 直接调用setup.py install有什么问题?

直接调用setup.py install可能会破坏版本管理,并且在某些情况下会导致安装混乱。而pip会处理依赖解析和版本控制,提供更稳定的安装环境。

2. 如何处理子包?

使用setuptoolsfind_packages()函数可以自动发现包和子包,无需手动列出每个子包。

3. setup.py是否必须命名为setup.py

setup.py只是一个约定的名称,可以使用其他名称,但这样会使安装和使用的过程变得不统一,增加用户的使用成本。

4. 新的Python版本是否还需要setup.py

较新的setuptoolspip版本可以省略setup.py,但目前setup.py仍然被广泛使用,并且在一些场景下还是必要的。


深入了解Python的setup.py文件
https://119291.xyz/posts/2025-04-21.in-depth-understanding-of-python-setup-py-file/
作者
ww
发布于
2025年4月21日
许可协议