We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Enforce exception handler uniquness
1. You should not be able to register the same exception more than once, or at least not on the same App/Blueprint.
2. Handlers should only be fetched in relation to the BP or App context of the matched route. This effectively means that some exceptions (`NotFound` could only be registered app level).

_Originally posted by @ahopkins in https://github.com/sanic-org/sanic/issues/2121#issuecomment-827077284_

--- 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
4 
5 from sanic.errorpages import BaseRenderer, TextRenderer, exception_response
6 from sanic.exceptions import (
7     HeaderNotFound,
8     InvalidRangeType,
9     RangeNotSatisfiable,
10 )
11 from sanic.log import deprecation, error_logger
12 from sanic.models.handler_types import RouteHandler
13 from sanic.response import text
14 
15 
16 class ErrorHandler:
17     """
18     Provide :class:`sanic.app.Sanic` application with a mechanism to handle
19     and process any and all uncaught exceptions in a way the application
20     developer will set fit.
21 
22     This error handling framework is built into the core that can be extended
23     by the developers to perform a wide range of tasks from recording the error
24     stats to reporting them to an external service that can be used for
25     realtime alerting system.
26 
27     """
28 
29     def __init__(
30         self,
31         base: Type[BaseRenderer] = TextRenderer,
32     ):
33         self.cached_handlers: Dict[
34             Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
35         ] = {}
36         self.debug = False
37         self.base = base
38 
39     @classmethod
40     def finalize(cls, *args, **kwargs):
41         deprecation(
42             "ErrorHandler.finalize is deprecated and no longer needed. "
43             "Please remove update your code to remove it. ",
44             22.12,
45         )
46 
47     def _full_lookup(self, exception, route_name: Optional[str] = None):
48         return self.lookup(exception, route_name)
49 
50     def add(self, exception, handler, route_names: Optional[List[str]] = None):
51         """
52         Add a new exception handler to an already existing handler object.
53 
54         :param exception: Type of exception that need to be handled
55         :param handler: Reference to the method that will handle the exception
56 
57         :type exception: :class:`sanic.exceptions.SanicException` or
58             :class:`Exception`
59         :type handler: ``function``
60 
61         :return: None
62         """
63         if route_names:
64             for route in route_names:
65                 self.cached_handlers[(exception, route)] = handler
66         else:
67             self.cached_handlers[(exception, None)] = handler
68 
69     def lookup(self, exception, route_name: Optional[str] = None):
70         """
71         Lookup the existing instance of :class:`ErrorHandler` and fetch the
72         registered handler for a specific type of exception.
73 
74         This method leverages a dict lookup to speedup the retrieval process.
75 
76         :param exception: Type of exception
77 
78         :type exception: :class:`sanic.exceptions.SanicException` or
79             :class:`Exception`
80 
81         :return: Registered function if found ``None`` otherwise
82         """
83         exception_class = type(exception)
84 
85         for name in (route_name, None):
86             exception_key = (exception_class, name)
87             handler = self.cached_handlers.get(exception_key)
88             if handler:
89                 return handler
90 
91         for name in (route_name, None):
92             for ancestor in type.mro(exception_class):
93                 exception_key = (ancestor, name)
94                 if exception_key in self.cached_handlers:
95                     handler = self.cached_handlers[exception_key]
96                     self.cached_handlers[
97                         (exception_class, route_name)
98                     ] = handler
99                     return handler
100 
101                 if ancestor is BaseException:
102                     break
103         self.cached_handlers[(exception_class, route_name)] = None
104         handler = None
105         return handler
106 
107     _lookup = _full_lookup
108 
109     def response(self, request, exception):
110         """Fetches and executes an exception handler and returns a response
111         object
112 
113         :param request: Instance of :class:`sanic.request.Request`
114         :param exception: Exception to handle
115 
116         :type request: :class:`sanic.request.Request`
117         :type exception: :class:`sanic.exceptions.SanicException` or
118             :class:`Exception`
119 
120         :return: Wrap the return value obtained from :func:`default`
121             or registered handler for that type of exception.
122         """
123         route_name = request.name if request else None
124         handler = self._lookup(exception, route_name)
125         response = None
126         try:
127             if handler:
128                 response = handler(request, exception)
129             if response is None:
130                 response = self.default(request, exception)
131         except Exception:
132             try:
133                 url = repr(request.url)
134             except AttributeError:  # no cov
135                 url = "unknown"
136             response_message = (
137                 "Exception raised in exception handler " '"%s" for uri: %s'
138             )
139             error_logger.exception(response_message, handler.__name__, url)
140 
141             if self.debug:
142                 return text(response_message % (handler.__name__, url), 500)
143             else:
144                 return text("An error occurred while handling an error", 500)
145         return response
146 
147     def default(self, request, exception):
148         """
149         Provide a default behavior for the objects of :class:`ErrorHandler`.
150         If a developer chooses to extent the :class:`ErrorHandler` they can
151         provide a custom implementation for this method to behave in a way
152         they see fit.
153 
154         :param request: Incoming request
155         :param exception: Exception object
156 
157         :type request: :class:`sanic.request.Request`
158         :type exception: :class:`sanic.exceptions.SanicException` or
159             :class:`Exception`
160         :return:
161         """
162         self.log(request, exception)
163         fallback = request.app.config.FALLBACK_ERROR_FORMAT
164         return exception_response(
165             request,
166             exception,
167             debug=self.debug,
168             base=self.base,
169             fallback=fallback,
170         )
171 
172     @staticmethod
173     def log(request, exception):
174         quiet = getattr(exception, "quiet", False)
175         noisy = getattr(request.app.config, "NOISY_EXCEPTIONS", False)
176         if quiet is False or noisy is True:
177             try:
178                 url = repr(request.url)
179             except AttributeError:  # no cov
180                 url = "unknown"
181 
182             error_logger.exception(
183                 "Exception occurred while handling uri: %s", url
184             )
185 
186 
187 class ContentRangeHandler:
188     """
189     A mechanism to parse and process the incoming request headers to
190     extract the content range information.
191 
192     :param request: Incoming api request
193     :param stats: Stats related to the content
194 
195     :type request: :class:`sanic.request.Request`
196     :type stats: :class:`posix.stat_result`
197 
198     :ivar start: Content Range start
199     :ivar end: Content Range end
200     :ivar size: Length of the content
201     :ivar total: Total size identified by the :class:`posix.stat_result`
202         instance
203     :ivar ContentRangeHandler.headers: Content range header ``dict``
204     """
205 
206     __slots__ = ("start", "end", "size", "total", "headers")
207 
208     def __init__(self, request, stats):
209         self.total = stats.st_size
210         _range = request.headers.getone("range", None)
211         if _range is None:
212             raise HeaderNotFound("Range Header Not Found")
213         unit, _, value = tuple(map(str.strip, _range.partition("=")))
214         if unit != "bytes":
215             raise InvalidRangeType(
216                 "%s is not a valid Range Type" % (unit,), self
217             )
218         start_b, _, end_b = tuple(map(str.strip, value.partition("-")))
219         try:
220             self.start = int(start_b) if start_b else None
221         except ValueError:
222             raise RangeNotSatisfiable(
223                 "'%s' is invalid for Content Range" % (start_b,), self
224             )
225         try:
226             self.end = int(end_b) if end_b else None
227         except ValueError:
228             raise RangeNotSatisfiable(
229                 "'%s' is invalid for Content Range" % (end_b,), self
230             )
231         if self.end is None:
232             if self.start is None:
233                 raise RangeNotSatisfiable(
234                     "Invalid for Content Range parameters", self
235                 )
236             else:
237                 # this case represents `Content-Range: bytes 5-`
238                 self.end = self.total - 1
239         else:
240             if self.start is None:
241                 # this case represents `Content-Range: bytes -5`
242                 self.start = self.total - self.end
243                 self.end = self.total - 1
244         if self.start >= self.end:
245             raise RangeNotSatisfiable(
246                 "Invalid for Content Range parameters", self
247             )
248         self.size = self.end - self.start + 1
249         self.headers = {
250             "Content-Range": "bytes %s-%s/%s"
251             % (self.start, self.end, self.total)
252         }
253 
254     def __bool__(self):
255         return self.size > 0
256
```
--- 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
@@ -47,6 +47,28 @@
     def _full_lookup(self, exception, route_name: Optional[str] = None):
         return self.lookup(exception, route_name)
 
+    def _add(
+        self,
+        key: Tuple[Type[BaseException], Optional[str]],
+        handler: RouteHandler,
+    ) -> None:
+        if key in self.cached_handlers:
+            exc, name = key
+            if name is None:
+                name = "__ALL_ROUTES__"
+
+            error_logger.warning(
+                f"Duplicate exception handler definition on: route={name} "
+                f"and exception={exc}"
+            )
+            deprecation(
+                "A duplicate exception handler definition was discovered. "
+                "This may cause unintended consequences. A warning has been "
+                "issued now, but it will not be allowed starting in v23.3.",
+                23.3,
+            )
+        self.cached_handlers[key] = handler
+
     def add(self, exception, handler, route_names: Optional[List[str]] = None):
         """
         Add a new exception handler to an already existing handler object.
@@ -62,9 +84,9 @@
         """
         if route_names:
             for route in route_names:
-                self.cached_handlers[(exception, route)] = handler
+                self._add((exception, route), handler)
         else:
-            self.cached_handlers[(exception, None)] = handler
+            self._add((exception, None), handler)
 
     def lookup(self, exception, route_name: Optional[str] = None):
         """

{"golden_diff": "diff --git a/sanic/handlers.py b/sanic/handlers.py\n--- a/sanic/handlers.py\n+++ b/sanic/handlers.py\n@@ -47,6 +47,28 @@\n     def _full_lookup(self, exception, route_name: Optional[str] = None):\n         return self.lookup(exception, route_name)\n \n+    def _add(\n+        self,\n+        key: Tuple[Type[BaseException], Optional[str]],\n+        handler: RouteHandler,\n+    ) -> None:\n+        if key in self.cached_handlers:\n+            exc, name = key\n+            if name is None:\n+                name = \"__ALL_ROUTES__\"\n+\n+            error_logger.warning(\n+                f\"Duplicate exception handler definition on: route={name} \"\n+                f\"and exception={exc}\"\n+            )\n+            deprecation(\n+                \"A duplicate exception handler definition was discovered. \"\n+                \"This may cause unintended consequences. A warning has been \"\n+                \"issued now, but it will not be allowed starting in v23.3.\",\n+                23.3,\n+            )\n+        self.cached_handlers[key] = handler\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@@ -62,9 +84,9 @@\n         \"\"\"\n         if route_names:\n             for route in route_names:\n-                self.cached_handlers[(exception, route)] = handler\n+                self._add((exception, route), handler)\n         else:\n-            self.cached_handlers[(exception, None)] = handler\n+            self._add((exception, None), handler)\n \n     def lookup(self, exception, route_name: Optional[str] = None):\n         \"\"\"\n", "issue": "Enforce exception handler uniquness\n1. You should not be able to register the same exception more than once, or at least not on the same App/Blueprint.\r\n2. Handlers should only be fetched in relation to the BP or App context of the matched route. This effectively means that some exceptions (`NotFound` could only be registered app level).\r\n\r\n_Originally posted by @ahopkins in https://github.com/sanic-org/sanic/issues/2121#issuecomment-827077284_\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom typing import Dict, List, Optional, Tuple, Type\n\nfrom sanic.errorpages import BaseRenderer, TextRenderer, exception_response\nfrom sanic.exceptions import (\n    HeaderNotFound,\n    InvalidRangeType,\n    RangeNotSatisfiable,\n)\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        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.base = base\n\n    @classmethod\n    def finalize(cls, *args, **kwargs):\n        deprecation(\n            \"ErrorHandler.finalize is deprecated and no longer needed. \"\n            \"Please remove update your code to remove it. \",\n            22.12,\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 = request.app.config.FALLBACK_ERROR_FORMAT\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 RangeNotSatisfiable(\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 RangeNotSatisfiable(\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 RangeNotSatisfiable(\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 RangeNotSatisfiable(\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\n\nfrom sanic.errorpages import BaseRenderer, TextRenderer, exception_response\nfrom sanic.exceptions import (\n    HeaderNotFound,\n    InvalidRangeType,\n    RangeNotSatisfiable,\n)\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        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.base = base\n\n    @classmethod\n    def finalize(cls, *args, **kwargs):\n        deprecation(\n            \"ErrorHandler.finalize is deprecated and no longer needed. \"\n            \"Please remove update your code to remove it. \",\n            22.12,\n        )\n\n    def _full_lookup(self, exception, route_name: Optional[str] = None):\n        return self.lookup(exception, route_name)\n\n    def _add(\n        self,\n        key: Tuple[Type[BaseException], Optional[str]],\n        handler: RouteHandler,\n    ) -> None:\n        if key in self.cached_handlers:\n            exc, name = key\n            if name is None:\n                name = \"__ALL_ROUTES__\"\n\n            error_logger.warning(\n                f\"Duplicate exception handler definition on: route={name} \"\n                f\"and exception={exc}\"\n            )\n            deprecation(\n                \"A duplicate exception handler definition was discovered. \"\n                \"This may cause unintended consequences. A warning has been \"\n                \"issued now, but it will not be allowed starting in v23.3.\",\n                23.3,\n            )\n        self.cached_handlers[key] = handler\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._add((exception, route), handler)\n        else:\n            self._add((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 = request.app.config.FALLBACK_ERROR_FORMAT\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 RangeNotSatisfiable(\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 RangeNotSatisfiable(\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 RangeNotSatisfiable(\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 RangeNotSatisfiable(\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"}]}