四个 Python 项目管理的构建工具

Python 历时这么久以来至今还未有一个事实上标准的项目管理及构建工具,以至于造成 Python 项目的结构与构建方式五花八门。这或许是体现了 Python 的自由意志。

不像 Java 在经历了最初的手工构建,到半自动化的 Ant, 再到 Maven 基本就是事实上的标准了。其间 Maven 还接受了其他的 Gradle(Android 项目主推), SBT(主要是 Scala 项目), Ant+Ivy, Buildr 等的挑战,但都很难撼动 Maven 的江湖地位,而且其他的差不多遵循了 Maven 的目录布局。

回到 Python,产生过 pip, pipenv, conda 那样的包管理工具,但对项目的目录布局没有任何约定。

关于构建很多还是延续了传统的 Makefile 的方式,再就是加上 setup.py 和 build.py 用程序代码来进行安装与构建。关于项目目录布局,有做成项目模板的,然后做成工具来应用项目模板。

下面大概浏览一下四个工具的使用

CookieCutter

PyScaffold

PyBuilder

Poetry

CookieCutter 一个经典的 Python 项目目录结构

$ pip install cookiecutter

$ cookiecutter gh:audreyr/cookiecutter-pypackage

# 以 github 上的 audreyr/cookiecutter-pypackage 为模板,再回答一堆的问题生成一个 Python 项目

......

project_name [Python Boilerplate]: sample

......

最后由 cookiecutter 生成的项目模板是下面的样子:

$ tree sample

sample

├── AUTHORS.rst

├── CONTRIBUTING.rst

├── HISTORY.rst

├── LICENSE

├── MANIFEST.in

├── Makefile

├── README.rst

├── docs

│   ├── Makefile

│   ├── authors.rst

│   ├── conf.py

│   ├── contributing.rst

│   ├── history.rst

│   ├── index.rst

│   ├── installation.rst

│   ├── make.bat

│   ├── readme.rst

│   └── usage.rst

├── requirements_dev.txt

├── sample

│   ├──__init__.py

│   ├── cli.py

│   └── sample.py

├── setup.cfg

├── setup.py

├── tests

│   ├──__init__.py

│   └── test_sample.py

└── tox.ini

3 directories, 26 files

这大概是当前比较流行的目录结构的主体框架,主要元素是:

$ tree sample

sample

├── Makefile

├── README.rst

├── docs

│   └── index.rst

├── requirements.txt

├── sample

│   ├──__init__.py

│   └── sample.py

├── setup.cfg

├── setup.py

└── tests

├──__init__.py

└── test_sample.py

项目 sample 目录中重复 sample 目录中放置 Python 源文件,tests目录中是测试文件,再加一个docs目录放文档,README.rst, 其他的用于构建的 setup, setup.cfg 和 Makefile 文件。

这其实是一个很经典的 Python 项目结构,接下来的构建就用make命令了,输入make会看到定义在 Makefile 文件中的指令

$ make

clean                remove all build, test, coverage and Python artifacts

clean-build          remove build artifacts

clean-pyc            remove Python file artifacts

clean-test           remove test and coverage artifacts

lintcheckstyle

testrun tests quicklywiththedefaultPython

test-all             run testsonevery Pythonversionwithtox

coveragecheckcode coverage quicklywiththedefaultPython

docs                 generate Sphinx HTML documentation,includingAPI docs

servedocs            compile the docs watchingforchanges

releasepackageandupload arelease

dist                 buildssourceandwheelpackage

installinstallthepackagetothe active Python's site-packages

为使用上面的构建过程,需要安装相应的包,如tox,wheel,coverage,sphinx,flake8, 它们都可以通过pip来安装。之后就可以make test,make coverage,make docs,make dist等。其中make docs可以生成一个很漂亮的 Web 文档。

PyScaffold 创建一个项目

PyScaffold 顾名思义,它是一个用来创建 Python 项目脚手架的工具,安装和使用:

$ pip install pyscaffold

$ putup sample

这样创建了一个 Python 项目,目录结构与前面  cookiecutter 所选的模板差不多,只不过它把源文件放在了src目录,而非sample目录。

$ tree sample

sample

├── AUTHORS.rst

├── CHANGELOG.rst

├── CONTRIBUTING.rst

├── LICENSE.txt

├── README.rst

├── docs

│   ├── Makefile

│   ├── _static

│   ├── authors.rst

│   ├── changelog.rst

│   ├── conf.py

│   ├── contributing.rst

│   ├── index.rst

│   ├── license.rst

│   ├── readme.rst

│   └── requirements.txt

├── pyproject.toml

├── setup.cfg

├── setup.py

├── src

│   └── sample

│       ├──__init__.py

│       └── skeleton.py

├── tests

│   ├── conftest.py

│   └── test_skeleton.py

└── tox.ini

整个项目的构建就要用tox这个工具了。tox是一个自动化测试和构建工具,它在构建过程中可创建 Python 虚拟环境,这让测试和构建能有一个干净的环境。

tox -av能显示出定义在tox.ini中所有的任务:

$ tox -av

defaultenvironments:

default-> Invoke pytesttorun automated tests

additional environments:

build     -> Build the packageinisolation accordingtoPEP517, see https://github.com/pypa/build

clean     -> Remove old distribution filesandtemporary build artifacts (./buildand./dist)

docs      -> Invoke sphinx-buildtobuild the docs

doctests  -> Invoke sphinx-buildtorun doctests

linkcheck -> Checkforbroken linksinthe documentation

