怎么将自己写的包打包上传到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,然后再打一次包上传。

你可能感兴趣的:(怎么将自己写的包打包上传到PyPi供其他人下载)