怎么将自己写的包打包上传到PyPi供其他人下载

怎么将自己写的包打包上传到PyPi供其他人下载

我们先装好依赖的包

打包和上传依赖wheel和twine这两个包。

pip install whell
pip install twine

先准备好项目

比方说我们想写这样一个包,这个包只有一个功能,那就是打印程序员佛祖字符画。

image.png
# __init__.py
buddha = ...

def print_buddha():
    print(buddha)

这个包就提供了一个佛祖字符画和一个打印函数。

# __main__.py
from . import print_buddha
print_buddha()

__main__.py让这个包可以被python -m直接运行,而__main__.py其实也就只干了一件事,那就是调用print_buddha打印字符画。

打包项目

打包项目你需要学习以下知识

  1. 创建setup.py
  2. 打包wheel
  3. 用twine上传的PyPi

一个标准的包的目录结构

packaging_tutorial
├── LICENSE # 开源协议证书
├── README.md # 说明文件
├── * your_pkg1
│ └── __init__.py
├── * your_pkg2
│ └── __init__.py
├──*setup.py # 顾名思义了
└── tests # 单元测试

加星的是必须的,其他的可有可无不影响打包和上传PyPi,就是不规范而已。

创建setup.py

setup.py是setuptools的构建脚本。它告诉setuptools有关您的软件包(例如名称和版本)以及要包括的代码文件的信息。

最基本的setup.py

# -*- coding: utf-8 -*-
from setuptools import setup, find_packages

try:
    long_description = open("README.md").read()
except IOError:
    long_description = ""

setup(
    name="Buddha",
    version="0.1.0",
    description="A pip package",
    license="MIT",
    author="你的名字",
    packages=find_packages(),
    long_description=long_description,
    classifiers=[
        "Programming Language :: Python",
        "Programming Language :: Python :: 3.6",
    ]
)

然后我们试一下打包:

 python setup.py sdist bdist_wheel

这是个组合命令,意思是先打sdist,再打bdist_wheel。


image.png

sdist打出来的是tar.gz格式压缩包,里面就是包源文件,可以供直接解压然后python setup.py install安装。

bdist_wheel打出来的是whl格式文件,这是pip官方安装包文件格式。

注意:egg格式已经过时了,现在PyPi的包都是用whl格式。

什么是egg?
Wheel和Egg都是打包格式,旨在支持不需要构建或编译的安装工件的用例,这在测试和生产工作流程中可能会耗费大量成本。
python setup.py bdist_egg 就可以打出egg格式的包。
Egg格式由setuptools于2004年推出,而Wheel格式由PEP 427于2012年推出。
目前,Wheel被认为是Python构建和二进制打包的标准。
这是Wheel和Egg之间重要区别的细分。

PiPy上传规范是同时要tar.gz和whl两个格式的包。

setup.py参数详解

注意:打了星的是必须参数

描述性参数 —— 提供包信息,供PiPy识别管理。

参数 类型 说明
*name str 包名称
*version str 包版本
*author str 程序的作者,这个包从头到尾都是你先开发的,那么你就是原作者。
*author_email str 程序的作者的邮箱地址
maintainer[^maintainer] str 维护者,如果你不是原作者,这个包是你修改原作者的包,那么你就是维护者。
maintainer_email str 维护者的邮箱地址
*url str 程序的官网地址
license str 程序的授权信息
description str 程序的简单描述
long_description str 程序的详细描述,详细描述在包上传PyPi后会在包页面下显示,支持RST和MD两种格式。
platforms str 程序适用的软件平台列表
classifiers str 程序的所属分类列表。影响上传PyPi会被分类到哪个类别。
keywords str 程序的关键字列表。同上。
download_url str 程序的下载地址

描述性参数只是作为PKG_INFO用的,没有什么特殊作用,就是描述用的,用来供pip和PyPi管理的,因此看上面就可以了。

包文件搜集 —— 设置包的哪些文件需要打包,怎么找这些文件。(很重要)

