深入了解Python的setup.py文件
技术背景
在Python开发中,经常需要安装和管理各种包和模块。setup.py文件是Python的一个重要工具,它是使用Distutils(Python标准库中用于分发Python模块的工具)打包和分发Python模块的标志。通过setup.py,可以方便地安装、打包和发布Python包,实现包的自动化管理。
实现步骤
安装Python包
如果你下载的Python包的根目录下有setup.py文件,可以使用以下命令进行安装:
python setup.py install
不过,现在更推荐使用pip来安装,因为直接调用setup.py有一些潜在问题,使用pip安装时,它会自动使用setup.py来完成安装:
pip install .
创建Python包
如果要创建自己的Python包,需要编写setup.py文件。以下是不同复杂度的包对应的setup.py编写示例:
简单包结构
假设包结构如下:
foo
├── foo
│ ├── data_struct.py
│ ├── __init__.py
│ └── internals.py
├── README
├── requirements.txt
└── setup.py
对应的setup.py文件内容如下:
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'], # 外部依赖包
)
复杂包结构
当包结构更复杂,包含脚本文件时,例如:
foo
├── foo
│ ├── data_struct.py
│ ├── __init__.py
│ └── internals.py
├── README
├── requirements.txt
├── scripts
│ ├── cool
│ └── skype
└── setup.py
setup.py文件内容如下:
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供他人使用,可以按照以下步骤操作:
- 首先,在本地构建分发文件:
# 前提:安装wheel
pip install wheel
python setup.py sdist bdist_wheel
- 然后,使用twine上传到测试服务器test.pypi.org进行测试:
twine upload --repository testpypi dist/*
输入用户名和密码后,等待几分钟,包就会出现在test.pypi.org上。
- 若测试通过,将包上传到正式的pypi.org:
twine upload dist/*
还可以选择使用GPG对包中的文件进行签名:
twine upload dist/* --sign
核心代码
以下是一个较为完整的setup.py示例,包含读取README文件作为长描述:
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,使依赖管理更清晰。
with open('requirements.txt') as f:
requirements = f.read().splitlines()
setup(
# ...
install_requires=requirements,
# ...
)
- 使用setuptools:setuptools是Distutils的增强版本,提供了更多功能,如自动发现包和子包。
from setuptools import setup, find_packages
setup(
# ...
packages=find_packages(),
# ...
)
常见问题
1. 直接调用setup.py install有什么问题?
直接调用setup.py install可能会破坏版本管理,并且在某些情况下会导致安装混乱。而pip会处理依赖解析和版本控制,提供更稳定的安装环境。
2. 如何处理子包?
使用setuptools的find_packages()函数可以自动发现包和子包,无需手动列出每个子包。
3. setup.py是否必须命名为setup.py?
setup.py只是一个约定的名称,可以使用其他名称,但这样会使安装和使用的过程变得不统一,增加用户的使用成本。
4. 新的Python版本是否还需要setup.py?
较新的setuptools和pip版本可以省略setup.py,但目前setup.py仍然被广泛使用,并且在一些场景下还是必要的。