收藏!四個 Python 項目管理與構(gòu)建工具
↑?關(guān)注 + 星標?,每天學(xué)Python新技能
后臺回復(fù)【大禮包】送你Python自學(xué)大禮包
不像 Java 在經(jīng)歷了最初的手工構(gòu)建,到半自動化的 Ant, 再到 Maven 基本就是事實上的標準了。其間 Maven 還接受了其他的 Gradle(Android 項目主推), SBT(主要是 Scala 項目), Ant+Ivy, Buildr 等的挑戰(zhàn),但都很難撼動 Maven 的江湖地位,而且其他的差不多遵循了 Maven 的目錄布局。
回到 Python,產(chǎn)生過 pip, pipenv, conda 那樣的包管理工具,但對項目的目錄布局沒有任何約定。
關(guān)于構(gòu)建很多還是延續(xù)了傳統(tǒng)的 Makefile 的方式,再就是加上 setup.py 和 build.py 用程序代碼來進行安裝與構(gòu)建。關(guān)于項目目錄布局,有做成項目模板的,然后做成工具來應(yīng)用項目模板。
下面大概瀏覽一下四個工具的使用
CookieCutter
PyScaffold
PyBuilder
Poetry
?CookieCutter 一個經(jīng)典的 Python 項目目錄結(jié)構(gòu)
$?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
這大概是當前比較流行的目錄結(jié)構(gòu)的主體框架,主要元素是:
$?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 目錄中重復(fù) sample 目錄中放置 Python 源文件,tests 目錄中是測試文件,再加一個 docs 目錄放文檔,README.rst, 其他的用于構(gòu)建的 setup, setup.cfg 和 Makefile 文件。
這其實是一個很經(jīng)典的 Python 項目結(jié)構(gòu),接下來的構(gòu)建就用 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
為使用上面的構(gòu)建過程,需要安裝相應(yīng)的包,如 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 項目,目錄結(jié)構(gòu)與前面 ?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
整個項目的構(gòu)建就要用 tox 這個工具了。tox 是一個自動化測試和構(gòu)建工具,它在構(gòu)建過程中可創(chuàng)建 Python 虛擬環(huán)境,這讓測試和構(gòu)建能有一個干凈的環(huán)境。tox 使用教程
tox -av 能顯示出定義在 tox.ini 中所有的任務(wù):
$?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 等, 下面是如何使用 PyScaffold 的動圖:https://yanbin.blog/wp-content/uploads/2021/09/pyscaffold-demo.gif
在我體驗 tox 命令過程中,每一步好像都比較慢,應(yīng)該是創(chuàng)建虛擬機要花些時間。tox 使用教程
?PyBuilder
最好再看另一個構(gòu)建工具 PyBuilder, 它所創(chuàng)建出的目錄結(jié)構(gòu)很接近于 Maven, 下面來瞧瞧
$?pip?install?pybuilder
$?mkdir?sample?&&?cd?sample????#?項目目錄需手工創(chuàng)建
$?pyb?--start-project??????????#?回答一些問題后創(chuàng)建所需的目錄和文件
完后看下它的目錄結(jié)構(gòu):
$?tree?sample
.
├──?build.py
├──?docs
├──?pyproject.toml
├──?setup.py
└──?src
????├──?main
????│???├──?python
????│???└──?scripts
????└──?unittest
????????└──?python
構(gòu)建過程仍然是用 pyb 命令,可用 pyb -h 查看幫助,pyb -t 列出所有的任務(wù), PyBuilder 的任務(wù)是以插件的方式加入的,插件配置在 ?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 也是在構(gòu)建或測試之前創(chuàng)建虛擬環(huán)境, 從 0.12.9 版開始可通過參數(shù) --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)境時就會安裝上面的依賴,并在其中運行測試與構(gòu)建。
?Poetry
最后一個 Poetry, 感覺這是一個更為成熟,項目活躍度也更高的 Python 構(gòu)建,它有著更強大的信賴管理功能,用 poetry add boto3 就能添加依賴,poetry show --tree 顯示出依賴樹。看下如何安裝及創(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 參數(shù),那么源文件目錄 sample 會放在 src 目錄下,即 sample/src/sample.
poetry init 會在當前目錄中生成 pyproject.toml 文件,目錄等的生成需手動完成。
它不關(guān)注文檔的生成,代碼規(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?文件中定義安裝相應(yīng)的依賴到當前的?Python?虛擬環(huán)境中
?#?比如在?/lib/python3.9/site-packages?目錄中,安裝好模塊后也可讓測試用例使用
poetry?install???????
其他主要的
1.??poetry?build????#?構(gòu)建可安裝的?*.whl?和?tar.gz?文件
2.??poetry?shell????#?會根據(jù)定義在?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??#?導(dǎo)出?requirements.txt?文件,?--dev??導(dǎo)出含?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, 內(nèi)容為
def?main():
????print('hello?poetry')
然后在 pyproject.toml 中寫上
[tool.poetry.scripts]
my-script="sample.my_module:main"
再執(zhí)行
$?poetry?run?my-script
就會輸出 "hello poetry"。
通過對以上四個工具的認識,項目結(jié)構(gòu)的復(fù)雜度由 cookiecutter-pyproject -> PyScaffold -> PyBuilder -> Poetry 依次降低,使用的難度大略也是相同的順序。
?參考鏈接
Set up tests, linters and type checking in Python projects in 2020 (https://medium.com/@cristobalcl/set-up-tests-linters-and-type-checking-in-python-projects-in-2020-9cc1b1e2750d) (介紹了 poetry 項目如何支持 coverage, lint 和 type checking)
Dependency management tools for Python (https://snyk.io/blog/dependency-management-tools-python/)
推薦閱讀
推薦閱讀
