本教程将指导您如何打包一个简单的Python项目。它将从0开始向您展示如何添加必要的文件和结构来创建包,如何构建包以及如何将其上传到PyPI供他人使用。

子曰:知之为不知,不知为不知,太菜也!

文章目录

要点说明:

  1. 本文从最基础的创建文件开始,如果不需,请跳至上传并发布包文件到PyPI
  2. 为了防止包冲突,可采用conda的虚拟环境来搭建环境
  3. 更多细节参看官网(会有坑)

项目框架


本教程使用一个名为的example_pkg简单项目。即使您已经有一个要打包的项目,我们仍然建议您按照本示例包使用此示例包,然后尝试使用自己的包。

TIPS:MANIFEST.in 文件用来表示忽略的文件目录,此处知道便可。

要在本地创建此项目,请创建以下文件结构:

packaging_tutorial/
  example_pkg/
    __init__.py

创建此结构后,您将需要在顶级文件夹中运行本教程中的所有命令 - 所以需要cd packaging_tutorial

您还应该编辑example_pkg/__init__.py并在其中放入以下代码:

name = "example_pkg"

这只是为了让您可以在本教程后面验证它是否正确安装,并且PyPI不会使用它。

添加文件


添加前须知

  • 假设你的包已经开发完成,并且根目录必须要有一个setup.py
  • 最好有一个 README.md用来描述你的包,虽然这不是必须的,但文档性说明,你最好还是要有的。
  • 如果你需要打包代码文件夹以外的文件,比如版权信息等等,你还需要写一个 LICENSE

您现在将创建一些文件。创建下面列出的新文件,下面会详细介绍每个文件的内容。

packaging_tutorial/
  example_pkg/
    __init__.py
  setup.py
  LICENSE
  README.md

创建的setup.py

setup.pysetuptools的构建脚本。它告诉setuptools你的包(例如名称和版本)以及要包含的代码文件。

打开setup.py并输入以下内容。更新软件包名称以包含您的用户名(例如example-pkg-theacodes),这可确保您拥有唯一的软件包名称,并且保证和其他人的软件包不会发生冲突。

