Compare commits

...

4 Commits

Author SHA1 Message Date
Adam Hopkins
a61c5ff55b Get better output on test failures 2022-02-27 13:29:16 +02:00
Arie Bovenberg
7523e87937 remove overlapping slots from app.Sanic, fix broken slots inherit of HTTPResponse (#2387) 2022-02-24 17:45:23 +02:00
Bluenix
d4fb44e986 Document middleware on_request and on_response (#2398) 2022-02-13 21:08:08 +02:00
Ryu juheon
68b654d981 fix(tasks): newly assigned `None` in registry (#2381) 2022-02-08 08:33:09 +02:00
9 changed files with 93 additions and 39 deletions

View File

@@ -8,7 +8,6 @@ on:
jobs:
testPy310:
if: github.event.pull_request.draft == false
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:

View File

@@ -140,6 +140,7 @@ To maintain the code consistency, Sanic uses following tools.
#. `isort <https://github.com/timothycrosley/isort>`_
#. `black <https://github.com/python/black>`_
#. `flake8 <https://github.com/PyCQA/flake8>`_
#. `slotscheck <https://github.com/ariebovenberg/slotscheck>`_
isort
*****
@@ -167,7 +168,13 @@ flake8
#. pycodestyle
#. Ned Batchelder's McCabe script
``isort``\ , ``black`` and ``flake8`` checks are performed during ``tox`` lint checks.
slotscheck
**********
``slotscheck`` ensures that there are no problems with ``__slots__``
(e.g. overlaps, or missing slots in base classes).
``isort``\ , ``black``\ , ``flake8`` and ``slotscheck`` checks are performed during ``tox`` lint checks.
The **easiest** way to make your code conform is to run the following before committing.

View File

@@ -44,11 +44,8 @@ from typing import (
from urllib.parse import urlencode, urlunparse
from warnings import filterwarnings
from sanic_routing.exceptions import ( # type: ignore
FinalizationError,
NotFound,
)
from sanic_routing.route import Route # type: ignore
from sanic_routing.exceptions import FinalizationError, NotFound
from sanic_routing.route import Route
from sanic.application.ext import setup_ext
from sanic.application.state import ApplicationState, Mode, ServerStage
@@ -142,7 +139,6 @@ class Sanic(BaseSanic, RunnerMixin, metaclass=TouchUpMeta):
"error_handler",
"go_fast",
"listeners",
"name",
"named_request_middleware",
"named_response_middleware",
"request_class",
@@ -1268,10 +1264,9 @@ class Sanic(BaseSanic, RunnerMixin, metaclass=TouchUpMeta):
...
def purge_tasks(self):
for task in self.tasks:
for key, task in self._task_registry.items():
if task.done() or task.cancelled():
name = task.get_name()
self._task_registry[name] = None
self._task_registry[key] = None
self._task_registry = {
k: v for k, v in self._task_registry.items() if v is not None

View File

@@ -16,9 +16,9 @@ class MiddlewareMixin(metaclass=SanicMeta):
self, middleware_or_request, attach_to="request", apply=True
):
"""
Decorate and register middleware to be called before a request.
Can either be called as *@app.middleware* or
*@app.middleware('request')*
Decorate and register middleware to be called before a request
is handled or after a response is created. Can either be called as
*@app.middleware* or *@app.middleware('request')*.
`See user guide re: middleware
<https://sanicframework.org/guide/basics/middleware.html>`__
@@ -47,12 +47,25 @@ class MiddlewareMixin(metaclass=SanicMeta):
)
def on_request(self, middleware=None):
"""Register a middleware to be called before a request is handled.
This is the same as *@app.middleware('request')*.
:param: middleware: A callable that takes in request.
"""
if callable(middleware):
return self.middleware(middleware, "request")
else:
return partial(self.middleware, attach_to="request")
def on_response(self, middleware=None):
"""Register a middleware to be called after a response is created.
This is the same as *@app.middleware('response')*.
:param: middleware:
A callable that takes in a request and its response.
"""
if callable(middleware):
return self.middleware(middleware, "response")
else:

View File

@@ -50,6 +50,16 @@ class BaseHTTPResponse:
The base class for all HTTP Responses
"""
__slots__ = (
"asgi",
"body",
"content_type",
"stream",
"status",
"headers",
"_cookies",
)
_dumps = json_dumps
def __init__(self):
@@ -156,7 +166,7 @@ class HTTPResponse(BaseHTTPResponse):
:type content_type: Optional[str]
"""
__slots__ = ("body", "status", "content_type", "headers", "_cookies")
__slots__ = ()
def __init__(
self,

View File

@@ -112,6 +112,7 @@ tests_require = [
"docutils",
"pygments",
"uvicorn<0.15.0",
"slotscheck>=0.8.0,<1",
types_ujson,
]

View File

@@ -5,6 +5,7 @@ from pathlib import Path
import pytest
from pyparsing import line
from sanic_routing import __version__ as __routing_version__
from sanic import __version__
@@ -52,8 +53,10 @@ def test_server_run(appname):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
firstline = lines[starting_line(lines) + 1]
error_message = f"Lines found: {lines}\nErr output: {err}"
assert exitcode != 1
assert lines, error_message
assert firstline == b"Goin' Fast @ http://127.0.0.1:8000"
@@ -80,6 +83,9 @@ def test_tls_options(cmd):
out, err, exitcode = capture(command)
assert exitcode != 1
lines = out.split(b"\n")
error_message = f"Lines found: {lines}\nErr output: {err}"
assert lines, error_message
firstline = lines[starting_line(lines) + 1]
assert firstline == b"Goin' Fast @ https://127.0.0.1:9999"
@@ -102,7 +108,9 @@ def test_tls_wrong_options(cmd):
assert exitcode == 1
assert not out
lines = err.decode().split("\n")
error_message = f"Lines found: {lines}\nErr output: {err}"
assert lines, error_message
errmsg = lines[6]
assert errmsg == "TLS certificates must be specified by either of:"
@@ -119,9 +127,11 @@ def test_host_port_localhost(cmd):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
expected = b"Goin' Fast @ http://localhost:9999"
error_message = f"Lines found: {lines}\nErr output: {err}"
assert exitcode != 1
assert expected in lines, f"Lines found: {lines}\nErr output: {err}"
assert lines, error_message
assert expected in lines, error_message
@pytest.mark.parametrize(
@@ -136,9 +146,11 @@ def test_host_port_ipv4(cmd):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
expected = b"Goin' Fast @ http://127.0.0.127:9999"
error_message = f"Lines found: {lines}\nErr output: {err}"
assert exitcode != 1
assert expected in lines, f"Lines found: {lines}\nErr output: {err}"
assert lines, error_message
assert expected in lines, error_message
@pytest.mark.parametrize(
@@ -153,9 +165,11 @@ def test_host_port_ipv6_any(cmd):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
expected = b"Goin' Fast @ http://[::]:9999"
error_message = f"Lines found: {lines}\nErr output: {err}"
assert exitcode != 1
assert expected in lines, f"Lines found: {lines}\nErr output: {err}"
assert lines, error_message
assert expected in lines, error_message
@pytest.mark.parametrize(
@@ -170,9 +184,11 @@ def test_host_port_ipv6_loopback(cmd):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
expected = b"Goin' Fast @ http://[::1]:9999"
error_message = f"Lines found: {lines}\nErr output: {err}"
assert exitcode != 1
assert expected in lines, f"Lines found: {lines}\nErr output: {err}"
assert lines, error_message
assert expected in lines, error_message
@pytest.mark.parametrize(
@@ -206,12 +222,12 @@ def test_debug(cmd):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
info = read_app_info(lines)
error_message = f"Lines found: {lines}\nErr output: {err}"
assert info["debug"] is True, f"Lines found: {lines}\nErr output: {err}"
assert (
info["auto_reload"] is False
), f"Lines found: {lines}\nErr output: {err}"
assert "dev" not in info, f"Lines found: {lines}\nErr output: {err}"
assert info, error_message
assert info["debug"] is True, error_message
assert info["auto_reload"] is False, error_message
assert "dev" not in info, error_message
@pytest.mark.parametrize("cmd", ("--dev", "-d"))
@@ -220,11 +236,11 @@ def test_dev(cmd):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
info = read_app_info(lines)
error_message = f"Lines found: {lines}\nErr output: {err}"
assert info["debug"] is True, f"Lines found: {lines}\nErr output: {err}"
assert (
info["auto_reload"] is True
), f"Lines found: {lines}\nErr output: {err}"
assert info, error_message
assert info["debug"] is True, error_message
assert info["auto_reload"] is True, error_message
@pytest.mark.parametrize("cmd", ("--auto-reload", "-r"))
@@ -233,12 +249,12 @@ def test_auto_reload(cmd):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
info = read_app_info(lines)
error_message = f"Lines found: {lines}\nErr output: {err}"
assert info["debug"] is False, f"Lines found: {lines}\nErr output: {err}"
assert (
info["auto_reload"] is True
), f"Lines found: {lines}\nErr output: {err}"
assert "dev" not in info, f"Lines found: {lines}\nErr output: {err}"
assert info, error_message
assert info["debug"] is False, error_message
assert info["auto_reload"] is True, error_message
assert "dev" not in info, error_message
@pytest.mark.parametrize(
@@ -249,10 +265,10 @@ def test_access_logs(cmd, expected):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
info = read_app_info(lines)
error_message = f"Lines found: {lines}\nErr output: {err}"
assert (
info["access_log"] is expected
), f"Lines found: {lines}\nErr output: {err}"
assert info, error_message
assert info["access_log"] is expected, error_message
@pytest.mark.parametrize("cmd", ("--version", "-v"))
@@ -276,7 +292,7 @@ def test_noisy_exceptions(cmd, expected):
out, err, exitcode = capture(command)
lines = out.split(b"\n")
info = read_app_info(lines)
error_message = f"Lines found: {lines}\nErr output: {err}"
assert (
info["noisy_exceptions"] is expected
), f"Lines found: {lines}\nErr output: {err}"
assert info, error_message
assert info["noisy_exceptions"] is expected, error_message

View File

@@ -80,6 +80,18 @@ async def test_purge_tasks(app: Sanic):
assert len(app._task_registry) == 0
async def test_purge_tasks_with_create_task(app: Sanic):
app.add_task(asyncio.create_task(dummy(3)), name="dummy")
await app.cancel_task("dummy")
assert len(app._task_registry) == 1
app.purge_tasks()
assert len(app._task_registry) == 0
def test_shutdown_tasks_on_app_stop():
class TestSanic(Sanic):
shutdown_tasks = Mock()

View File

@@ -21,6 +21,7 @@ commands =
flake8 sanic
black --config ./.black.toml --check --verbose sanic/
isort --check-only sanic --profile=black
slotscheck --verbose -m sanic
[testenv:type-checking]
commands =