前提
転職黙示録 (5) 意外と使えるPoetry入門 (Poetry + FastAPI)などを見てPoetryのプロジェクトにFastAPIを依存性として加えておきましょう(手前味噌).
またpoetryのpyproject.tomlのtool.poetry.scriptsセクションに記述するコマンドを便宜上poetryスクリプトと呼びます.
モチベーション
poetryにもNPMスクリプトのような機能があるのですが, ただNPMスクリプトのようにターミナルに入力するコマンドをコピペしても動きません. つまり以下のようにしても動きません.
[tool.poetry.scripts]
start = "poetry run uvicorn project_name.main:main --reload"
Poetryスクリプトの書き方
記法はmodule:functionとするようです. したがって
[tool.poetry.scripts]
start = "project_name.main:main"
とするのが正しいようです. project_nameとmainをドットでつなぐのは絶対インポートのようです. 実行は
poetry run start
です.
Uvicornによる起動
次にUvicornはASGIサーバーでFastAPIで作ったアプリケーションを起動してくれます. First Stepsの例を載せときます.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
これはコマンドラインから
poetry run uvicorn project-name.main:main --reload
と実行できます. しかしpoetryスクリプトからは実行できません. まず呼び出すべきmain関数がありません. そのためmain関数を作ってそこから呼び出すように変更します.
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
def main():
uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)
if __name__ == "__main__":
main()
これを,
poetry run start
で実行すると
WARNING: You must pass the application as an import string to enable 'reload' or 'workers'.
と警告をくらいます. 動かないので実質エラーですが警告どおりアプリケーションをimport stringとして渡せとあるので今度はappを文字列にしてみます.
ERROR: Error loading ASGI app. Import string "app" must be in format ":".
今度はエラーをくらいました.
結果
モジュールは絶対パスでproject_name.mainでした. 問題はattributeですがモジュールの後にappを指定すると動きました.
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
def main():
uvicorn.run("project_name.main:app", host="0.0.0.0", port=8000, reload=True)
if __name__ == "__main__":
main()
これでpoetry run startでUvicornサーバーがFastAPIのアプリケーションを起動してくれます. 大勝利
まとめ
Pythonの属性ってよく分かりませんね
Reference
Poetryスクリプトに関しては情報がなく分からなさすぎてstackoverflowに質問したやつです. そのまま答えとはなりませんでしたが.