We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
RecursionError on Sanic subclass initialisation
Discovered at https://github.com/sanic-org/sanic/issues/2071

version: latest sanic master (`8a2ea626c6d04a5eb1e28d071ffa56bf9ad98a12`)

description:

RecursionError occurs when initialising Sanic subclass

minimal code to reproduce:

```python
from sanic import Sanic


class Custom(Sanic):
    pass

custom = Custom("custom")
```


Potential fix: https://github.com/sanic-org/sanic/pull/2072

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sanic/blueprints.py`
Content:
```
1 from __future__ import annotations
2 
3 import asyncio
4 
5 from collections import defaultdict
6 from types import SimpleNamespace
7 from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Union
8 
9 from sanic_routing.exceptions import NotFound  # type: ignore
10 from sanic_routing.route import Route  # type: ignore
11 
12 from sanic.base import BaseSanic
13 from sanic.blueprint_group import BlueprintGroup
14 from sanic.exceptions import SanicException
15 from sanic.models.futures import FutureRoute, FutureStatic
16 from sanic.models.handler_types import (
17     ListenerType,
18     MiddlewareType,
19     RouteHandler,
20 )
21 
22 
23 if TYPE_CHECKING:
24     from sanic import Sanic  # noqa
25 
26 
27 class Blueprint(BaseSanic):
28     """
29     In *Sanic* terminology, a **Blueprint** is a logical collection of
30     URLs that perform a specific set of tasks which can be identified by
31     a unique name.
32 
33     It is the main tool for grouping functionality and similar endpoints.
34 
35     `See user guide re: blueprints
36     <https://sanicframework.org/guide/best-practices/blueprints.html>`__
37 
38     :param name: unique name of the blueprint
39     :param url_prefix: URL to be prefixed before all route URLs
40     :param host: IP Address of FQDN for the sanic server to use.
41     :param version: Blueprint Version
42     :param strict_slashes: Enforce the API urls are requested with a
43         training */*
44     """
45 
46     __fake_slots__ = (
47         "_apps",
48         "_future_routes",
49         "_future_statics",
50         "_future_middleware",
51         "_future_listeners",
52         "_future_exceptions",
53         "_future_signals",
54         "ctx",
55         "exceptions",
56         "host",
57         "listeners",
58         "middlewares",
59         "name",
60         "routes",
61         "statics",
62         "strict_slashes",
63         "url_prefix",
64         "version",
65         "websocket_routes",
66     )
67 
68     def __init__(
69         self,
70         name: str,
71         url_prefix: Optional[str] = None,
72         host: Optional[str] = None,
73         version: Optional[int] = None,
74         strict_slashes: Optional[bool] = None,
75     ):
76 
77         self._apps: Set[Sanic] = set()
78         self.ctx = SimpleNamespace()
79         self.exceptions: List[RouteHandler] = []
80         self.host = host
81         self.listeners: Dict[str, List[ListenerType]] = {}
82         self.middlewares: List[MiddlewareType] = []
83         self.name = name
84         self.routes: List[Route] = []
85         self.statics: List[RouteHandler] = []
86         self.strict_slashes = strict_slashes
87         self.url_prefix = url_prefix
88         self.version = version
89         self.websocket_routes: List[Route] = []
90 
91     def __repr__(self) -> str:
92         args = ", ".join(
93             [
94                 f'{attr}="{getattr(self, attr)}"'
95                 if isinstance(getattr(self, attr), str)
96                 else f"{attr}={getattr(self, attr)}"
97                 for attr in (
98                     "name",
99                     "url_prefix",
100                     "host",
101                     "version",
102                     "strict_slashes",
103                 )
104             ]
105         )
106         return f"Blueprint({args})"
107 
108     @property
109     def apps(self):
110         if not self._apps:
111             raise SanicException(
112                 f"{self} has not yet been registered to an app"
113             )
114         return self._apps
115 
116     def route(self, *args, **kwargs):
117         kwargs["apply"] = False
118         return super().route(*args, **kwargs)
119 
120     def static(self, *args, **kwargs):
121         kwargs["apply"] = False
122         return super().static(*args, **kwargs)
123 
124     def middleware(self, *args, **kwargs):
125         kwargs["apply"] = False
126         return super().middleware(*args, **kwargs)
127 
128     def listener(self, *args, **kwargs):
129         kwargs["apply"] = False
130         return super().listener(*args, **kwargs)
131 
132     def exception(self, *args, **kwargs):
133         kwargs["apply"] = False
134         return super().exception(*args, **kwargs)
135 
136     def signal(self, event: str, *args, **kwargs):
137         kwargs["apply"] = False
138         return super().signal(event, *args, **kwargs)
139 
140     @staticmethod
141     def group(*blueprints, url_prefix="", version=None, strict_slashes=None):
142         """
143         Create a list of blueprints, optionally grouping them under a
144         general URL prefix.
145 
146         :param blueprints: blueprints to be registered as a group
147         :param url_prefix: URL route to be prepended to all sub-prefixes
148         :param version: API Version to be used for Blueprint group
149         :param strict_slashes: Indicate strict slash termination behavior
150             for URL
151         """
152 
153         def chain(nested) -> Iterable[Blueprint]:
154             """itertools.chain() but leaves strings untouched"""
155             for i in nested:
156                 if isinstance(i, (list, tuple)):
157                     yield from chain(i)
158                 elif isinstance(i, BlueprintGroup):
159                     yield from i.blueprints
160                 else:
161                     yield i
162 
163         bps = BlueprintGroup(
164             url_prefix=url_prefix,
165             version=version,
166             strict_slashes=strict_slashes,
167         )
168         for bp in chain(blueprints):
169             bps.append(bp)
170         return bps
171 
172     def register(self, app, options):
173         """
174         Register the blueprint to the sanic app.
175 
176         :param app: Instance of :class:`sanic.app.Sanic` class
177         :param options: Options to be used while registering the
178             blueprint into the app.
179             *url_prefix* - URL Prefix to override the blueprint prefix
180         """
181 
182         self._apps.add(app)
183         url_prefix = options.get("url_prefix", self.url_prefix)
184 
185         routes = []
186         middleware = []
187         exception_handlers = []
188         listeners = defaultdict(list)
189 
190         # Routes
191         for future in self._future_routes:
192             # attach the blueprint name to the handler so that it can be
193             # prefixed properly in the router
194             future.handler.__blueprintname__ = self.name
195             # Prepend the blueprint URI prefix if available
196             uri = url_prefix + future.uri if url_prefix else future.uri
197 
198             strict_slashes = (
199                 self.strict_slashes
200                 if future.strict_slashes is None
201                 and self.strict_slashes is not None
202                 else future.strict_slashes
203             )
204             name = app._generate_name(future.name)
205 
206             apply_route = FutureRoute(
207                 future.handler,
208                 uri[1:] if uri.startswith("//") else uri,
209                 future.methods,
210                 future.host or self.host,
211                 strict_slashes,
212                 future.stream,
213                 future.version or self.version,
214                 name,
215                 future.ignore_body,
216                 future.websocket,
217                 future.subprotocols,
218                 future.unquote,
219                 future.static,
220             )
221 
222             route = app._apply_route(apply_route)
223             operation = (
224                 routes.extend if isinstance(route, list) else routes.append
225             )
226             operation(route)
227 
228         # Static Files
229         for future in self._future_statics:
230             # Prepend the blueprint URI prefix if available
231             uri = url_prefix + future.uri if url_prefix else future.uri
232             apply_route = FutureStatic(uri, *future[1:])
233             route = app._apply_static(apply_route)
234             routes.append(route)
235 
236         route_names = [route.name for route in routes if route]
237 
238         # Middleware
239         if route_names:
240             for future in self._future_middleware:
241                 middleware.append(app._apply_middleware(future, route_names))
242 
243         # Exceptions
244         for future in self._future_exceptions:
245             exception_handlers.append(app._apply_exception_handler(future))
246 
247         # Event listeners
248         for listener in self._future_listeners:
249             listeners[listener.event].append(app._apply_listener(listener))
250 
251         for signal in self._future_signals:
252             signal.condition.update({"blueprint": self.name})
253             app._apply_signal(signal)
254 
255         self.routes = [route for route in routes if isinstance(route, Route)]
256 
257         # Deprecate these in 21.6
258         self.websocket_routes = [
259             route for route in self.routes if route.ctx.websocket
260         ]
261         self.middlewares = middleware
262         self.exceptions = exception_handlers
263         self.listeners = dict(listeners)
264 
265     async def dispatch(self, *args, **kwargs):
266         condition = kwargs.pop("condition", {})
267         condition.update({"blueprint": self.name})
268         kwargs["condition"] = condition
269         await asyncio.gather(
270             *[app.dispatch(*args, **kwargs) for app in self.apps]
271         )
272 
273     def event(self, event: str, timeout: Optional[Union[int, float]] = None):
274         events = set()
275         for app in self.apps:
276             signal = app.signal_router.name_index.get(event)
277             if not signal:
278                 raise NotFound("Could not find signal %s" % event)
279             events.add(signal.ctx.event)
280 
281         return asyncio.wait(
282             [event.wait() for event in events],
283             return_when=asyncio.FIRST_COMPLETED,
284             timeout=timeout,
285         )
286
```

Path: `sanic/base.py`
Content:
```
1 from typing import Any, Tuple
2 from warnings import warn
3 
4 from sanic.mixins.exceptions import ExceptionMixin
5 from sanic.mixins.listeners import ListenerMixin
6 from sanic.mixins.middleware import MiddlewareMixin
7 from sanic.mixins.routes import RouteMixin
8 from sanic.mixins.signals import SignalMixin
9 
10 
11 class Base(type):
12     def __new__(cls, name, bases, attrs):
13         init = attrs.get("__init__")
14 
15         def __init__(self, *args, **kwargs):
16             nonlocal init
17             nonlocal name
18 
19             bases = [
20                 b for base in type(self).__bases__ for b in base.__bases__
21             ]
22 
23             for base in bases:
24                 base.__init__(self, *args, **kwargs)
25 
26             if init:
27                 init(self, *args, **kwargs)
28 
29         attrs["__init__"] = __init__
30         return type.__new__(cls, name, bases, attrs)
31 
32 
33 class BaseSanic(
34     RouteMixin,
35     MiddlewareMixin,
36     ListenerMixin,
37     ExceptionMixin,
38     SignalMixin,
39     metaclass=Base,
40 ):
41     __fake_slots__: Tuple[str, ...]
42 
43     def __str__(self) -> str:
44         return f"<{self.__class__.__name__} {self.name}>"
45 
46     def __repr__(self) -> str:
47         return f'{self.__class__.__name__}(name="{self.name}")'
48 
49     def __setattr__(self, name: str, value: Any) -> None:
50         # This is a temporary compat layer so we can raise a warning until
51         # setting attributes on the app instance can be removed and deprecated
52         # with a proper implementation of __slots__
53         if name not in self.__fake_slots__:
54             warn(
55                 f"Setting variables on {self.__class__.__name__} instances is "
56                 "deprecated and will be removed in version 21.9. You should "
57                 f"change your {self.__class__.__name__} instance to use "
58                 f"instance.ctx.{name} instead."
59             )
60         super().__setattr__(name, value)
61
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sanic/base.py b/sanic/base.py
--- a/sanic/base.py
+++ b/sanic/base.py
@@ -8,38 +8,19 @@
 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
