四個 Python 項目管理與構建工具

不像 Java 在經歷了最初的手工構建,到半自動化的 Ant, 再到 Maven 基本就是事實上的標準了。其間 Maven 還接受了其他的 Gradle(Android 項目主推), SBT(主要是 Scala 項目), Ant+Ivy, Buildr 等的挑戰(zhàn),但都很難撼動 Maven 的江湖地位,而且其他的差不多遵循了 Maven 的目錄布局。
回到 Python,產生過 pip, pipenv, conda 那樣的包管理工具,但對項目的目錄布局沒有任何約定。
關于構建很多還是延續(xù)了傳統(tǒng)的 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
lint?????????????????check?style
test?????????????????run?tests?quickly?with?the?default?Python
test-all?????????????run?tests?on?every?Python?version?with?tox
coverage?????????????check?code?coverage?quickly?with?the?default?Python
docs?????????????????generate?Sphinx?HTML?documentation,?including?API?docs
servedocs????????????compile?the?docs?watching?for?changes
release??????????????package?and?upload?a?release
dist?????????????????builds?source?and?wheel?package
install??????????????install?the?package?to?the?active?Python's?site-packages
為使用上面的構建過程,需要安裝相應的包,如?tox,?wheel,?coverage,?sphinx,?flake8, 它們都可以通過 ?pip?來安裝。之后就可以?make test,?make coverage,?make docs,make dist?等。其中?make docs?可以生成一個很漂亮的 Web 文檔。
?PyScaffold 創(chuàng)建一個項目
PyScaffold 顧名思義,它是一個用來創(chuàng)建 Python 項目腳手架的工具,安裝和使用:
$?pip?install?pyscaffold
$?putup?sample
這樣創(chuàng)建了一個 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?是一個自動化測試和構建工具,它在構建過程中可創(chuàng)建 Python 虛擬環(huán)境,這讓測試和構建能有一個干凈的環(huán)境。
tox -av?能顯示出定義在?tox.ini?中所有的任務:
$?tox?-av
default?environments:
default???->?Invoke?pytest?to?run?automated?tests
additional?environments:
build?????->?Build?the?package?in?isolation?according?to?PEP517,?see?https://github.com/pypa/build
clean?????->?Remove?old?distribution?files?and?temporary?build?artifacts?(./build?and?./dist)
docs??????->?Invoke?sphinx-build?to?build?the?docs
doctests??->?Invoke?sphinx-build?to?run?doctests
linkcheck?->?Check?for?broken?links?in?the?documentation
publish???->?Publish?the?package?you?have?been?developing?to?a?package?index?server.?By?default,?it?uses?testpypi.?If?you?really?want?to?publish?your?package?to?be?publicly?accessible?in?PyPI,?use?the?`--?--repository?pypi`?option.
要執(zhí)行哪個命令便用?tox -e build,?tox -e docs?等
在我體驗 tox 命令過程中,每一步好像都比較慢,應該是創(chuàng)建虛擬機要花些時間。
?PyBuilder
最好再看另一個構建工具 PyBuilder, 它所創(chuàng)建出的目錄結構很接近于 Maven, 下面來瞧瞧
$?pip?install?pybuilder
$?mkdir?sample?&&?cd?sample????#?項目目錄需手工創(chuàng)建
$?pyb?--start-project??????????#?回答一些問題后創(chuàng)建所需的目錄和文件
完后看下它的目錄結構:
$?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?-??Execute?analysis?plugins.
????????????????????????????depends?on?tasks:?prepare?run_unit_tests
????????????????????clean?-?Cleans?the?generated?output.
??????????compile_sources?-?Compiles?source?files?that?need?compilation.
????????????????????????????depends?on?tasks:?prepare
?????????????????coverage?-?<no?description?available>
????????????????????????????depends?on?tasks:?verify
??????????????????install?-?Installs?the?published?project.
????????????????????????????depends?on?tasks:?package?publish(optional)
??????????????????package?-?Packages?the?application.?Package?a?python?application.
????????????????????????????depends?on?tasks:?compile_sources?run_unit_tests(optional)
??????????????????prepare?-?Prepares?the?project?for?building.?Creates?target?VEnvs
????????print_module_path?-?Print?the?module?path.
???????print_scripts_path?-?Print?the?script?path.
??????????????????publish?-?Publishes?the?project.
????????????????????????????depends?on?tasks:?package?verify(optional)?coverage(optional)
????run_integration_tests?-?Runs?integration?tests?on?the?packaged?application.
????????????????????????????depends?on?tasks:?package
???????????run_unit_tests?-?Runs?all?unit?tests.?Runs?unit?tests?based?on?Python'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 也是在構建或測試之前創(chuàng)建虛擬環(huán)境, 從 0.12.9 版開始可通過參數?--no-venvs?跳過創(chuàng)建虛擬環(huán)境這一步。使用了?--no-venvs?的話 Python 代碼將會在運行 ?pyb?的當前 Python 環(huán)境中執(zhí)行,所需的依賴將要手工安裝。
項目的依賴也要定義在?build.py?文件中
@init
def?set_properties(project):
????project.depends_on('boto3',?'>=1.18.52')
????project.build_depends_on('mock')
隨后在執(zhí)行?pyb?創(chuàng)建虛擬環(huán)境時就會安裝上面的依賴,并在其中運行測試與構建。
?Poetry
最后一個 Poetry, 感覺這是一個更為成熟,項目活躍度也更高的 Python 構建,它有著更強大的信賴管理功能,用?poetry add boto3?就能添加依賴,poetry show --tree?顯示出依賴樹??聪氯绾伟惭b及創(chuàng)建一個項目
$?pip?install?poetry
$?poetry?new?sample
它創(chuàng)建的項目比上面都簡單
$?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?文件,目錄等的生成需手動完成。
它不關注文檔的生成,代碼規(guī)范的檢查,代碼覆蓋率都沒有。它的項目配置更集中,全部在?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?來安裝依賴?),
poetry?add?boto3????
?#?將依照?pyproject.toml?文件中定義安裝相應的依賴到當前的?Python?虛擬環(huán)境中
?#?比如在?/lib/python3.9/site-packages?目錄中,安裝好模塊后也可讓測試用例使用
poetry?install???????
其他主要的
1.??poetry?build????#?構建可安裝的?*.whl?和?tar.gz?文件
2.??poetry?shell????#?會根據定義在?pyproject.toml?文件中的依賴創(chuàng)建并使用虛擬環(huán)境
3.??poetry?run?pytest????#?運行使用?pytest?的測試用例,如?tests/test_sample.py
4.??poetry?run?python?-m?unittest?tests/sample_tests.py??#?運行?unittest?測試用例
5.??poetry?export?--without-hashes?--output?requirements.txt??#?導出?requirements.txt?文件,?--dev??導出含?dev?的依賴,或者用?poetry?export?--without-hashes?>?requirements.txt
poetry run?能執(zhí)行任何系統(tǒng)命令,只是它會在它要的虛擬環(huán)境中執(zhí)行。所以可以想見,poetry?的項目要生成文檔或覆蓋率都必須用?poetry run ...?命令來支持?sphinx,?coverage?或?flake8。
在 sample 目錄(與 pyproject.toml 文件平級)中創(chuàng)建文件?my_module.py, 內容為
def?main():
????print('hello?poetry')
然后在?pyproject.toml?中寫上
[tool.poetry.scripts]
my-script="sample.my_module:main"
再執(zhí)行
$?poetry?run?my-script
就會輸出 "hello poetry"。
通過對以上四個工具的認識,項目結構的復雜度由 cookiecutter-pyproject -> PyScaffold -> PyBuilder -> Poetry 依次降低,使用的難度大略也是相同的順序。
原文鏈接:https://yanbin.blog/python-dependency-management-build-tools
文章轉載:Python編程學習圈
(版權歸原作者所有,侵刪)

點擊下方“閱讀原文”查看更多
