一個困擾我兩年的 Flask bug
優(yōu)質文章,第一時間送達!
作者:李輝,Web 開發(fā)者
出處:greyli.com
嚴格來說算不上 bug,而是一個很容易導致出錯的設計。
具體行為是,如果你安裝了 python-dotenv,同時在 Flask 程序的上層目錄創(chuàng)建了 .env 或 .flaskenv 文件,那么你將沒法成功執(zhí)行 flask run 等命令,因為這會導致 Flask 沒法正確找到對應的 Flask 程序實例。
這個問題從 Flask 開始引入 CLI 機制開始就存在了,困擾了我兩年。18 年偶然在用戶根目錄創(chuàng)建了一個 .env 文件,發(fā)現(xiàn) Flask 程序沒法運行了,當時遇到的各種 bug 太多,沒仔細考慮這兩者之間的關聯(lián)。后來經(jīng)過幾次測試,才確定下來是上層目錄的 .env 和 .flaskenv 文件導致,但是一時找不到原因,就暫時放下了。直到 19 年 11 月,花了幾個小時排查,還是沒找到原因。
中間花了很長時間來追蹤 Windows 特定的 Flask 程序無法啟動的 bug(TypeError: environment can only contain strings),實在是怕了。因為 Flask 的 CLI 涉及太多東西,有時你要鉆進 python-dotenv(#101) 和 Werkzeug(#1320) 才能找到問題的原因。
但是問題不解決的話,你永遠睡不好覺?!禙lask Web 開發(fā)實戰(zhàn)》第一部分的示例程序都放在了一個程序倉庫,而且都放在了子目錄,這意味著如果讀者錯誤的在倉庫根目錄創(chuàng)建 .env 和 .flaskenv 文件的話,就會導致子目錄下的六個示例程序沒法運行。前后大概收到 6 個相關的讀者反饋,雖然后續(xù)在網(wǎng)站上添加了提醒,在重印的書里介紹創(chuàng)建 .env/.flaskenv 文件的地方追加提醒,但這終究沒有真正解決問題,而且總會有人可以完美的錯過所有提示。
如果每個人都可以在書上標記出錯位置并共享,那么這一頁應該會有很多紅色小叉號(參考《超級馬里奧制造》,也許未來某個電子書平臺會做出來這個功能 :P)。
前幾天在這個 Issue 的提醒下,又花了兩個小時排查,這次終于找到原因。加上寫 PR(#3560)和 Issue(#3561),前后兩年一共花了 8 個小時,這個問題終于有了著落。沒意外的話,預計會在下一個版本的 Flask 中更新。下面是具體原因。
本來以為這個問題和 python-dotenv 或 Werkzeug 相關,沒想到只是 Flask 本身代碼的問題,我太笨了,這個問題本可以早一點解決。
按照預定的行為,當安裝了 python-dotenv,F(xiàn)lask 會自動加載 .env 和 .flaskenv 里的環(huán)境變量。python-dotenv 在搜索存儲環(huán)境變量的文件時,會從當前目錄開始向上搜索,如果找到就返回對應的文件路徑。但是這時 Flask 如果發(fā)現(xiàn) .env 或 .flaskenv 的所在目錄不是當前目錄,就會把當前工作目錄切換到 .env 和 .flaskenv 所在的目錄(相關源碼)。而如果你的程序模塊或程序包不是和 .env/.flaskenv 同級目錄的話,就會導致找不到程序實例。
使用下面的步驟可以重現(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
示例項目的文件結構如下:
- flask-env-test
- .env
- hello
- app.py
像示例程序這樣把程序存儲在 app.py 文件中時,運行 flask run 你會看到下面的報錯:
$ 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 指定了程序的導入路徑,那么錯誤大概會是這樣:
$ 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 后強烈推薦的一套工具庫
實戰(zhàn):Flask Vue 生成漂亮的詞云
Github 熱門,程序員想拿高薪建議都看看
回復下方「關鍵詞」,獲取優(yōu)質資源
回復關鍵詞「 pybook03」,立即獲取主頁君與小伙伴一起翻譯的《Think Python 2e》電子版
回復關鍵詞「入門資料」,立即獲取主頁君整理的 10 本 Python 入門書的電子版
回復關鍵詞「m」,立即獲取Python精選優(yōu)質文章合集
回復關鍵詞「」,將數(shù)字替換成 0 及以上數(shù)字,有驚喜好禮哦~
題圖:pexels,CC0 授權。
好文章,我在看??