# Version 21.12
- 概要
- 知っておきたい
- アプリケーション名とブループリント名の厳格化
- 厳格なアプリケーションとブループリントのプロパティ
- 削除
- ストリーミング応答のアップグレード (まだの場合)
- CLIのオーバーホールとMOTD(本日のメッセージ)について
- サーバーの実行モードと debug に来る変更点
- 最大許容ワーカー数
- ファーストクラスのSanic Extensionsサポート
- コンテキストに応じた例外処理
- バックグランドタスクの管理
- 定義におけるルートコンテキストのkwargs
- ブループリントはいつでも登録可能
- シグナルイベントを Enum で表す
- 環境変数のカスタム型キャスト
- uvloop を設定値で無効にする
- 複数のTLS証明書でSanicサーバーを実行する
- ニュース
- 謝礼
# 概要
このリリースは、バージョン21のリリースサイクルの最終リリースとなります。バージョン21は今後長期サポートに入り、2023年12月までの2年間サポートされる予定です。
# 知っておきたい
詳しくはChangelog (opens new window)をご覧ください。注目すべき新機能・不具合、アップグレード対象...
# アプリケーション名とブループリント名の厳格化
v21.6](./v21.6.md#stricter-application-and-blueprint-names-and-deprecation) では、アプリケーションとブループリントの名前は新しい制限に適合することが求められました。この変更は、起動時に強制されるようになりました。
以下の制約に従った名前でなければいけません。
- 英数字(
a-zA-Z0-9
)のみ使用可能です。 - ハイフン(
-
)またはアンダースコア(_
)を含むことができます。 - 文字またはアンダースコア (
a-zA-Z_
) で始まる必要があります。
# 厳格なアプリケーションとブループリントのプロパティ
Sanic
や Blueprint
オブジェクトのプロパティを直接設定できる古い寛容さは、非推奨となり、今後は許可されなくなりました。必ず ctx
オブジェクトを使用してください。
app = Sanic("MyApp")
app.ctx.db = Database()
# 削除
以下の非推奨機能は廃止されました。
sanic.exceptions.abort
sanic.views.CompositionView
sanic.response.StreamingHTTPResponse
# ストリーミング応答のアップグレード (まだの場合)
レスポンスメソッド sanic.response.stream
は 非推奨 となり、v22.6 で削除される予定です。まだ旧式のストリーミングレスポンスを使用している場合は、アップグレードをお願いします。
旧 - 非推奨
async def sample_streaming_fn(response):
await response.write("foo,")
await response.write("bar")
@app.route("/")
async def test(request: Request):
return stream(sample_streaming_fn, content_type="text/csv")
現在
async def sample_streaming_fn(response):
await response.write("foo,")
await response.write("bar")
@app.route("/")
async def test(request: Request):
response = await request.respond(content_type="text/csv")
await response.send("foo,")
await response.send("bar")
# CLIのオーバーホールとMOTD(本日のメッセージ)について
SanicのCLIはかなり大規模なアップグレードを受けました。これは app.run()
と同等にするために多くの新機能を追加しています。また、新しい MOTD 表示も含まれており、実行中の環境について素早く、一目でわかるハイライトを提供します。MOTDはTTYを意識しているので、サーバーのログではあまり冗長になりません。これは主にアプリケーション開発時の利便性を目的としています。
$ sanic --help
usage: sanic [-h] [--version] [--factory] [-s] [-H HOST] [-p PORT] [-u UNIX] [--cert CERT] [--key KEY] [--tls DIR] [--tls-strict-host]
[-w WORKERS | --fast] [--access-logs | --no-access-logs] [--debug] [-d] [-r] [-R PATH] [--motd | --no-motd] [-v]
[--noisy-exceptions | --no-noisy-exceptions]
module
▄███ █████ ██ ▄█▄ ██ █ █ ▄██████████
██ █ █ █ ██ █ █ ██
▀███████ ███▄ ▀ █ █ ██ ▄ █ ██
██ █████████ █ ██ █ █ ▄▄
████ ████████▀ █ █ █ ██ █ ▀██ ███████
To start running a Sanic application, provide a path to the module, where
app is a Sanic() instance:
$ sanic path.to.server:app
Or, a path to a callable that returns a Sanic() instance:
$ sanic path.to.factory:create_app --factory
Or, a path to a directory to run as a simple HTTP server:
$ sanic ./path/to/static --simple
Required
========
Positional:
module Path to your Sanic app. Example: path.to.server:app
If running a Simple Server, path to directory to serve. Example: ./
Optional
========
General:
-h, --help show this help message and exit
--version show program's version number and exit
Application:
--factory Treat app as an application factory, i.e. a () -> <Sanic app> callable
-s, --simple Run Sanic as a Simple Server, and serve the contents of a directory
(module arg should be a path)
Socket binding:
-H HOST, --host HOST Host address [default 127.0.0.1]
-p PORT, --port PORT Port to serve on [default 8000]
-u UNIX, --unix UNIX location of unix socket
TLS certificate:
--cert CERT Location of fullchain.pem, bundle.crt or equivalent
--key KEY Location of privkey.pem or equivalent .key file
--tls DIR TLS certificate folder with fullchain.pem and privkey.pem
May be specified multiple times to choose multiple certificates
--tls-strict-host Only allow clients that send an SNI matching server certs
Worker:
-w WORKERS, --workers WORKERS Number of worker processes [default 1]
--fast Set the number of workers to max allowed
--access-logs Display access logs
--no-access-logs No display access logs
Development:
--debug Run the server in debug mode
-d, --dev Currently is an alias for --debug. But starting in v22.3,
--debug will no longer automatically trigger auto_restart.
However, --dev will continue, effectively making it the
same as debug + auto_reload.
-r, --reload, --auto-reload Watch source directory for file changes and reload on changes
-R PATH, --reload-dir PATH Extra directories to watch and reload on changes
Output:
--motd Show the startup display
--no-motd No show the startup display
-v, --verbosity Control logging noise, eg. -vv or --verbosity=2 [default 0]
--noisy-exceptions Output stack traces for all exceptions
--no-noisy-exceptions No output stack traces for all exceptions
# サーバーの実行モードと debug
に来る変更点
現在、DEV
と PRODUCTION
の2つの実行モードがあります。デフォルトでは、Sanicサーバーは PRODUCTION
モードで実行されます。これはデプロイメントを想定している。
現在、DEV
モードは古いSanicのバージョンで debug=True
が動作する方式と非常によく似ています。しかし、v22.3では しかし、v22.3では、debug=True
は自動リロードを有効にしなくなりました**。デバッグと自動リロードを行いたい場合は、DEV
モードを有効にする必要があります。
開発
$ sanic server:app --dev
app.run(debug=True, auto_reload=True)
運営
$ sanic server:app
app.run()
v22.3から、PRODUCTION
モードはデフォルトでアクセスログを有効にしなくなりました。
変更点の概要は以下の通りです。
フラグ | モード | トレースバック | ログ | アクセスログ | 再読込 | 最大ワーカー |
---|---|---|---|---|---|---|
--debug | DEBUG | はい | DEBUG | はい | ^1 | |
PROD | いいえ | INFO ^2 | ^3 | |||
--dev | DEBUG | はい | DEBUG | はい | はい | |
--fast | はい |
- ^1
--debug
で自動リロードを非推奨とし、22.3 で削除する。 - ^2 22.3以降ではWARNINGに移行します。
- ^3 22.3以降は「いいえ」
# 最大許容ワーカー数
fast
を使用すると、許可された最大数のワーカーを簡単にスピンアップさせることができます。
$ sanic server:app --fast
app.run(fast=True)
# ファーストクラスのSanic Extensionsサポート
Sanic Extensions は、特に API 開発者のために意図された多くの追加機能を提供します。パッケージが環境にある限り、追加設定なしで、それが提供するすべての機能を簡単に実装できるようになりました。これらの機能は以下の通りです。
HEAD
、OPTIONS
、TRACE
のエンドポイントの自動作成- CORS保護
- 定義済み、エンドポイント固有のレスポンスシリアライザー
- ルートハンドラへの依存性注入
- RedocやSwaggerによるOpenAPIドキュメンテーション
- リクエストのクエリ引数とボディ入力の検証
Sanicと一緒にインストールするのが望ましいですが、パッケージ単体でインストールすることも可能です。
$ pip install sanic[ext]
$ pip install sanic sanic-ext
その後、追加の設定は必要ありません。Sanic Extensionsはアプリケーションにアタッチされ、これ以上の構成は必要なく、すべての追加機能を提供します。
もし、動作方法を変更したり、追加の設定を提供したい場合は、app.extend
を使用してSanic Extensionsを変更することができます。以下の例は同等です。Config
オブジェクトは、IDE 開発に役立つ型アノテーションを提供するためのものです。
# This is optional, not required
app = Sanic("MyApp")
app.extend(config={"oas_url_prefix": "/apidocs"})
# This is optional, not required
app = Sanic("MyApp")
app.config.OAS_URL_PREFIX = "/apidocs"
# This is optional, not required
from sanic_ext import Config
app = Sanic("MyApp")
app.extend(config=Config(oas_url_prefix="/apidocs"))
# コンテキストに応じた例外処理
v21.9 では、アプリケーション全体で一貫して例外を発生させる能力を単純化するために、例外にデフォルトメッセージを追加しました。
class TeapotError(SanicException):
status_code = 418
message = "Sorry, I cannot brew coffee"
raise TeapotError
しかし、これには2つのことが欠けていました。
- ダイナミックで予測可能なメッセージ・フォーマット
- エラーメッセージに追加のコンテキストを追加する機能(これについては後ほど詳しく説明します)
現在のリリースでは、エラーメッセージを書くときにコンテキストを提供するために、Sanic例外が発生したときに追加情報を持つことができます。
class TeapotError(SanicException):
status_code = 418
@property
def message(self):
return f"Sorry {self.extra['name']}, I cannot make you coffee"
raise TeapotError(extra={"name": "Adam"})
新機能として、例外インスタンスに extra
メタを渡すことができるようになりました。この extra
情報オブジェクトは、 PRODUCTION
モードでは抑制されますが、 DEVELOPMENT
モードでは表示されます。
PRODUCTION
DEVELOPMENT
2.の話に戻ります: エラーメッセージにコンテキストを追加する機能
これは、マイクロサービスや、エラーメッセージをJSON形式で返すつもりのAPIを作るときに特に有効です。この使用例では、クライアントに詳細を返すために、解析可能なエラーメッセージだけでなく、例外の周りに何らかのコンテキストを持たせたいと考えています。
raise TeapotError(context={"foo": "bar"})
これは、(利用可能であれば)常にエラーで渡されるようにしたい情報です。以下のような感じです。
PRODUCTION
{
"description": "I'm a teapot",
"status": 418,
"message": "Sorry Adam, I cannot make you coffee",
"context": {
"foo": "bar"
}
}
DEVELOPMENT
{
"description": "I'm a teapot",
"status": 418,
"message": "Sorry Adam, I cannot make you coffee",
"context": {
"foo": "bar"
},
"extra": {
"name": "Adam",
"more": "lines",
"complex": {
"one": "two"
}
},
"path": "/",
"args": {},
"exceptions": [
{
"type": "TeapotError",
"exception": "Sorry Adam, I cannot make you coffee",
"frames": [
{
"file": "handle_request",
"line": 83,
"name": "handle_request",
"src": ""
},
{
"file": "/tmp/p.py",
"line": 17,
"name": "handler",
"src": "raise TeapotError("
}
]
}
]
}
# バックグランドタスクの管理
app.add_task
メソッドを使用してバックグラウンドタスクを作成するとき、オプションで name
キーワード引数を渡すことができるようになり、フェッチやキャンセルができるようになりました。
app.add_task(dummy, name="dummy_task")
task = app.get_task("dummy_task")
app.cancel_task("dummy_task")
# 定義におけるルートコンテキストのkwargs
ルートが定義されるとき、ctx_
というプレフィックスを持つキーワード引数をいくつでも追加することができます。これらの値は、ルートの ctx
オブジェクトに注入されます。
@app.get("/1", ctx_label="something")
async def handler1(request):
...
@app.get("/2", ctx_label="something")
async def handler2(request):
...
@app.get("/99")
async def handler99(request):
...
@app.on_request
async def do_something(request):
if request.route.ctx.label == "something":
...
# ブループリントはいつでも登録可能
Sanicの以前のバージョンでは、ブループリントをアプリケーションにアタッチできるタイミングに厳密な順序がありました。もし、app.blueprint(bp)
を、すべてのオブジェクトをBlueprintインスタンスにアタッチする前に実行すると、それらは見逃されることになります。
現在では、いつでもブループリントをアタッチすることができ、それにアタッチされたすべてのものがスタートアップ時に含まれます。
# うるさい例外 (すべての例外をログに強制的に記録)
新しい設定値として NOISY_EXCEPTIONS
があります。この値が False
(デフォルト) の場合、Sanic はすべての SanicException
の quiet
プロパティを尊重します。つまり、quiet=True
の例外はログ出力に表示されません。
しかし、 NOISY_EXCEPTIONS=True
に設定すると、 quiet
の値に関係なく、すべての例外がログに記録されるようになります。
これはデバッグをするときに便利です。
app.config.NOISY_EXCEPTIONS = True
# シグナルイベントを Enum
で表す
便宜上、すべてのビルトインシグナル値を持つ Enum
が存在します。
from sanic.signals import Event
@app.signal(Event.HTTP_LIFECYCLE_BEGIN)
async def connection_opened(conn_info):
...
# 環境変数のカスタム型キャスト
デフォルトでは、Sanic は環境変数を config
インスタンスに適用する際に、 int
, float
, または bool
値に変換します。これを独自のコンバータで拡張することができる。
app = Sanic(..., config=Config(converters=[UUID]))
# uvloop
を設定値で無効にする
設定値によって uvloop
の使用を制御することができます。
app.config.USE_UVLOOP = False
# 複数のTLS証明書でSanicサーバーを実行する
Sanicは、複数のTLS証明書を使用して実行することができます。
app.run(
ssl=[
"/etc/letsencrypt/live/example.com/",
"/etc/letsencrypt/live/mysite.example/",
]
)
# ニュース
# 近日公開予定: SanicでPythonのWeb開発
コア開発者の一人である@ahopkins (opens new window)によるSanicに関する本が近日発売予定です。
詳しくはsanicbook.com (opens new window)でご覧ください。
ウェブアプリケーションのパフォーマンスとスケーラビリティを向上させるために、Sanicを使った作業の実践的な知識を身につけましょう。その一方で、アプリを大幅にオーバーエンジニアリングすることなく、変化するビジネスニーズに合わせてカスタマイズする方法を学び、開発スキルをレベルアップします。
書籍の収益の一部はSanic Community Organizationに入り、Sanicの開発・運営資金として活用されます。つまり、この本を買うことも、Sanicを支援する方法のひとつなのです。
# ドキュメントのダークモード
まだお気づきでないようですが、このSanicのウェブサイトはネイティブのダークモードでご利用いただけるようになりました。ページの右上にあるテーマを切り替えることができます。
# 謝礼
今回のリリースに参加された皆さん、ありがとうございました。 👏
@adarsharegmi (opens new window) @ahopkins (opens new window) @ashleysommer (opens new window) @ChihweiLHBird (opens new window) @cnicodeme (opens new window) @kianmeng (opens new window) @meysam81 (opens new window) @nuxion (opens new window) @prryplatypus (opens new window) @realDragonium (opens new window) @SaidBySolo (opens new window) @sjsadowski (opens new window) @Tronic (opens new window) @Varriount (opens new window) @vltr (opens new window) @whos4n3 (opens new window)
そして、ドキュメントの同期と中国語への翻訳を維持してくれた@miss85246 (opens new window) と @ZinkLu (opens new window) には、多大なる感謝を捧げます。
もし、このプロジェクトを楽しんでいただけるなら、ぜひ貢献をご検討ください。もちろんコードの貢献は大歓迎ですが、どんな形の貢献も大歓迎です。ドキュメントを書いたり、使用例を紹介したり、会話に参加してあなたの声を伝えたり、もし可能であれば、金銭的な貢献 (opens new window)も検討してみてください。