如之前的博文所说,Python的第三方模块都在这个网站管理。
pypi的意思即Python Package Index。
那我们是不是也可以构建自己的第三方模块并上传呢?答案是肯定的,软件世界本来就是靠每一个开发者增砖加瓦而来。
pypi上关于打包和上传第三方模块的官方说明文档在。
创建模块框架
为了演示,我们可以构建一个这样的第三方模块:
其中的文件我们都先保持空白,其用途会在后续填充内容时一一介绍。
pyproject.toml
作为示例,我们可以往这个文件中填充以下内容:
[build-system] requires = [ "setuptools>=42", "wheel" ] build-backend = "setuptools.build_meta"
这个文件是第三方模块构建时会用到的配置文件,requires
会指定一个包含构建工具版本以及构建时候需要用到的工具等的列表,而build-backend
会指定用何种工具构建。
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.
关于几个开源许可证之间的关系,可以参考这个说明:
想了解更多关于许可证的内容可以阅读这个。
README.md
这个文档用于说明你的模块用途和使用方式,和github一样,这个说明文档会直接显示在pypi网站上。
这个示例中说明文档用的是markdown编写,这也是目前非常流行的软件示例文档编写语言,想了解更多可以阅读《》。
setup.cfg
组织发布文档的内容有两种方式,静态和动态。静态是通过定义setup.cfg
文件来实现,动态是编写setup.py
文件。
一般来说推荐使用静态方式,动态仅用于某些特殊情况,比如需要加入一些动态构建信息。
这个示例这种我们使用以下构建信息来填充setup.cfg
:
[metadata] # replace with your username: name = example-pkg-icexmoon version = 0.0.1 author = Example Author author_email = author@example.com description = A small example package long_description = file: README.md long_description_content_type = text/markdown url = https://github.com/pypa/sampleproject project_urls = Bug Tracker = https://github.com/pypa/sampleproject/issues classifiers = Programming Language :: Python :: 3 License :: OSI Approved :: MIT License Operating System :: OS Independent [options] include_package_data = False package_dir = = src packages = find: python_requires = >=3.6 install_requires = requests [options.package_data] * = *.info [options.packages.find] where = src
这是一个最简单地构建信息,我们来介绍一些主要参数:
-
name:你要发布的模块名称,需要在pypi上唯一,所以这里建议加入你自己的名称来保证唯一性。
-
version:你程序版本号。
-
author:这个不用解释了吧。
-
long_description:模块的详细说明,这里可以直接指定到你创建好的说明文档,比如
file: README.md
-
long_description_content_type:详细说明内容的类型,这里当然是
markdown
,我猜测你创建一个html
类型的说明文档也是可行的。 -
url:你的项目地址,对个人开发者来说一般是github上的项目地址。
-
project_urls:这里可以定义多个你项目的地址,比如说问题反馈页面之类的。
-
classifiers:模块运行条件,比如Python版本号,操作系统,软件许可证等。
-
package_dir:软件包目录,空表示根目录。
-
packages:模块依赖,可以说明对其它模块的依赖列表,这里可以通过
find:
来实现对代码自动检索依赖。 -
python_requires:需要的Python版本。
-
where:模块所在目录。
-
options.package_data:需要打包进源码内的非代码文件,这里是和包名一一对应的,但可以使用通配符,比如
*=*.txt
就表示包含所有包下边的txt文件。 -
include_package_data:是否使用mainfest.in把非代码文件打包进安装程序,这里边牵扯很多问题,官方文档我来回看了好几遍,都没弄清楚
include_package_data
/package_data
/mainfest.in
之间的关系。建议不要使用这个。知乎上有篇文章说的有点道理,想了解的可以看。 -
install_requires:模块依赖,安装的时候如果缺少相应模块,会自动安装。
更详细的说明请阅读。
setup.py
如之前所说,setup.py
用于动态建构模块,但在使用静态构建模块的时候这个文件是可选的,即可有可无,但如果你加入了这个文件,此时也需要加入以下内容,如果没有,则会构建出错:
import setuptools
setuptools.setup()
__init__.py
Python模块下都会包含这个文件,以和普通文件夹进行区分,可以作为模块的入口文件写入初始化代码,也可以保持空文件。
tests
构建测试用文件夹,保持空即可。
构建发布文档
更新相关工具
在构建发布文档之前我们最好更新一下代码构建工具,以使用最新的构建工具构建代码。
在cmd下执行:
python3 -m pip install --upgrade build
如果遇到类似我这样的错误:
说明是因为连接pypi.org
超时的原因,这个好像在国内很普遍,因为pip工具默认的timeout
选项是15秒,这里我们修改为30秒再请求:
python3 -m pip install --upgrade build --timeout 30
更新成功。
如果pip没更新的,这里最好也更新一下:
python3 -m pip install --upgrade pip --timeout=30
还需要更新一个setuptools
,虽然在构建过程中如果setuptools
版本过旧,会自动更新,但我天朝的网络环境,懂的都懂,最好还是手动更新一下:
python3 -m pip install --upgrade setuptools --timeout=50
不知道为什么,这个700k左右的小工具下载速度慢的令人发指,而且
timeout
设置为30的话会失败,所以这里用了50。
构建发布文档
在cmd中将工作目录指向模块的根目录,即本示例中的packaging_tutorial
目录,并执行构建命令:
python3 -m build
出现上面的信息就表示构建成功了。
新建的发布文档会出现在模块目录下的dist
目录中:
其中whl
文件是真正的发布文件,tar.gz
是打包的源代码文件,相当于备胎,在某些不能正常安装使用模块的情况下就会使用源码。
上传发布文档
开发中的模块可以现在本地测试妥当后再发布,可以使用命令
pip install markdown_img_icexmoon-0.1.0-py3-none-any.whl --force-reinstall
直接安装本地打好的发布包,通过这种方法安装和从pypi仓库安装是一样的,这样可以绕过pypi仓库直接测试本地开发的模块,验证没问题了再上传pypi仓库。
好了,现在我们需要在pypi上注册一个账户用于发布,但我们这里是进行测试,所以可以使用测试用pypi:
注册好后前往创建一个token:
因为还没有上传项目,所以这里创建一个可以用于所有项目的token:
需要保存好这个token,页面上只会展示一次。
我们还需要安装一个上传用工具:
python3 -m pip install --user --upgrade twine --timeout 100
又是一个很难下的工具,直接超时指定到100
安装好后用以下命令上传发布文档:
python3 -m twine upload --repository testpypi dist/*
正式环境发布可以用这个:
python -m twine upload dist/* --skip-existing
--skip-existing
可以跳过已发布的版本,只发布没发布的版本
会要求你输入账号密码,账号可以使用__token__
,密码就使用token。
这里不一定需要使用token,使用密码也是可以的,只是相对来说不安全。
如果不想每次都输入账号和密码,可以设置用户环境变量:
TWINE_PASSWORD对应pypi的密码,TWINE_USERNAME对应pypi的账号,当然必须是你的私人电脑。
现在你就可以在testpypi上看到你上传的项目了:
因为是pypi测试环境,对于用pip安装你构建的模块这一部分内容就不再做演示,如果想尝试的可以阅读官方文档,但最好是构建虚拟pip环境进行尝试,否则可能污染你的模块环境。
想了解更多Python模块的内容的可以阅读《》
强烈建议阅读
文章评论