打包发布Python模块的方法详解


Posted in Python onSeptember 18, 2016

前言

昨天把自己的VASP文件处理库进行了打包并上传到PyPI,现在可以直接通过pip和easy_install来安装VASPy啦(同时欢迎使用VASP做计算化学的童鞋们加星和参与进来),

VASPy的GotHub地址:https://github.com/PytLab/VASPy
VASPy的PyPI地址:https://pypi.python.org/pypi/vaspy/

由于自己的记性真是不咋地,怕时间久了就忘了,于是在这里趁热打铁以自己的VASPy程序为例对python的打包和上传进行下总结。

VASPy包文件结构

首先写贴上来VASPy包的整个文件结构, 后面的内容都是以此为例进行说明:

VASPy/
├── LICENSE
├── MANIFEST
├── MANIFEST.in
├── README.rst
├── requirements.txt
├── scripts
│  ├── change_incar_parameters.py
│  ├── create_inputs.py
│  └── ...
├── setup.cfg
├── setup.py
├── tests
│  ├── incar_test.py
│  ├── __init__.py
│  ├── oszicar_test.py
│  ├── outcar_test.py
│  ├── testdata
│  │  ├── CONTCAR
│  │  ├── DOS_SUM
│  │  ├── ELFCAR
│  │  └── ...
│  └── ...
└── vaspy
  ├── __init__.py
  ├── iter.py
  ├── matstudio.py
  └── ...
 
4 directories, 54 files

打包和安装第三方包的工具

这里我们需要借助setuptools和pip等工具进行自己包的打包和发布以及安装,如果需要构建成wheel还需要安装wheel模块。如果python版本>=2.7.9或者>=3.4,setuptools和pip是已经安装好的,可能需要进行更新到最新版本

pip install -U pip setuptools

可以使用包管理工具,例如

yum install pip
sudo apt-get install pip

通过get-pip.py脚本安装,如果检测到没有安装wheel和setuptools也会自动安装

python get-pip.py

具体的工具安装和介绍就不多讲了,可以请参考requirements for installing packages

包中不同文件的作用

setup.py

这个文件是打包整个项目最重要的文件,它里面提供了两个主要的功能:

setup()函数,此函数的参数指定了如何配置自己的项目。
命令行工具,包括打包,测试,发布等。可以通过下面的命令查看;

python setup.py --help-commands

setup.cfg

此文件包含了构建时候的一些默认参数例如构建bdist_wheel的时候的--universal参数

[bdist_wheel]
universal=1

这样每次打包的时候就会默认使用--universal参数了,效果类似:

python setup.py bdist_wheel --universal

README.rst

这个最初我是用markdown写的,打包发布到PyPI之后发现PyPI不支持markdown的渲染,页面上真是一片混乱,于是就用reStrutruedText的语法重新写了一遍。毕竟标记语言语法基本上可以秒上手,实在不行找个模板比葫芦画瓢就行。
reStructureText的语法规则可参考官方文档:Quick reStructuredText

其实还有一种方法就是使用pandoc将markdown转换成rst格式,一种省事的方式就是使用pyandoc模块在发布的时候自动转换。
具体方法可以参考:Use Markdown README's in Python modules

MANIFEST.in

此文件在打包的时候告诉setuptools还需要额外打包那些文件,例如我VASPy中的单元测试的测试数据文件我就使用这个文件将其包含进来。当然README,LICENSE这些也可以通过它来一起打包进来。
下面是我自己的MANIFEST.in的内容:

include README.rst
include requirements.txt
include LICENSE
recursive-include scripts *
recursive-include tests *

具体的语法规则可以参考:The MANIFEST.in template

vaspy/

此文件夹就是vaspy源代码所在的包。

tests/

此文件夹也是一个子包,包含了单元测试脚本,为了能使用python setup.py test进行单元测试,特地添加了__init__.pys使其成为一个包。

setup()的参数

这里只介绍我使用的几个参数,其他参数的具体使用可以参考:https://docs.python.org/3/distutils/setupscript.html