--- a/sanic/blueprints.py
+++ b/sanic/blueprints.py
@@ -73,6 +73,7 @@
         version: Optional[int] = None,
         strict_slashes: Optional[bool] = None,
     ):
+        super().__init__()
 
         self._apps: Set[Sanic] = set()
         self.ctx = SimpleNamespace()

{"golden_diff": "diff --git a/sanic/base.py b/sanic/base.py\n--- a/sanic/base.py\n+++ b/sanic/base.py\n@@ -8,38 +8,19 @@\n from sanic.mixins.signals import SignalMixin\n \n \n-class Base(type):\n-    def __new__(cls, name, bases, attrs):\n-        init = attrs.get(\"__init__\")\n-\n-        def __init__(self, *args, **kwargs):\n-            nonlocal init\n-            nonlocal name\n-\n-            bases = [\n-                b for base in type(self).__bases__ for b in base.__bases__\n-            ]\n-\n-            for base in bases:\n-                base.__init__(self, *args, **kwargs)\n-\n-            if init:\n-                init(self, *args, **kwargs)\n-\n-        attrs[\"__init__\"] = __init__\n-        return type.__new__(cls, name, bases, attrs)\n-\n-\n class BaseSanic(\n     RouteMixin,\n     MiddlewareMixin,\n     ListenerMixin,\n     ExceptionMixin,\n     SignalMixin,\n-    metaclass=Base,\n ):\n     __fake_slots__: Tuple[str, ...]\n \n+    def __init__(self, *args, **kwargs) -> None:\n+        for base in BaseSanic.__bases__:\n+            base.__init__(self, *args, **kwargs)  # type: ignore\n+\n     def __str__(self) -> str:\n         return f\"<{self.__class__.__name__} {self.name}>\"\n \ndiff --git a/sanic/blueprints.py b/sanic/blueprints.py\n--- a/sanic/blueprints.py\n+++ b/sanic/blueprints.py\n@@ -73,6 +73,7 @@\n         version: Optional[int] = None,\n         strict_slashes: Optional[bool] = None,\n     ):\n+        super().__init__()\n \n         self._apps: Set[Sanic] = set()\n         self.ctx = SimpleNamespace()\n", "issue": "RecursionError on Sanic subclass initialisation\nDiscovered at https://github.com/sanic-org/sanic/issues/2071\r\n\r\nversion: latest sanic master (`8a2ea626c6d04a5eb1e28d071ffa56bf9ad98a12`)\r\n\r\ndescription:\r\n\r\nRecursionError occurs when initialising Sanic subclass\r\n\r\nminimal code to reproduce:\r\n\r\n```python\r\nfrom sanic import Sanic\r\n\r\n\r\nclass Custom(Sanic):\r\n    pass\r\n\r\ncustom = Custom(\"custom\")\r\n```\r\n\r\n\r\nPotential fix: https://github.com/sanic-org/sanic/pull/2072\n", "before_files": [{"content": "from __future__ import annotations\n\nimport asyncio\n\nfrom collections import defaultdict\nfrom types import SimpleNamespace\nfrom typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Union\n\nfrom sanic_routing.exceptions import NotFound  # type: ignore\nfrom sanic_routing.route import Route  # type: ignore\n\nfrom sanic.base import BaseSanic\nfrom sanic.blueprint_group import BlueprintGroup\nfrom sanic.exceptions import SanicException\nfrom sanic.models.futures import FutureRoute, FutureStatic\nfrom sanic.models.handler_types import (\n    ListenerType,\n    MiddlewareType,\n    RouteHandler,\n)\n\n\nif TYPE_CHECKING:\n    from sanic import Sanic  # noqa\n\n\nclass Blueprint(BaseSanic):\n    \"\"\"\n    In *Sanic* terminology, a **Blueprint** is a logical collection of\n    URLs that perform a specific set of tasks which can be identified by\n    a unique name.\n\n    It is the main tool for grouping functionality and similar endpoints.\n\n    `See user guide re: blueprints\n    <https://sanicframework.org/guide/best-practices/blueprints.html>`__\n\n    :param name: unique name of the blueprint\n    :param url_prefix: URL to be prefixed before all route URLs\n    :param host: IP Address of FQDN for the sanic server to use.\n    :param version: Blueprint Version\n    :param strict_slashes: Enforce the API urls are requested with a\n        training */*\n    \"\"\"\n\n    __fake_slots__ = (\n        \"_apps\",\n        \"_future_routes\",\n        \"_future_statics\",\n        \"_future_middleware\",\n        \"_future_listeners\",\n        \"_future_exceptions\",\n        \"_future_signals\",\n        \"ctx\",\n        \"exceptions\",\n        \"host\",\n        \"listeners\",\n        \"middlewares\",\n        \"name\",\n        \"routes\",\n        \"statics\",\n        \"strict_slashes\",\n        \"url_prefix\",\n        \"version\",\n        \"websocket_routes\",\n    )\n\n    def __init__(\n        self,\n        name: str,\n        url_prefix: Optional[str] = None,\n        host: Optional[str] = None,\n        version: Optional[int] = None,\n        strict_slashes: Optional[bool] = None,\n    ):\n\n        self._apps: Set[Sanic] = set()\n        self.ctx = SimpleNamespace()\n        self.exceptions: List[RouteHandler] = []\n        self.host = host\n        self.listeners: Dict[str, List[ListenerType]] = {}\n        self.middlewares: List[MiddlewareType] = []\n        self.name = name\n        self.routes: List[Route] = []\n        self.statics: List[RouteHandler] = []\n        self.strict_slashes = strict_slashes\n        self.url_prefix = url_prefix\n        self.version = version\n        self.websocket_routes: List[Route] = []\n\n    def __repr__(self) -> str:\n        args = \", \".join(\n            [\n                f'{attr}=\"{getattr(self, attr)}\"'\n                if isinstance(getattr(self, attr), str)\n                else f\"{attr}={getattr(self, attr)}\"\n                for attr in (\n                    \"name\",\n                    \"url_prefix\",\n                    \"host\",\n                    \"version\",\n                    \"strict_slashes\",\n                )\n            ]\n        )\n        return f\"Blueprint({args})\"\n\n    @property\n    def apps(self):\n        if not self._apps:\n            raise SanicException(\n                f\"{self} has not yet been registered to an app\"\n            )\n        return self._apps\n\n    def route(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().route(*args, **kwargs)\n\n    def static(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().static(*args, **kwargs)\n\n    def middleware(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().middleware(*args, **kwargs)\n\n    def listener(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().listener(*args, **kwargs)\n\n    def exception(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().exception(*args, **kwargs)\n\n    def signal(self, event: str, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().signal(event, *args, **kwargs)\n\n    @staticmethod\n    def group(*blueprints, url_prefix=\"\", version=None, strict_slashes=None):\n        \"\"\"\n        Create a list of blueprints, optionally grouping them under a\n        general URL prefix.\n\n        :param blueprints: blueprints to be registered as a group\n        :param url_prefix: URL route to be prepended to all sub-prefixes\n        :param version: API Version to be used for Blueprint group\n        :param strict_slashes: Indicate strict slash termination behavior\n            for URL\n        \"\"\"\n\n        def chain(nested) -> Iterable[Blueprint]:\n            \"\"\"itertools.chain() but leaves strings untouched\"\"\"\n            for i in nested:\n                if isinstance(i, (list, tuple)):\n                    yield from chain(i)\n                elif isinstance(i, BlueprintGroup):\n                    yield from i.blueprints\n                else:\n                    yield i\n\n        bps = BlueprintGroup(\n            url_prefix=url_prefix,\n            version=version,\n            strict_slashes=strict_slashes,\n        )\n        for bp in chain(blueprints):\n            bps.append(bp)\n        return bps\n\n    def register(self, app, options):\n        \"\"\"\n        Register the blueprint to the sanic app.\n\n        :param app: Instance of :class:`sanic.app.Sanic` class\n        :param options: Options to be used while registering the\n            blueprint into the app.\n            *url_prefix* - URL Prefix to override the blueprint prefix\n        \"\"\"\n\n        self._apps.add(app)\n        url_prefix = options.get(\"url_prefix\", self.url_prefix)\n\n        routes = []\n        middleware = []\n        exception_handlers = []\n        listeners = defaultdict(list)\n\n        # Routes\n        for future in self._future_routes:\n            # attach the blueprint name to the handler so that it can be\n            # prefixed properly in the router\n            future.handler.__blueprintname__ = self.name\n            # Prepend the blueprint URI prefix if available\n            uri = url_prefix + future.uri if url_prefix else future.uri\n\n            strict_slashes = (\n                self.strict_slashes\n                if future.strict_slashes is None\n                and self.strict_slashes is not None\n                else future.strict_slashes\n            )\n            name = app._generate_name(future.name)\n\n            apply_route = FutureRoute(\n                future.handler,\n                uri[1:] if uri.startswith(\"//\") else uri,\n                future.methods,\n                future.host or self.host,\n                strict_slashes,\n                future.stream,\n                future.version or self.version,\n                name,\n                future.ignore_body,\n                future.websocket,\n                future.subprotocols,\n                future.unquote,\n                future.static,\n            )\n\n            route = app._apply_route(apply_route)\n            operation = (\n                routes.extend if isinstance(route, list) else routes.append\n            )\n            operation(route)\n\n        # Static Files\n        for future in self._future_statics:\n            # Prepend the blueprint URI prefix if available\n            uri = url_prefix + future.uri if url_prefix else future.uri\n            apply_route = FutureStatic(uri, *future[1:])\n            route = app._apply_static(apply_route)\n            routes.append(route)\n\n        route_names = [route.name for route in routes if route]\n\n        # Middleware\n        if route_names:\n            for future in self._future_middleware:\n                middleware.append(app._apply_middleware(future, route_names))\n\n        # Exceptions\n        for future in self._future_exceptions:\n            exception_handlers.append(app._apply_exception_handler(future))\n\n        # Event listeners\n        for listener in self._future_listeners:\n            listeners[listener.event].append(app._apply_listener(listener))\n\n        for signal in self._future_signals:\n            signal.condition.update({\"blueprint\": self.name})\n            app._apply_signal(signal)\n\n        self.routes = [route for route in routes if isinstance(route, Route)]\n\n        # Deprecate these in 21.6\n        self.websocket_routes = [\n            route for route in self.routes if route.ctx.websocket\n        ]\n        self.middlewares = middleware\n        self.exceptions = exception_handlers\n        self.listeners = dict(listeners)\n\n    async def dispatch(self, *args, **kwargs):\n        condition = kwargs.pop(\"condition\", {})\n        condition.update({\"blueprint\": self.name})\n        kwargs[\"condition\"] = condition\n        await asyncio.gather(\n            *[app.dispatch(*args, **kwargs) for app in self.apps]\n        )\n\n    def event(self, event: str, timeout: Optional[Union[int, float]] = None):\n        events = set()\n        for app in self.apps:\n            signal = app.signal_router.name_index.get(event)\n            if not signal:\n                raise NotFound(\"Could not find signal %s\" % event)\n            events.add(signal.ctx.event)\n\n        return asyncio.wait(\n            [event.wait() for event in events],\n            return_when=asyncio.FIRST_COMPLETED,\n            timeout=timeout,\n        )\n", "path": "sanic/blueprints.py"}, {"content": "from typing import Any, Tuple\nfrom warnings import warn\n\nfrom sanic.mixins.exceptions import ExceptionMixin\nfrom sanic.mixins.listeners import ListenerMixin\nfrom sanic.mixins.middleware import MiddlewareMixin\nfrom sanic.mixins.routes import RouteMixin\nfrom sanic.mixins.signals import SignalMixin\n\n\nclass Base(type):\n    def __new__(cls, name, bases, attrs):\n        init = attrs.get(\"__init__\")\n\n        def __init__(self, *args, **kwargs):\n            nonlocal init\n            nonlocal name\n\n            bases = [\n                b for base in type(self).__bases__ for b in base.__bases__\n            ]\n\n            for base in bases:\n                base.__init__(self, *args, **kwargs)\n\n            if init:\n                init(self, *args, **kwargs)\n\n        attrs[\"__init__\"] = __init__\n        return type.__new__(cls, name, bases, attrs)\n\n\nclass BaseSanic(\n    RouteMixin,\n    MiddlewareMixin,\n    ListenerMixin,\n    ExceptionMixin,\n    SignalMixin,\n    metaclass=Base,\n):\n    __fake_slots__: Tuple[str, ...]\n\n    def __str__(self) -> str:\n        return f\"<{self.__class__.__name__} {self.name}>\"\n\n    def __repr__(self) -> str:\n        return f'{self.__class__.__name__}(name=\"{self.name}\")'\n\n    def __setattr__(self, name: str, value: Any) -> None:\n        # This is a temporary compat layer so we can raise a warning until\n        # setting attributes on the app instance can be removed and deprecated\n        # with a proper implementation of __slots__\n        if name not in self.__fake_slots__:\n            warn(\n                f\"Setting variables on {self.__class__.__name__} instances is \"\n                \"deprecated and will be removed in version 21.9. You should \"\n                f\"change your {self.__class__.__name__} instance to use \"\n                f\"instance.ctx.{name} instead.\"\n            )\n        super().__setattr__(name, value)\n", "path": "sanic/base.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport asyncio\n\nfrom collections import defaultdict\nfrom types import SimpleNamespace\nfrom typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Union\n\nfrom sanic_routing.exceptions import NotFound  # type: ignore\nfrom sanic_routing.route import Route  # type: ignore\n\nfrom sanic.base import BaseSanic\nfrom sanic.blueprint_group import BlueprintGroup\nfrom sanic.exceptions import SanicException\nfrom sanic.models.futures import FutureRoute, FutureStatic\nfrom sanic.models.handler_types import (\n    ListenerType,\n    MiddlewareType,\n    RouteHandler,\n)\n\n\nif TYPE_CHECKING:\n    from sanic import Sanic  # noqa\n\n\nclass Blueprint(BaseSanic):\n    \"\"\"\n    In *Sanic* terminology, a **Blueprint** is a logical collection of\n    URLs that perform a specific set of tasks which can be identified by\n    a unique name.\n\n    It is the main tool for grouping functionality and similar endpoints.\n\n    `See user guide re: blueprints\n    <https://sanicframework.org/guide/best-practices/blueprints.html>`__\n\n    :param name: unique name of the blueprint\n    :param url_prefix: URL to be prefixed before all route URLs\n    :param host: IP Address of FQDN for the sanic server to use.\n    :param version: Blueprint Version\n    :param strict_slashes: Enforce the API urls are requested with a\n        training */*\n    \"\"\"\n\n    __fake_slots__ = (\n        \"_apps\",\n        \"_future_routes\",\n        \"_future_statics\",\n        \"_future_middleware\",\n        \"_future_listeners\",\n        \"_future_exceptions\",\n        \"_future_signals\",\n        \"ctx\",\n        \"exceptions\",\n        \"host\",\n        \"listeners\",\n        \"middlewares\",\n        \"name\",\n        \"routes\",\n        \"statics\",\n        \"strict_slashes\",\n        \"url_prefix\",\n        \"version\",\n        \"websocket_routes\",\n    )\n\n    def __init__(\n        self,\n        name: str,\n        url_prefix: Optional[str] = None,\n        host: Optional[str] = None,\n        version: Optional[int] = None,\n        strict_slashes: Optional[bool] = None,\n    ):\n        super().__init__()\n\n        self._apps: Set[Sanic] = set()\n        self.ctx = SimpleNamespace()\n        self.exceptions: List[RouteHandler] = []\n        self.host = host\n        self.listeners: Dict[str, List[ListenerType]] = {}\n        self.middlewares: List[MiddlewareType] = []\n        self.name = name\n        self.routes: List[Route] = []\n        self.statics: List[RouteHandler] = []\n        self.strict_slashes = strict_slashes\n        self.url_prefix = url_prefix\n        self.version = version\n        self.websocket_routes: List[Route] = []\n\n    def __repr__(self) -> str:\n        args = \", \".join(\n            [\n                f'{attr}=\"{getattr(self, attr)}\"'\n                if isinstance(getattr(self, attr), str)\n                else f\"{attr}={getattr(self, attr)}\"\n                for attr in (\n                    \"name\",\n                    \"url_prefix\",\n                    \"host\",\n                    \"version\",\n                    \"strict_slashes\",\n                )\n            ]\n        )\n        return f\"Blueprint({args})\"\n\n    @property\n    def apps(self):\n        if not self._apps:\n            raise SanicException(\n                f\"{self} has not yet been registered to an app\"\n            )\n        return self._apps\n\n    def route(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().route(*args, **kwargs)\n\n    def static(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().static(*args, **kwargs)\n\n    def middleware(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().middleware(*args, **kwargs)\n\n    def listener(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().listener(*args, **kwargs)\n\n    def exception(self, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().exception(*args, **kwargs)\n\n    def signal(self, event: str, *args, **kwargs):\n        kwargs[\"apply\"] = False\n        return super().signal(event, *args, **kwargs)\n\n    @staticmethod\n    def group(*blueprints, url_prefix=\"\", version=None, strict_slashes=None):\n        \"\"\"\n        Create a list of blueprints, optionally grouping them under a\n        general URL prefix.\n\n        :param blueprints: blueprints to be registered as a group\n        :param url_prefix: URL route to be prepended to all sub-prefixes\n        :param version: API Version to be used for Blueprint group\n        :param strict_slashes: Indicate strict slash termination behavior\n            for URL\n        \"\"\"\n\n        def chain(nested) -> Iterable[Blueprint]:\n            \"\"\"itertools.chain() but leaves strings untouched\"\"\"\n            for i in nested:\n                if isinstance(i, (list, tuple)):\n                    yield from chain(i)\n                elif isinstance(i, BlueprintGroup):\n                    yield from i.blueprints\n                else:\n                    yield i\n\n        bps = BlueprintGroup(\n            url_prefix=url_prefix,\n            version=version,\n            strict_slashes=strict_slashes,\n        )\n        for bp in chain(blueprints):\n            bps.append(bp)\n        return bps\n\n    def register(self, app, options):\n        \"\"\"\n        Register the blueprint to the sanic app.\n\n        :param app: Instance of :class:`sanic.app.Sanic` class\n        :param options: Options to be used while registering the\n            blueprint into the app.\n            *url_prefix* - URL Prefix to override the blueprint prefix\n        \"\"\"\n\n        self._apps.add(app)\n        url_prefix = options.get(\"url_prefix\", self.url_prefix)\n\n        routes = []\n        middleware = []\n        exception_handlers = []\n        listeners = defaultdict(list)\n\n        # Routes\n        for future in self._future_routes:\n            # attach the blueprint name to the handler so that it can be\n            # prefixed properly in the router\n            future.handler.__blueprintname__ = self.name\n            # Prepend the blueprint URI prefix if available\n            uri = url_prefix + future.uri if url_prefix else future.uri\n\n            strict_slashes = (\n                self.strict_slashes\n                if future.strict_slashes is None\n                and self.strict_slashes is not None\n                else future.strict_slashes\n            )\n            name = app._generate_name(future.name)\n\n            apply_route = FutureRoute(\n                future.handler,\n                uri[1:] if uri.startswith(\"//\") else uri,\n                future.methods,\n                future.host or self.host,\n                strict_slashes,\n                future.stream,\n                future.version or self.version,\n                name,\n                future.ignore_body,\n                future.websocket,\n                future.subprotocols,\n                future.unquote,\n                future.static,\n            )\n\n            route = app._apply_route(apply_route)\n            operation = (\n                routes.extend if isinstance(route, list) else routes.append\n            )\n            operation(route)\n\n        # Static Files\n        for future in self._future_statics:\n            # Prepend the blueprint URI prefix if available\n            uri = url_prefix + future.uri if url_prefix else future.uri\n            apply_route = FutureStatic(uri, *future[1:])\n            route = app._apply_static(apply_route)\n            routes.append(route)\n\n        route_names = [route.name for route in routes if route]\n\n        # Middleware\n        if route_names:\n            for future in self._future_middleware:\n                middleware.append(app._apply_middleware(future, route_names))\n\n        # Exceptions\n        for future in self._future_exceptions:\n            exception_handlers.append(app._apply_exception_handler(future))\n\n        # Event listeners\n        for listener in self._future_listeners:\n            listeners[listener.event].append(app._apply_listener(listener))\n\n        for signal in self._future_signals:\n            signal.condition.update({\"blueprint\": self.name})\n            app._apply_signal(signal)\n\n        self.routes = [route for route in routes if isinstance(route, Route)]\n\n        # Deprecate these in 21.6\n        self.websocket_routes = [\n            route for route in self.routes if route.ctx.websocket\n        ]\n        self.middlewares = middleware\n        self.exceptions = exception_handlers\n        self.listeners = dict(listeners)\n\n    async def dispatch(self, *args, **kwargs):\n        condition = kwargs.pop(\"condition\", {})\n        condition.update({\"blueprint\": self.name})\n        kwargs[\"condition\"] = condition\n        await asyncio.gather(\n            *[app.dispatch(*args, **kwargs) for app in self.apps]\n        )\n\n    def event(self, event: str, timeout: Optional[Union[int, float]] = None):\n        events = set()\n        for app in self.apps:\n            signal = app.signal_router.name_index.get(event)\n            if not signal:\n                raise NotFound(\"Could not find signal %s\" % event)\n            events.add(signal.ctx.event)\n\n        return asyncio.wait(\n            [event.wait() for event in events],\n            return_when=asyncio.FIRST_COMPLETED,\n            timeout=timeout,\n        )\n", "path": "sanic/blueprints.py"}, {"content": "from typing import Any, Tuple\nfrom warnings import warn\n\nfrom sanic.mixins.exceptions import ExceptionMixin\nfrom sanic.mixins.listeners import ListenerMixin\nfrom sanic.mixins.middleware import MiddlewareMixin\nfrom sanic.mixins.routes import RouteMixin\nfrom sanic.mixins.signals import SignalMixin\n\n\nclass BaseSanic(\n    RouteMixin,\n    MiddlewareMixin,\n    ListenerMixin,\n    ExceptionMixin,\n    SignalMixin,\n):\n    __fake_slots__: Tuple[str, ...]\n\n    def __init__(self, *args, **kwargs) -> None:\n        for base in BaseSanic.__bases__:\n            base.__init__(self, *args, **kwargs)  # type: ignore\n\n    def __str__(self) -> str:\n        return f\"<{self.__class__.__name__} {self.name}>\"\n\n    def __repr__(self) -> str:\n        return f'{self.__class__.__name__}(name=\"{self.name}\")'\n\n    def __setattr__(self, name: str, value: Any) -> None:\n        # This is a temporary compat layer so we can raise a warning until\n        # setting attributes on the app instance can be removed and deprecated\n        # with a proper implementation of __slots__\n        if name not in self.__fake_slots__:\n            warn(\n                f\"Setting variables on {self.__class__.__name__} instances is \"\n                \"deprecated and will be removed in version 21.9. You should \"\n                f\"change your {self.__class__.__name__} instance to use \"\n                f\"instance.ctx.{name} instead.\"\n            )\n        super().__setattr__(name, value)\n", "path": "sanic/base.py"}]}