参数 说明
*package_dir 用来给setuptools指示packages里的包名要从哪些目录下找,默认是setup.py所在的根目录下找packages。
*packages 打包的包目录(通常为包含 __init__.py 的文件夹)。可以手动一个个包名添加,也可以直接用find_package自动找指定目录下所有带 __init__.py的文件夹。默认只将文件夹内所有的.py文件打包。如果文件夹内有其他类型文件,并且包依赖这些文件,需要通过设置package_data来声明要打包的文件/类型。搜集的文件夹会被安装到site-packages目录下。
*package_data 指定包内需要包含的数据文件类型。默认packages只会把.py文件打包进去,如果包依赖其他类型文件就需要在package_data里声明要打包进去的文件类型。
include_package_data 如果设置为True,这将告诉setuptools自动将它找到的所有数据文件包含在MANIFEST.in文件指定的软件包目录中。MANIFEST.in可通过setuptool插件自动跟踪版本控制工具生成。
exclude_package_data 将包名称映射到应该从包目录中排除的全局模式列表的字典。您可以使用它来修剪include_package_data包含的所有多余文件。有关完整的描述和示例,请参见“包括数据文件”部分。这个参数服务于include_package_data。
*py_modules 需要打包的 Python 单文件列表。如果模块只是一个py文件,那么添加到这里打包进去。注意只需要写文件名,不要带.py后缀。
*data_files 打包时需要打包的数据文件,如图片,配置文件等。格式("路径","文件"),路径是PYTHON_HOME目录下的相对路径。
scripts 指定可执行脚本,安装时脚本会被安装到系统PATH路径下(PYTHON_HOME\Scripts)。注意,一般是指命令行脚本,只有这种脚本安装到系统PATH路径下可以直接在命令行里调用。

setup.py 需要提供以上参数数据用来搜集需要打到包里的文件:
注意:打了星的是重要参数

根据上面的说明,我们来演练一下。首先项目要做些修改和添加一些功能。


image.png
  • 我们把包的源码都放到src目录下了。
  • buddha模块里增加一个buddha.txt的文本用来存我们的佛祖字符画,并将buddha模块里写死的字符画改为读这个文件。
  • 增加一个buddha.bat脚本,这个脚本里面就一行python -m buddha,调用buddha模块打印字符画,让buddha包支持命令行直接调用,就省去输入python -m的麻烦。
  • 增加一个字符画txt文本,里面就是佛祖字符画,这个文本就当做是个文档,我们会放到PYTHON_HOME的Doc文件夹里。
  • 增加一个single_module,试一下单文件模块怎么打包到包里。

接着修改setup.py:


setup(
    # 包信息
    ...

    # 包搜集
    package_dir={"":"src"},
    packages=find_packages("src"),
    package_data={"buddha":["*.txt"]}, 
    py_modules=["single_module"],
    package_data={"buddha":["*.txt"]}
    data_files=[("Doc",["src/buddha_doc.txt"])],
    scripts=["src/buddha.bat"],
)
  • find_packages需要指定从遍历哪个文件夹下的包。你可能会有疑问,为什么设置了package_dir还需要指明,不是会默认从src目录下找吗?其实是这样的,find_package这个函数只是返回一个字符串数组,在我们的项目里返回的就是["buddha"]。如果你不用find_package那么就是手写["buddha"]find_package只是个工具函数,省去你手写的麻烦,但是并不是setuptools内部的机制,find_package不认package_dirsetuptools最终会用packages的字符串数组到package_dir去找包,然后copybuild文件夹,最终一起打到dist目录下生成二进制whl文件。
  • packages默认只搜集py文件,buddha.txt不会被打到包里,因此需要在package_data里指明。
  • 我们的single_module是一个文件模块,packages只处理文件夹模块。因此要用py_modules参数来添加。
  • 我们有个buddha_doc.txt字符画文本,我们把它当做文档,希望包安装的时候能够被放到PYTHON_HOME目录下的Doc文件夹里。
    image.png

    (这本身没什么意义,只是演示怎么将自己的文件安装到自己希望的位置,如果你了解pth文件你就知道将文件安装到自己想要的位置有什么意义。)
  • 我们有个buddha.bat脚本,希望其能够被安装到PYTHON_HOME/Scripts目录下,这样命令行就能直接调用。

