import re from typing import Any from sanic.base.meta import SanicMeta from sanic.exceptions import SanicException from sanic.mixins.commands import CommandMixin from sanic.mixins.exceptions import ExceptionMixin from sanic.mixins.listeners import ListenerMixin from sanic.mixins.middleware import MiddlewareMixin from sanic.mixins.routes import RouteMixin from sanic.mixins.signals import SignalMixin from sanic.mixins.static import StaticMixin VALID_NAME = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_\-]*$") class BaseSanic( RouteMixin, StaticMixin, MiddlewareMixin, ListenerMixin, ExceptionMixin, SignalMixin, CommandMixin, metaclass=SanicMeta, ): __slots__ = ("name",) def __init__( self, name: str | None = None, *args: Any, **kwargs: Any ) -> None: class_name = self.__class__.__name__ if name is None: raise SanicException( f"{class_name} instance cannot be unnamed. " "Please use Sanic(name='your_application_name') instead.", ) if not VALID_NAME.match(name): raise SanicException( f"{class_name} instance named '{name}' uses an invalid " "format. Names must begin with a character and may only " "contain alphanumeric characters, _, or -." ) self.name = name for base in BaseSanic.__bases__: base.__init__(self, *args, **kwargs) # type: ignore def __str__(self) -> str: return f"<{self.__class__.__name__} {self.name}>" def __repr__(self) -> str: return f'{self.__class__.__name__}(name="{self.name}")' def __setattr__(self, name: str, value: Any) -> None: try: super().__setattr__(name, value) except AttributeError as e: raise AttributeError( f"Setting variables on {self.__class__.__name__} instances is " "not allowed. You should change your " f"{self.__class__.__name__} instance to use " f"instance.ctx.{name} instead.", ) from e