# バージョン 21.3
# 概要
Sanicが速くなりました。
まあ、すでに速かったんですけどね。しかし、v21リリースの最初のイテレーションで、いくつかの主要なマイルストーンを取り入れ、目に見える改善を行いました。これらは、何年も前から温めていたアイデアを、ようやくリリースバージョンに取り入れたものです。
Breaking changes
バージョン21.3では、多くの新機能が導入されています。しかし、いくつかの破壊的な変更も含まれています。このため、これらの変更は前回のLTSの後に導入されました。もし、削除されたものに依存している場合は、アップグレードできるようになるまで v20.12LTS を使い続ける必要があります。
pip install "sanic>=20.12,<20.13"
pip freeze > requirements.txt
ほとんどの典型的なインストールでは、問題なくアップグレードできるはずです。
# 知っておきたいこと
注目の新機能・不具合、アップグレード対象...
# Python 3.7以上必須
このバージョンでPython 3.6のサポートが終了します。バージョン 20.12LTS は 2022 年 12 月の EOL まで、バージョン 19.12LTS は 2021 年 12 月の EOL まで Python 3.6 のサポートを継続します。
LTSポリシーについてもっと読む。
# 一級市民としてのストリーミング
最も大きな速度向上は、リクエストとレスポンスのサイクルを1つのフローに統一したことです。以前は、通常のサイクルとストリーミングサイクルの間に違いがありました。これは、互換性のためにAPIは同じままですが、フードの下で簡素化されました。正味の利点は、すべての リクエストが新しい利点を見ることができるようになったことです。
ストリーミングの変更についてもっと読む。
# ルーターの見直し
古いSanicのルーターは正規表現をベースにしていました。さらに、それは実行時に修正するのが難しく、いくつかのパフォーマンスの問題をもたらした多くの癖に悩まされていました。この変更は何年もかけて行われ、現在では 起動時にルータをコンパイルされたツリーに変換する (opens new window)ようになっています。今年中のさらなる改良にご期待ください。
外向きのAPIは後方互換性を保っています。しかし、特にルーター内部の何かにアクセスしていた場合、いくつかの変更に気づくことが多いでしょう。例えば
Router.get()
に新しい戻り値が追加されました。Route
は、namedtuple
ではなく、ちゃんとしたクラスオブジェクトになりました。- ルータを手動で構築する場合、使用可能にする前に
Router.finalize()
を呼び出す必要があります。 - ルートにマッチする新しいパターン
<date:ymd>
が追加されました。 - 少なくとも1つのルートが定義されていないと、アプリケーションを起動することはできません。
ルーターは独自のリポジトリに置かれるようになりました。sanic-org/sanic-router (opens new window) また、独自の standalone package on PyPI (opens new window) に配置されています。
# シグナルAPI ⭐️
BETA機能: APIはv21.6で完成予定です。
新しいルーターの副次的な利点は、それが新しいシグナルAPI (opens new window)をも動かす二重の役割を果たすことです。この機能は現在公開されており、おそらく公開されるAPIは最終的に変更されることはないでしょう。
この機能の核となる考えは以下の通りです。
- 開発者がサーバーとリクエストのライフサイクルにプラグインするための、より大きな制御とアクセスを可能にすること。
- アプリケーションでメッセージを同期させ、送信するための新しいツールを提供すること、および
- 最終的にパフォーマンスをさらに向上させること。
このAPIでは、3つの新しいメソッドを導入しています。
@app.signal(...)
- シグナルハンドラを定義するためのメソッドです。これは、ルートに非常によく似た外観と動作をします。シグナルがディスパッチされるたびに、このハンドラが実行されます。app.event(...)
- イベントが発生するまで実行を一時停止するために、アプリケーションの任意の場所で使用できる待ち受けです。app.dispatch(...)
- イベントをトリガーして、シグナルハンドラを実行させます。
@app.signal("foo.bar.<thing>")
async def signal_handler(thing, **kwargs):
print(f"[signal_handler] {thing=}", kwargs)
async def wait_for_event(app):
while True:
print("> waiting")
await app.event("foo.bar.*")
print("> event found\n")
@app.after_server_start
async def after_server_start(app, loop):
app.add_task(wait_for_event(app))
@app.get("/")
async def trigger(request):
await app.dispatch("foo.bar.baz")
return response.text("Done.")
# ルートネーミング
以前は、ルートはroute.name
とroute.endpoint
の両方で参照されていました。似たようなものですが、両者は若干異なっていました。現在では、すべてのルートは一貫した名前空間と参照方法を持つようになりました。
<app名>.[オプショナル:<ブループリント名>.]<ハンドラ名>
この新しい「名前」は、route.name
というプロパティに割り当てられます。私たちはroute.endpoint
を非推奨としており、v21.9でこのプロパティを削除する予定です。それまでは、route.name
のエイリアスになります。
また、静的ルート、websocketルート、blueprintルートなどに使用されていたネーミングプレフィックスが削除されました。
# 新しいデコレータ
IDEのオートコンプリートを支援する新しいデコレーターをいくつか追加しました。
# Alias to @app.listener("...")
@app.before_server_start
@app.after_server_stop
@app.before_server_start
@app.after_server_stop
# Alias to @app.middleware("...")
@app.on_request
@app.on_response
# ルート内の引用符の解除
非アスキー文字を使用するルートがある場合、Sanicはあなたのためにテキストをunquote
しないでしょう。ルート定義にそうするように特別に指示する必要があります。
@app.route("/overload/<param>", methods=["GET"], unquote=True)
async def handler2(request, param):
return text("OK2 " + param)
request, response = app.test_client.get("/overload/您好")
assert response.text == "OK2 您好"
これを忘れると、テキストがエンコードされたままになってしまいます。
# Request.match_info
を変更する。
これまで match_info
はマッチしたパスパラメータのデータを提供してきました。ミドルウェアなどで、これを変更できるようになりました。
@app.on_request
def convert_to_snake_case(request):
request.match_info = to_snake(request.match_info)
# ルートにおけるバージョンタイプ
routesの引数version
に以下のタイプが指定できるようになりました。
str
int
float
@app.route("/foo", version="2.1.1")
@app.route("/foo", version=2)
@app.route("/foo", version=2.1)
# ボディを使った安全なメソッド処理
GET
、HEAD
、OPTIONS
、DELETE
のルートハンドラは、渡された HTTP のボディをデコードしません。これをオーバーライドすることができます。
@app.delete(..., ignore_body=False)
# アプリケーション、ブループリント、ブループリント・グループのパリティ
Sanic
クラスと Blueprint
クラスは共通のベースを使用しています。以前は、多くの機能が重複していたため、両者の間で若干異なる実装になっていました。現在は、どちらも同じベースクラスを継承しているため、開発者やプラグインはより一貫した API を使用できるようになりました。
また、Blueprint Groups は version
や strict_slashes
キーワード引数のような一般的な URL 拡張をサポートするようになりました。
# 依存関係から httpx
を削除
httpx
への依存はもうありません。
# testing
ライブラリを削除
Sanicの内部テストクライアントは削除されました。現在は独自のリポジトリに置かれています。sanic-org/sanic-testing (opens new window) にあり、また、独自の standalone package on PyPI (opens new window) にもあります。
sanic-testing
がインストールされていれば、これまで通り Sanic()
アプリケーションインスタンスで利用することができます。そのため、 ** 唯一の** 変更点は、テストスイートの要件に sanic-testing
を追加することです。
# アプリケーションと接続レベルのコンテキスト (ctx
) オブジェクト
バージョン19.9でrequest.ctx
APIを追加 (opens new window)しました。この便利な構造により、 (例えばミドルウェアの) リクエストオブジェクトにプロパティやデータをアタッチし、 アプリケーション内の他の場所でその情報を再利用することが簡単にできるようになりました。
同様に、このコンセプトは2つの場所で拡張されています。
- アプリケーションインスタンス
- トランスポートコネクション
# アプリケーションコンテキスト
一般的なユースケースは、アプリのインスタンスにプロパティをアタッチすることです。一貫性を保つため、そして Sanic プロパティとの名前の衝突の問題を避けるために、ctx
オブジェクトは現在 Sanic
インスタンスに存在します。
@app.before_server_startup
async def startup_db(app, _):
# WRONG
app.db = await connect_to_db()
# CORRECT
app.ctx.db = await connect_to_db()
# 接続コンテキスト
クライアントがキープアライブヘッダを送信すると、Sanicはトランスポートソケットを一定期間オープンしたままにしようとします。クライアントがキープアライブヘッダを送信すると、Sanicはトランスポートソケットを一定期間オープンしたままにしようとします。そのトランスポートオブジェクトは今、ctx
オブジェクトを利用できるようになりました。これは事実上、1つのクライアントからの複数のリクエスト(トランスポートレイヤーが再利用されている)が状態を共有することができることを意味します。
@app.on_request
async def increment_foo(request):
if not hasattr(request.conn_info.ctx, "foo"):
request.conn_info.ctx.foo = 0
request.conn_info.ctx.foo += 1
@app.get("/")
async def count_foo(request):
return text(f"request.conn_info.ctx.foo={request.conn_info.ctx.foo}")
$ curl localhost:8000 localhost:8000 localhost:8000
request.conn_info.ctx.foo=1
request.conn_info.ctx.foo=2
request.conn_info.ctx.foo=3
WARNING
接続レベルのコンテキストは実験的な機能であり、v21.6で最終的に有効化される予定です。
# ニュース
# 新しいフロントページ 🎉
ドキュメントを2つに分けました。コードベース内部のdocstringsは、これまで通りReadTheDocsにshinxのdocをビルドしていきます。しかし、それはAPIドキュメントに限定されるでしょう。新しいフロントページには、"Sanicユーザーガイド"が置かれます。
新しいサイトはVuepressで動作します。寄付を歓迎します。また、ドキュメントの翻訳のお手伝いも募集しています。
この一環として、RTDのドキュメントもリフレッシュし、APIドキュメントのみに変更しました。
# チャットは Discord に移動
Gitterチャットルームは廃止に一歩近づきました。その代わりに、私たちはDiscordサーバ (opens new window)を開設しました。
# オープンコレクティブ
Sanicコミュニティ組織は、Sanicの開発を財政的に支援したい人なら誰でもできるように、Open Collectiveのページを開設 (opens new window)しています。
# 2021年版リリース管理者
2019年、2020年ともにリリースマネージャーを務めてくれた@sjsadowskiと@yunstanfordに感謝します。今年のリリースマネージャーは@ahopkinsと@vltrです。
# 謝礼
今回のリリースに参加された皆様、ありがとうございました。👏
@ahopkins (opens new window) @akshgpt7 (opens new window) @artcg (opens new window) @ashleysommer (opens new window) @elis-k (opens new window) @harshanarayana (opens new window) @sjsadowski (opens new window) @tronic (opens new window) @vltr (opens new window),
中国語への翻訳を担当した@ConnorZhang (opens new window)と@ZinkLu (opens new window)に感謝します。
すべてのPRへのリンクを得るために、変更履歴をチェックすることを忘れないでください。