Conversion of User Guide to the SHH stack (#2781)

This commit is contained in:
Adam Hopkins
2023-09-06 15:44:00 +03:00
committed by GitHub
parent 47215d4635
commit d255d1aae1
332 changed files with 51495 additions and 2013 deletions

View File

@@ -0,0 +1,510 @@
# Version 21.12 (LTS)
.. toc::
## Introduction
This is the final release of the version 21 [release cycle](../../org/policies.md#release-schedule). Version 21 will now enter long-term support and will be supported for two years until December 2023.
## What to know
More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade...
### Strict application and blueprint names
In [v21.6](./v21.6.md#stricter-application-and-blueprint-names-and-deprecation) application and blueprint names were required to conform to a new set of restrictions. That change is now being enforced at startup time.
Names **must**:
1. Only use alphanumeric characters (`a-zA-Z0-9`)
2. May contain a hyphen (`-`) or an underscore (`_`)
3. Must begin with a letter or underscore (`a-zA-Z_`)
### Strict application and blueprint properties
The old leniency to allow directly setting properties of a `Sanic` or `Blueprint` object was deprecated and no longer allowed. You must use the `ctx` object.
```python
app = Sanic("MyApp")
app.ctx.db = Database()
```
### Removals
The following deprecated features no longer exist:
- `sanic.exceptions.abort`
- `sanic.views.CompositionView`
- `sanic.response.StreamingHTTPResponse`
### Upgrade your streaming responses (if not already)
The `sanic.response.stream` response method has been **deprecated** and will be removed in v22.6. If you are sill using an old school streaming response, please upgrade it.
**OLD - Deprecated**
```python
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")
```
**Current**
```python
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 overhaul and MOTD (Message of the Day)
The Sanic CLI has received a fairly extensive upgrade. It adds a bunch of new features to make it on par with `app.run()`. It also includes a new MOTD display to provide quick, at-a-glance highlights about your running environment. The MOTD is TTY-aware, and therefore will be less verbose in server logs. It is mainly intended as a convenience during application development.
```
$ 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
```
### Server running modes and changes coming to `debug`
There are now two running modes: `DEV` and `PRODUCTION`. By default, Sanic server will run under `PRODUCTION` mode. This is intended for deployments.
Currently, `DEV` mode will operate very similarly to how `debug=True` does in older Sanic versions. However, in v22.3. `debug=True` will **no longer** enable auto-reload. If you would like to have debugging and auto-reload, you should enable `DEV` mode.
**DEVELOPMENT**
```
$ sanic server:app --dev
```
```python
app.run(debug=True, auto_reload=True)
```
**PRODUCTION**
```
$ sanic server:app
```
```python
app.run()
```
Beginning in v22.3, `PRODUCTION` mode will no longer enable access logs by default.
A summary of the changes are as follows:
| Flag | Mode | Tracebacks | Logging | Access logs | Reload | Max workers |
|---------|-------|------------|---------|-------------|--------|-------------|
| --debug | DEBUG | yes | DEBUG | yes | ^1 | |
| | PROD | no | INFO ^2 | ^3 | | |
| --dev | DEBUG | yes | DEBUG | yes | yes | |
| --fast | | | | | | yes |
- ^1 `--debug` to deprecate auto-reloading and remove in 22.3
- ^2 After 22.3 this moves to WARNING
- ^3 After 22.3: no
### Max allowed workers
You can easily spin up the maximum number of allowed workers using `--fast`.
```
$ sanic server:app --fast
```
```python
app.run(fast=True)
```
### First-class Sanic Extensions support
[Sanic Extensions](../../plugins/sanic-ext/getting-started.md) provides a number of additional features specifically intended for API developers. You can now easily implement all of the functionality it has to offer without additional setup as long as the package is in the environment. These features include:
- Auto create `HEAD`, `OPTIONS`, and `TRACE` endpoints
- CORS protection
- Predefined, endpoint-specific response serializers
- Dependency injection into route handlers
- OpenAPI documentation with Redoc and/or Swagger
- Request query arguments and body input validation
The preferred method is to install it along with Sanic, but you can also install the packages on their own.
.. column::
```
$ pip install sanic[ext]
```
.. column::
```
$ pip install sanic sanic-ext
```
After that, no additional configuration is required. Sanic Extensions will be attached to your application and provide all of the additional functionality with **no further configuration**.
If you want to change how it works, or provide additional configuration, you can change Sanic extensions using `app.extend`. The following examples are equivalent. The `Config` object is to provide helpful type annotations for IDE development.
.. column::
```python
# This is optional, not required
app = Sanic("MyApp")
app.extend(config={"oas_url_prefix": "/apidocs"})
```
.. column::
```python
# This is optional, not required
app = Sanic("MyApp")
app.config.OAS_URL_PREFIX = "/apidocs"
```
.. column::
```python
# This is optional, not required
from sanic_ext import Config
app = Sanic("MyApp")
app.extend(config=Config(oas_url_prefix="/apidocs"))
```
.. column::
### Contextual exceptions
In [v21.9](./v21.9.md#default-exception-messages) we added default messages to exceptions that simplify the ability to consistently raise exceptions throughout your application.
```python
class TeapotError(SanicException):
status_code = 418
message = "Sorry, I cannot brew coffee"
raise TeapotError
```
But this lacked two things:
1. A dynamic and predictable message format
2. The ability to add additional context to an error message (more on this in a moment)
The current release allows any Sanic exception to have additional information to when raised to provide context when writing an error message:
```python
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"})
```
The new feature allows the passing of `extra` meta to the exception instance. This `extra` info object **will be suppressed** when in `PRODUCTION` mode, but displayed in `DEVELOPMENT` mode.
.. column::
**PRODUCTION**
![image](https://user-images.githubusercontent.com/166269/139014161-cda67cd1-843f-4ad2-9fa1-acb94a59fc4d.png)
.. column::
**DEVELOPMENT**
![image](https://user-images.githubusercontent.com/166269/139014121-0596b084-b3c5-4adb-994e-31ba6eba6dad.png)
Getting back to item 2 from above: _The ability to add additional context to an error message_
This is particularly useful when creating microservices or an API that you intend to pass error messages back in JSON format. In this use case, we want to have some context around the exception beyond just a parseable error message to return details to the client.
```python
raise TeapotError(context={"foo": "bar"})
```
This is information **that we want** to always be passed in the error (when it is available). Here is what it should look like:
.. column::
**PRODUCTION**
```json
{
"description": "I'm a teapot",
"status": 418,
"message": "Sorry Adam, I cannot make you coffee",
"context": {
"foo": "bar"
}
}
```
.. column::
**DEVELOPMENT**
```json
{
"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("
}
]
}
]
}
```
### Background task management
When using the `app.add_task` method to create a background task, there now is the option to pass an optional `name` keyword argument that allows it to be fetched, or cancelled.
```python
app.add_task(dummy, name="dummy_task")
task = app.get_task("dummy_task")
app.cancel_task("dummy_task")
```
### Route context kwargs in definitions
When a route is defined, you can add any number of keyword arguments with a `ctx_` prefix. These values will be injected into the route `ctx` object.
```python
@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":
...
```
### Blueprints can be registered at any time
In previous versions of Sanic, there was a strict ordering of when a Blueprint could be attached to an application. If you ran `app.blueprint(bp)` *before* attaching all objects to the Blueprint instance, they would be missed.
Now, you can attach a Blueprint at anytime and everything attached to it will be included at startup.
### Noisy exceptions (force all exceptions to logs)
There is a new `NOISY_EXCEPTIONS` config value. When it is `False` (which is the default), Sanic will respect the `quiet` property of any `SanicException`. This means that an exception with `quiet=True` will not be displayed to the log output.
However, when setting `NOISY_EXCEPTIONS=True`, all exceptions will be logged regardless of the `quiet` value.
This can be helpful when debugging.
```python
app.config.NOISY_EXCEPTIONS = True
```
### Signal events as `Enum`
There is an `Enum` with all of the built-in signal values for convenience.
```python
from sanic.signals import Event
@app.signal(Event.HTTP_LIFECYCLE_BEGIN)
async def connection_opened(conn_info):
...
```
### Custom type casting of environment variables
By default, Sanic will convert an `int`, `float`, or a `bool` value when applying environment variables to the `config` instance. You can extend this with your own converter:
```python
app = Sanic(..., config=Config(converters=[UUID]))
```
### Disable `uvloop` by configuration value
The usage of `uvloop` can be controlled by configuration value:
```python
app.config.USE_UVLOOP = False
```
### Run Sanic server with multiple TLS certificates
Sanic can be run with multiple TLS certificates:
```python
app.run(
ssl=[
"/etc/letsencrypt/live/example.com/",
"/etc/letsencrypt/live/mysite.example/",
]
)
```
## News
### Coming Soon: Python Web Development with Sanic
A book about Sanic is coming soon by one of the core developers, [@ahopkins](https://github.com/ahopkins).
Learn more at [sanicbook.com](https://sanicbook.com).
> Get equipped with the practical knowledge of working with Sanic to increase the performance and scalability of your web applications. While doing that, we will level-up your development skills as you learn to customize your application to meet the changing business needs without having to significantly over-engineer the app.
A portion of book proceeds goes into the Sanic Community Organization to help fund the development and operation of Sanic. So, buying the book is another way you can support Sanic.
### Dark mode for the docs
If you have not already noticed, this Sanic website is now available in a native dark mode. You can toggle the theme at the top right of the page.
## Thank you
Thank you to everyone that participated in this release: :clap:
[@adarsharegmi](https://github.com/adarsharegmi)
[@ahopkins](https://github.com/ahopkins)
[@ashleysommer](https://github.com/ashleysommer)
[@ChihweiLHBird](https://github.com/ChihweiLHBird)
[@cnicodeme](https://github.com/cnicodeme)
[@kianmeng](https://github.com/kianmeng)
[@meysam81](https://github.com/meysam81)
[@nuxion](https://github.com/nuxion)
[@prryplatypus](https://github.com/prryplatypus)
[@realDragonium](https://github.com/realDragonium)
[@SaidBySolo](https://github.com/SaidBySolo)
[@sjsadowski](https://github.com/sjsadowski)
[@Tronic](https://github.com/tronic)
[@Varriount](https://github.com/Varriount)
[@vltr](https://github.com/vltr)
[@whos4n3](https://github.com/whos4n3)
And, a special thank you to [@miss85246](https://github.com/miss85246) and [@ZinkLu](https://github.com/ZinkLu) for their tremendous work keeping the documentation synced and translated into Chinese.
---
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](https://opencollective.com/sanic-org/).

View File

@@ -0,0 +1,268 @@
# Version 21.3
.. toc::
## Introduction
Sanic is now faster.
Well, it already was fast. But with the first iteration of the v21 release, we incorporated a few major milestones that have made some tangible improvements. These encompass some ideas that have been in the works for years, and have finally made it into the released version.
.. warning:: Breaking changes
Version 21.3 introduces a lot of new features. But, it also includes some breaking changes. This is why these changes were introduced after the last LTS. If you rely upon something that has been removed, you should continue to use v20.12LTS until you are able to upgrade.
```bash
pip install "sanic>=20.12,<20.13"
pip freeze > requirements.txt
```
For most typical installations, you should be able to upgrade without a problem.
## What to know
Notable new or breaking features, and what to upgrade...
### Python 3.7+ Only
This version drops Python 3.6 support. Version 20.12LTS will continue to support Python 3.6 until its EOL in December, 2022, and version 19.12LTS will support it until its EOL in December, 2021.
Read more about our [LTS policy](../project/policies.md#long-term-support-v-interim-releases).
### Streaming as first class citizen
The biggest speed improvement came from unifying the request/response cycle into a single flow. Previously, there was a difference between regular cycles, and streaming cycles. This has been simplified under the hood, even though the API is staying the same right now for compatibility. The net benefit is that **all** requests now should see a new benefit.
Read more about [streaming changes](../advanced/streaming.md#response-streaming).
### Router overhaul
The old Sanic router was based upon regular expressions. In addition it suffered from a number of quirks that made it hard to modify at run time, and resulted in some performance issues. This change has been years in the making and now [converts the router to a compiled tree at startup](https://community.sanicframework.org/t/a-fast-new-router/649/41). Look for additional improvements throughout the year.
The outward facing API has kept backwards compatibility. However, if you were accessing anything inside the router specifically, you many notice some changes. For example:
1. `Router.get()` has a new return value
2. `Route` is now a proper class object and not a `namedtuple`
3. If building the router manually, you will need to call `Router.finalize()` before it is usable
4. There is a new `<date:ymd>` pattern that can be matched in your routes
5. You cannot startup an application without at least one route defined
The router is now located in its own repository: [sanic-org/sanic-router](https://github.com/sanic-org/sanic-router) and is also its own [standalone package on PyPI](https://pypi.org/project/sanic-routing/).
### Signals API ⭐️
_BETA Feature: API to be finalized in v21.6_
A side benefit of the new router is that it can do double duty also powering the [new signals API](https://github.com/sanic-org/sanic/issues/1630). This feature is being released for public usage now, and likely the public API will not change in its final form.
The core ideas of this feature are:
1. to allow the developer greater control and access to plugging into the server and request lifecycles,
2. to provide new tools to synchronize and send messages through your application, and
3. to ultimately further increase performance.
The API introduces three new methods:
- `@app.signal(...)` - For defining a signal handler. It looks and operates very much like a route. Whenever that signal is dispatched, this handler will be executed.
- `app.event(...)` - An awaitable that can be used anywhere in your application to pause execution until the event is triggered.
- `app.dispatch(...)` - Trigger an event and cause the signal handlers to execute.
```python
@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 naming
Routes used to be referenced by both `route.name` and `route.endpoint`. While similar, they were slightly different. Now, all routes will be **consistently** namespaced and referenced.
```text
<app name>.[optional:<blueprint name>.]<handler name>
```
This new "name" is assigned to the property `route.name`. We are deprecating `route.endpoint`, and will remove that property in v21.9. Until then, it will be an alias for `route.name`.
In addition, naming prefixes that had been in use for things like static, websocket, and blueprint routes have been removed.
### New decorators
Several new convenience decorators to help IDEs with autocomplete.
```python
# 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
```
### Unquote in route
If you have a route that uses non-ascii characters, Sanic will no longer `unquote` the text for you. You will need to specifically tell the route definition that it should do so.
```python
@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 您好"
```
If you forget to do so, your text will remain encoded.
### Alter `Request.match_info`
The `match_info` has always provided the data for the matched path parameters. You now have access to modify that, for example in middleware.
```python
@app.on_request
def convert_to_snake_case(request):
request.match_info = to_snake(request.match_info)
```
### Version types in routes
The `version` argument in routes can now be:
- `str`
- `int`
- `float`
```python
@app.route("/foo", version="2.1.1")
@app.route("/foo", version=2)
@app.route("/foo", version=2.1)
```
### Safe method handling with body
Route handlers for `GET`, `HEAD`, `OPTIONS` and `DELETE` will not decode any HTTP body passed to it. You can override this:
```python
@app.delete(..., ignore_body=False)
```
### Application, Blueprint and Blueprint Group parity
The `Sanic` and `Blueprint` classes share a common base. Previously they duplicated a lot of functionality, that lead to slightly different implementations between them. Now that they both inherit the same base class, developers and plugins should have a more consistent API to work with.
Also, Blueprint Groups now also support common URL extensions like the `version` and `strict_slashes` keyword arguments.
### Dropped `httpx` from dependencies
There is no longer a dependency on `httpx`.
### Removed `testing` library
Sanic internal testing client has been removed. It is now located in its own repository: [sanic-org/sanic-testing](https://github.com/sanic-org/sanic-testing) and is also its own [standalone package on PyPI](https://pypi.org/project/sanic-testing/).
If you have `sanic-testing` installed, it will be available and usable on your `Sanic()` application instances as before. So, the **only** change you will need to make is to add `sanic-testing` to your test suite requirements.
### Application and connection level context (`ctx`) objects
Version 19.9 [added ](https://github.com/sanic-org/sanic/pull/1666/files) the `request.ctx` API. This helpful construct easily allows for attaching properties and data to a request object (for example, in middleware), and reusing the information elsewhere int he application.
Similarly, this concept is being extended in two places:
1. the application instance, and
2. a transport connection.
#### Application context
A common use case is to attach properties to the app instance. For the sake of consistency, and to avoid the issue of name collision with Sanic properties, the `ctx` object now exists on `Sanic` instances.
```python
@app.before_server_startup
async def startup_db(app, _):
# WRONG
app.db = await connect_to_db()
# CORRECT
app.ctx.db = await connect_to_db()
```
#### Connection context
When a client sends a keep alive header, Sanic will attempt to keep the transport socket [open for a period of time](../deployment/configuration.md#keep-alive-timeout). That transport object now has a `ctx` object available on it. This effectively means that multiple requests from a single client (where the transport layer is being reused) may share state.
```python
@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}")
```
```bash
$ 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::
Connection level context is an experimental feature, and should be finalized in v21.6.
## News
### A NEW frontpage 🎉
We have split the documentation into two. The docstrings inside the codebase will still continue to build sphinx docs to ReadTheDocs. However, it will be limited to API documentation. The new frontpage will house the "Sanic User Guide".
The new site runs on Vuepress. Contributions are welcome. We also invite help in translating the documents.
As a part of this, we also freshened up the RTD documentation and changed it to API docs only.
### Chat has moved to Discord
The Gitter chatroom has taken one step closer to being phased out. In its place we opened a [Discord server](https://discord.gg/FARQzAEMAA).
### Open Collective
The Sanic Community Organization has [opened a page on Open Collective](https://opencollective.com/sanic-org) to enable anyone that would like to financially support the development of Sanic.
### 2021 Release Managers
Thank you to @sjsadowski and @yunstanford for acting as release managers for both 2019 and 2020. This year's release managers are @ahopkins and @vltr.
## Thank you
Thank you to everyone that participated in this release: :clap:
[@ahopkins](https://github.com/ahopkins) [@akshgpt7](https://github.com/akshgpt7) [@artcg](https://github.com/artcg) [@ashleysommer](https://github.com/ashleysommer) [@elis-k](https://github.com/elis-k) [@harshanarayana](https://github.com/harshanarayana) [@sjsadowski](https://github.com/sjsadowski) [@tronic](https://github.com/tronic) [@vltr](https://github.com/vltr),
To [@ConnorZhang](https://github.com/miss85246) and [@ZinkLu](https://github.com/ZinkLu) for translating our documents into Chinese,
---
Make sure to checkout the changelog to get links to all the PRs, etc.

View File

@@ -0,0 +1,346 @@
# Version 21.6
.. toc::
## Introduction
This is the second release of the version 21 [release cycle](../project/policies.md#release-schedule). There will be one more release in September before version 21 is "finalized" in the December long-term support version. One thing users may have noticed starting in 21.3, the router was moved to its own package: [`sanic-routing`](https://pypi.org/project/sanic-routing). This change is likely to stay for now. Starting with this release, the minimum required version is 0.7.0.
## What to know
More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade...
### Deprecation of `StreamingHTTPResponse`
The use of `StreamingHTTPResponse` has been deprecated and will be removed in the 21.12 release. This impacts both `sanic.response.stream` and `sanic.response.file_stream`, which both under the hood instantiate `StreamingHTTPResponse`.
Although the exact migration path has yet to be determined, `sanic.response.stream` and `sanic.response.file_stream` will continue to exist in v21.12 in some form as convenience operators. Look for more details throughout this Summer as we hope to have this finalized by the September release.
### Deprecation of `CompositionView`
Usage of `CompositionView` has been deprecated and will be removed in 21.12.
### Deprecation of path parameter types: `string` and `number`
Going forward, you should use `str` and `float` for path param types instead of `string` and `number`.
```python
@app.get("/<foo:str>/<bar:float>")
async def handler(request, foo: str, bar: float):
...
```
Existing `string` and `number` types are aliased and will continue to work, but will be removed in v21.12.
### Version 0.7 router upgrades
This includes a number of bug fixes and more gracefully handles a wider array of edge cases than v0.6. If you experience any patterns that are not supported, [please report them](https://github.com/sanic-org/sanic-routing/issues). You can see some of the issues resolved on the `sanic-routing` [release notes](https://github.com/sanic-org/sanic-routing/releases).
### Inline streaming with `eof()`
Version 21.3 included [big changes in how streaming is handled](https://sanic.dev/en/guide/release-notes/v21.3.html#what-to-know). The pattern introduced will become the default (see below). As a convenience, a new `response.eof()` method has been included. It should be called once the final data has been pushed to the client:
```python
@app.route("/")
async def test(request):
response = await request.respond(content_type="text/csv")
await response.send("foo,")
await response.send("bar")
await response.eof()
return response
```
### New path parameter type: `slug`
You can now specify a dynamic path segment as a `slug` with appropriate matching:
```python
@app.get("/articles/<article_slug:slug>")
async def article(request, article_slug: str):
...
```
Slugs must consist of lowercase letters or digits. They may contain a hyphen (`-`), but it cannot be the first character.
```
this-is-a-slug
with-123-is-also-a-slug
111-at-start-is-a-slug
NOT-a-slug
-NOT-a-slug
```
### Stricter application and blueprint names, and deprecation
Your application and `Blueprint` instances must conform to a stricter set of requirements:
1. Only consisting of alphanumeric characters
2. May contain a hyphen (`-`) or an underscore (`_`)
3. Must begin with a letter (uppercase or lowercase)
The naming convention is similar to Python variable naming conventions, with the addition of allowing hyphens (`-`).
The looser standard has been deprecatated. Beginning in 21.12, non-conformance will be a startup time error.
### A new access on `Route` object: `route.uri`
The `Route` object in v21.3 no longer had a `uri` attribute. Instead, the closes you could get was `route.path`. However, because of how `sanic-routing` works, the `path` property does *not* have a leading `/`. This has been corrected so that now there is a `route.uri` with a leading slash:
```python
route.uri == f"/{route.path}"
```
### A new accessor on `Request` object impacting IPs
To access the IP address of the incoming request, Sanic has had a convenience accessor on the request object: `request.ip`. That is not new, and comes from an underlying object that provides details about the open HTTP connection: `request.conn_info`.
The current version adds a new `client_ip` accessor to that `conn_info` object. For IPv4, you will not notice a difference. However, for IPv6 applications, the new accessor will provide an "unwrapped" version of the address. Consider the following example:
```python
@app.get("/")
async def handler(request):
return json(
{
"request.ip": request.ip,
"request.conn_info.client": request.conn_info.client,
"request.conn_info.client_ip": request.conn_info.client_ip,
}
)
app.run(sock=my_ipv6_sock)
```
```bash
$ curl http://\[::1\]:8000
{
"request.ip": "::1",
"request.conn_info.client": "[::1]",
"request.conn_info.client_ip": "::1"
}
```
### Alternate `Config` and `Sanic.ctx` objects
You can now pass your own config and context objects to your Sanic applications. A custom configuration *should* be a subclass of `sanic.config.Config`. The context object can be anything you want, with no restrictions whatsoever.
```python
class CustomConfig(Config):
...
config = CustomConfig()
app = Sanic("custom", config=config)
assert isinstance(app.config, CustomConfig)
```
And...
```python
class CustomContext:
...
ctx = CustomContext()
app = Sanic("custom", ctx=ctx)
assert isinstance(app.ctx, CustomContext)
```
### Sanic CLI improvements
1. New flag for existing feature: `--auto-reload`
2. Some new shorthand flags for existing arguments
3. New feature: `--factory`
4. New feature: `--simple`
5. New feature: `--reload-dir`
#### Factory applications
For applications that follow the factory pattern (a function that returns a `sanic.Sanic` instance), you can now launch your application from the Sanic CLI using the `--factory` flag.
```python
from sanic import Blueprint, Sanic, text
bp = Blueprint(__file__)
@bp.get("/")
async def handler(request):
return text("😎")
def create_app() -> Sanic:
app = Sanic(__file__)
app.blueprint(bp)
return app
```
You can now run it:
```bash
$ sanic path.to:create_app --factory
```
#### Sanic Simple Server
Sanic CLI now includes a simple pattern to serve a directory as a web server. It will look for an `index.html` at the directory root.
```bash
$ sanic ./path/to/dir --simple
```
.. warning::
This feature is still in early *beta* mode. It is likely to change in scope.
#### Additional reload directories
When using either `debug` or `auto-reload`, you can include additional directories for Sanic to watch for new files.
```bash
sanic ... --reload-dir=/path/to/foo --reload-dir=/path/to/bar
```
.. tip::
You do *NOT* need to include this on your application directory. Sanic will automatically reload when any Python file in your application changes. You should use the `reload-dir` argument when you want to listen and update your application when static files are updated.
### Version prefix
When adding `version`, your route is prefixed with `/v<YOUR_VERSION_NUM>`. This will always be at the beginning of the path. This is not new.
```python
# /v1/my/path
app.route("/my/path", version=1)
```
Now, you can alter the prefix (and therefore add path segments *before* the version).
```python
# /api/v1/my/path
app.route("/my/path", version=1, version_prefix="/api/v")
```
The `version_prefix` argument is can be defined in:
- `app.route` and `bp.route` decorators (and all the convenience decorators also)
- `Blueprint` instantiation
- `Blueprint.group` constructor
- `BlueprintGroup` instantiation
- `app.blueprint` registration
### Signal event auto-registration
Setting `config.EVENT_AUTOREGISTER` to `True` will allow you to await any signal event even if it has not previously been defined with a signal handler.
```python
@app.signal("do.something.start")
async def signal_handler():
await do_something()
await app.dispatch("do.something.complete")
# somethere else in your app:
await app.event("do.something.complete")
```
### Infinitely reusable and nestable `Blueprint` and `BlueprintGroup`
A single `Blueprint` may not be assigned and reused to multiple groups. The groups themselves can also by infinitely nested into one or more other groups. This allows for an unlimited range of composition.
### HTTP methods as `Enum`
Sanic now has `sanic.HTTPMethod`, which is an `Enum`. It can be used interchangeably with strings:
```python
from sanic import Sanic, HTTPMethod
@app.route("/", methods=["post", "PUT", HTTPMethod.PATCH])
async def handler(...):
...
```
### Expansion of `HTTPMethodView`
Class based views may be attached now in one of three ways:
**Option 1 - Existing**
```python
class DummyView(HTTPMethodView):
...
app.add_route(DummyView.as_view(), "/dummy")
```
**Option 2 - From `attach` method**
```python
class DummyView(HTTPMethodView):
...
DummyView.attach(app, "/")
```
**Option 3 - From class definition at `__init_subclass__`**
```python
class DummyView(HTTPMethodView, attach=app, uri="/"):
...
```
Options 2 and 3 are useful if your CBV is located in another file:
```python
from sanic import Sanic, HTTPMethodView
class DummyView(HTTPMethodView, attach=Sanic.get_app(), uri="/"):
...
```
## News
### Discord and support forums
If you have not already joined our community, you can become a part by joining the [Discord server](https://discord.gg/FARQzAEMAA) and the [Community Forums](https://community.sanicframework.org/). Also, follow [@sanicframework](https://twitter.com/sanicframework) on Twitter.
### SCO 2022 elections
The Summer 🏝/Winter ❄️ (choose your Hemisphere) is upon us. That means we will be holding elections for the SCO. This year, we will have the following positions to fill:
- Steering Council Member (2 year term)
- Steering Council Member (2 year term)
- Steering Council Member (1 year term)
- Release Manager v22
- Release Manager v22
[@vltr](https://github.com/vltr) will be staying on to complete his second year on the Steering Council.
If you are interested in learning more, you can read about the SCO [roles and responsibilities](../project/scope.md#roles-and-responsibilities), or Adam Hopkins on Discord.
Nominations will begin September 1. More details will be available on the Forums as we get closer.
### New project underway
We have added a new project to the SCO umbrella: [`sanic-ext`](https://github.com/sanic-org/sanic-ext). It is not yet released, and in heavy active development. The goal for the project will ultimately be to replace [`sanic-openapi`](https://github.com/sanic-org/sanic-openapi) with something that provides more features for web application developers, including input validation, CORS handling, and HTTP auto-method handlers. If you are interested in helping out, let us know on Discord. Look for an initial release of this project sometime (hopefully) before the September release.
## Thank you
Thank you to everyone that participated in this release: :clap:
[@aaugustin](https://github.com/aaugustin)
[@ahopkins](https://github.com/ahopkins)
[@ajaygupta2790](https://github.com/ajaygupta2790)
[@ashleysommer](https://github.com/ashleysommer)
[@ENT8R](https://github.com/ent8r)
[@fredlllll](https://github.com/fredlllll)
[@graingert](https://github.com/graingert)
[@harshanarayana](https://github.com/harshanarayana)
[@jdraymon](https://github.com/jdraymon)
[@Kyle-Verhoog](https://github.com/kyle-verhoog)
[@sanjeevanahilan](https://github.com/sanjeevanahilan)
[@sjsadowski](https://github.com/sjsadowski)
[@Tronic](https://github.com/tronic)
[@vltr](https://github.com/vltr)
[@ZinkLu](https://github.com/zinklu)
---
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](https://opencollective.com/sanic-org/).

View File

@@ -0,0 +1,234 @@
# Version 21.9
.. toc::
## Introduction
This is the third release of the version 21 [release cycle](../../org/policies.md#release-schedule). Version 21 will be "finalized" in the December long-term support version release.
## What to know
More details in the [Changelog](https://sanic.readthedocs.io/en/stable/sanic/changelog.html). Notable new or breaking features, and what to upgrade...
### Removal of config values: `WEBSOCKET_READ_LIMIT`, `WEBSOCKET_WRITE_LIMIT` and `WEBSOCKET_MAX_QUEUE`
With the complete overhaul of the websocket implementation, these configuration values were removed. There currently is not a plan to replace them.
### Deprecation of default value of `FALLBACK_ERROR_FORMAT`
When no error handler is attached, Sanic has used `html` as the fallback format-type. This has been deprecated and will change to `text` starting in v22.3. While the value of this has changed to `auto`, it will still continue to use HTML as the last resort thru v21.12LTS before changing.
### `ErrorHandler.lookup` signature deprecation
The `ErrorHandler.lookup` now **requires** two positional arguments:
```python
def lookup(self, exception, route_name: Optional[str]):
```
A non-conforming method will cause Blueprint-specific exception handlers to not properly attach.
### Reminder of upcoming removals
As a reminder, the following items have already been deprecated, and will be removed in version 21.12LTS
- `CompositionView`
- `load_env` (use `env_prefix` instead)
- Sanic objects (application instances, blueprints, and routes) must by alphanumeric conforming to: `^[a-zA-Z][a-zA-Z0-9_\-]*$`
- Arbitrary assignment of objects to application and blueprint instances (use `ctx` instead; removal of this has been bumped from 21.9 to 21.12)
### Overhaul of websockets
There has been a huge overhaul to the handling of websocket connections. Thanks to [@aaugustin](https://github.com/aaugustin) the [`websockets`](https://websockets.readthedocs.io/en/stable/index.html) now has a new implementation that allows Sanic to handle the I/O of websocket connections on its own. Therefore, Sanic has bumped the minimum version to `websockets>=10.0`.
The change should mostly be unnoticeable to developers, except that some of the oddities around websocket handlers in Sanic have been corrected. For example, you now should be able to catch the `CancellError` yourself when someone disconnects:
```python
@app.websocket("/")
async def handler(request, ws):
try:
while True:
await asyncio.sleep(0.25)
except asyncio.CancelledError:
print("User closed connection")
```
### Built-in signals
Version [21.3](./v21.3.md) introduced [signals](../advanced/signals.md). Now, Sanic dispatches signal events **from within the codebase** itself. This means that developers now have the ability to hook into the request/response cycle at a much closer level than before.
Previously, if you wanted to inject some logic you were limited to middleware. Think of integrated signals as _super_-middleware. The events that are dispatched now include:
- `http.lifecycle.begin`
- `http.lifecycle.complete`
- `http.lifecycle.exception`
- `http.lifecycle.handle`
- `http.lifecycle.read_body`
- `http.lifecycle.read_head`
- `http.lifecycle.request`
- `http.lifecycle.response`
- `http.lifecycle.send`
- `http.middleware.after`
- `http.middleware.before`
- `http.routing.after`
- `http.routing.before`
- `server.init.after`
- `server.init.before`
- `server.shutdown.after`
- `server.shutdown.before`
.. note::
The `server` signals are the same as the four (4) main server listener events. In fact, those listeners themselves are now just convenience wrappers to signal implementations.
### Smarter `auto` exception formatting
Sanic will now try to respond with an appropriate exception format based upon the endpoint and the client. For example, if your endpoint always returns a `sanic.response.json` object, then any exceptions will automatically be formatted in JSON. The same is true for `text` and `html` responses.
Furthermore, you now can _explicitly_ control which formatter to use on a route-by-route basis using the route definition:
```python
@app.route("/", error_format="json")
async def handler(request):
pass
```
### Blueprint copying
Blueprints can be copied to new instances. This will carry forward everything attached to it, like routes, middleware, etc.
```python
v1 = Blueprint("Version1", version=1)
@v1.route("/something")
def something(request):
pass
v2 = v1.copy("Version2", version=2)
app.blueprint(v1)
app.blueprint(v2)
```
```
/v1/something
/v2/something
```
### Blueprint group convenience methods
Blueprint groups should now have all of the same methods available to them as regular Blueprints. With this, along with Blueprint copying, Blueprints should now be very composable and flexible.
### Accept header parsing
Sanic `Request` objects can parse an `Accept` header to provide an ordered list of the client's content-type preference. You can simply access it as an accessor:
```python
print(request.accept)
# ["*/*"]
```
It also is capable of handling wildcard matching. For example, assuming the incoming request included:
```
Accept: */*
```
Then, the following is `True`:
```python
"text/plain" in request.accept
```
### Default exception messages
Any exception that derives from `SanicException` can now define a default exception message. This makes it more convenient and maintainable to reuse the same exception in multiple places without running into DRY issues with the message that the exception provides.
```python
class TeaError(SanicException):
message = "Tempest in a teapot"
raise TeaError
```
### Type annotation conveniences
It is now possible to control the path parameter types using Python's type annotations. Instead of doing this:
```python
@app.route("/<one:int>/<two:float>/<three:uuid>")
def handler(request: Request, one: int, two: float, three: UUID):
...
```
You can now simply do this:
```python
@app.route("/<one>/<two>/<three>")
def handler(request: Request, one: int, two: float, three: UUID):
...
```
Both of these examples will result in the same routing principles to be applied.
### Explicit static resource type
You can now explicitly tell a `static` endpoint whether it is supposed to treat the resource as a file or a directory:
```python
static("/", "/path/to/some/file", resource_type="file"))
```
## News
### Release of `sanic-ext` and deprecation of `sanic-openapi`
One of the core principles of Sanic is that it is meant to be a tool, not a dictator. As the frontpage of this website states:
> Build the way you want to build without letting your tooling constrain you.
This means that a lot of common features used (specifically by Web API developers) do not exist in the `sanic` repository. This is for good reason. Being unopinionated provides the developer freedom and flexibility.
But, sometimes you do not want to have to build and rebuild the same things. Sanic has until now really relied upon the awesome support of the community to fill in the gaps with plugins.
From the early days, there has been an official `sanic-openapi` package that offered the ability to create OpenAPI documentation based upon your application. But, that project has been plagued over the years and has not been given as much priority as the main project.
Starting with the release of v21.9, the SCO is deprecating the `sanic-openapi` package and moving it to maintenance mode. This means that it will continue to get updates as needed to maintain it for the current future, but it will not receive any new feature enhancements.
A new project called `sanic-ext` is taking its place. This package provides not only the ability to build OAS3 documentation, but fills in many of the gaps that API developers may want in their applications. For example, out of the box it will setup CORS, and auto enable `HEAD` and `OPTIONS` responses where needed. It also has the ability validate incoming data using either standard library Dataclasses or Pydantic models.
The list of goodies includes:
- CORS protection
- incoming request validation
- auto OAS3 documentation using Redoc and/or Swagger UI
- auto `HEAD`, `OPTIONS`, and `TRACE` responses
- dependency injection
- response serialization
This project is still in `alpha` mode for now and is subject to change. While it is considered to be production capable, there may be some need to change the API as we continue to add features.
Checkout the [documentation](../../plugins/sanic-ext/getting-started.md) for more details.
## Thank you
Thank you to everyone that participated in this release: :clap:
[@aaugustin](https://github.com/aaugustin)
[@ahopkins](https://github.com/ahopkins)
[@ashleysommer](https://github.com/ashleysommer)
[@cansarigol3megawatt](https://github.com/cansarigol3megawatt)
[@ChihweiLHBird](https://github.com/ChihweiLHBird)
[@gluhar2006](https://github.com/gluhar2006)
[@komar007](https://github.com/komar007)
[@ombe1229](https://github.com/ombe1229)
[@prryplatypus](https://github.com/prryplatypus)
[@SaidBySolo](https://github.com/SaidBySolo)
[@Tronic](https://github.com/tronic)
[@vltr](https://github.com/vltr)
And, a special thank you to [@miss85246](https://github.com/miss85246) and [@ZinkLu](https://github.com/ZinkLu) for their tremendous work keeping the documentation synced and translated into Chinese.
---
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](https://opencollective.com/sanic-org/).