22.3 Deprecations and changes (#2362)
This commit is contained in:
parent
8b0eaa097c
commit
8dfa49b648
|
@ -1061,6 +1061,7 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
|
||||||
host: Optional[str] = None,
|
host: Optional[str] = None,
|
||||||
port: Optional[int] = None,
|
port: Optional[int] = None,
|
||||||
*,
|
*,
|
||||||
|
dev: bool = False,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
auto_reload: Optional[bool] = None,
|
auto_reload: Optional[bool] = None,
|
||||||
ssl: Union[None, SSLContext, dict, str, list, tuple] = None,
|
ssl: Union[None, SSLContext, dict, str, list, tuple] = None,
|
||||||
|
@ -1143,9 +1144,11 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta):
|
||||||
"#asynchronous-support"
|
"#asynchronous-support"
|
||||||
)
|
)
|
||||||
|
|
||||||
if auto_reload or auto_reload is None and debug:
|
if dev:
|
||||||
|
debug = True
|
||||||
auto_reload = True
|
auto_reload = True
|
||||||
if os.environ.get("SANIC_SERVER_RUNNING") != "true":
|
|
||||||
|
if auto_reload and os.environ.get("SANIC_SERVER_RUNNING") != "true":
|
||||||
return reloader_helpers.watchdog(1.0, self)
|
return reloader_helpers.watchdog(1.0, self)
|
||||||
|
|
||||||
if sock is None:
|
if sock is None:
|
||||||
|
|
|
@ -79,13 +79,6 @@ Or, a path to a directory to run as a simple HTTP server:
|
||||||
error_logger.exception("Failed to run app")
|
error_logger.exception("Failed to run app")
|
||||||
|
|
||||||
def _precheck(self):
|
def _precheck(self):
|
||||||
if self.args.debug and self.main_process:
|
|
||||||
error_logger.warning(
|
|
||||||
"Starting in v22.3, --debug will no "
|
|
||||||
"longer automatically run the auto-reloader.\n Switch to "
|
|
||||||
"--dev to continue using that functionality."
|
|
||||||
)
|
|
||||||
|
|
||||||
# # Custom TLS mismatch handling for better diagnostics
|
# # Custom TLS mismatch handling for better diagnostics
|
||||||
if self.main_process and (
|
if self.main_process and (
|
||||||
# one of cert/key missing
|
# one of cert/key missing
|
||||||
|
@ -174,8 +167,9 @@ Or, a path to a directory to run as a simple HTTP server:
|
||||||
"workers": self.args.workers,
|
"workers": self.args.workers,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.args.auto_reload:
|
for maybe_arg in ("auto_reload", "dev"):
|
||||||
kwargs["auto_reload"] = True
|
if getattr(self.args, maybe_arg, False):
|
||||||
|
kwargs[maybe_arg] = True
|
||||||
|
|
||||||
if self.args.path:
|
if self.args.path:
|
||||||
if self.args.auto_reload or self.args.debug:
|
if self.args.auto_reload or self.args.debug:
|
||||||
|
|
|
@ -180,19 +180,18 @@ class DevelopmentGroup(Group):
|
||||||
"--debug",
|
"--debug",
|
||||||
dest="debug",
|
dest="debug",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Run the server in debug mode",
|
help=(
|
||||||
|
"Run the server in DEBUG mode. It includes DEBUG logging, "
|
||||||
|
"additional context on exceptions, and other settings "
|
||||||
|
"not-safe for PRODUCTION, but helpful for debugging problems."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.container.add_argument(
|
self.container.add_argument(
|
||||||
"-d",
|
"-d",
|
||||||
"--dev",
|
"--dev",
|
||||||
dest="debug",
|
dest="dev",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help=(
|
help=("Debug + auto_reload."),
|
||||||
"Currently is an alias for --debug. But starting in v22.3, \n"
|
|
||||||
"--debug will no longer automatically trigger auto_restart. \n"
|
|
||||||
"However, --dev will continue, effectively making it the \n"
|
|
||||||
"same as debug + auto_reload."
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
self.container.add_argument(
|
self.container.add_argument(
|
||||||
"-r",
|
"-r",
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from inspect import signature
|
|
||||||
from typing import Dict, List, Optional, Tuple, Type, Union
|
from typing import Dict, List, Optional, Tuple, Type, Union
|
||||||
|
|
||||||
from sanic.config import Config
|
from sanic.config import Config
|
||||||
from sanic.errorpages import (
|
from sanic.errorpages import (
|
||||||
DEFAULT_FORMAT,
|
DEFAULT_FORMAT,
|
||||||
BaseRenderer,
|
BaseRenderer,
|
||||||
HTMLRenderer,
|
TextRenderer,
|
||||||
exception_response,
|
exception_response,
|
||||||
)
|
)
|
||||||
from sanic.exceptions import (
|
from sanic.exceptions import (
|
||||||
|
@ -35,13 +34,11 @@ class ErrorHandler:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Beginning in v22.3, the base renderer will be TextRenderer
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
fallback: Union[str, Default] = _default,
|
fallback: Union[str, Default] = _default,
|
||||||
base: Type[BaseRenderer] = HTMLRenderer,
|
base: Type[BaseRenderer] = TextRenderer,
|
||||||
):
|
):
|
||||||
self.handlers: List[Tuple[Type[BaseException], RouteHandler]] = []
|
|
||||||
self.cached_handlers: Dict[
|
self.cached_handlers: Dict[
|
||||||
Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
|
Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
|
||||||
] = {}
|
] = {}
|
||||||
|
@ -95,8 +92,8 @@ class ErrorHandler:
|
||||||
def finalize(
|
def finalize(
|
||||||
cls,
|
cls,
|
||||||
error_handler: ErrorHandler,
|
error_handler: ErrorHandler,
|
||||||
|
config: Config,
|
||||||
fallback: Optional[str] = None,
|
fallback: Optional[str] = None,
|
||||||
config: Optional[Config] = None,
|
|
||||||
):
|
):
|
||||||
if fallback:
|
if fallback:
|
||||||
deprecation(
|
deprecation(
|
||||||
|
@ -107,14 +104,10 @@ class ErrorHandler:
|
||||||
22.6,
|
22.6,
|
||||||
)
|
)
|
||||||
|
|
||||||
if config is None:
|
if not fallback:
|
||||||
deprecation(
|
fallback = config.FALLBACK_ERROR_FORMAT
|
||||||
"Starting in v22.3, config will be a required argument "
|
|
||||||
"for ErrorHandler.finalize().",
|
|
||||||
22.3,
|
|
||||||
)
|
|
||||||
|
|
||||||
if fallback and fallback != DEFAULT_FORMAT:
|
if fallback != DEFAULT_FORMAT:
|
||||||
if error_handler._fallback is not _default:
|
if error_handler._fallback is not _default:
|
||||||
error_logger.warning(
|
error_logger.warning(
|
||||||
f"Setting the fallback value to {fallback}. This changes "
|
f"Setting the fallback value to {fallback}. This changes "
|
||||||
|
@ -128,27 +121,9 @@ class ErrorHandler:
|
||||||
f"Error handler is non-conforming: {type(error_handler)}"
|
f"Error handler is non-conforming: {type(error_handler)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
sig = signature(error_handler.lookup)
|
|
||||||
if len(sig.parameters) == 1:
|
|
||||||
deprecation(
|
|
||||||
"You are using a deprecated error handler. The lookup "
|
|
||||||
"method should accept two positional parameters: "
|
|
||||||
"(exception, route_name: Optional[str]). "
|
|
||||||
"Until you upgrade your ErrorHandler.lookup, Blueprint "
|
|
||||||
"specific exceptions will not work properly. Beginning "
|
|
||||||
"in v22.3, the legacy style lookup method will not "
|
|
||||||
"work at all.",
|
|
||||||
22.3,
|
|
||||||
)
|
|
||||||
legacy_lookup = error_handler._legacy_lookup
|
|
||||||
error_handler._lookup = legacy_lookup # type: ignore
|
|
||||||
|
|
||||||
def _full_lookup(self, exception, route_name: Optional[str] = None):
|
def _full_lookup(self, exception, route_name: Optional[str] = None):
|
||||||
return self.lookup(exception, route_name)
|
return self.lookup(exception, route_name)
|
||||||
|
|
||||||
def _legacy_lookup(self, exception, route_name: Optional[str] = None):
|
|
||||||
return self.lookup(exception)
|
|
||||||
|
|
||||||
def add(self, exception, handler, route_names: Optional[List[str]] = None):
|
def add(self, exception, handler, route_names: Optional[List[str]] = None):
|
||||||
"""
|
"""
|
||||||
Add a new exception handler to an already existing handler object.
|
Add a new exception handler to an already existing handler object.
|
||||||
|
@ -162,9 +137,6 @@ class ErrorHandler:
|
||||||
|
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
# self.handlers is deprecated and will be removed in version 22.3
|
|
||||||
self.handlers.append((exception, handler))
|
|
||||||
|
|
||||||
if route_names:
|
if route_names:
|
||||||
for route in route_names:
|
for route in route_names:
|
||||||
self.cached_handlers[(exception, route)] = handler
|
self.cached_handlers[(exception, route)] = handler
|
||||||
|
|
|
@ -5,7 +5,7 @@ from websockets.server import ServerConnection
|
||||||
from websockets.typing import Subprotocol
|
from websockets.typing import Subprotocol
|
||||||
|
|
||||||
from sanic.exceptions import ServerError
|
from sanic.exceptions import ServerError
|
||||||
from sanic.log import deprecation, error_logger
|
from sanic.log import error_logger
|
||||||
from sanic.server import HttpProtocol
|
from sanic.server import HttpProtocol
|
||||||
|
|
||||||
from ..websockets.impl import WebsocketImplProtocol
|
from ..websockets.impl import WebsocketImplProtocol
|
||||||
|
@ -29,9 +29,6 @@ class WebSocketProtocol(HttpProtocol):
|
||||||
*args,
|
*args,
|
||||||
websocket_timeout: float = 10.0,
|
websocket_timeout: float = 10.0,
|
||||||
websocket_max_size: Optional[int] = None,
|
websocket_max_size: Optional[int] = None,
|
||||||
websocket_max_queue: Optional[int] = None, # max_queue is deprecated
|
|
||||||
websocket_read_limit: Optional[int] = None, # read_limit is deprecated
|
|
||||||
websocket_write_limit: Optional[int] = None, # write_limit deprecated
|
|
||||||
websocket_ping_interval: Optional[float] = 20.0,
|
websocket_ping_interval: Optional[float] = 20.0,
|
||||||
websocket_ping_timeout: Optional[float] = 20.0,
|
websocket_ping_timeout: Optional[float] = 20.0,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
|
@ -40,27 +37,6 @@ class WebSocketProtocol(HttpProtocol):
|
||||||
self.websocket: Optional[WebsocketImplProtocol] = None
|
self.websocket: Optional[WebsocketImplProtocol] = None
|
||||||
self.websocket_timeout = websocket_timeout
|
self.websocket_timeout = websocket_timeout
|
||||||
self.websocket_max_size = websocket_max_size
|
self.websocket_max_size = websocket_max_size
|
||||||
if websocket_max_queue is not None and websocket_max_queue > 0:
|
|
||||||
# TODO: Reminder remove this warning in v22.3
|
|
||||||
deprecation(
|
|
||||||
"Websocket no longer uses queueing, so websocket_max_queue"
|
|
||||||
" is no longer required.",
|
|
||||||
22.3,
|
|
||||||
)
|
|
||||||
if websocket_read_limit is not None and websocket_read_limit > 0:
|
|
||||||
# TODO: Reminder remove this warning in v22.3
|
|
||||||
deprecation(
|
|
||||||
"Websocket no longer uses read buffers, so "
|
|
||||||
"websocket_read_limit is not required.",
|
|
||||||
22.3,
|
|
||||||
)
|
|
||||||
if websocket_write_limit is not None and websocket_write_limit > 0:
|
|
||||||
# TODO: Reminder remove this warning in v22.3
|
|
||||||
deprecation(
|
|
||||||
"Websocket no longer uses write buffers, so "
|
|
||||||
"websocket_write_limit is not required.",
|
|
||||||
22.3,
|
|
||||||
)
|
|
||||||
self.websocket_ping_interval = websocket_ping_interval
|
self.websocket_ping_interval = websocket_ping_interval
|
||||||
self.websocket_ping_timeout = websocket_ping_timeout
|
self.websocket_ping_timeout = websocket_ping_timeout
|
||||||
|
|
||||||
|
|
34
tests/asyncmock.py
Normal file
34
tests/asyncmock.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
"""
|
||||||
|
For 3.7 compat
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncMock(Mock):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.await_count = 0
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
self.call_count += 1
|
||||||
|
parent = super(AsyncMock, self)
|
||||||
|
|
||||||
|
async def dummy():
|
||||||
|
self.await_count += 1
|
||||||
|
return parent.__call__(*args, **kwargs)
|
||||||
|
|
||||||
|
return dummy()
|
||||||
|
|
||||||
|
def __await__(self):
|
||||||
|
return self().__await__()
|
||||||
|
|
||||||
|
def assert_awaited_once(self):
|
||||||
|
if not self.await_count == 1:
|
||||||
|
msg = (
|
||||||
|
f"Expected to have been awaited once."
|
||||||
|
f" Awaited {self.await_count} times."
|
||||||
|
)
|
||||||
|
raise AssertionError(msg)
|
|
@ -103,7 +103,7 @@ def test_tls_wrong_options(cmd):
|
||||||
assert not out
|
assert not out
|
||||||
lines = err.decode().split("\n")
|
lines = err.decode().split("\n")
|
||||||
|
|
||||||
errmsg = lines[8]
|
errmsg = lines[6]
|
||||||
assert errmsg == "TLS certificates must be specified by either of:"
|
assert errmsg == "TLS certificates must be specified by either of:"
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,13 +200,25 @@ def test_num_workers(num, cmd):
|
||||||
assert len(worker_lines) == num * 2, f"Lines found: {lines}"
|
assert len(worker_lines) == num * 2, f"Lines found: {lines}"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("cmd", ("--debug", "-d"))
|
@pytest.mark.parametrize("cmd", ("--debug",))
|
||||||
def test_debug(cmd):
|
def test_debug(cmd):
|
||||||
command = ["sanic", "fake.server.app", cmd]
|
command = ["sanic", "fake.server.app", cmd]
|
||||||
out, err, exitcode = capture(command)
|
out, err, exitcode = capture(command)
|
||||||
lines = out.split(b"\n")
|
lines = out.split(b"\n")
|
||||||
info = read_app_info(lines)
|
info = read_app_info(lines)
|
||||||
|
|
||||||
|
assert info["debug"] is True
|
||||||
|
assert info["auto_reload"] is False
|
||||||
|
assert "dev" not in info
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("cmd", ("--dev", "-d"))
|
||||||
|
def test_dev(cmd):
|
||||||
|
command = ["sanic", "fake.server.app", cmd]
|
||||||
|
out, err, exitcode = capture(command)
|
||||||
|
lines = out.split(b"\n")
|
||||||
|
info = read_app_info(lines)
|
||||||
|
|
||||||
assert info["debug"] is True
|
assert info["debug"] is True
|
||||||
assert info["auto_reload"] is True
|
assert info["auto_reload"] is True
|
||||||
|
|
||||||
|
@ -220,6 +232,7 @@ def test_auto_reload(cmd):
|
||||||
|
|
||||||
assert info["debug"] is False
|
assert info["debug"] is False
|
||||||
assert info["auto_reload"] is True
|
assert info["auto_reload"] is True
|
||||||
|
assert "dev" not in info
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
|
@ -67,7 +67,7 @@ def test_auto_fallback_with_data(app):
|
||||||
|
|
||||||
_, response = app.test_client.get("/error")
|
_, response = app.test_client.get("/error")
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
|
|
||||||
_, response = app.test_client.post("/error", json={"foo": "bar"})
|
_, response = app.test_client.post("/error", json={"foo": "bar"})
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
|
@ -75,7 +75,7 @@ def test_auto_fallback_with_data(app):
|
||||||
|
|
||||||
_, response = app.test_client.post("/error", data={"foo": "bar"})
|
_, response = app.test_client.post("/error", data={"foo": "bar"})
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
|
|
||||||
|
|
||||||
def test_auto_fallback_with_content_type(app):
|
def test_auto_fallback_with_content_type(app):
|
||||||
|
@ -91,7 +91,7 @@ def test_auto_fallback_with_content_type(app):
|
||||||
"/error", headers={"content-type": "foo/bar", "accept": "*/*"}
|
"/error", headers={"content-type": "foo/bar", "accept": "*/*"}
|
||||||
)
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
|
|
||||||
|
|
||||||
def test_route_error_format_set_on_auto(app):
|
def test_route_error_format_set_on_auto(app):
|
||||||
|
@ -174,6 +174,17 @@ def test_route_error_format_unknown(app):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def test_fallback_with_content_type_html(app):
|
||||||
|
app.config.FALLBACK_ERROR_FORMAT = "auto"
|
||||||
|
|
||||||
|
_, response = app.test_client.get(
|
||||||
|
"/error",
|
||||||
|
headers={"content-type": "application/json", "accept": "text/html"},
|
||||||
|
)
|
||||||
|
assert response.status == 500
|
||||||
|
assert response.content_type == "text/html; charset=utf-8"
|
||||||
|
|
||||||
|
|
||||||
def test_fallback_with_content_type_mismatch_accept(app):
|
def test_fallback_with_content_type_mismatch_accept(app):
|
||||||
app.config.FALLBACK_ERROR_FORMAT = "auto"
|
app.config.FALLBACK_ERROR_FORMAT = "auto"
|
||||||
|
|
||||||
|
@ -186,10 +197,10 @@ def test_fallback_with_content_type_mismatch_accept(app):
|
||||||
|
|
||||||
_, response = app.test_client.get(
|
_, response = app.test_client.get(
|
||||||
"/error",
|
"/error",
|
||||||
headers={"content-type": "text/plain", "accept": "foo/bar"},
|
headers={"content-type": "text/html", "accept": "foo/bar"},
|
||||||
)
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
|
|
||||||
app.router.reset()
|
app.router.reset()
|
||||||
|
|
||||||
|
@ -208,7 +219,7 @@ def test_fallback_with_content_type_mismatch_accept(app):
|
||||||
headers={"accept": "foo/bar"},
|
headers={"accept": "foo/bar"},
|
||||||
)
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
_, response = app.test_client.get(
|
_, response = app.test_client.get(
|
||||||
"/alt1",
|
"/alt1",
|
||||||
headers={"accept": "foo/bar,*/*"},
|
headers={"accept": "foo/bar,*/*"},
|
||||||
|
@ -221,7 +232,7 @@ def test_fallback_with_content_type_mismatch_accept(app):
|
||||||
headers={"accept": "foo/bar"},
|
headers={"accept": "foo/bar"},
|
||||||
)
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
_, response = app.test_client.get(
|
_, response = app.test_client.get(
|
||||||
"/alt2",
|
"/alt2",
|
||||||
headers={"accept": "foo/bar,*/*"},
|
headers={"accept": "foo/bar,*/*"},
|
||||||
|
@ -234,6 +245,13 @@ def test_fallback_with_content_type_mismatch_accept(app):
|
||||||
headers={"accept": "foo/bar"},
|
headers={"accept": "foo/bar"},
|
||||||
)
|
)
|
||||||
assert response.status == 500
|
assert response.status == 500
|
||||||
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
|
|
||||||
|
_, response = app.test_client.get(
|
||||||
|
"/alt3",
|
||||||
|
headers={"accept": "foo/bar,text/html"},
|
||||||
|
)
|
||||||
|
assert response.status == 500
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/html; charset=utf-8"
|
||||||
|
|
||||||
|
|
||||||
|
@ -288,6 +306,10 @@ def test_allow_fallback_error_format_set_main_process_start(app):
|
||||||
def test_setting_fallback_on_config_changes_as_expected(app):
|
def test_setting_fallback_on_config_changes_as_expected(app):
|
||||||
app.error_handler = ErrorHandler()
|
app.error_handler = ErrorHandler()
|
||||||
|
|
||||||
|
_, response = app.test_client.get("/error")
|
||||||
|
assert response.content_type == "text/plain; charset=utf-8"
|
||||||
|
|
||||||
|
app.config.FALLBACK_ERROR_FORMAT = "html"
|
||||||
_, response = app.test_client.get("/error")
|
_, response = app.test_client.get("/error")
|
||||||
assert response.content_type == "text/html; charset=utf-8"
|
assert response.content_type == "text/html; charset=utf-8"
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ class SanicExceptionTestException(Exception):
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def exception_app():
|
def exception_app():
|
||||||
app = Sanic("test_exceptions")
|
app = Sanic("test_exceptions")
|
||||||
|
app.config.FALLBACK_ERROR_FORMAT = "html"
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
|
|
|
@ -216,31 +216,6 @@ def test_exception_handler_processed_request_middleware(
|
||||||
assert response.text == "Done."
|
assert response.text == "Done."
|
||||||
|
|
||||||
|
|
||||||
def test_single_arg_exception_handler_notice(
|
|
||||||
exception_handler_app: Sanic, caplog: LogCaptureFixture
|
|
||||||
):
|
|
||||||
class CustomErrorHandler(ErrorHandler):
|
|
||||||
def lookup(self, exception):
|
|
||||||
return super().lookup(exception, None)
|
|
||||||
|
|
||||||
exception_handler_app.error_handler = CustomErrorHandler()
|
|
||||||
|
|
||||||
message = (
|
|
||||||
"[DEPRECATION v22.3] You are using a deprecated error handler. The "
|
|
||||||
"lookup method should accept two positional parameters: (exception, "
|
|
||||||
"route_name: Optional[str]). Until you upgrade your "
|
|
||||||
"ErrorHandler.lookup, Blueprint specific exceptions will not work "
|
|
||||||
"properly. Beginning in v22.3, the legacy style lookup method will "
|
|
||||||
"not work at all."
|
|
||||||
)
|
|
||||||
with pytest.warns(DeprecationWarning) as record:
|
|
||||||
_, response = exception_handler_app.test_client.get("/1")
|
|
||||||
|
|
||||||
assert len(record) == 1
|
|
||||||
assert record[0].message.args[0] == message
|
|
||||||
assert response.status == 400
|
|
||||||
|
|
||||||
|
|
||||||
def test_error_handler_noisy_log(
|
def test_error_handler_noisy_log(
|
||||||
exception_handler_app: Sanic, monkeypatch: MonkeyPatch
|
exception_handler_app: Sanic, monkeypatch: MonkeyPatch
|
||||||
):
|
):
|
||||||
|
@ -279,7 +254,7 @@ def test_exception_handler_response_was_sent(
|
||||||
|
|
||||||
@app.route("/2")
|
@app.route("/2")
|
||||||
async def handler2(request: Request):
|
async def handler2(request: Request):
|
||||||
response = await request.respond()
|
await request.respond()
|
||||||
raise ServerError("Exception")
|
raise ServerError("Exception")
|
||||||
|
|
||||||
with caplog.at_level(logging.WARNING):
|
with caplog.at_level(logging.WARNING):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from asyncio import Event, Queue, TimeoutError
|
from asyncio import Event, Queue, TimeoutError
|
||||||
from unittest.mock import AsyncMock, Mock, call
|
from unittest.mock import Mock, call
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -11,6 +11,12 @@ from sanic.exceptions import ServerError
|
||||||
from sanic.server.websockets.frame import WebsocketFrameAssembler
|
from sanic.server.websockets.frame import WebsocketFrameAssembler
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
except ImportError:
|
||||||
|
from asyncmock import AsyncMock # type: ignore
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_ws_frame_get_message_incomplete_timeout_0():
|
async def test_ws_frame_get_message_incomplete_timeout_0():
|
||||||
assembler = WebsocketFrameAssembler(Mock())
|
assembler = WebsocketFrameAssembler(Mock())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user