Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config option to skip Touchup step, for debugging purposes #2361

Merged
merged 9 commits into from Mar 24, 2022
11 changes: 8 additions & 3 deletions sanic/app.py
Expand Up @@ -1510,7 +1510,8 @@ def finalize(self):
if not Sanic.test_mode:
raise e

def signalize(self):
def signalize(self, allow_fail_builtin=True):
self.signal_router.allow_fail_builtin = allow_fail_builtin
try:
self.signal_router.finalize()
except FinalizationError as e:
Expand All @@ -1525,8 +1526,11 @@ async def _startup(self):
if hasattr(self, "_ext"):
self.ext._display()

if self.state.is_debug:
self.config.TOUCHUP = False

# Setup routers
self.signalize()
self.signalize(self.config.TOUCHUP)
self.finalize()

# TODO: Replace in v22.6 to check against apps in app registry
Expand All @@ -1546,7 +1550,8 @@ async def _startup(self):
# TODO:
# - Raise warning if secondary apps have error handler config
ErrorHandler.finalize(self.error_handler, config=self.config)
TouchUp.run(self)
if self.config.TOUCHUP:
TouchUp.run(self)

self.state.is_started = True

Expand Down
2 changes: 2 additions & 0 deletions sanic/config.py
Expand Up @@ -38,6 +38,7 @@
"REQUEST_MAX_SIZE": 100000000, # 100 megabytes
"REQUEST_TIMEOUT": 60, # 60 seconds
"RESPONSE_TIMEOUT": 60, # 60 seconds
"TOUCHUP": True,
"USE_UVLOOP": _default,
"WEBSOCKET_MAX_SIZE": 2 ** 20, # 1 megabyte
"WEBSOCKET_PING_INTERVAL": 20,
Expand Down Expand Up @@ -81,6 +82,7 @@ class Config(dict, metaclass=DescriptorMeta):
REQUEST_TIMEOUT: int
RESPONSE_TIMEOUT: int
SERVER_NAME: str
TOUCHUP: bool
USE_UVLOOP: Union[Default, bool]
WEBSOCKET_MAX_SIZE: int
WEBSOCKET_PING_INTERVAL: int
Expand Down
4 changes: 3 additions & 1 deletion sanic/signals.py
Expand Up @@ -80,6 +80,7 @@ def __init__(self) -> None:
group_class=SignalGroup,
stacking=True,
)
self.allow_fail_builtin = True
self.ctx.loop = None

def get( # type: ignore
Expand Down Expand Up @@ -129,7 +130,8 @@ async def _dispatch(
try:
group, handlers, params = self.get(event, condition=condition)
except NotFound as e:
if fail_not_found:
is_reserved = event.split(".", 1)[0] in RESERVED_NAMESPACES
if fail_not_found and (not is_reserved or self.allow_fail_builtin):
raise e
else:
if self.ctx.app.debug and self.ctx.app.state.verbosity >= 1:
Expand Down
48 changes: 48 additions & 0 deletions tests/test_touchup.py
Expand Up @@ -2,6 +2,8 @@

import pytest

from sanic_routing.exceptions import NotFound

from sanic.signals import RESERVED_NAMESPACES
from sanic.touchup import TouchUp

Expand All @@ -28,3 +30,49 @@ async def test_ode_removes_dispatch_events(app, caplog, verbosity, result):
)
in logs
) is result


@pytest.mark.parametrize("skip_it,result", ((False, True), (True, False)))
async def test_skip_touchup(app, caplog, skip_it, result):
app.config.TOUCHUP = (not skip_it)
with caplog.at_level(logging.DEBUG, logger="sanic.root"):
app.state.verbosity = 2
await app._startup()
assert app.signal_router.allow_fail_builtin is (not skip_it)
logs = caplog.record_tuples

for signal in RESERVED_NAMESPACES["http"]:
assert (
(
"sanic.root",
logging.DEBUG,
f"Disabling event: {signal}",
)
in logs
) is result
not_found_exceptions = 0
# Skip-touchup disables NotFound exceptions on the dispatcher
for signal in RESERVED_NAMESPACES["http"]:
try:
await app.dispatch(event=signal, inline=True)
except NotFound:
not_found_exceptions += 1
assert (not_found_exceptions > 0) is result


@pytest.mark.parametrize("skip_it,result", ((False, True), (True, True)))
async def test_skip_touchup_non_reserved(app, caplog, skip_it, result):
app.config.SKIP_TOUCHUP = skip_it

@app.signal("foo.bar.one")
def sync_signal(*_):
...
await app._startup()
assert app.signal_router.allow_fail_builtin is (not skip_it)
not_found_exception = False
# Skip-touchup doesn't disable NotFound exceptions for user-defined signals
try:
await app.dispatch(event="foo.baz.two", inline=True)
except NotFound:
not_found_exception = True
assert not_found_exception is result