From 6763e2bb0a390825e463abde6669631b9549ed01 Mon Sep 17 00:00:00 2001 From: Arthur Goldberg Date: Sun, 21 Mar 2021 09:09:31 +0100 Subject: [PATCH] fix?: recursion error on Sanic subclass initialisation (#2072) * fix?: recursion error on Sanic subclass init * tests: add test case for sanic subclass initialisation * Remove BaseSanic metaclass Co-authored-by: Adam Hopkins --- sanic/base.py | 27 ++++----------------------- sanic/blueprints.py | 1 + tests/test_app.py | 7 +++++++ 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/sanic/base.py b/sanic/base.py index 51706149..368288c4 100644 --- a/sanic/base.py +++ b/sanic/base.py @@ -8,38 +8,19 @@ from sanic.mixins.routes import RouteMixin from sanic.mixins.signals import SignalMixin -class Base(type): - def __new__(cls, name, bases, attrs): - init = attrs.get("__init__") - - def __init__(self, *args, **kwargs): - nonlocal init - nonlocal name - - bases = [ - b for base in type(self).__bases__ for b in base.__bases__ - ] - - for base in bases: - base.__init__(self, *args, **kwargs) - - if init: - init(self, *args, **kwargs) - - attrs["__init__"] = __init__ - return type.__new__(cls, name, bases, attrs) - - class BaseSanic( RouteMixin, MiddlewareMixin, ListenerMixin, ExceptionMixin, SignalMixin, - metaclass=Base, ): __fake_slots__: Tuple[str, ...] + def __init__(self, *args, **kwargs) -> None: + for base in BaseSanic.__bases__: + base.__init__(self, *args, **kwargs) # type: ignore + def __str__(self) -> str: return f"<{self.__class__.__name__} {self.name}>" diff --git a/sanic/blueprints.py b/sanic/blueprints.py index f8b0323c..85b60ddc 100644 --- a/sanic/blueprints.py +++ b/sanic/blueprints.py @@ -73,6 +73,7 @@ class Blueprint(BaseSanic): version: Optional[int] = None, strict_slashes: Optional[bool] = None, ): + super().__init__() self._apps: Set[Sanic] = set() self.ctx = SimpleNamespace() diff --git a/tests/test_app.py b/tests/test_app.py index bfe7900c..f096496a 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -405,3 +405,10 @@ def test_app_set_context(app): retrieved = Sanic.get_app(app.name) assert retrieved.ctx.foo == 1 + + +def test_subclass_initialisation(): + class CustomSanic(Sanic): + pass + + CustomSanic("test_subclass_initialisation")