这两天为了方便,折腾了一下自己的写的一个工具,研究了一下怎么发布自己的Python库,记录在此,主要介绍以下内容
- Python库发布的完整过程
- 通过Python库发布自己的命令行工具的方法
检查目录组织
要发布Python库,首先要检查自己的目录组织是否符合编译程序的要求,以我的库MarkTex为例,目录树结构如下:
.
├── MANIFEST.in
├── marktex
│ ├── config.py
│ ├── example
│ │ └── ...
│ ├── __init__.py
│ ├── markast
│ │ ├── document.py
│ │ ├── environment.py
│ │ ├── __init__.py
│ │ ├── line.py
│ │ ├── parser.py
│ │ ├── token.py
│ │ ├── utils.py
│ │ └── xmls.py
│ ├── marktex.py
│ └── texrender
│ └── ...
└── setup.py
可以看到在项目根目录下的一的子目录./marktex
才是项目代码所在位置,项目根目录下,除了项目代码,必须的文件是setup.py
检查包内引用
如果引用不对,即使因为IDE的原因项目没有报错,编译打包后运行一样也会报错。
具体引用的方式,经过我的测试,有两种,第一种是假设自己的包已经被编译成功,那么我们要引入包内的相关内容,可以写绝对路径,如我在./marktex/markast/environment.py
下要引入./marktex/markast/line.py
中的一个类,那么写法可以是:
# environment.py
from marktex.markast.line import NewLine
这种绝对路径的方法可以引入项目下其他文件夹的类:
# environment.py
from marktex.texrender.toTex import MarkTex
另一种就是相对路径,将绝对路径下包括文件所在的目录在内的全部删除,只留下点即可
# environment.py
from .line import NewLine
注意这种方法就只能是所在目录内的相互引用,Python中没有如../
这样还可以去上一层找包的语法
具体也可以不用检查的那么仔细,在编译完后,完全可以在其他目录导入包尝试一下,看出错代码再改即可。
安装文件setup.py
我们使用setuptools
这个库进行Python库的编译,编译之前我们要对我们的项目进行相关说明,也就有了setup.py
这个文件,这个文件的模板如下,可以直接套用:
from setuptools import setup,find_packages
long_description = "" #这里可以导入外部的README.md
setup(
name='TODO', # 项目名
version='TODO', # 如 0.0.1/0.0.1.dev1
description='TODO',
long_description = long_description,
url='TODO', # 如果有github之类的相关链接
author='TODO', # 作者
author_email='TODO', # 邮箱
license='MIT',
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
],
keywords='TODO', # 关键词之间空格相隔一般
install_requires = [
"TODO",
],
packages=find_packages(),
include_package_data = True, #
entry_points={ #如果发布的库包括了命令行工具
'console_scripts':[
'cmdname = cmdtoolfilepath:methodname' #
]
},
)
里面的大部分都比较通俗易懂,有两个参数需要注意,一个是include_package_data
,编译的时候如果项目内有非.py
的文件,默认是不会编译进去的,如果项目用到一些相关文件,可以将该参数设置为True,同时在setup.py
文件旁生成一个MANIFEST.in
文件来声明哪些文件是包括的,该文件的格式如下:
include marktex/example/*.md
注意其路径是相对于运行setup.py
时的当前路径来说的,比如我的项目是marktex
,要添加该项目example
目录下的所有md文件,那么写的时候一般从marktex/example/
开始写
还有一个参数是entry_points
,该参数用于生成脚本工具,格式如模板里所示,具体的内容,以我的项目为例,我要将marktex.marktex.py
作为最后调用的工具,那么内容应该这样写:
'console_scripts':[
'marktex = marktex.marktex:main'
]
其中,左侧表示最终命令行中使用的命令的名词,右侧则是具体到方法的路径,如果没有具体的方法,那么可以写main来表示该文件,该文件如何具体编写可以参考我的项目文件 marktex.py
当编译成功后,我就可以进行如些的操作:
marktex a.md -o "./"
编译与发布
最后两步是编译和发布,编译命令很简单:
python setup.py sdist bdist_wheel
编译完成后,如果你要先在本地安装测试,那么在dist文件下找到你编译后的文件,运行:
pip install path/to/whl/xxx.whl
如果没有更新版本号,那安装多半是无法继续进行下去,可以通过添加参数强制安装:
pip install --force-reinstall path/to/whl/xxx.whl
在测试完成后,就到了最后的发布环节,你首先需要在 https://pypi.org/ 注册一个账号,随后运行,根据提示输入账号密码:
twine upload --skip-existing dist/*
PS:当然,第一次你可能需要安装
twine
这个包
PSS:如果配置好文件可以在以后不需要输入账号密码,具体如何配置请Google
至此,就完成了全部的过程
附录
为了方便操作,我写了两个脚本来帮助我完成编译、安装、上传的任务,附在这里:
build.cmd
用于编译,并且在目录下找到最后生成的文件进行编译
python setup.py sdist bdist_wheel
SET CountI=0
SET BakDir="./dist/"
for /f %%a in ('dir %BakDir% /a:-d /B /o:-D') do (
rem echo %%a
SET FileName=%%a
SET CountI=CountI+1
rem echo %CountI%
if %CountI% == 0 goto bakup2
)
:bakup2
rem pip install --force-reinstall %BakDir%%FileName%
pip install %BakDir%%FileName%
publish.cmd
用于发布版本
twine upload --skip-existing dist/*