# Version 22.3
- What to know
- Application multi-serve
- 👶 BETA FEATURE - New path parameter type: file extensions
- 🚨 BREAKING CHANGE - Path parameter matching of non-empty strings
- 🚨 BREAKING CHANGE - sanic.worker.GunicornWorker has been removed
- Authorization header parsing
- CLI arguments optionally injected into application factory
- New reloader process listener events
- The event loop is no longer a required argument of a listener
- Removal - Debug mode does not automatically start the reloader
- Deprecation - Loading of lower case environment variables
- Thank you
This is the first release of the version 22 release cycle. All of the standard SCO libraries are now entering the same release cycle and will follow the same versioning pattern. Those packages are:
# What to know
More details in the Changelog (opens new window). Notable new or breaking features, and what to upgrade...
# Application multi-serve
The Sanic server now has an API to allow you to run multiple applications side-by-side in the same process. This is done by calling
app.prepare(...) on one or more application instances, one or many times. Each time it should be bound to a unique host/port combination. Then, you begin serving the applications by calling
app = Sanic("One") app2 = Sanic("Two") app.prepare(port=9999) app.prepare(port=9998) app.prepare(port=9997) app2.prepare(port=8888) app2.prepare(port=8887) Sanic.serve()
In the above snippet, there are two applications that will be run concurrently and bound to multiple ports. This feature is not supported in the CLI.
This pattern is meant to be an alternative to running
app.run(...). It should be noted that
app.run is now just a shorthand for the above pattern and is still fully supported.
# 👶 BETA FEATURE - New path parameter type: file extensions
A very common pattern is to create a route that dynamically generates a file. The endpoint is meant to match on a file with an extension. There is a new path parameter to match files:
@app.get("/path/to/<filename:ext>") async def handler(request, filename, ext): ...
This will catch any pattern that ends with a file extension. You may, however want to expand this by specifying which extensions, and also by using other path parameter types for the file name.
For example, if you want to catch a
.jpg file that is only numbers:
@app.get("/path/to/<filename=int:ext=jpg>") async def handler(request, filename, ext): ...
Some potential examples:
# 🚨 BREAKING CHANGE - Path parameter matching of non-empty strings
A dynamic path parameter will only match on a non-empty string.
Previously a route with a dynamic string parameter (
/<foo:str>) would match on any string, including empty strings. It will now only match a non-empty string. To retain the old behavior, you should use the new parameter type:
@app.get("/path/to/<foo:strorempty>") async def handler(request, foo) ...
# 🚨 BREAKING CHANGE -
sanic.worker.GunicornWorker has been removed
Departing from our normal deprecation policy, the
GunicornWorker was removed as a part of the process of upgrading the Sanic server to include multi-serve. This decision was made largely in part because even while it existed it was not an optimal strategy for deploying Sanic.
If you want to deploy Sanic using
gunicorn, then you are advised to do it using the strategy implemented by
uvicorn (opens new window). This will effectively run Sanic as an ASGI application through
uvicorn. You can upgrade to this pattern by installing
pip install uvicorn
Then, you should be able to run it with a pattern like this:
gunicorn path.to.sanic:app -k uvicorn.workers.UvicornWorker
# Authorization header parsing
Authorization header has been partially parseable for some time now. You have been able to use
request.token to gain access to a header that was in one of the following two forms:
Authorization: Token <SOME TOKEN HERE> Authorization: Bearer <SOME TOKEN HERE>
Sanic can now parse more credential types like
Authorization: Basic Z2lsLWJhdGVzOnBhc3N3b3JkMTIz
This can be accessed now as
print(request.credentials) # Credentials(auth_type='Basic', token='Z2lsLWJhdGVzOnBhc3N3b3JkMTIz', _username='gil-bates', _password='password123')
# CLI arguments optionally injected into application factory
Sanic will now attempt to inject the parsed CLI arguments into your factory if you are using one.
def create_app(args): app = Sanic("MyApp") print(args) return app
$sanic p:create_app --factory Namespace(module='p:create_app', factory=True, simple=False, host='127.0.0.1', port=8000, unix='', cert=None, key=None, tls=None, tlshost=False, workers=1, fast=False, access_log=False, debug=False, auto_reload=False, path=None, dev=False, motd=True, verbosity=None, noisy_exceptions=False)
If you are running the CLI with
--factory, you also have the option of passing arbitrary arguments to the command, which will be injected into the argument
sanic p:create_app --factory --foo=bar Namespace(module='p:create_app', factory=True, simple=False, host='127.0.0.1', port=8000, unix='', cert=None, key=None, tls=None, tlshost=False, workers=1, fast=False, access_log=False, debug=False, auto_reload=False, path=None, dev=False, motd=True, verbosity=None, noisy_exceptions=False, foo='bar')
# New reloader process listener events
When running Sanic server with auto-reload, there are two new events that trigger a listener only on the reloader process:
These are only triggered if the reloader is running.
@app.reload_process_start async def reload_start(*_): print(">>>>>> reload_start <<<<<<") @app.reload_process_stop async def reload_stop(*_): print(">>>>>> reload_stop <<<<<<")
# The event loop is no longer a required argument of a listener
You can leave out the
loop argument of a listener. Both of these examples work as expected:
@app.before_server_start async def without(app): ... @app.before_server_start async def with(app, loop): ...
# Removal - Debug mode does not automatically start the reloader
When running with
debug=True, the Sanic server will not automatically start the auto-reloader. This feature of doing both on debug was deprecated in v21 and removed in this release. If you would like to have both debug mode and auto-reload, you can use
dev = debug mode + auto reloader
# Deprecation - Loading of lower case environment variables
Sanic loads prefixed environment variables as configuration values. It has not distinguished between uppercase and lowercase as long as the prefix matches. However, it has always been the convention that the keys should be uppercase. This is deprecated and you will receive a warning if the value is not uppercase. In v22.9 only uppercase and prefixed keys will be loaded.
# Packt publishes new book on Sanic web development
There is a new book on Python Web Development with Sanic by @ahopkins (opens new window). The book is endorsed by the SCO and part of the proceeds of all sales go directly to the SCO for further development of Sanic.
You can learn more at sanicbook.com (opens new window)
# Thank you
Thank you to everyone that participated in this release: 👏
@aericson (opens new window) @ahankinson (opens new window) @ahopkins (opens new window) @ariebovenberg (opens new window) @ashleysommer (opens new window) @Bluenix2 (opens new window) @ChihweiLHBird (opens new window) @dotlambda (opens new window) @eric-spitler (opens new window) @howzitcdf (opens new window) @jonra1993 (opens new window) @prryplatypus (opens new window) @raphaelauv (opens new window) @SaidBySolo (opens new window) @SerGeRybakov (opens new window) @Tronic (opens new window)
If you enjoy the project, please consider contributing. Of course we love code contributions, but we also love contributions in any form. Consider writing some documentation, showing off use cases, joining conversations and making your voice known, and if you are able: financial contributions (opens new window).