戰(zhàn):讓 Flaskr 項(xiàng)目可安裝——pyproject.toml 描述項(xiàng)目與 pip 可編輯安裝全解)
Flask 教程實(shí)戰(zhàn)讓 Flaskr 項(xiàng)目可安裝——pyproject.toml 描述項(xiàng)目與 pip 可編輯安裝全解【免費(fèi)下載鏈接】flaskThe Python micro framework for building web applications.項(xiàng)目地址: https://gitcode.com/gh_mirrors/fl/flask本篇基于 Flask 官方教程的 Make the Project Installable 章節(jié)展開(kāi)講解如何把一個(gè) Flask 應(yīng)用教程中的博客應(yīng)用 Flaskr變成標(biāo)準(zhǔn)的 Python 可安裝項(xiàng)目編寫pyproject.toml、以可編輯editable模式安裝、理解依賴聲明與構(gòu)建后端。讀完后你將掌握使用標(biāo)準(zhǔn) Python 打包工具鏈管理項(xiàng)目依賴、在任意目錄導(dǎo)入應(yīng)用、并隔離測(cè)試環(huán)境與開(kāi)發(fā)環(huán)境的完整方案同時(shí)能看到 Flask 倉(cāng)庫(kù)自身正是用同一套方式打包的見(jiàn) examples/tutorial 示例工程與 pyproject.toml。為什么要把項(xiàng)目做成可安裝在教程前面各章中Flaskr 應(yīng)用由 examples/tutorial/flaskr 組成的包之所以能運(yùn)行僅僅是因?yàn)槟阋恢蓖A粼陧?xiàng)目目錄下Python 解釋器恰好能把flaskr當(dāng)作本地模塊找到。讓項(xiàng)目可安裝Make the Project Installable意味著你可以構(gòu)建出一個(gè)wheel文件并在另一個(gè)環(huán)境中安裝它——就像當(dāng)初在開(kāi)發(fā)環(huán)境中安裝 Flask 一樣。這帶來(lái)的收益包括部署方式統(tǒng)一部署你的項(xiàng)目與安裝任何其他 Python 庫(kù)完全一樣全程使用標(biāo)準(zhǔn) Python 工具pip、wheel、虛擬環(huán)境管理一切隨處可導(dǎo)入安裝之后無(wú)論從哪個(gè)目錄運(yùn)行都可以import flaskr不再受必須在項(xiàng)目目錄里的限制依賴隨包聲明可以像管理其他包一樣管理項(xiàng)目依賴pip install yourproject.whl會(huì)連帶安裝dependencies中聲明的所有依賴測(cè)試環(huán)境隔離測(cè)試工具如 pytest 虛擬環(huán)境可以把測(cè)試環(huán)境從開(kāi)發(fā)環(huán)境中隔離出來(lái)避免兩者互相污染。教程原文在此處有一個(gè)值得記住的提示這一步雖然是教程靠后才引入的但在你今后的真實(shí)項(xiàng)目中應(yīng)該從一開(kāi)始就這么做。用 pyproject.toml 描述項(xiàng)目pyproject.toml文件描述你的項(xiàng)目及其構(gòu)建方式。教程給出的最小完整版本如下# pyproject.toml [project] name flaskr version 1.0.0 description The basic blog app built in the Flask tutorial. dependencies [ flask, ] [build-system] requires [flit_core4] build-backend flit_core.buildapi逐項(xiàng)說(shuō)明各字段的含義字段作用[project] name項(xiàng)目/包名即 pip 中顯示的名稱這里為flaskr[project] version語(yǔ)義化版本號(hào)教程示例固定為1.0.0[project] description一句話項(xiàng)目描述展示在包索引等元數(shù)據(jù)中[project] dependencies運(yùn)行時(shí)依賴列表。安裝本包時(shí) pip 會(huì)自動(dòng)解析并安裝。flask不帶版本約束表示任意最新兼容版本[build-system] requires構(gòu)建本包所需的環(huán)境依賴。flit_core4表示使用 flit 構(gòu)建工具且限定大版本低于 4[build-system] build-backendPEP 517 構(gòu)建后端入口flit_core.buildapi是 flit 提供的標(biāo)準(zhǔn)后端關(guān)于這些文件與選項(xiàng)的更多解釋可參考 Python 官方的 Packaging 教程文檔中鏈接的 packaging.python.org 教程頁(yè)面這里不再展開(kāi)。倉(cāng)庫(kù)中的教程示例工程提供了更完整的真實(shí)版本 examples/tutorial/pyproject.toml在最小版本之上補(bǔ)充了實(shí)際項(xiàng)目中常見(jiàn)的配置# examples/tutorial/pyproject.toml節(jié)選 [project] name flaskr version 1.0.0 description The basic blog app built in the Flask tutorial. readme README.rst license {file LICENSE.txt} maintainers [{name Pallets, email contactpalletsprojects.com}] classifiers [Private :: Do Not Upload] dependencies [ flask, ] [project.urls] Documentation https://flask.palletsprojects.com/tutorial/ [project.optional-dependencies] test [pytest] [build-system] requires [flit_core4] build-backend flit_core.buildapi [tool.flit.module] name flaskr [tool.flit.sdist] include [ tests/, ] [tool.pytest.ini_options] testpaths [tests] filterwarnings [error]與教程最小版本的差異點(diǎn)值得注意[project.optional-dependencies] test [pytest]聲明了可選的測(cè)試依賴組安裝命令寫作pip install .[test]這樣 pytest 只在需要跑測(cè)試時(shí)才會(huì)進(jìn)入環(huán)境[tool.flit.module] name flaskr顯式告訴 flit 要打包的模塊名。由于name flaskr與頂層包目錄同名這一節(jié)其實(shí)也可以省略示例工程寫出它屬于顯式化[tool.flit.sdist] include把tests/目錄納入源碼發(fā)行sdist保證發(fā)布出去的源碼包含測(cè)試classifiers [Private :: Do Not Upload]是一個(gè)約定俗成的分類器防止有人誤把這個(gè)私有示例上傳到 PyPI。值得一提的是Flask 框架本身也使用同一套 flit 打包體系??磦}(cāng)庫(kù)根目錄的 pyproject.toml# 根目錄 pyproject.toml節(jié)選 [build-system] requires [flit_core3.11,4] build-backend flit_core.buildapi [tool.flit.module] name flask并且 pyproject.toml 中的[project.scripts]一節(jié)聲明了flask flask.cli:main控制臺(tái)腳本入口——這就是為什么pip install flask之后你在終端能直接使用flask命令。教程項(xiàng)目不需要自定義命令入口Flaskr 的命令如init-db是通過(guò) Click 注冊(cè)到應(yīng)用上的由flask命令發(fā)現(xiàn)并調(diào)用。以可編輯模式安裝項(xiàng)目在激活的虛擬環(huán)境中用pip安裝你的項(xiàng)目$ pip install -e .這條命令告訴 pip 在當(dāng)前目錄找到pyproject.toml并以editable可編輯或development開(kāi)發(fā)模式安裝項(xiàng)目??删庉嬆J降暮诵暮x是后續(xù)修改本地代碼時(shí)無(wú)需重新安裝只有在改變項(xiàng)目元數(shù)據(jù)例如dependencies中新增依賴時(shí)才需要重新執(zhí)行安裝命令。Flask 官方教程示例工程同樣遵循這一流程。其 examples/tutorial/README.rst 給出的完整步驟是先創(chuàng)建并激活虛擬環(huán)境再執(zhí)行pip install -e .如果基于 Flask 主分支開(kāi)發(fā)則先pip install -e ../..從源碼安裝開(kāi)發(fā)版 Flask再pip install -e .安裝 Flaskr。安裝完成后可以用pip list觀察項(xiàng)目是否已安裝教程原文的輸出示例$ pip list Package Version Location -------------- --------- ---------------------------------- click 6.7 Flask 1.0 flaskr 1.0.0 /home/user/Projects/flask-tutorial itsdangerous 0.24 Jinja2 2.10 MarkupSafe 1.0 pip 9.0.3 Werkzeug 0.14.1輸出中flaskr一行的Location指向項(xiàng)目目錄這是可編輯安裝的典型特征包的位置不是 site-packages 里的副本而是源碼目錄本身。示例中的具體版本號(hào)是教程撰寫時(shí)期的舊版本當(dāng)前倉(cāng)庫(kù)的 Flask 在 pyproject.toml 中聲明支持 Python 3.10依賴werkzeug3.1.0、jinja23.1.2等實(shí)際pip list會(huì)以當(dāng)時(shí)解析到的版本為準(zhǔn)。安裝后從任意目錄運(yùn)行應(yīng)用安裝后運(yùn)行方式與你此前在教程中做的沒(méi)有任何變化——--app依然是flaskrflask run依然啟動(dòng)應(yīng)用區(qū)別在于你可以在任意目錄調(diào)用它而不再局限于flask-tutorial目錄內(nèi)$ flask --app flaskr init-db $ flask --app flaskr run --debug打開(kāi) http://127.0.0.1:5000 即可看到 Flaskr 首頁(yè)。從源碼層面看這個(gè)隨處可運(yùn)行的能力來(lái)自flask命令的應(yīng)用定位邏輯。src/flask/cli.py 中的locate_app()負(fù)責(zé)把--app flaskr這樣的字符串參數(shù)變成應(yīng)用實(shí)例def locate_app( module_name: str, app_name: str | None, raise_if_not_found: bool True ) - Flask | None: try: __import__(module_name) except ImportError: # Reraise the ImportError if it occurred within the imported module. ... elif raise_if_not_found: raise NoAppException(fCould not import {module_name!r}.) from None else: return None module sys.modules[module_name] if app_name is None: return find_best_app(module) else: return find_app_by_string(module, app_name)它通過(guò)__import__(module_name)走標(biāo)準(zhǔn)導(dǎo)入機(jī)制導(dǎo)入模塊然后按名稱查找Flask實(shí)例。未安裝未 editable 安裝時(shí)__import__(flaskr)只有當(dāng)前工作目錄恰好在sys.path中才能成功這正是教程強(qiáng)調(diào)只能從項(xiàng)目目錄里運(yùn)行的原因可編輯安裝讓flaskr的包元數(shù)據(jù)注冊(cè)進(jìn)了環(huán)境的 site-packages指向源碼目錄標(biāo)準(zhǔn)導(dǎo)入機(jī)制從此在任何工作目錄下都能解析到它flask命令的--app機(jī)制才真正隨處可用。為測(cè)試環(huán)境提供隔離的依賴教程原文指出的第三個(gè)收益——測(cè)試工具可以隔離測(cè)試環(huán)境與開(kāi)發(fā)環(huán)境——在示例工程中落地為 examples/tutorial/pyproject.toml 的可選依賴組與 examples/tutorial/README.rst 的測(cè)試流程$ pip install .[test] $ pytest這里的.[test]表示以可編輯模式安裝項(xiàng)目本身并額外安裝test可選依賴組即 pytest。測(cè)試代碼從 examples/tutorial/tests/conftest.py 開(kāi)頭即可看到安裝帶來(lái)的直接效果——from flaskr import create_app這類導(dǎo)入不依賴任何相對(duì)路徑技巧只要 flaskr 已安裝就能在任意位置工作from flaskr import create_app from flaskr.db import get_db from flaskr.db import init_db pytest.fixture def app(): Create and configure a new app instance for each test. # create a temporary file to isolate the database for each test db_fd, db_path tempfile.mkstemp() # create the app with common test config app create_app({TESTING: True, DATABASE: db_path}) ...配合 examples/tutorial/tests/test_factory.py 中對(duì)create_app()工廠函數(shù)的直接測(cè)試可以看出因?yàn)轫?xiàng)目是安裝好的包而不是散落在目錄里的腳本測(cè)試可以在獨(dú)立虛擬環(huán)境中只安裝聲明過(guò)的依賴來(lái)運(yùn)行驗(yàn)證配置注入TESTING: True、數(shù)據(jù)庫(kù)臨時(shí)文件隔離等行為而不受開(kāi)發(fā)機(jī)環(huán)境的干擾。小結(jié)可安裝項(xiàng)目的標(biāo)準(zhǔn)工作流把本章內(nèi)容收斂為一條可復(fù)制的工作流在項(xiàng)目根目錄編寫pyproject.toml聲明name、version、dependencies與[build-system]flit_core flit_core.buildapi在項(xiàng)目目錄內(nèi)執(zhí)行pip install -e .完成可編輯安裝用pip list確認(rèn)包名與Location指向源碼目錄之后在任意目錄執(zhí)行flask --app flaskr init-db、flask --app flaskr run --debug行為與安裝前一致需要跑測(cè)試時(shí)執(zhí)行pip install .[test]再pytest讓測(cè)試環(huán)境按聲明的依賴組獨(dú)立裝配。這套流程與 Flask 自身的打包方式flit 構(gòu)建后端 PEP 517一致也是教程建議新項(xiàng)目從一開(kāi)始就采用的標(biāo)準(zhǔn)化做法。下一章 tests 將在此基礎(chǔ)上展開(kāi)測(cè)試細(xì)節(jié)deploy 則會(huì)討論如何把這樣一個(gè)已可安裝的應(yīng)用部署到生產(chǎn)環(huán)境。【免費(fèi)下載鏈接】flaskThe Python micro framework for building web applications.項(xiàng)目地址: https://gitcode.com/gh_mirrors/fl/flask創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考