一個(gè)困擾我兩年的 Flask bug
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)!
作者:李輝,Web 開發(fā)者
出處:greyli.com
嚴(yán)格來(lái)說(shuō)算不上 bug,而是一個(gè)很容易導(dǎo)致出錯(cuò)的設(shè)計(jì)。
具體行為是,如果你安裝了 python-dotenv,同時(shí)在 Flask 程序的上層目錄創(chuàng)建了 .env 或 .flaskenv 文件,那么你將沒(méi)法成功執(zhí)行 flask run 等命令,因?yàn)檫@會(huì)導(dǎo)致 Flask 沒(méi)法正確找到對(duì)應(yīng)的 Flask 程序?qū)嵗?/p>
這個(gè)問(wèn)題從 Flask 開始引入 CLI 機(jī)制開始就存在了,困擾了我兩年。18 年偶然在用戶根目錄創(chuàng)建了一個(gè) .env 文件,發(fā)現(xiàn) Flask 程序沒(méi)法運(yùn)行了,當(dāng)時(shí)遇到的各種 bug 太多,沒(méi)仔細(xì)考慮這兩者之間的關(guān)聯(lián)。后來(lái)經(jīng)過(guò)幾次測(cè)試,才確定下來(lái)是上層目錄的 .env 和 .flaskenv 文件導(dǎo)致,但是一時(shí)找不到原因,就暫時(shí)放下了。直到 19 年 11 月,花了幾個(gè)小時(shí)排查,還是沒(méi)找到原因。
中間花了很長(zhǎng)時(shí)間來(lái)追蹤 Windows 特定的 Flask 程序無(wú)法啟動(dòng)的 bug(TypeError: environment can only contain strings),實(shí)在是怕了。因?yàn)?Flask 的 CLI 涉及太多東西,有時(shí)你要鉆進(jìn) python-dotenv(#101) 和 Werkzeug(#1320) 才能找到問(wèn)題的原因。
但是問(wèn)題不解決的話,你永遠(yuǎn)睡不好覺(jué)?!禙lask Web 開發(fā)實(shí)戰(zhàn)》第一部分的示例程序都放在了一個(gè)程序倉(cāng)庫(kù),而且都放在了子目錄,這意味著如果讀者錯(cuò)誤的在倉(cāng)庫(kù)根目錄創(chuàng)建 .env 和 .flaskenv 文件的話,就會(huì)導(dǎo)致子目錄下的六個(gè)示例程序沒(méi)法運(yùn)行。前后大概收到 6 個(gè)相關(guān)的讀者反饋,雖然后續(xù)在網(wǎng)站上添加了提醒,在重印的書里介紹創(chuàng)建 .env/.flaskenv 文件的地方追加提醒,但這終究沒(méi)有真正解決問(wèn)題,而且總會(huì)有人可以完美的錯(cuò)過(guò)所有提示。
如果每個(gè)人都可以在書上標(biāo)記出錯(cuò)位置并共享,那么這一頁(yè)應(yīng)該會(huì)有很多紅色小叉號(hào)(參考《超級(jí)馬里奧制造》,也許未來(lái)某個(gè)電子書平臺(tái)會(huì)做出來(lái)這個(gè)功能 :P)。
前幾天在這個(gè) Issue 的提醒下,又花了兩個(gè)小時(shí)排查,這次終于找到原因。加上寫 PR(#3560)和 Issue(#3561),前后兩年一共花了 8 個(gè)小時(shí),這個(gè)問(wèn)題終于有了著落。沒(méi)意外的話,預(yù)計(jì)會(huì)在下一個(gè)版本的 Flask 中更新。下面是具體原因。
本來(lái)以為這個(gè)問(wèn)題和 python-dotenv 或 Werkzeug 相關(guān),沒(méi)想到只是 Flask 本身代碼的問(wèn)題,我太笨了,這個(gè)問(wèn)題本可以早一點(diǎn)解決。
按照預(yù)定的行為,當(dāng)安裝了 python-dotenv,F(xiàn)lask 會(huì)自動(dòng)加載 .env 和 .flaskenv 里的環(huán)境變量。python-dotenv 在搜索存儲(chǔ)環(huán)境變量的文件時(shí),會(huì)從當(dāng)前目錄開始向上搜索,如果找到就返回對(duì)應(yīng)的文件路徑。但是這時(shí) Flask 如果發(fā)現(xiàn) .env 或 .flaskenv 的所在目錄不是當(dāng)前目錄,就會(huì)把當(dāng)前工作目錄切換到 .env 和 .flaskenv 所在的目錄(相關(guān)源碼)。而如果你的程序模塊或程序包不是和 .env/.flaskenv 同級(jí)目錄的話,就會(huì)導(dǎo)致找不到程序?qū)嵗?/p>
使用下面的步驟可以重現(xiàn):
$ git clone https://github.com/greyli/flask-env-test
$ cd flask-env-test
$ pip install -r requirements.txt # or just pip install flask[dotenv]
$ cd hello
$ flask run
示例項(xiàng)目的文件結(jié)構(gòu)如下:
- flask-env-test
- .env
- hello
- app.py
像示例程序這樣把程序存儲(chǔ)在 app.py 文件中時(shí),運(yùn)行 flask run 你會(huì)看到下面的報(bào)錯(cuò):
$ flask run
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
Usage: flask run [OPTIONS]
Error: Could not locate a Flask application. You did not provide the "FLASK_APP" environment variable, and a "wsgi.py" or "app.py" module was not found in the current directory.
如果你使用 FLASK_APP 指定了程序的導(dǎo)入路徑,那么錯(cuò)誤大概會(huì)是這樣:
$ flask run
* Serving Flask app "myapp"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
Usage: flask run [OPTIONS]
Error: Could not import "myapp".
https://github.com/greyli/helloflask/issues/200
https://github.com/pallets/flask/issues/3561
https://github.com/pallets/flask/pull/3560
PyCharm 2020.1 穩(wěn)定版發(fā)布
pip install 今年將出現(xiàn)重大變化!
入坑 Python 后強(qiáng)烈推薦的一套工具庫(kù)
實(shí)戰(zhàn):Flask Vue 生成漂亮的詞云
Github 熱門,程序員想拿高薪建議都看看
回復(fù)下方「關(guān)鍵詞」,獲取優(yōu)質(zhì)資源
回復(fù)關(guān)鍵詞「 pybook03」,立即獲取主頁(yè)君與小伙伴一起翻譯的《Think Python 2e》電子版
回復(fù)關(guān)鍵詞「入門資料」,立即獲取主頁(yè)君整理的 10 本 Python 入門書的電子版
回復(fù)關(guān)鍵詞「m」,立即獲取Python精選優(yōu)質(zhì)文章合集
回復(fù)關(guān)鍵詞「」,將數(shù)字替換成 0 及以上數(shù)字,有驚喜好禮哦~
題圖:pexels,CC0 授權(quán)。
好文章,我在看??