We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Error Handler mismatch warning
The warning for error handler mismatch is triggering on v22.3 accidentally when setting `FALLBACK_ERROR_FORMAT`.

```python
app.config.FALLBACK_ERROR_FORMAT = "text"


@app.get("/")
async def handler(request: Request):
    1 / 0
```

This can be resolved as follows:

```python
    @classmethod
    def _get_fallback_value(cls, error_handler: ErrorHandler, config: Config):
        if error_handler._fallback is not _default:
            if config._FALLBACK_ERROR_FORMAT == error_handler._fallback:  # <<<<< This line needs this change
                return error_handler.fallback

            error_logger.warning(
                "Conflicting error fallback values were found in the "
                "error handler and in the app.config while handling an "
                "exception. Using the value from app.config."
            )
        return config.FALLBACK_ERROR_FORMAT
```

https://github.com/sanic-org/sanic/blob/5d683c6ea4b615e80c51d80189436437b824cce6/sanic/handlers.py#L79

--- 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/handlers.py`
Content:
```
1 from __future__ import annotations
2 
3 from typing import Dict, List, Optional, Tuple, Type, Union
4 
5 from sanic.config import Config
6 from sanic.errorpages import (
7     DEFAULT_FORMAT,
8     BaseRenderer,
9     TextRenderer,
10     exception_response,
11 )
12 from sanic.exceptions import (
13     ContentRangeError,
14     HeaderNotFound,
15     InvalidRangeType,
16     SanicException,
17 )
18 from sanic.helpers import Default, _default
19 from sanic.log import deprecation, error_logger
20 from sanic.models.handler_types import RouteHandler
21 from sanic.response import text
22 
23 
24 class ErrorHandler:
25     """
26     Provide :class:`sanic.app.Sanic` application with a mechanism to handle
27     and process any and all uncaught exceptions in a way the application
28     developer will set fit.
29 
30     This error handling framework is built into the core that can be extended
31     by the developers to perform a wide range of tasks from recording the error
32     stats to reporting them to an external service that can be used for
33     realtime alerting system.
34 
35     """
36 
37     def __init__(
38         self,
39         fallback: Union[str, Default] = _default,
40         base: Type[BaseRenderer] = TextRenderer,
41     ):
42         self.cached_handlers: Dict[
43             Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
44         ] = {}
45         self.debug = False
46         self._fallback = fallback
47         self.base = base
48 
49         if fallback is not _default:
50             self._warn_fallback_deprecation()
51 
52     @property
53     def fallback(self):  # no cov
54         # This is for backwards compat and can be removed in v22.6
55         if self._fallback is _default:
56             return DEFAULT_FORMAT
57         return self._fallback
58 
59     @fallback.setter
60     def fallback(self, value: str):  # no cov
61         self._warn_fallback_deprecation()
62         if not isinstance(value, str):
63             raise SanicException(
64                 f"Cannot set error handler fallback to: value={value}"
65             )
66         self._fallback = value
67 
68     @staticmethod
69     def _warn_fallback_deprecation():
70         deprecation(
71             "Setting the ErrorHandler fallback value directly is "
72             "deprecated and no longer supported. This feature will "
73             "be removed in v22.6. Instead, use "
74             "app.config.FALLBACK_ERROR_FORMAT.",
75             22.6,
76         )
77 
78     @classmethod
79     def _get_fallback_value(cls, error_handler: ErrorHandler, config: Config):
80         if error_handler._fallback is not _default:
81             if config._FALLBACK_ERROR_FORMAT is _default:
82                 return error_handler.fallback
83 
84             error_logger.warning(
85                 "Conflicting error fallback values were found in the "
86                 "error handler and in the app.config while handling an "
87                 "exception. Using the value from app.config."
88             )
89         return config.FALLBACK_ERROR_FORMAT
90 
91     @classmethod
92     def finalize(
93         cls,
94         error_handler: ErrorHandler,
95         config: Config,
96         fallback: Optional[str] = None,
97     ):
98         if fallback:
99             deprecation(
100                 "Setting the ErrorHandler fallback value via finalize() "
101                 "is deprecated and no longer supported. This feature will "
102                 "be removed in v22.6. Instead, use "
103                 "app.config.FALLBACK_ERROR_FORMAT.",
104                 22.6,
105             )
106 
107         if not fallback:
108             fallback = config.FALLBACK_ERROR_FORMAT
109 
110         if fallback != DEFAULT_FORMAT:
111             if error_handler._fallback is not _default:
112                 error_logger.warning(
113                     f"Setting the fallback value to {fallback}. This changes "
114                     "the current non-default value "
115                     f"'{error_handler._fallback}'."
116                 )
117             error_handler._fallback = fallback
118 
119         if not isinstance(error_handler, cls):
120             error_logger.warning(
121                 f"Error handler is non-conforming: {type(error_handler)}"
122             )
123 
124     def _full_lookup(self, exception, route_name: Optional[str] = None):
125         return self.lookup(exception, route_name)
126 
127     def add(self, exception, handler, route_names: Optional[List[str]] = None):
128         """
129         Add a new exception handler to an already existing handler object.
130 
131         :param exception: Type of exception that need to be handled
132         :param handler: Reference to the method that will handle the exception
133 
134         :type exception: :class:`sanic.exceptions.SanicException` or
135             :class:`Exception`
136         :type handler: ``function``
137 
138         :return: None
139         """
140         if route_names:
141             for route in route_names:
142                 self.cached_handlers[(exception, route)] = handler
143         else:
144             self.cached_handlers[(exception, None)] = handler
145 
146     def lookup(self, exception, route_name: Optional[str] = None):
147         """
148         Lookup the existing instance of :class:`ErrorHandler` and fetch the
149         registered handler for a specific type of exception.
150 
151         This method leverages a dict lookup to speedup the retrieval process.
152 
153         :param exception: Type of exception
154 
155         :type exception: :class:`sanic.exceptions.SanicException` or
156             :class:`Exception`
157 
158         :return: Registered function if found ``None`` otherwise
159         """
160         exception_class = type(exception)
161 
162         for name in (route_name, None):
163             exception_key = (exception_class, name)
164             handler = self.cached_handlers.get(exception_key)
165             if handler:
166                 return handler
167 
168         for name in (route_name, None):
169             for ancestor in type.mro(exception_class):
170                 exception_key = (ancestor, name)
171                 if exception_key in self.cached_handlers:
172                     handler = self.cached_handlers[exception_key]
173                     self.cached_handlers[
174                         (exception_class, route_name)
175                     ] = handler
176                     return handler
177 
178                 if ancestor is BaseException:
179                     break
180         self.cached_handlers[(exception_class, route_name)] = None
181         handler = None
182         return handler
183 
184     _lookup = _full_lookup
185 
186     def response(self, request, exception):
187         """Fetches and executes an exception handler and returns a response
188         object
189 
190         :param request: Instance of :class:`sanic.request.Request`
191         :param exception: Exception to handle
192 
193         :type request: :class:`sanic.request.Request`
194         :type exception: :class:`sanic.exceptions.SanicException` or
195             :class:`Exception`
196 
197         :return: Wrap the return value obtained from :func:`default`
198             or registered handler for that type of exception.
199         """
200         route_name = request.name if request else None
201         handler = self._lookup(exception, route_name)
202         response = None
203         try:
204             if handler:
205                 response = handler(request, exception)
206             if response is None:
207                 response = self.default(request, exception)
208         except Exception:
209             try:
210                 url = repr(request.url)
211             except AttributeError:  # no cov
212                 url = "unknown"
213             response_message = (
214                 "Exception raised in exception handler " '"%s" for uri: %s'
215             )
216             error_logger.exception(response_message, handler.__name__, url)
217 
218             if self.debug:
219                 return text(response_message % (handler.__name__, url), 500)
220             else:
221                 return text("An error occurred while handling an error", 500)
222         return response
223 
224     def default(self, request, exception):
225         """
226         Provide a default behavior for the objects of :class:`ErrorHandler`.
227         If a developer chooses to extent the :class:`ErrorHandler` they can
228         provide a custom implementation for this method to behave in a way
229         they see fit.
230 
231         :param request: Incoming request
232         :param exception: Exception object
233 
234         :type request: :class:`sanic.request.Request`
235         :type exception: :class:`sanic.exceptions.SanicException` or
236             :class:`Exception`
237         :return:
238         """
239         self.log(request, exception)
240         fallback = ErrorHandler._get_fallback_value(self, request.app.config)
241         return exception_response(
242             request,
243             exception,
244             debug=self.debug,
245             base=self.base,
246             fallback=fallback,
247         )
248 
249     @staticmethod
250     def log(request, exception):
251         quiet = getattr(exception, "quiet", False)
252         noisy = getattr(request.app.config, "NOISY_EXCEPTIONS", False)
253         if quiet is False or noisy is True:
254             try:
255                 url = repr(request.url)
256             except AttributeError:  # no cov
257                 url = "unknown"
258 
259             error_logger.exception(
260                 "Exception occurred while handling uri: %s", url
261             )
262 
263 
264 class ContentRangeHandler:
265     """
266     A mechanism to parse and process the incoming request headers to
267     extract the content range information.
268 
269     :param request: Incoming api request
270     :param stats: Stats related to the content
271 
272     :type request: :class:`sanic.request.Request`
273     :type stats: :class:`posix.stat_result`
274 
275     :ivar start: Content Range start
276     :ivar end: Content Range end
277     :ivar size: Length of the content
278     :ivar total: Total size identified by the :class:`posix.stat_result`
279         instance
280     :ivar ContentRangeHandler.headers: Content range header ``dict``
281     """
282 
283     __slots__ = ("start", "end", "size", "total", "headers")
284 
285     def __init__(self, request, stats):
286         self.total = stats.st_size
287         _range = request.headers.getone("range", None)
288         if _range is None:
289             raise HeaderNotFound("Range Header Not Found")
290         unit, _, value = tuple(map(str.strip, _range.partition("=")))
291         if unit != "bytes":
292             raise InvalidRangeType(
293                 "%s is not a valid Range Type" % (unit,), self
294             )
295         start_b, _, end_b = tuple(map(str.strip, value.partition("-")))
296         try:
297             self.start = int(start_b) if start_b else None
298         except ValueError:
299             raise ContentRangeError(
300                 "'%s' is invalid for Content Range" % (start_b,), self
301             )
302         try:
303             self.end = int(end_b) if end_b else None
304         except ValueError:
305             raise ContentRangeError(
306                 "'%s' is invalid for Content Range" % (end_b,), self
307             )
308         if self.end is None:
309             if self.start is None:
310                 raise ContentRangeError(
311                     "Invalid for Content Range parameters", self
312                 )
313             else:
314                 # this case represents `Content-Range: bytes 5-`
315                 self.end = self.total - 1
316         else:
317             if self.start is None:
318                 # this case represents `Content-Range: bytes -5`
319                 self.start = self.total - self.end
320                 self.end = self.total - 1
321         if self.start >= self.end:
322             raise ContentRangeError(
323                 "Invalid for Content Range parameters", self
324             )
325         self.size = self.end - self.start + 1
326         self.headers = {
327             "Content-Range": "bytes %s-%s/%s"
328             % (self.start, self.end, self.total)
329         }
330 
331     def __bool__(self):
332         return self.size > 0
333
```
--- 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/handlers.py b/sanic/handlers.py
--- a/sanic/handlers.py
+++ b/sanic/handlers.py
@@ -78,7 +78,7 @@
     @classmethod
     def _get_fallback_value(cls, error_handler: ErrorHandler, config: Config):
         if error_handler._fallback is not _default:
-            if config._FALLBACK_ERROR_FORMAT is _default:
+            if config._FALLBACK_ERROR_FORMAT == error_handler._fallback:
                 return error_handler.fallback
 
             error_logger.warning(

{"golden_diff": "diff --git a/sanic/handlers.py b/sanic/handlers.py\n--- a/sanic/handlers.py\n+++ b/sanic/handlers.py\n@@ -78,7 +78,7 @@\n     @classmethod\n     def _get_fallback_value(cls, error_handler: ErrorHandler, config: Config):\n         if error_handler._fallback is not _default:\n-            if config._FALLBACK_ERROR_FORMAT is _default:\n+            if config._FALLBACK_ERROR_FORMAT == error_handler._fallback:\n                 return error_handler.fallback\n \n             error_logger.warning(\n", "issue": "Error Handler mismatch warning\nThe warning for error handler mismatch is triggering on v22.3 accidentally when setting `FALLBACK_ERROR_FORMAT`.\r\n\r\n```python\r\napp.config.FALLBACK_ERROR_FORMAT = \"text\"\r\n\r\n\r\n@app.get(\"/\")\r\nasync def handler(request: Request):\r\n    1 / 0\r\n```\r\n\r\nThis can be resolved as follows:\r\n\r\n```python\r\n    @classmethod\r\n    def _get_fallback_value(cls, error_handler: ErrorHandler, config: Config):\r\n        if error_handler._fallback is not _default:\r\n            if config._FALLBACK_ERROR_FORMAT == error_handler._fallback:  # <<<<< This line needs this change\r\n                return error_handler.fallback\r\n\r\n            error_logger.warning(\r\n                \"Conflicting error fallback values were found in the \"\r\n                \"error handler and in the app.config while handling an \"\r\n                \"exception. Using the value from app.config.\"\r\n            )\r\n        return config.FALLBACK_ERROR_FORMAT\r\n```\r\n\r\nhttps://github.com/sanic-org/sanic/blob/5d683c6ea4b615e80c51d80189436437b824cce6/sanic/handlers.py#L79\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom typing import Dict, List, Optional, Tuple, Type, Union\n\nfrom sanic.config import Config\nfrom sanic.errorpages import (\n    DEFAULT_FORMAT,\n    BaseRenderer,\n    TextRenderer,\n    exception_response,\n)\nfrom sanic.exceptions import (\n    ContentRangeError,\n    HeaderNotFound,\n    InvalidRangeType,\n    SanicException,\n)\nfrom sanic.helpers import Default, _default\nfrom sanic.log import deprecation, error_logger\nfrom sanic.models.handler_types import RouteHandler\nfrom sanic.response import text\n\n\nclass ErrorHandler:\n    \"\"\"\n    Provide :class:`sanic.app.Sanic` application with a mechanism to handle\n    and process any and all uncaught exceptions in a way the application\n    developer will set fit.\n\n    This error handling framework is built into the core that can be extended\n    by the developers to perform a wide range of tasks from recording the error\n    stats to reporting them to an external service that can be used for\n    realtime alerting system.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        fallback: Union[str, Default] = _default,\n        base: Type[BaseRenderer] = TextRenderer,\n    ):\n        self.cached_handlers: Dict[\n            Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]\n        ] = {}\n        self.debug = False\n        self._fallback = fallback\n        self.base = base\n\n        if fallback is not _default:\n            self._warn_fallback_deprecation()\n\n    @property\n    def fallback(self):  # no cov\n        # This is for backwards compat and can be removed in v22.6\n        if self._fallback is _default:\n            return DEFAULT_FORMAT\n        return self._fallback\n\n    @fallback.setter\n    def fallback(self, value: str):  # no cov\n        self._warn_fallback_deprecation()\n        if not isinstance(value, str):\n            raise SanicException(\n                f\"Cannot set error handler fallback to: value={value}\"\n            )\n        self._fallback = value\n\n    @staticmethod\n    def _warn_fallback_deprecation():\n        deprecation(\n            \"Setting the ErrorHandler fallback value directly is \"\n            \"deprecated and no longer supported. This feature will \"\n            \"be removed in v22.6. Instead, use \"\n            \"app.config.FALLBACK_ERROR_FORMAT.\",\n            22.6,\n        )\n\n    @classmethod\n    def _get_fallback_value(cls, error_handler: ErrorHandler, config: Config):\n        if error_handler._fallback is not _default:\n            if config._FALLBACK_ERROR_FORMAT is _default:\n                return error_handler.fallback\n\n            error_logger.warning(\n                \"Conflicting error fallback values were found in the \"\n                \"error handler and in the app.config while handling an \"\n                \"exception. Using the value from app.config.\"\n            )\n        return config.FALLBACK_ERROR_FORMAT\n\n    @classmethod\n    def finalize(\n        cls,\n        error_handler: ErrorHandler,\n        config: Config,\n        fallback: Optional[str] = None,\n    ):\n        if fallback:\n            deprecation(\n                \"Setting the ErrorHandler fallback value via finalize() \"\n                \"is deprecated and no longer supported. This feature will \"\n                \"be removed in v22.6. Instead, use \"\n                \"app.config.FALLBACK_ERROR_FORMAT.\",\n                22.6,\n            )\n\n        if not fallback:\n            fallback = config.FALLBACK_ERROR_FORMAT\n\n        if fallback != DEFAULT_FORMAT:\n            if error_handler._fallback is not _default:\n                error_logger.warning(\n                    f\"Setting the fallback value to {fallback}. This changes \"\n                    \"the current non-default value \"\n                    f\"'{error_handler._fallback}'.\"\n                )\n            error_handler._fallback = fallback\n\n        if not isinstance(error_handler, cls):\n            error_logger.warning(\n                f\"Error handler is non-conforming: {type(error_handler)}\"\n            )\n\n    def _full_lookup(self, exception, route_name: Optional[str] = None):\n        return self.lookup(exception, route_name)\n\n    def add(self, exception, handler, route_names: Optional[List[str]] = None):\n        \"\"\"\n        Add a new exception handler to an already existing handler object.\n\n        :param exception: Type of exception that need to be handled\n        :param handler: Reference to the method that will handle the exception\n\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n        :type handler: ``function``\n\n        :return: None\n        \"\"\"\n        if route_names:\n            for route in route_names:\n                self.cached_handlers[(exception, route)] = handler\n        else:\n            self.cached_handlers[(exception, None)] = handler\n\n    def lookup(self, exception, route_name: Optional[str] = None):\n        \"\"\"\n        Lookup the existing instance of :class:`ErrorHandler` and fetch the\n        registered handler for a specific type of exception.\n\n        This method leverages a dict lookup to speedup the retrieval process.\n\n        :param exception: Type of exception\n\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n\n        :return: Registered function if found ``None`` otherwise\n        \"\"\"\n        exception_class = type(exception)\n\n        for name in (route_name, None):\n            exception_key = (exception_class, name)\n            handler = self.cached_handlers.get(exception_key)\n            if handler:\n                return handler\n\n        for name in (route_name, None):\n            for ancestor in type.mro(exception_class):\n                exception_key = (ancestor, name)\n                if exception_key in self.cached_handlers:\n                    handler = self.cached_handlers[exception_key]\n                    self.cached_handlers[\n                        (exception_class, route_name)\n                    ] = handler\n                    return handler\n\n                if ancestor is BaseException:\n                    break\n        self.cached_handlers[(exception_class, route_name)] = None\n        handler = None\n        return handler\n\n    _lookup = _full_lookup\n\n    def response(self, request, exception):\n        \"\"\"Fetches and executes an exception handler and returns a response\n        object\n\n        :param request: Instance of :class:`sanic.request.Request`\n        :param exception: Exception to handle\n\n        :type request: :class:`sanic.request.Request`\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n\n        :return: Wrap the return value obtained from :func:`default`\n            or registered handler for that type of exception.\n        \"\"\"\n        route_name = request.name if request else None\n        handler = self._lookup(exception, route_name)\n        response = None\n        try:\n            if handler:\n                response = handler(request, exception)\n            if response is None:\n                response = self.default(request, exception)\n        except Exception:\n            try:\n                url = repr(request.url)\n            except AttributeError:  # no cov\n                url = \"unknown\"\n            response_message = (\n                \"Exception raised in exception handler \" '\"%s\" for uri: %s'\n            )\n            error_logger.exception(response_message, handler.__name__, url)\n\n            if self.debug:\n                return text(response_message % (handler.__name__, url), 500)\n            else:\n                return text(\"An error occurred while handling an error\", 500)\n        return response\n\n    def default(self, request, exception):\n        \"\"\"\n        Provide a default behavior for the objects of :class:`ErrorHandler`.\n        If a developer chooses to extent the :class:`ErrorHandler` they can\n        provide a custom implementation for this method to behave in a way\n        they see fit.\n\n        :param request: Incoming request\n        :param exception: Exception object\n\n        :type request: :class:`sanic.request.Request`\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n        :return:\n        \"\"\"\n        self.log(request, exception)\n        fallback = ErrorHandler._get_fallback_value(self, request.app.config)\n        return exception_response(\n            request,\n            exception,\n            debug=self.debug,\n            base=self.base,\n            fallback=fallback,\n        )\n\n    @staticmethod\n    def log(request, exception):\n        quiet = getattr(exception, \"quiet\", False)\n        noisy = getattr(request.app.config, \"NOISY_EXCEPTIONS\", False)\n        if quiet is False or noisy is True:\n            try:\n                url = repr(request.url)\n            except AttributeError:  # no cov\n                url = \"unknown\"\n\n            error_logger.exception(\n                \"Exception occurred while handling uri: %s\", url\n            )\n\n\nclass ContentRangeHandler:\n    \"\"\"\n    A mechanism to parse and process the incoming request headers to\n    extract the content range information.\n\n    :param request: Incoming api request\n    :param stats: Stats related to the content\n\n    :type request: :class:`sanic.request.Request`\n    :type stats: :class:`posix.stat_result`\n\n    :ivar start: Content Range start\n    :ivar end: Content Range end\n    :ivar size: Length of the content\n    :ivar total: Total size identified by the :class:`posix.stat_result`\n        instance\n    :ivar ContentRangeHandler.headers: Content range header ``dict``\n    \"\"\"\n\n    __slots__ = (\"start\", \"end\", \"size\", \"total\", \"headers\")\n\n    def __init__(self, request, stats):\n        self.total = stats.st_size\n        _range = request.headers.getone(\"range\", None)\n        if _range is None:\n            raise HeaderNotFound(\"Range Header Not Found\")\n        unit, _, value = tuple(map(str.strip, _range.partition(\"=\")))\n        if unit != \"bytes\":\n            raise InvalidRangeType(\n                \"%s is not a valid Range Type\" % (unit,), self\n            )\n        start_b, _, end_b = tuple(map(str.strip, value.partition(\"-\")))\n        try:\n            self.start = int(start_b) if start_b else None\n        except ValueError:\n            raise ContentRangeError(\n                \"'%s' is invalid for Content Range\" % (start_b,), self\n            )\n        try:\n            self.end = int(end_b) if end_b else None\n        except ValueError:\n            raise ContentRangeError(\n                \"'%s' is invalid for Content Range\" % (end_b,), self\n            )\n        if self.end is None:\n            if self.start is None:\n                raise ContentRangeError(\n                    \"Invalid for Content Range parameters\", self\n                )\n            else:\n                # this case represents `Content-Range: bytes 5-`\n                self.end = self.total - 1\n        else:\n            if self.start is None:\n                # this case represents `Content-Range: bytes -5`\n                self.start = self.total - self.end\n                self.end = self.total - 1\n        if self.start >= self.end:\n            raise ContentRangeError(\n                \"Invalid for Content Range parameters\", self\n            )\n        self.size = self.end - self.start + 1\n        self.headers = {\n            \"Content-Range\": \"bytes %s-%s/%s\"\n            % (self.start, self.end, self.total)\n        }\n\n    def __bool__(self):\n        return self.size > 0\n", "path": "sanic/handlers.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom typing import Dict, List, Optional, Tuple, Type, Union\n\nfrom sanic.config import Config\nfrom sanic.errorpages import (\n    DEFAULT_FORMAT,\n    BaseRenderer,\n    TextRenderer,\n    exception_response,\n)\nfrom sanic.exceptions import (\n    ContentRangeError,\n    HeaderNotFound,\n    InvalidRangeType,\n    SanicException,\n)\nfrom sanic.helpers import Default, _default\nfrom sanic.log import deprecation, error_logger\nfrom sanic.models.handler_types import RouteHandler\nfrom sanic.response import text\n\n\nclass ErrorHandler:\n    \"\"\"\n    Provide :class:`sanic.app.Sanic` application with a mechanism to handle\n    and process any and all uncaught exceptions in a way the application\n    developer will set fit.\n\n    This error handling framework is built into the core that can be extended\n    by the developers to perform a wide range of tasks from recording the error\n    stats to reporting them to an external service that can be used for\n    realtime alerting system.\n\n    \"\"\"\n\n    def __init__(\n        self,\n        fallback: Union[str, Default] = _default,\n        base: Type[BaseRenderer] = TextRenderer,\n    ):\n        self.cached_handlers: Dict[\n            Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]\n        ] = {}\n        self.debug = False\n        self._fallback = fallback\n        self.base = base\n\n        if fallback is not _default:\n            self._warn_fallback_deprecation()\n\n    @property\n    def fallback(self):  # no cov\n        # This is for backwards compat and can be removed in v22.6\n        if self._fallback is _default:\n            return DEFAULT_FORMAT\n        return self._fallback\n\n    @fallback.setter\n    def fallback(self, value: str):  # no cov\n        self._warn_fallback_deprecation()\n        if not isinstance(value, str):\n            raise SanicException(\n                f\"Cannot set error handler fallback to: value={value}\"\n            )\n        self._fallback = value\n\n    @staticmethod\n    def _warn_fallback_deprecation():\n        deprecation(\n            \"Setting the ErrorHandler fallback value directly is \"\n            \"deprecated and no longer supported. This feature will \"\n            \"be removed in v22.6. Instead, use \"\n            \"app.config.FALLBACK_ERROR_FORMAT.\",\n            22.6,\n        )\n\n    @classmethod\n    def _get_fallback_value(cls, error_handler: ErrorHandler, config: Config):\n        if error_handler._fallback is not _default:\n            if config._FALLBACK_ERROR_FORMAT == error_handler._fallback:\n                return error_handler.fallback\n\n            error_logger.warning(\n                \"Conflicting error fallback values were found in the \"\n                \"error handler and in the app.config while handling an \"\n                \"exception. Using the value from app.config.\"\n            )\n        return config.FALLBACK_ERROR_FORMAT\n\n    @classmethod\n    def finalize(\n        cls,\n        error_handler: ErrorHandler,\n        config: Config,\n        fallback: Optional[str] = None,\n    ):\n        if fallback:\n            deprecation(\n                \"Setting the ErrorHandler fallback value via finalize() \"\n                \"is deprecated and no longer supported. This feature will \"\n                \"be removed in v22.6. Instead, use \"\n                \"app.config.FALLBACK_ERROR_FORMAT.\",\n                22.6,\n            )\n\n        if not fallback:\n            fallback = config.FALLBACK_ERROR_FORMAT\n\n        if fallback != DEFAULT_FORMAT:\n            if error_handler._fallback is not _default:\n                error_logger.warning(\n                    f\"Setting the fallback value to {fallback}. This changes \"\n                    \"the current non-default value \"\n                    f\"'{error_handler._fallback}'.\"\n                )\n            error_handler._fallback = fallback\n\n        if not isinstance(error_handler, cls):\n            error_logger.warning(\n                f\"Error handler is non-conforming: {type(error_handler)}\"\n            )\n\n    def _full_lookup(self, exception, route_name: Optional[str] = None):\n        return self.lookup(exception, route_name)\n\n    def add(self, exception, handler, route_names: Optional[List[str]] = None):\n        \"\"\"\n        Add a new exception handler to an already existing handler object.\n\n        :param exception: Type of exception that need to be handled\n        :param handler: Reference to the method that will handle the exception\n\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n        :type handler: ``function``\n\n        :return: None\n        \"\"\"\n        if route_names:\n            for route in route_names:\n                self.cached_handlers[(exception, route)] = handler\n        else:\n            self.cached_handlers[(exception, None)] = handler\n\n    def lookup(self, exception, route_name: Optional[str] = None):\n        \"\"\"\n        Lookup the existing instance of :class:`ErrorHandler` and fetch the\n        registered handler for a specific type of exception.\n\n        This method leverages a dict lookup to speedup the retrieval process.\n\n        :param exception: Type of exception\n\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n\n        :return: Registered function if found ``None`` otherwise\n        \"\"\"\n        exception_class = type(exception)\n\n        for name in (route_name, None):\n            exception_key = (exception_class, name)\n            handler = self.cached_handlers.get(exception_key)\n            if handler:\n                return handler\n\n        for name in (route_name, None):\n            for ancestor in type.mro(exception_class):\n                exception_key = (ancestor, name)\n                if exception_key in self.cached_handlers:\n                    handler = self.cached_handlers[exception_key]\n                    self.cached_handlers[\n                        (exception_class, route_name)\n                    ] = handler\n                    return handler\n\n                if ancestor is BaseException:\n                    break\n        self.cached_handlers[(exception_class, route_name)] = None\n        handler = None\n        return handler\n\n    _lookup = _full_lookup\n\n    def response(self, request, exception):\n        \"\"\"Fetches and executes an exception handler and returns a response\n        object\n\n        :param request: Instance of :class:`sanic.request.Request`\n        :param exception: Exception to handle\n\n        :type request: :class:`sanic.request.Request`\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n\n        :return: Wrap the return value obtained from :func:`default`\n            or registered handler for that type of exception.\n        \"\"\"\n        route_name = request.name if request else None\n        handler = self._lookup(exception, route_name)\n        response = None\n        try:\n            if handler:\n                response = handler(request, exception)\n            if response is None:\n                response = self.default(request, exception)\n        except Exception:\n            try:\n                url = repr(request.url)\n            except AttributeError:  # no cov\n                url = \"unknown\"\n            response_message = (\n                \"Exception raised in exception handler \" '\"%s\" for uri: %s'\n            )\n            error_logger.exception(response_message, handler.__name__, url)\n\n            if self.debug:\n                return text(response_message % (handler.__name__, url), 500)\n            else:\n                return text(\"An error occurred while handling an error\", 500)\n        return response\n\n    def default(self, request, exception):\n        \"\"\"\n        Provide a default behavior for the objects of :class:`ErrorHandler`.\n        If a developer chooses to extent the :class:`ErrorHandler` they can\n        provide a custom implementation for this method to behave in a way\n        they see fit.\n\n        :param request: Incoming request\n        :param exception: Exception object\n\n        :type request: :class:`sanic.request.Request`\n        :type exception: :class:`sanic.exceptions.SanicException` or\n            :class:`Exception`\n        :return:\n        \"\"\"\n        self.log(request, exception)\n        fallback = ErrorHandler._get_fallback_value(self, request.app.config)\n        return exception_response(\n            request,\n            exception,\n            debug=self.debug,\n            base=self.base,\n            fallback=fallback,\n        )\n\n    @staticmethod\n    def log(request, exception):\n        quiet = getattr(exception, \"quiet\", False)\n        noisy = getattr(request.app.config, \"NOISY_EXCEPTIONS\", False)\n        if quiet is False or noisy is True:\n            try:\n                url = repr(request.url)\n            except AttributeError:  # no cov\n                url = \"unknown\"\n\n            error_logger.exception(\n                \"Exception occurred while handling uri: %s\", url\n            )\n\n\nclass ContentRangeHandler:\n    \"\"\"\n    A mechanism to parse and process the incoming request headers to\n    extract the content range information.\n\n    :param request: Incoming api request\n    :param stats: Stats related to the content\n\n    :type request: :class:`sanic.request.Request`\n    :type stats: :class:`posix.stat_result`\n\n    :ivar start: Content Range start\n    :ivar end: Content Range end\n    :ivar size: Length of the content\n    :ivar total: Total size identified by the :class:`posix.stat_result`\n        instance\n    :ivar ContentRangeHandler.headers: Content range header ``dict``\n    \"\"\"\n\n    __slots__ = (\"start\", \"end\", \"size\", \"total\", \"headers\")\n\n    def __init__(self, request, stats):\n        self.total = stats.st_size\n        _range = request.headers.getone(\"range\", None)\n        if _range is None:\n            raise HeaderNotFound(\"Range Header Not Found\")\n        unit, _, value = tuple(map(str.strip, _range.partition(\"=\")))\n        if unit != \"bytes\":\n            raise InvalidRangeType(\n                \"%s is not a valid Range Type\" % (unit,), self\n            )\n        start_b, _, end_b = tuple(map(str.strip, value.partition(\"-\")))\n        try:\n            self.start = int(start_b) if start_b else None\n        except ValueError:\n            raise ContentRangeError(\n                \"'%s' is invalid for Content Range\" % (start_b,), self\n            )\n        try:\n            self.end = int(end_b) if end_b else None\n        except ValueError:\n            raise ContentRangeError(\n                \"'%s' is invalid for Content Range\" % (end_b,), self\n            )\n        if self.end is None:\n            if self.start is None:\n                raise ContentRangeError(\n                    \"Invalid for Content Range parameters\", self\n                )\n            else:\n                # this case represents `Content-Range: bytes 5-`\n                self.end = self.total - 1\n        else:\n            if self.start is None:\n                # this case represents `Content-Range: bytes -5`\n                self.start = self.total - self.end\n                self.end = self.total - 1\n        if self.start >= self.end:\n            raise ContentRangeError(\n                \"Invalid for Content Range parameters\", self\n            )\n        self.size = self.end - self.start + 1\n        self.headers = {\n            \"Content-Range\": \"bytes %s-%s/%s\"\n            % (self.start, self.end, self.total)\n        }\n\n    def __bool__(self):\n        return self.size > 0\n", "path": "sanic/handlers.py"}]}