Python发布自己的包到pypi
为什么要打包发布
我们在日常开发中需要用到各种第三方库,帮助我们来提高开发效率,而不是重复的造轮子,并且,我们在使用第三方库的时候可能会遇到一些依赖呀,环境等问题,熟悉打包发布的流程对于我们解决这类问题很有帮助,下面我们来屡一下打包发布的流程。
第一版
项目结构如下:
./
└── foo.py
只有一个foo.py,我们在其中实现了一个函数
def hello(name):
return "Hello %s" % name
我们想让老王也用我这个功能,我们可以把这个foo.py发给老王,老王把foo.py放在自己的项目中,在其他文件中直接执行
from foo import hello
就可以使用我们的功能,但是这样的话,老王的项目中就包含了我们项目的代码,显得有些混乱,如果把我们的代码当成一个第三方库,让老王来用,就不会存在这样的问题了,python可以完成这样的操作
-
使用setuptools打包我们的项目,
-
在项目根目录下创建setup.py
from distutils.core import setup setup( name='foo', version='1.0', py_modules=['foo'], ) -
执行打包命令
python setup.py sdist生成dist文件夹,文件夹中包含foo-1.0.tar.gz,我们将这个文件发送给老王
-
-
安装
-
解压
tar -zxvf foo-1.0.tar.gz -
执行安装命令
cd foo-1.0 python setup.py install
-
这样,foo模块就安装在了python专门用来存放第三方库的路径:/lib/python3.6/site-packages,当我们import foo的时候,python会在sys.path中按照顺序去搜索,而我们这个路径是在sys.path中的,所以会正常引入。所以python setup.py install 的作用就是将python包放入到site-packages中
第二版
第一版中存在的问题
-
我们需要将打包后的文件发送给老王,相当于只能给认识的人用,如果想让互联网上不认识的人使用,怎么办呢?
在互联网上建立一个包管理平台,大家把包上传到这个里面,供其他人下载安装,这个平台就是pypi,我们也可以建立自己的包管理平台。
-
按照上面的搞法就实现了包的发布,下载安装,但是直接去下载,下载到本地解压,解压完之后安装,这些步骤是有些繁琐的,为了解决这个问题,就出现了用于安装第三方库的工具:easy_install,pip;还有用于发布的工具:poetry,twine
下面我们使用setuptool、twine、pip来发布一个我们自己的包
-
创建项目,项目结构
./ ├── evansjwu │ ├── __init__.py # 为空 │ └── work.py └── setup.pysetup.py内容如下
from setuptools import setup setup( name="evansjwu", version="0.0.1" packages=["evansjwu"] ) -
打包,下面命令生成的是tar.gz压缩文件,也可以指定生成其他类型的文件
python setup.py sdist -
上传,这里我们使用pypi提供的测试环境完成,需要在test.pypi.org注册账号
➜ roo python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/* Uploading distributions to https://test.pypi.org/legacy/ Enter your username: wushaojun321 Enter your password: Uploading evansjwu-0.0.1.macosx-10.9-x86_64.tar.gz 100%|█████████████████████████████████████████████████████████████| 3.24k/3.24k [00:08<00:00, 403B/s] View at: https://test.pypi.org/project/evansjwu/0.0.1/ -
在其他虚拟环境中安装、测试
pip install -i https://test.pypi.org/simple/ evansjwu安装完成之后就可以在自己的项目中from evansjwu import work 使用了
至此,我们就完成了一套简单的打包,发布流程,如果要发布到正式的pypi环境,只需要替换上面的url即可。上面只是为了便于理解,简化版的,实际的工作中。遇到的远比上面的情况复杂,比如,需要指定依赖的包,需要附带一些静态的数据文件等等,这些都可以在setup.py中配置。
以下是使用setuptool.setup函数之后,打包的一些可选参数
Standard commands:
build build everything needed to install
build_py "build" pure Python modules (copy to build directory)
build_ext build C/C++ extensions (compile/link to build directory)
build_clib build C/C++ libraries used by Python extensions
build_scripts "build" scripts (copy and fixup #! line)
clean clean up temporary files from 'build' command
install install everything from build directory
install_lib install all Python modules (extensions and pure Python)
install_headers install C/C++ header files
install_scripts install scripts (Python or otherwise)
install_data install data files
sdist create a source distribution (tarball, zip file, etc.)
register register the distribution with the Python package index
bdist create a built (binary) distribution
bdist_dumb create a "dumb" built distribution
bdist_rpm create an RPM distribution
bdist_wininst create an executable installer for MS Windows
check perform some checks on the package
upload upload binary package to PyPI
Extra commands:
bdist_wheel create a wheel distribution
alias define a shortcut to invoke one or more commands
bdist_egg create an "egg" distribution
develop install package in 'development mode'
dist_info create a .dist-info directory
easy_install Find/get/install Python packages
egg_info create a distribution's .egg-info directory
install_egg_info Install an .egg-info directory for the package
rotate delete older distributions, keeping N newest files
saveopts save supplied options to setup.cfg or other config file
setopt set an option in setup.cfg or another config file
test run unit tests after in-place build (deprecated)
upload_docs Upload documentation to PyPI
flake8 Run Flake8 on modules registered in setup.py
以下是setuptools.setup函数的一些可配置项
--name 包名称------------生成的egg名称
--version (-V) 包版本----生成egg包的版本号
--author 程序的作者------包的制作者名字
--author_email 程序的作者的邮箱地址
--maintainer 维护者
--maintainer_email 维护者的邮箱地址
--url 程序的官网地址
--license 程序的授权信息
--description 程序的简单描述-------程序的概要介绍
--long_description 程序的详细描述---程序的详细描述
--platforms 程序适用的软件平台列表
--classifiers 程序的所属分类列表
--keywords 程序的关键字列表
--packages 需要处理的包目录(包含__init__.py的文件夹)-------和setup.py同一目录下搜索各个含有 init.py的包
--py_modules 需要打包的python文件列表
--download_url 程序的下载地址
--cmdclass
--data_files 打包时需要打包的数据文件,如图片,配置文件等
--scripts 安装时需要执行的脚步列表
--package_dir 告诉setuptools哪些目录下的文件被映射到哪个源码包。一个例子:package_dir = {'': 'lib'},表示“root package”中的模块都在lib 目录中。
--requires 定义依赖哪些模块
--provides定义可以为哪些模块提供依赖
--find_packages() 对于简单工程来说,手动增加packages参数很容易,刚刚我们用到了这个函数,它默认在和setup.py同一目录下搜索各个含有 init.py的包。
其实我们可以将包统一放在一个src目录中,另外,这个包内可能还有aaa.txt文件和data数据文件夹。另外,也可以排除一些特定的包
find_packages(exclude=[".tests", ".tests.", "tests.", "tests"])
--install_requires = ["requests"] 需要安装的依赖包
--entry_points 动态发现服务和插件
python包管理工具的演化之路
以下工具按照时间顺序排序
-
distutils:2000年发布,能够进行python模块的安装和发布
-
setuptools和distribute,增强版的distutils,里面包含easy_install,其中distribute是setuptools的一个分支,其实是一个东西
-
eggs:一种setuptools可以识别的格式,使用setuptools可以解析,安装它
-
pip:2008年发布,easy_install 的替代品,支持更多格式的安装,包括
-
从pypi安装,默认方式
-
源码压缩包的方式:python setup.py sdist 产生的
-
whl格式
-
egg格式
-
发展趋势是:客户端使用pip,发布使用whl格式
总结
万变不离其宗,这东西的原理就是将一个python项目打包,发布到服务器上,其他人从服务器上下载安装使用,为了提升效率,人们开发出来一些工具,来简化中间这个操作,之前提倡eggs+easy_install,现在是pip+whl,之后可能会出现更便利的工具。