打包发布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 socketserver框架全面解析
Sep 21 Python
Python使用matplotlib和pandas实现的画图操作【经典示例】
Jun 13 Python
Python拼接字符串的7种方法总结
Nov 01 Python
Python面向对象之类的定义与继承用法示例
Jan 14 Python
Django实现微信小程序的登录验证功能并维护登录态
Jul 04 Python
python画双y轴图像的示例代码
Jul 07 Python
更新pip3与pyttsx3文字语音转换的实现方法
Aug 08 Python
Django Docker容器化部署之Django-Docker本地部署
Oct 09 Python
mac使用python识别图形验证码功能
Jan 10 Python
python json 递归打印所有json子节点信息的例子
Feb 27 Python
实例代码讲解Python 线程池
Aug 24 Python
Python Pandas模块实现数据的统计分析的方法
Jun 24 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
中英文字符串翻转函数
2008/12/09 PHP
php下获取http状态的实现代码
2014/05/09 PHP
smarty中英文多编码字符截取乱码问题解决方法
2014/10/28 PHP
PHP中上传多个文件的表单设计例子
2014/11/19 PHP
浅谈PHP中的面向对象OOP中的魔术方法
2017/06/12 PHP
Laravel模型事件的实现原理详解
2018/03/14 PHP
js中document.getElementByid、document.all和document.layers区分介绍
2011/12/08 Javascript
你必须知道的Javascript知识点之"this指针"的应用
2013/04/23 Javascript
jQuery动画animate方法使用介绍
2013/05/06 Javascript
在JavaScript应用中实现延迟加载的方法
2015/06/25 Javascript
javascript关于继承解析
2016/05/10 Javascript
全面了解JS中的匿名函数
2016/06/29 Javascript
JQuery EasyUI学习教程之datagrid 添加、修改、删除操作
2016/07/09 Javascript
jQuery密码强度验证控件使用详解
2017/01/05 Javascript
JavaScript实现二维坐标点排序效果
2017/07/18 Javascript
vue和webpack打包项目相对路径修改的方法
2018/06/15 Javascript
webpack HappyPack实战详解
2019/10/08 Javascript
js实现计时器秒表功能
2019/12/16 Javascript
微信小程序indexOf的替换方法(推荐)
2020/01/14 Javascript
vue vantUI tab切换时 list组件不触发load事件的问题及解决方法
2020/02/14 Javascript
js实现全选和全不选
2020/07/28 Javascript
跟老齐学Python之有容乃大的list(3)
2014/09/15 Python
Python 2.7.x 和 3.x 版本的重要区别小结
2014/11/28 Python
Python+Selenium自动化实现分页(pagination)处理
2017/03/31 Python
Anaconda下配置python+opencv+contribx的实例讲解
2018/08/06 Python
django的ORM模型的实现原理
2019/03/04 Python
python如何更新包
2020/06/11 Python
AE美国鹰美国官方网站:American Eagle Outfitters
2016/08/22 全球购物
Linux的主要特性
2016/09/03 面试题
下面代码从性能上考虑,有什么问题
2015/04/03 面试题
临床护士自荐信
2014/01/31 职场文书
机械设计毕业生自荐信
2014/02/02 职场文书
2015年民主生活会发言材料
2014/12/15 职场文书
质量保证书怎么写
2015/02/27 职场文书
Nginx反向代理多个服务器的实现方法
2021/03/31 Servers
Win11 引入 Windows 365 云操作系统,适应疫情期间混合办公模式:启动时直接登录、模
2022/04/06 数码科技