注意:data_filesscripts这两个参数不享受package_dir的效果,必须指定根目录下相对路径。

打包看看:

python setup.py sdist bdist_wheel

image.png

试一下安装:

pip isntall dist\buddha-0.1.0-py3-none-any.whl
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Processing c:\users\administrator\desktop\pylab\dist\buddha-0.1.0-py3-none-any.whl
Installing collected packages: buddha
Successfully installed buddha-0.1.0

我们去PYTHON_HOME看看我们的包被安装到哪里。


image.png
image.png
image.png
image.png

我们的包各种文件都被安装到了我们想要的位置。

试一下命令行调用buddha.bat:

image.png

python里导入buddha模块:

image.png

python里导入single_module模块:

image.png

依赖

参数 说明
ext_modules 指定c扩展模块
requires 指定依赖的其他包。你的包依赖了其他外部包就添加到这里,安装你的包的时候会一并安装。(已过时,被install_requires代替了)
install_requires 安装时需要安装的依赖包,同上。
setup_requires 指定运行 setup.py 文件本身所依赖的包。如果你在setup.py里面引用了依赖的包,就需要添加到这里。
extras_require 当前包的高级/额外特性需要依赖的分发包。extras你可以理解为可选外部依赖,比如你的包有导出数据功能,默认支持csv格式,如果要导出excel格式则需要安装openxlrd,那么openxlrd就是可选外部依赖。
provides 指定可以为哪些模块提供依赖。pip已经忽略这个参数了。
dependency_links 指定依赖包的下载地址。pip已经不支持了。

命令行

参数 类型 说明
cmdclass Dict[str, class] 添加自定义命令到setup.py命令行界面。
entry_points Dict[str,str] 动态发现服务和插件
  • cmdclass 比较少用到。我们知道setup.py有build install两个子命令,sdist和bdist_wheel也是其子命令。cmdclass可以让我们自己自定义setup.py的子命令。推荐文章《How To Add Custom Build Steps and Commands To setup.py
  • entry_points,某种意义上讲,跟前面的scripts参数很像,其作用就是为了公开一个命令给控制台。

例子:

    entry_points={
        "console_scripts": [
            "print_buddha = buddha:print_buddha",
        ],
        "gui_scripts": [
            "single_module = sindle_module:a_module",
        ]
    }
  • print_buddha是要生成的命令名,调用pring_buddha会去执行buddha模块里的print_buddha函数。
  • entry_point 格式是 命令名=模块路径(与import路径一致):函数名。
  • 包安装后会在Scripts目录下生成一个print_buddha.exe,这也是为什么我们可以直接在控制台调用print_buddha的原因。
  • console_scripts和gui_scripts的区别在于console_scripts下生成的exe调用的时候会用标准输入输出重定向到控制台,用起来就跟用命令一样;而gui_scripts生成的exe则不会重定向到控制台,控制台上调用了什么都不会打印,因此主要用来启动一个gui程序,例如用tkinter写的界面。
  • entry_points的作用有两个,当我们的入口函数不是模块的main.py而是某个py文件里的函数的时候,entry_points可以那个函数直接暴露到命令行。另一个作用是公开入口点给其他

压缩选项

参数 类型 说明
zip_safe bool 不压缩包,而是以目录的形式安装。这个选项在打egg格式的包的时候有用,现在都用whl不用egg了。

更加详细的说明可以去参考官方文档《setuptools documeng: Building and Distributing Packages with Setuptools

上传包到PyPi

注册PyPi账号

PyPi官网注册一个账号,通过各种验证通。

上传PyPi

python -m twine upload dist/*

将dist下的tar.gz和whl文件上传到PyPi。

会提示输入用户名密码,照着做就行。

上传成功后就会出现在PyPi和你的项目页里。

更新版本

你无法重新上传覆盖版本,所以如果你的包有bug或者有修改,你必须修改setup.py里的version,然后再打一次包上传。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容