name

versions = "vaspy"

是整个项目的名字,打包后会使用此名字和版本号。

version

from vaspy import __version__
version = __version__

description

是一个简短的对项目的描述,一般一句话就好,会显示在pypi上名字下端。

long_description

是一个长的描述,相当于对项目的一个简洁,如果此字符串是rst格式的,PyPI会自动渲染成HTML显示。这里可以直接读取README.rst中的内容。

url

包的连接,通常为GitHub上的链接或者readthedocs的链接。

packages

需要包含的子包列表,setuptools提供了find_packages()帮助我们在根路径下寻找包,这个函数distutil是没有的。

setup_requires

这个参数定义了VASPy安装和顺利运行所需要的其他依赖项(最基本的),使用pip安装的时候会对这些依赖项进行安装。
关于这个参数与requirements.txt的区别可以参考:install_requires vs Requirements files

classifier

这个参数提供了一系列的分类,在PyPI上会将其放入不同的目录中讲项目进行归类。
具体的categories的名称和规则参考:https://pypi.python.org/pypi?%3Aaction=list_classifiers

test_suite

这个参数可以帮助我们使用

python setup.py test

来跑单元测试,再也不需要单独再写一个脚本例如run_tests.py这样来跑单元测试了。
此参数的官方解释:

A string naming a unittest.TestCase subclass (or a package or module containing one or more of them, or a method of such a subclass), or naming a function that can be called with no arguments and returns a unittest.TestSuite. If the named suite is a module, and the module has an additional_tests() function, it is called and the results are added to the tests to be run. If the named suite is a package, any submodules and subpackages are recursively added to the overall test suite.

也就是说这个参数可以接受多种类型的参数:

接收unittest.TestCase子类,我们可以讲所有单元测试写入一个测试用例中,然后import进来,再传你给test_suite
接收函数对象,此函数对象没有任何参数,且返回一个unittest.TestSuite.这样我们就可以单独写一个函数,将多个测试用例合并成一个suite然后返回,然后再将函数import进来传给test_suite。

模块和包名称,我就是使用这种方式,之前自己的测试都是分开的多个脚本,这样我添加一个__init__.py就可以将其变成一个包,将包名传给test_suite,setuptools就会神奇的将此包下的所有测试全部跑一边,这样我以后再加测试脚本的时候直接就添加新的脚本就好了,其他的都不需要改动了。

运行效果:

zjshao@SHAO-PC:/mnt/d/Dropbox/Code/CentOS_code/VASPy$ python setup.py test
running test
running egg_info
creating vaspy.egg-info
writing vaspy.egg-info/PKG-INFO
writing top-level names to vaspy.egg-info/top_level.txt
writing dependency_links to vaspy.egg-info/dependency_links.txt
writing manifest file 'vaspy.egg-info/SOURCES.txt'
reading manifest file 'vaspy.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'vaspy.egg-info/SOURCES.txt'
running build_ext
test_compare (tests.incar_test.InCarTest)
Make sure we can compare two InCar objects correctly. ... ok
test_eq (tests.incar_test.InCarTest)
Test __eq__() function. ... ok
...
此处省略若干输出
 
----------------------------------------------------------------------
Ran 22 tests in 3.574s
 
OK

发布自己的python包

1. 首先先去PyPI注册帐号

2. 配置~/.pypirc如下:

[distutils]
index-servers =
  pypi
  pypitest
 
[pypi]
username:ShaoZhengjiang
password:mypassword
 
[pypitest]
username:ShaoZhengjiang
password:mypassword

3. 然后注册并上传自己的包到测试服务器

pypi提供了一个测试服务器,我们可以在这个测试服务器上做测试。

python setup.py register -r pypitest

然后

python setup.py sdist upload -r pypitest

若没有问题我们应该不会得到任何错误。

4. 上传至PyPI

若上面的测试成功,我们就可以按照相同的步骤将包注册并上传。

python setup.py register -r pypi
python setup.py sdist upload -r pypi

