Python 是一种出色的编程语言,而且还有更多优点。然而,其最弱点之一是包装。这是社会上众所周知的事实。多年来,安装、导入、使用和创建包已经有所改进,但它仍然无法与 Go 和 Rust 等较新的语言相提并论,后者可以从 Python 和其他更成熟的语言的斗争中学到很多东西。
在本教程中,您将学习构建和共享自己的包所需的一切。有关 Python 包的一般背景信息,请阅读如何使用 Python 包。
打包项目是一个过程,通过这个过程,您可以获取一组一致的 Python 模块和可能的其他文件,并将它们放入可以轻松使用的结构中。您必须考虑多种因素,例如对其他包的依赖关系、内部结构(子包)、版本控制、目标受众以及包的形式(源代码和/或二进制文件)。
让我们从一个简单的例子开始。 conman 包是用于管理配置的包。它支持多种文件格式以及使用 etcd
的分布式配置。
包的内容通常存储在单个目录中(尽管将子包拆分到多个目录中很常见),有时(如本例所示)存储在其自己的 git 存储库中。
根目录包含各种配置文件(setup.py是必需的,也是最重要的一个),包代码本身通常位于一个子目录中,其名称最好是包的名称一个测试目录。这是 conman
的样子:
> tree . ├── LICENSE ├── MANIFEST.in ├── README.md ├── conman │ ├── __init__.py │ ├── __pycache__ │ ├── conman_base.py │ ├── conman_etcd.py │ └── conman_file.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── test-requirements.txt ├── tests │ ├── __pycache__ │ ├── conman_etcd_test.py │ ├── conman_file_test.py │ └── etcd_test_util.py └── tox.ini
让我们快速浏览一下 setup.py 文件。它从 setuptools 包中导入两个函数:setup()
和 find_packages()
。然后它调用 setup()
函数并使用 find_packages()
作为参数之一。
from setuptools import setup, find_packages setup(name='conman', version='0.3', url='https://github.com/the-gigi/conman', license='MIT', author='Gigi Sayfan', author_email='the.gigi@gmail.com', description='Manage configuration files', packages=find_packages(exclude=['tests']), long_description=open('README.md').read(), zip_safe=False, setup_requires=['nose>=1.0'], test_suite='nose.collector')
这很正常。虽然 setup.py 文件是一个常规的 Python 文件,您可以在其中做任何您想做的事情,但它的主要工作是使用适当的参数调用 setup()
函数参数,因为在安装包时它将由各种工具以标准方式调用。我将在下一节中详细介绍。
除了setup.py之外,还有一些其他可选配置文件可以显示在此处并用于各种目的。
setup()
函数采用大量命名参数来控制包安装的许多方面以及运行各种命令。许多参数指定将包上传到存储库时用于搜索和过滤的元数据。
name
:你的包的名称(以及它将如何在 PyPI 上列出)version
:这对于维护正确的依赖管理至关重要url
:包的 URL,通常是 GitHub 或 readthedocs URLpackages
:需要包含的子包列表; find_packages()
在这里提供帮助setup_requires
:在这里指定依赖项test_suite
:测试时运行哪个工具long_description
在此设置为 README.md 文件的内容,这是拥有单一事实来源的最佳实践。
setup.py
文件还提供命令行界面来运行各种命令。例如,要运行单元测试,您可以键入: python setup.py test
running test running egg_info writing conman.egg-info/PKG-INFO writing top-level names to conman.egg-info/top_level.txt writing dependency_links to conman.egg-info/dependency_links.txt reading manifest file 'conman.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' writing manifest file 'conman.egg-info/SOURCES.txt' running build_ext test_add_bad_key (conman_etcd_test.ConManEtcdTest) ... ok test_add_good_key (conman_etcd_test.ConManEtcdTest) ... ok test_dictionary_access (conman_etcd_test.ConManEtcdTest) ... ok test_initialization (conman_etcd_test.ConManEtcdTest) ... ok test_refresh (conman_etcd_test.ConManEtcdTest) ... ok test_add_config_file_from_env_var (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_guess_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_unknown_wrong_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_with_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_wrong_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_with_base_dir (conman_file_test.ConmanFileTest) ... ok test_dictionary_access (conman_file_test.ConmanFileTest) ... ok test_guess_file_type (conman_file_test.ConmanFileTest) ... ok test_init_no_files (conman_file_test.ConmanFileTest) ... ok test_init_some_bad_files (conman_file_test.ConmanFileTest) ... ok test_init_some_good_files (conman_file_test.ConmanFileTest) ... ok ---------------------------------------------------------------------- Ran 16 tests in 0.160s OK
setup.cfg
is 是一个 ini 格式文件,其中可能包含传递给 setup.py
的命令的选项默认值。在这里, setup.cfg
包含 nosetests
(我们的测试运行程序)的一些选项:
[nosetests] verbose=1 nocapture=1
此文件包含不属于内部包目录的一部分,但您仍想包含的文件。这些通常是自述文件、许可证文件等。一个重要的文件是 requirements.txt。 pip 使用此文件来安装其他所需的软件包。
这是 conman 的 MANIFEST.in 文件:
include LICENSE include README.md include requirements.txt
您可以在 setup.py 的 install_requires
部分和 install_requires
部分和 requirements.txt 文件中指定依赖项。 Pip 将自动从 install_requires
安装依赖项,但不会从 requirements.txt 文件安装。要安装这些要求,您必须在运行 pip 时明确指定它: pip install -r requests.txt
requirements.txt
install_requires
安装依赖项,但不会从 🎜requirements.txt🎜 文件安装。要安装这些要求,您必须在运行 pip 时明确指定它: pip install -r requests.txt
。🎜
install_requires
选项旨在指定主要版本级别的最低和更抽象的要求。 requirements.txt 文件用于更具体的要求,通常包含固定的次要版本。
这是conman的需求文件。您可以看到所有版本都已固定,这意味着如果其中一个软件包升级并引入破坏 conman 的更改,它可能会受到负面影响。
PyYAML==3.11 python-etcd==0.4.3 urllib3==1.7 pyOpenSSL==0.15.1 psutil==4.0.0 six==1.7.3
固定让您可预测且安心。如果许多人在不同时间安装您的软件包,这一点尤其重要。如果没有固定,每个人都会根据安装时间获得不同的依赖版本组合。固定的缺点是,如果您不跟上依赖项的开发,您可能会陷入某些依赖项的旧的、性能不佳甚至易受攻击的版本。
我最初在2014年写了conman,并没有太关注它。现在,在本教程中,我升级了所有内容,并且几乎每个依赖项都进行了一些重大改进。
您可以创建源发行版或二进制发行版。我将涵盖两者。
使用以下命令创建源发行版:python setup.py sdist
。这是 conman 的输出:
> python setup.py sdist running sdist running egg_info writing conman.egg-info/PKG-INFO writing top-level names to conman.egg-info/top_level.txt writing dependency_links to conman.egg-info/dependency_links.txt reading manifest file 'conman.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' writing manifest file 'conman.egg-info/SOURCES.txt' warning: sdist: standard file not found: should have one of README, README.rst, README.txt running check creating conman-0.3 creating conman-0.3/conman creating conman-0.3/conman.egg-info making hard links in conman-0.3... hard linking LICENSE -> conman-0.3 hard linking MANIFEST.in -> conman-0.3 hard linking README.md -> conman-0.3 hard linking requirements.txt -> conman-0.3 hard linking setup.cfg -> conman-0.3 hard linking setup.py -> conman-0.3 hard linking conman/__init__.py -> conman-0.3/conman hard linking conman/conman_base.py -> conman-0.3/conman hard linking conman/conman_etcd.py -> conman-0.3/conman hard linking conman/conman_file.py -> conman-0.3/conman hard linking conman.egg-info/PKG-INFO -> conman-0.3/conman.egg-info hard linking conman.egg-info/SOURCES.txt -> conman-0.3/conman.egg-info hard linking conman.egg-info/dependency_links.txt -> conman-0.3/conman.egg-info hard linking conman.egg-info/not-zip-safe -> conman-0.3/conman.egg-info hard linking conman.egg-info/top_level.txt -> conman-0.3/conman.egg-info copying setup.cfg -> conman-0.3 Writing conman-0.3/setup.cfg creating dist Creating tar archive removing 'conman-0.3' (and everything under it)
如您所见,我收到一条关于缺少带有标准前缀之一的 README 文件的警告,因为我喜欢 Markdown,所以我有一个 README.md 。除此之外,还包括所有包源文件和附加文件。然后,在conman.egg-info目录中创建了一堆元数据。最后,创建一个名为 conman-0.3.tar.gz 的压缩 tar 存档,并将其放入 dist 子目录中。
安装这个包需要一个构建步骤(即使它是纯Python)。您可以正常使用 pip 安装它,只需传递包的路径即可。例如:
pip install dist/conman-0.3.tar.gz Processing ./dist/conman-0.3.tar.gz Installing collected packages: conman Running setup.py install for conman ... done Successfully installed conman-0.3
Conman 已安装到站点包中,可以像任何其他包一样导入:
import conman conman.__file__ '/Users/gigi/.virtualenvs/conman/lib/python2.7/site-packages/conman/__init__.pyc'
Wheels 是一种相对较新的方式来打包 Python 代码和可选的 C 扩展。它们取代了鸡蛋的形式。轮子有几种类型:纯Python轮子、平台轮子、通用轮子。纯 Python 轮子是像 conman 这样的包,没有任何 C 扩展代码。
平台轮子确实有 C 扩展代码。通用轮子是纯 Python 轮子,兼容具有相同代码库的 Python 2 和 Python 3(它们甚至不需要 2 到 3)。
如果您有一个纯 Python 包,并且希望您的包同时支持 Python 2 和 Python 3(变得越来越重要),那么您可以构建一个通用构建,而不是为 Python 2 构建一个轮子,为 Python 构建一个轮子3.
Python 3 是当前受到积极支持的 Python 版本,不断更新、改进和社区支持;建议对所有新项目和迁移使用 Python 3。如果你的包有C扩展代码,你必须为每个平台构建一个平台轮。轮子的巨大好处,特别是对于带有 C 扩展的软件包来说,是不需要在目标机器上提供编译器和支持库。该轮子已经包含一个内置包。所以你知道它不会构建失败,而且安装速度要快得多,因为它实际上只是一个副本。使用 Numpy 和 Pandas 等科学库的人可以真正体会到这一点,因为安装此类软件包过去需要很长时间,并且如果缺少某些库或编译器配置不正确,则可能会失败。
构建纯轮子或平台轮子的命令是:python setup.py bdist_wheel
。
Setuptools——提供 setup()
函数的引擎——将自动检测是否需要纯轮子或平台轮子。
running bdist_wheel running build running build_py creating build creating build/lib creating build/lib/conman copying conman/__init__.py -> build/lib/conman copying conman/conman_base.py -> build/lib/conman copying conman/conman_etcd.py -> build/lib/conman copying conman/conman_file.py -> build/lib/conman installing to build/bdist.macosx-10.9-x86_64/wheel running install running install_lib creating build/bdist.macosx-10.9-x86_64 creating build/bdist.macosx-10.9-x86_64/wheel creating build/bdist.macosx-10.9-x86_64/wheel/conman copying build/lib/conman/__init__.py -> build/bdist.macosx-10.9-x86_64/wheel/conman copying build/lib/conman/conman_base.py -> build/bdist.macosx-10.9-x86_64/wheel/conman copying build/lib/conman/conman_etcd.py -> build/bdist.macosx-10.9-x86_64/wheel/conman copying build/lib/conman/conman_file.py -> build/bdist.macosx-10.9-x86_64/wheel/conman running install_egg_info running egg_info creating conman.egg-info writing conman.egg-info/PKG-INFO writing top-level names to conman.egg-info/top_level.txt writing dependency_links to conman.egg-info/dependency_links.txt writing manifest file 'conman.egg-info/SOURCES.txt' reading manifest file 'conman.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' writing manifest file 'conman.egg-info/SOURCES.txt' Copying conman.egg-info to build/bdist.macosx-10.9-x86_64/wheel/conman-0.3-py2.7.egg-info running install_scripts creating build/bdist.macosx-10.9-x86_64/wheel/conman-0.3.dist-info/WHEEL
查看dist
目录,可以看到创建了一个纯Python的轮子:
ls -la dist dist/ total 32 -rw-r--r-- 1 gigi staff 5.5K Feb 29 07:57 conman-0.3-py2-none-any.whl -rw-r--r-- 1 gigi staff 4.4K Feb 28 23:33 conman-0.3.tar.gz
名称 conman-0.3-py2-none-any.whl
有几个组件:
要构建通用包,您只需添加 --universal
,如 python setup.py bdist_wheel --universal
。
生成的轮子名为 conman-0.3-py2.py3-none-any.whl
。
请注意,如果您创建通用包,您有责任确保您的代码实际上可以在 Python 2 和 Python 3 下运行。
Toml(Tom's Obvious Minimal Language)是一种易于使用的配置文件格式,用于配置软件应用程序。尽管 setup.py 仍然被广泛使用和支持,PEP518 建议使用 pyproject.toml 文件而不是 setup.py 进行打包和分发。
让我们使用pyproject.toml创建一个名为 apex
的简单 Python 包,用于检查电池状态并在电池充满时显示一条消息。
创建一个名为 apex 的目录结构。在 apex 内,添加一个 pyproject.toml 和一个 README.md 文件。
.apex ├── pyproject.toml └── README.md
在根 apex 目录中,创建一个名为 apex 的子目录,其中包含一个 __init__.py 文件以使其成为一个包和一个 battery.py 文件。您的项目目录现在应如下所示:
. ├── apex │ ├── battery.py │ └── __init__.py ├── pyproject.toml └── README.md
使用 pip 安装 psutil 包。
pip install psutil
Psutil(进程和系统实用程序)是一个用于 Python 中进程和系统监控的跨平台库。 Psutil 可以检索有关系统上运行的进程的信息,例如状态、CPU 使用情况和内存使用情况。它还可以操纵系统进程。
在battery.py文件中,添加检查电池是否已充满的代码。
import psutil def check_battery(): battery = psutil.sensors_battery() plugged = battery.power_plugged percent = battery.percent if percent == 100 and plugged: print "Battery is full. Unplug your Charger" else: print "Battery is not yet full." if __name__ == "__main__": message = check_battery() print(message)
pyproject.toml 文件包含包的元数据,包括:
构建系统
名称
版本
项目依赖项.
打开pyproject.toml并指定 setuptools
作为构建系统。
[build-system] requires = ["setuptools","wheel"] build-backend ="setuptools.build_meta"
指定包的名称、版本号和项目依赖项列表。现在 pyproject.toml 文件如下所示:
[build-system] requires = ["setuptools","wheel"] build-backend ="setuptools.build_meta" [project] name="apex" version ="1.0.0" [project-dependencies] psutil ="5.9.5"
最后,在README.md文件中添加以下内容。
# apex **apex** is a Python package that allows you to check the battery status of your laptop and display a message when the battery is full. ## Features - Retrieve battery status information - Display a message when the battery is full - Cross-platform support (Windows, macOS, Linux, etc.) ## Installation Install **apex** using `pip`: ```shell pip install apex
使用 build
命令构建包。
python -m build
您应该看到下面的输出,该输出已被我截断。
creating build/bdist.linux-x86_64/wheel/apex-1.0.0.dist-info/WHEEL creating '/home/vaati/Desktop/apex/dist/.tmp-d8_lqaaj/apex-1.0.0-py3-none-any.whl' and adding 'build/bdist.linux-x86_64/wheel' to it adding 'apex/__init__.py' adding 'apex/battery.py' adding 'apex-1.0.0.dist-info/METADATA' adding 'apex-1.0.0.dist-info/WHEEL' adding 'apex-1.0.0.dist-info/top_level.txt' adding 'apex-1.0.0.dist-info/RECORD' removing build/bdist.linux-x86_64/wheel Successfully built apex-1.0.0.tar.gz and apex-1.0.0-py3-none-any.whl
构建会创建一个 dist 文件夹,其中包含包的分发文件:
构建过程还会生成一个 apex.egg-info 文件夹,其中包含有关包的元数据。
. ├── apex │ ├── battery.py │ └── __init__.py ├── apex.egg-info │ ├── dependency_links.txt │ ├── PKG-INFO │ ├── SOURCES.txt │ └── top_level.txt ├── dist │ ├── apex-1.0.0-py3-none-any.whl │ └── apex-1.0.0.tar.gz ├── pyproject.toml └── README.md
编写自己的 Python 包需要处理大量工具,指定大量元数据,并仔细考虑您的依赖项和目标受众。但回报是巨大的。
如果您编写有用的代码并正确打包它,人们将能够轻松安装它并从中受益。
以上是创建您自己的 Python 包的详细内容。更多信息请关注PHP中文网其他相关文章!