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 <admhpkns@gmail.com>
This commit is contained in:
Arthur Goldberg 2021-03-21 09:09:31 +01:00 committed by GitHub
parent 15a8b5c894
commit 6763e2bb0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 12 additions and 23 deletions

View File

@ -8,38 +8,19 @@ from sanic.mixins.routes import RouteMixin
from sanic.mixins.signals import SignalMixin 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( class BaseSanic(
RouteMixin, RouteMixin,
MiddlewareMixin, MiddlewareMixin,
ListenerMixin, ListenerMixin,
ExceptionMixin, ExceptionMixin,
SignalMixin, SignalMixin,
metaclass=Base,
): ):
__fake_slots__: Tuple[str, ...] __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: def __str__(self) -> str:
return f"<{self.__class__.__name__} {self.name}>" return f"<{self.__class__.__name__} {self.name}>"

View File

@ -73,6 +73,7 @@ class Blueprint(BaseSanic):
version: Optional[int] = None, version: Optional[int] = None,
strict_slashes: Optional[bool] = None, strict_slashes: Optional[bool] = None,
): ):
super().__init__()
self._apps: Set[Sanic] = set() self._apps: Set[Sanic] = set()
self.ctx = SimpleNamespace() self.ctx = SimpleNamespace()

View File

@ -405,3 +405,10 @@ def test_app_set_context(app):
retrieved = Sanic.get_app(app.name) retrieved = Sanic.get_app(app.name)
assert retrieved.ctx.foo == 1 assert retrieved.ctx.foo == 1
def test_subclass_initialisation():
class CustomSanic(Sanic):
pass
CustomSanic("test_subclass_initialisation")