Ok,之后我们就可以在PyPI(https://pypi.python.org/pypi/vaspy/)上看到我们自己的包了。

Python 相关文章推荐
python 数据加密代码
Dec 24 Python
浅谈MySQL中的触发器
May 05 Python
使用Python将数组的元素导出到变量中(unpacking)
Oct 27 Python
解决Python requests 报错方法集锦
Mar 19 Python
Python自动化运维之IP地址处理模块详解
Dec 10 Python
Python如何发布程序的详细教程
Oct 09 Python
PyQt5 closeEvent关闭事件退出提示框原理解析
Jan 08 Python
python 爬取疫情数据的源码
Feb 09 Python
Python实现AI换脸功能
Apr 10 Python
PyTorch: Softmax多分类实战操作
Jul 07 Python
刚学完怎么用Python实现定时任务,转头就跑去撩妹!
Jun 05 Python
理解python中装饰器的作用
Jul 21 Python
在python的类中动态添加属性与生成对象
Sep 17 #Python
Python中字符串的处理技巧分享
Sep 17 #Python
Python中对象迭代与反迭代的技巧总结
Sep 17 #Python
发布你的Python模块详解
Sep 15 #Python
Python selenium 三种等待方式解读
Sep 15 #Python
玩转python selenium鼠标键盘操作(ActionChains)
Apr 12 #Python
Python selenium文件上传方法汇总
Nov 19 #Python
You might like
乱谈我对耳机、音箱的感受
2021/03/02 无线电
php相当简单的分页类
2008/10/02 PHP
php 获取mysql数据库信息代码
2009/03/12 PHP
centos 5.6 升级php到5.3的方法
2011/05/14 PHP
php中长文章分页显示实现代码
2012/09/29 PHP
PHP中使用Session配合Javascript实现文件上传进度条功能
2014/10/15 PHP
CI框架使用composer安装的依赖包步骤与方法分析
2016/11/21 PHP
Docker配置PHP开发环境教程
2016/12/21 PHP
Django 中 cookie的使用
2017/08/17 PHP
javascript 进度条 实现代码
2009/07/30 Javascript
Javascript 学习笔记 错误处理
2009/07/30 Javascript
JQuery小知识
2010/10/15 Javascript
深入理解Javascript闭包 新手版
2010/12/28 Javascript
基于JQuery的浮动DIV显示提示信息并自动隐藏
2011/02/11 Javascript
js中indexof的用法详细解析
2013/12/24 Javascript
js 触发select onchange事件代码
2014/03/20 Javascript
浅谈javascript中return语句
2015/07/15 Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
2016/01/29 Javascript
javascript函数自动执行常用方法汇总
2016/03/28 Javascript
微信小程序 loading(加载中提示框)实例
2016/10/28 Javascript
基于vue.js的分页插件详解
2017/11/27 Javascript
node实现生成带参数的小程序二维码并保存到本地功能示例
2018/12/05 Javascript
详解微信小程序用定时器实现倒计时效果
2019/04/30 Javascript
使用原生js编写一个简单的框选功能方法
2019/05/13 Javascript
小程序瀑布流组件实现翻页与图片懒加载
2020/05/19 Javascript
[05:31]DOTA2英雄梦之声_第08期_莉娜
2014/06/23 DOTA
python中不能连接超时的问题及解决方法
2018/06/10 Python
python实现自动发送邮件
2018/06/20 Python
python使用zip将list转为json的方法
2018/12/31 Python
Django扫码抽奖平台的配置过程详解
2021/01/14 Python
番木瓜健康和保健产品第一大制造商:Herbal Papaya
2017/04/25 全球购物
Beauty Expert美国/加拿大:购买奢侈美容产品
2018/12/05 全球购物
Jdbc数据访问技术面试题
2012/03/30 面试题
护士岗位职责
2014/02/16 职场文书
查摆问题整改措施范文
2014/10/11 职场文书
用PYTHON去计算88键钢琴的琴键频率和音高
2022/04/10 Python