我在自己打包python文件以及上传到pypi上的过程中遇到了很多问题,找了很多博客,但是没有找到适合我的,总是会出现各种问题,所以我打算自己写个博客来记录一下成功打包并且上传到pypi的过程。本文主要讲解如何创建自己的python包并且上传到pypi以便能够方便pip install, 便于代码的封装和泛用,在windows下成功构建,各位看官按需使用。
0.1 文件目录架构
首先确定你要打包的文件,例如我要打包的是一个叫做learnkeyhole的包,那么它的文件结构为:
├──learnkeyhole
│ ├──learnkeyhole
│ ├── nets
│ ├── utils
│ ├── __init__.py
│ ├── __main__.py
│ ├── .gitignore
│ ├── miou.py
│ ├── ....
│ ├── window.ui
│ ├──README.md
│ ├──requirements.txt
│ ├──setup.cfg
│ ├──setup.py
│ ├──LICENSE
我的文件实际架构为
其中和以上代码里面不同的dist,build,.egg.info
文件是经过打包以后生成的,将在后面详解setup时提到。
0.1.1 创建包文件
按照上述文件目录架构创建各个文件,其中README.md
,LICENSE
参考自己的需求填写即可。
LICENSE文件编写
我使用MIT格式的LICENSE,按照这个格式粘贴到LICENSE里面即可。
MIT License
Copyright (c) 2023 My_name
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.
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文件编写
主要讲解一下自己的包的功能和使用方法,为了能够使该文件能够在pypi上显示(pypi支持rst文件显示),之后会在setup.py
中说明。
必须包含的文件
__init__.py
:我要打包的文件在learnkeyhole
中,为了setuptools
能够将文件夹识别为python包,必须要创建__init__.py
,内容为空。
同时我这里在learnkeyhole
下面还有子文件夹,其中的nets
和utils
中也需要创建__init__.py
以便能够在之后的打包中包括进去。
.gitignore
:这个文件需要在打包时忽略某些文件,例如打包时忽略__pycache__/
这个文件夹。
.idea/
__pycache__/
0.1.2 setup.py和setup.cfg创建
首先确认自己的环境中已经安装了setuptools
和distutils
库
setup.cfg
提供一种方式,可以让包的开发者提供命令的默认选项,同时为用户提供修改的机会。对setup.cfg的解析,是在setup.py之后,在命令行执行前。
setup.py
中具体描述构建包的各种参数,其中setup.py中的参数可以对setup.cfg中的参数进行覆盖。
cfg
的格式
以下是cfg的格式内容,按照注释进行自己的更改
[metadata]
name=learnkeyhole #your package name
version=your_version
author=your_name
author_email=your_email
description=Use this package to train your keyhole and predict it rapidly and right
license=MIT
url= https://github.com/wu-xz21/learnkeyhole #github地址或其他地址,这个地址随便填写就行,主要要能访问就行,最好是你的repository地址。
classifiers=
Environment :: Web Environment
Intended Audience :: Developers
License :: OSI Approved :: MIT License
#Natural Language :: Chinese #我这里把它注释掉了,因为之后构建的时候报错了,不知道为甚,不过没关系,注释掉没有影响
Operating System :: MacOS
Operating System :: Microsoft
Operating System :: POSIX
Operating System :: Unix
# Topic :: NLP #我这里把它注释掉了,因为之后构建的时候报错了,不知道为甚,不过没关系,注释掉没有影响
Topic :: Software Development :: Libraries :: Python Modules
Programming Language :: Python :: 3.6 #python版本
Programming Language :: Python :: 3.8
[options]
zip_safe=True
packages=find_packages() #这里find_package最好这样写,另外的写法可能会报错
include_package_data=True #重要
python_requires= >=3.6,<=3.9 #对于python版本的要求,
install_requires= #python包需要的依赖,根据自己的项目而定
pandas>=1.5.0
numpy>=1.20.2
scipy>=1.9.0
matplotlib>=3.5.0
opencv_python>=4.4.0.40
torch>=1.7.1
torchvision>=0.8.2
tqdm>=4.55.0
pillow>=8.2.0
h5py>=3.6.0
PyQt5>=5.14.0
以上内容中install_requires
参数为包运行所需要的环境,内容同requiresments.txt
中的内容相同。
其中,依赖最好通过>=
指定,直接用==
指定的话可能因为本身pip的版本未更新导致后续找不到版本,并且可以的话不要使用最新版本,有可能pip install
找不到。
name
,version
, author
,author_email
等内容均需自己指定,注意每次上传新的包到pypi时version
都需要往上更改版本,否则会因为版本冲突报错,导致上传失败。
setup.py
的格式
下面是setup.py
的格式
from __future__ import print_function #这个import必须放在第一行
import distutils.spawn
import sys
from setuptools import setup, find_packages
# 读取你的README.md文件以便能够在pypi中显示
from os import path
this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
long_description = f.read()
setup(
packages=find_packages(),
package_data = {
# 如果包中含有.txt文件,则包含它,我这里还有一个ui文件,那么也要包含。
'': ['*.txt'],
'': ['*.ui'],
},
include_package_data=True, #这个一定要设置为True
entry_points={
'console_scripts':[
'learnkeyhole = learnkeyhole.__main__:main'
]
},
long_description=long_description, #这里的long_description结合上面的读取README.md
long_description_content_type='text/markdown' #long_descriptionde的类型
)
要想自己写的README.md
能在pypi上显示,需要导入并且设置编码格式utf-8
,在setup
的参数中填入long_description
中。
为了包含非py文件,需要使用package_data
参数,例如我的包中还有ui文件,需要设置'':['*.ui']
来包含进来。
entry_points
参数设置了在命令行中输入包的名字之后的指令。
例如我的主要程序功能在__main__.py
中,因此,当我在命令行输入learnkeyhole
时,根据'learnkeyhole = learnkeyhole.__main__:main'
这条代码,__main__.py
中的main函数将会被执行。
0.2 打包
通过以上操作,我们的包文件已经成功构建,之后就是快乐的打包。
运行cmd
,转到setup.py
所在的文件夹,运行命令
python setup.py sdist
python setup.py sdist bdist_wheel
其中,第一条在dist文件夹里生成tar.gz文件,第二条生成whl文件,这两个文件之后均会被上传。
0.3 上传pypi
0.3.1 pypi注册
官方网址:https://pypi.org
.pypirc
文件创建
注册账号,为了在上传的时候不需要输入密码,需要创建.pypirc
文件。在默认的用户目录下创建,例如我的目录为:
C:\Users\wu-xz\.pypirc
文件内容为:
[distutils]
index-servers=
pypi
[pypi]
repository = https://upload.pypi.org/legacy/
username = wu-xz
password = ********* #这里输入你注册时使用的密码
0.3.2 使用twine工具
上传使用twine
包进行,在cmd中运行
pip install twine
安装好包以后,使用twine
检查需要打包的包,在setup.py
所在的文件夹运行
twine check dist/*
若输出为PASSED
,则说明没有问题;否则,根据报错检查错误,有可能会出现关于版本的错误,此时需要修改setup.py
中的version
。
检查通过以后,运行以下命令
twine upload dist/*
然后会上传到.pypirc中指定的账号中。
注意:此过程中不能使用vpn,亲测vpn会中断连接。
登录pypi主页,查看是否上传成功;我的主页这样显示:
其中,README.md也正常显示了。
0.3.3 从pypi上安装pip包
通过以上步骤,我已经成功打包并且上传,下面通过pip安装:
#我的叫learnkeyhole
pip install -i https://pypi.org/simple/ learnkeyhole
至此,整个流程就结束了。如果因为版本更新,你可以继续重复以上步骤更新版本。
以上内容纯属个人总结,难免有所差错,望批评指正!