publish   -> Publish the package you have been developingtoa packageindexserver. Bydefault, itusestestpypi.Ifyou really wanttopublish your packagetobe publicly accessibleinPyPI, use the `-- --repository pypi` option.

要执行哪个命令便用tox -e build,tox -e docs等

在我体验 tox 命令过程中,每一步好像都比较慢,应该是创建虚拟机要花些时间。

PyBuilder

最好再看另一个构建工具 PyBuilder, 它所创建出的目录结构很接近于 Maven, 下面来瞧瞧

$ pip install pybuilder

$mkdir sample &&cdsample# 项目目录需手工创建

$pyb --start-project# 回答一些问题后创建所需的目录和文件

完后看下它的目录结构:

$ tree sample.

├── build.py

├── docs

├── pyproject.toml

├── setup.py

└── src

├── main

│   ├── python

│   └── scripts

└── unittest

└── python

构建过程仍然是用pyb命令,可用pyb -h查看帮助,pyb -t列出所有的任务, PyBuilder 的任务是以插件的方式加入的,插件配置在build.py文件中。

$ pyb -t sample

Tasks found for project "sample":

analyze-Executeanalysis plugins.

dependsontasks:preparerun_unit_tests

clean - Cleans thegeneratedoutput.

compile_sources - Compilessourcefiles that need compilation.

dependsontasks:prepare

coverage - 

dependsontasks:verify

install- Installs the published project.

dependsontasks:packagepublish(optional)

package- Packages the application.Packagea python application.

dependsontasks: compile_sources run_unit_tests(optional)

prepare- Prepares theprojectforbuilding. Creates target VEnvs

print_module_path - Print themodulepath.

print_scripts_path - Print the script path.

publish - Publishes the project.

dependsontasks:packageverify(optional) coverage(optional)

run_integration_tests - Runs integration testsonthe packaged application.

dependsontasks:package

run_unit_tests - Runs all unit tests. Runs unit tests basedonPython's unittest module

depends on tasks: compile_sources

upload - Upload a project to PyPi.

verify - Verifies the project and possibly integration tests.

depends on tasks: run_integration_tests(optional)

$ pyb run_unit_tests sample

PyBuilder 也是在构建或测试之前创建虚拟环境, 从 0.12.9 版开始可通过参数--no-venvs跳过创建虚拟环境这一步。使用了--no-venvs的话 Python 代码将会在运行pyb的当前 Python 环境中执行,所需的依赖将要手工安装。

项目的依赖也要定义在build.py文件中

@init

defset_properties(project):

project.depends_on('boto3','>=1.18.52')

project.build_depends_on('mock')

随后在执行pyb创建虚拟环境时就会安装上面的依赖,并在其中运行测试与构建。

Poetry

最后一个 Poetry, 感觉这是一个更为成熟,项目活跃度也更高的 Python 构建,它有着更强大的信赖管理功能,用poetry add boto3就能添加依赖,poetry show --tree显示出依赖树。看下如何安装及创建一个项目

$ pipinstallpoetry

$ poetrynewsample

它创建的项目比上面都简单

$ tree sample

sample

├── README.rst

├── pyproject.toml

├── sample

│   └──__init__.py

└── tests

├──__init__.py

└── test_sample.py

如果给poetry new带上--src参数,那么源文件目录sample会放在src目录下,即sample/src/sample.

poetry init会在当前目录中生成pyproject.toml文件,目录等的生成需手动完成。

它不关注文档的生成,代码规范的检查,代码覆盖率都没有。它的项目配置更集中,全部在pyproject.toml文件中,toml是什么呢?它是一种配置文件的格式 Tom's Obvious, Minimal Language (https://github.com/toml-lang/toml).

pyproject.toml有些类似 NodeJS 的package.json文件,比如 poetry add, poetry install 命令的行

# 往 pyproject.toml 中添加对  boto3 的依赖并安装(add 还能从本地或 git 来安装依赖 ),

poetryaddboto3

# 将依照 pyproject.toml 文件中定义安装相应的依赖到当前的 Python 虚拟环境中

# 比如在 <test-venv>/lib/python3.9/site-packages 目录中,安装好模块后也可让测试用例使用

poetry install

其他主要的

1.  poetry build# 构建可安装的 *.whl 和 tar.gz 文件

2.  poetry shell# 会根据定义在 pyproject.toml 文件中的依赖创建并使用虚拟环境

3.  poetry run pytest# 运行使用 pytest 的测试用例,如 tests/test_sample.py

4.  poetry run python -m unittest tests/sample_tests.py# 运行 unittest 测试用例

5.  poetryexport--without-hashes --output requirements.txt# 导出 requirements.txt 文件, --dev  导出含 dev 的依赖,或者用 poetry export --without-hashes > requirements.txt

poetry run能执行任何系统命令,只是它会在它要的虚拟环境中执行。所以可以想见,poetry的项目要生成文档或覆盖率都必须用poetry run ...命令来支持sphinx,coverage或flake8。

在 sample 目录(与 pyproject.toml 文件平级)中创建文件my_module.py, 内容为

defmain():

print('hello poetry')

然后在pyproject.toml中写上

[tool.poetry.scripts]

my-script="sample.my_module:main"

再执行

$ poetry runmy-script

就会输出 "hello poetry"。

通过对以上四个工具的认识,项目结构的复杂度由 cookiecutter-pyproject -> PyScaffold -> PyBuilder -> Poetry 依次降低,使用的难度大略也是相同的顺序。

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

推荐阅读更多精彩内容