import setuptoolswith open("README.md", "r") as fh:
    long_description = fh.read()setuptools.setup(
    name="example-pkg-your-username",
    version="0.0.1",
    author="Example Author",
    author_email="author@example.com",
    description="A small example package",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/pypa/sampleproject",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.6',)

setup()需要注意几个点。此示例包列出了最重要的几个:

  • name 是包的分发名称。只能包含字母、数字和中划线。但是要保证在 pypi.org上没有重名。请务必使用您自己的包名称更新此内容,因为这样尽可能的能避免和其他包名冲突。

  • version 是包版本。看 PEP 440有关版本的更多详细信息。

  • authorauthor_email 用于识别包的作者。

  • description 是一个简短的,一句话的包的总结。

  • long_description是包的详细说明。这显示在PytPI的包详细信息包中。在一般情况下,README.md作为描述信息是一种常见模式。

  • long_description_content_type告诉索引什么类型的标记用于长描述。上面代码中,这个值为Markdown

  • url是项目主页的URL。对于许多项目,可以指向GitHub,GitLab,Bitbucket或类似代码托管服务的链接。

  • packages是应包含在分发包中的所有Python 导入包的列表。我们可以使用find_packages()自动发现所有包和子包,而不是手动列出每个包。在这种情况下,包列表将是example_pkg,因为它是唯一存在的包。

  • classifiers给出了你的包一些额外的元数据。在上面代码中,该软件包仅与Python 3兼容,根据MIT许可证进行许可,并且与操作系统无关。您应始终至少包含您的软件包所使用的Python版本,软件包可用的许可证以及您的软件包将使用的操作系统。有关分类器的完整列表,请参阅这里

除了这里提到的还有很多。有关详细信息,请参阅 打包和分发项目

创建README.md

打开README.md并输入以下内容。如果您愿意,可以自定义此项。

# Example Package

This is a simple example package. You can use
[Github-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.

创建许可证

上传到PyPI的每个包都包含许可证,这一点很重要。这告诉用户安装您的软件包需要使用您的软件包的条款。有关选择许可证的帮助,请访问。选择许可证后,打开LICENSE并输入许可证文本。例如,如果您选择了MIT许可证:

Copyright (c) 2018 The Python Packaging Authority

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

生成分发资源

下一步是为包生成分发包。这些是上传到包索引的资源,可以通过pip安装。

确保您拥有setuptoolswheel并升级到了最新版本:

python3 -m pip install --user --upgrade setuptools wheel

提示: 如果您在安装它们时遇到问题,请参阅 安装包 教程。
现在从setup.py位于的同一目录运行此命令:

python3 setup.py sdist bdist_wheel

此命令应输出大量文本,一旦完成,应在dist目录中生成两个文件:

dist/
  example_pkg_your_username-0.0.1-py3-none-any.whl
  example_pkg_your_username-0.0.1.tar.gz

tar.gz文件是源存档,而该.whl文件是构建的发行版。较新的pip版本优先安装构建的发行版,但如果需要,将回退到源代码存档。您应该始终上传源存档并为项目兼容的平台提供构建的存档。

上传并发布包文件到PyPI


创建 PyPI账号

非常简单,直接通过官网注册, 但是需要验证邮件并确认激活。

创建用户验证文件~/.pypirc

提示:如何在win中配置pypi
在自己的用户目录下新建一个空白文件命名为.pypirc,内容如下:

[distutils]
index-servers=pypi

[pypi]
repository = https://upload.pypi.org/legacy/
username =password =

用户名和密码就是上一步骤所创建的,直接明文输入。如果你觉得明文密码不安全也可以留空,在后面的上传过程中会提示你手动输入。

上传并完成发布

python3 -m twine upload dist/*

查看结果

至此,你已经成功上传了你发行包!可以在官网查看。如果正常,应该出现如下画面。
PyPI打包实践教程-2019_打包

让别人使用你的包


包发布完成后,其他人只需要使用pip就可以安装你的包文件(将FreeBird换成你的包名即可)。比如:

pip install FreeBird

如果你更新了包,别人可以可以通过–update参数来更新:

pip install FreeBird --update

您可以通过导入模块并引用先前name放置的属性来测试它是否已正确安装__init__.py
运行Python解释器:

python

然后导入模块并打印出name属性。这应该是与你导入的包一样,而不是你给你的分发包中setup.py设置的名字。(上述代码中的FreeBird),因为你的导入包是example_pkg

>>> import example_pkg
>>> example_pkg.name
'example_pkg'

可能遇到的问题

Upload failed (403): Invalid or non-existent authentication information.
错误的用户验证信息,你需要创建一个用户验证文件 ~/.pypirc。请参阅上文。

Upload failed (403): You are not allowed to edit ‘xxx’ package information
你需要先注册你的包才可以开始上传,运行注册命令:python setup.py register

Server response (401): Incomplete registration; check your email
你的PyPI账户还没完成邮箱验证,你需要去注册邮箱找到一封验证邮件完成验证后再重试失败的步骤。

Server response (400): Invalid classifier “Topic :: Software Development :: Utilities”
你的setup.py文件中的classifier信息有误,请按官网的正确分类书写classifier.

error: No dist file created in earlier command
你还没打包就开始了上传命令,建议打包和上传的操作放在一起做,比如:

python setup sdist upload
error: Upload failed (499): Client Disconnected

这应该是网络问题,多重试几次。

Upload failed (400): File already exists
文件已经存在了,你每一次上次都应该更新版本号。

参考文档


https://segmentfault.com/a/1190000008663126

关于作者:Java\Python技术爱好者,目前还是一枚学生小鲜肉,转载请注明原文出处。
欢迎到我的公众号:自由的小黑中去讨论。

PyPI打包实践教程-2019_打包_02



你懂了没?