refactor: consistent exception naming (#2420)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
This commit is contained in:
		| @@ -58,7 +58,7 @@ from sanic.blueprints import Blueprint | ||||
| from sanic.compat import OS_IS_WINDOWS, enable_windows_color_support | ||||
| from sanic.config import SANIC_PREFIX, Config | ||||
| from sanic.exceptions import ( | ||||
|     InvalidUsage, | ||||
|     BadRequest, | ||||
|     SanicException, | ||||
|     ServerError, | ||||
|     URLBuildError, | ||||
| @@ -281,7 +281,7 @@ class Sanic(BaseSanic, RunnerMixin, metaclass=TouchUpMeta): | ||||
|             valid = ", ".join( | ||||
|                 map(lambda x: x.lower(), ListenerEvent.__members__.keys()) | ||||
|             ) | ||||
|             raise InvalidUsage(f"Invalid event: {event}. Use one of: {valid}") | ||||
|             raise BadRequest(f"Invalid event: {event}. Use one of: {valid}") | ||||
|  | ||||
|         if "." in _event: | ||||
|             self.signal(_event.value)( | ||||
|   | ||||
| @@ -19,7 +19,7 @@ import typing as t | ||||
| from functools import partial | ||||
| from traceback import extract_tb | ||||
|  | ||||
| from sanic.exceptions import InvalidUsage, SanicException | ||||
| from sanic.exceptions import BadRequest, SanicException | ||||
| from sanic.helpers import STATUS_CODES | ||||
| from sanic.request import Request | ||||
| from sanic.response import HTTPResponse, html, json, text | ||||
| @@ -506,7 +506,7 @@ def exception_response( | ||||
|                         # $ curl localhost:8000 -d '{"foo": "bar"}' | ||||
|                         # And provide them with JSONRenderer | ||||
|                         renderer = JSONRenderer if request.json else base | ||||
|                     except InvalidUsage: | ||||
|                     except BadRequest: | ||||
|                         renderer = base | ||||
|             else: | ||||
|                 renderer = RENDERERS_BY_CONFIG.get(render_format, renderer) | ||||
|   | ||||
| @@ -42,7 +42,7 @@ class NotFound(SanicException): | ||||
|     quiet = True | ||||
|  | ||||
|  | ||||
| class InvalidUsage(SanicException): | ||||
| class BadRequest(SanicException): | ||||
|     """ | ||||
|     **Status**: 400 Bad Request | ||||
|     """ | ||||
| @@ -51,11 +51,14 @@ class InvalidUsage(SanicException): | ||||
|     quiet = True | ||||
|  | ||||
|  | ||||
| class BadURL(InvalidUsage): | ||||
| InvalidUsage = BadRequest | ||||
|  | ||||
|  | ||||
| class BadURL(BadRequest): | ||||
|     ... | ||||
|  | ||||
|  | ||||
| class MethodNotSupported(SanicException): | ||||
| class MethodNotAllowed(SanicException): | ||||
|     """ | ||||
|     **Status**: 405 Method Not Allowed | ||||
|     """ | ||||
| @@ -68,6 +71,9 @@ class MethodNotSupported(SanicException): | ||||
|         self.headers = {"Allow": ", ".join(allowed_methods)} | ||||
|  | ||||
|  | ||||
| MethodNotSupported = MethodNotAllowed | ||||
|  | ||||
|  | ||||
| class ServerError(SanicException): | ||||
|     """ | ||||
|     **Status**: 500 Internal Server Error | ||||
| @@ -129,19 +135,19 @@ class PayloadTooLarge(SanicException): | ||||
|     quiet = True | ||||
|  | ||||
|  | ||||
| class HeaderNotFound(InvalidUsage): | ||||
| class HeaderNotFound(BadRequest): | ||||
|     """ | ||||
|     **Status**: 400 Bad Request | ||||
|     """ | ||||
|  | ||||
|  | ||||
| class InvalidHeader(InvalidUsage): | ||||
| class InvalidHeader(BadRequest): | ||||
|     """ | ||||
|     **Status**: 400 Bad Request | ||||
|     """ | ||||
|  | ||||
|  | ||||
| class ContentRangeError(SanicException): | ||||
| class RangeNotSatisfiable(SanicException): | ||||
|     """ | ||||
|     **Status**: 416 Range Not Satisfiable | ||||
|     """ | ||||
| @@ -154,7 +160,10 @@ class ContentRangeError(SanicException): | ||||
|         self.headers = {"Content-Range": f"bytes */{content_range.total}"} | ||||
|  | ||||
|  | ||||
| class HeaderExpectationFailed(SanicException): | ||||
| ContentRangeError = RangeNotSatisfiable | ||||
|  | ||||
|  | ||||
| class ExpectationFailed(SanicException): | ||||
|     """ | ||||
|     **Status**: 417 Expectation Failed | ||||
|     """ | ||||
| @@ -163,6 +172,9 @@ class HeaderExpectationFailed(SanicException): | ||||
|     quiet = True | ||||
|  | ||||
|  | ||||
| HeaderExpectationFailed = ExpectationFailed | ||||
|  | ||||
|  | ||||
| class Forbidden(SanicException): | ||||
|     """ | ||||
|     **Status**: 403 Forbidden | ||||
| @@ -172,7 +184,7 @@ class Forbidden(SanicException): | ||||
|     quiet = True | ||||
|  | ||||
|  | ||||
| class InvalidRangeType(ContentRangeError): | ||||
| class InvalidRangeType(RangeNotSatisfiable): | ||||
|     """ | ||||
|     **Status**: 416 Range Not Satisfiable | ||||
|     """ | ||||
|   | ||||
| @@ -10,9 +10,9 @@ from sanic.errorpages import ( | ||||
|     exception_response, | ||||
| ) | ||||
| from sanic.exceptions import ( | ||||
|     ContentRangeError, | ||||
|     HeaderNotFound, | ||||
|     InvalidRangeType, | ||||
|     RangeNotSatisfiable, | ||||
|     SanicException, | ||||
| ) | ||||
| from sanic.helpers import Default, _default | ||||
| @@ -296,18 +296,18 @@ class ContentRangeHandler: | ||||
|         try: | ||||
|             self.start = int(start_b) if start_b else None | ||||
|         except ValueError: | ||||
|             raise ContentRangeError( | ||||
|             raise RangeNotSatisfiable( | ||||
|                 "'%s' is invalid for Content Range" % (start_b,), self | ||||
|             ) | ||||
|         try: | ||||
|             self.end = int(end_b) if end_b else None | ||||
|         except ValueError: | ||||
|             raise ContentRangeError( | ||||
|             raise RangeNotSatisfiable( | ||||
|                 "'%s' is invalid for Content Range" % (end_b,), self | ||||
|             ) | ||||
|         if self.end is None: | ||||
|             if self.start is None: | ||||
|                 raise ContentRangeError( | ||||
|                 raise RangeNotSatisfiable( | ||||
|                     "Invalid for Content Range parameters", self | ||||
|                 ) | ||||
|             else: | ||||
| @@ -319,7 +319,7 @@ class ContentRangeHandler: | ||||
|                 self.start = self.total - self.end | ||||
|                 self.end = self.total - 1 | ||||
|         if self.start >= self.end: | ||||
|             raise ContentRangeError( | ||||
|             raise RangeNotSatisfiable( | ||||
|                 "Invalid for Content Range parameters", self | ||||
|             ) | ||||
|         self.size = self.end - self.start + 1 | ||||
|   | ||||
| @@ -12,8 +12,8 @@ from enum import Enum | ||||
|  | ||||
| from sanic.compat import Header | ||||
| from sanic.exceptions import ( | ||||
|     HeaderExpectationFailed, | ||||
|     InvalidUsage, | ||||
|     BadRequest, | ||||
|     ExpectationFailed, | ||||
|     PayloadTooLarge, | ||||
|     ServerError, | ||||
|     ServiceUnavailable, | ||||
| @@ -53,14 +53,14 @@ class Http(metaclass=TouchUpMeta): | ||||
|     :raises ServerError: | ||||
|     :raises PayloadTooLarge: | ||||
|     :raises Exception: | ||||
|     :raises InvalidUsage: | ||||
|     :raises HeaderExpectationFailed: | ||||
|     :raises BadRequest: | ||||
|     :raises ExpectationFailed: | ||||
|     :raises RuntimeError: | ||||
|     :raises ServerError: | ||||
|     :raises ServerError: | ||||
|     :raises InvalidUsage: | ||||
|     :raises InvalidUsage: | ||||
|     :raises InvalidUsage: | ||||
|     :raises BadRequest: | ||||
|     :raises BadRequest: | ||||
|     :raises BadRequest: | ||||
|     :raises PayloadTooLarge: | ||||
|     :raises RuntimeError: | ||||
|     """ | ||||
| @@ -248,7 +248,7 @@ class Http(metaclass=TouchUpMeta): | ||||
|  | ||||
|                 headers.append(h) | ||||
|         except Exception: | ||||
|             raise InvalidUsage("Bad Request") | ||||
|             raise BadRequest("Bad Request") | ||||
|  | ||||
|         headers_instance = Header(headers) | ||||
|         self.upgrade_websocket = ( | ||||
| @@ -281,7 +281,7 @@ class Http(metaclass=TouchUpMeta): | ||||
|                 if expect.lower() == "100-continue": | ||||
|                     self.expecting_continue = True | ||||
|                 else: | ||||
|                     raise HeaderExpectationFailed(f"Unknown Expect: {expect}") | ||||
|                     raise ExpectationFailed(f"Unknown Expect: {expect}") | ||||
|  | ||||
|             if headers.getone("transfer-encoding", None) == "chunked": | ||||
|                 self.request_body = "chunked" | ||||
| @@ -510,7 +510,7 @@ class Http(metaclass=TouchUpMeta): | ||||
|  | ||||
|                 if len(buf) > 64: | ||||
|                     self.keep_alive = False | ||||
|                     raise InvalidUsage("Bad chunked encoding") | ||||
|                     raise BadRequest("Bad chunked encoding") | ||||
|  | ||||
|                 await self._receive_more() | ||||
|  | ||||
| @@ -518,14 +518,14 @@ class Http(metaclass=TouchUpMeta): | ||||
|                 size = int(buf[2:pos].split(b";", 1)[0].decode(), 16) | ||||
|             except Exception: | ||||
|                 self.keep_alive = False | ||||
|                 raise InvalidUsage("Bad chunked encoding") | ||||
|                 raise BadRequest("Bad chunked encoding") | ||||
|  | ||||
|             if size <= 0: | ||||
|                 self.request_body = None | ||||
|  | ||||
|                 if size < 0: | ||||
|                     self.keep_alive = False | ||||
|                     raise InvalidUsage("Bad chunked encoding") | ||||
|                     raise BadRequest("Bad chunked encoding") | ||||
|  | ||||
|                 # Consume CRLF, chunk size 0 and the two CRLF that follow | ||||
|                 pos += 4 | ||||
|   | ||||
| @@ -3,7 +3,7 @@ from functools import partial | ||||
| from typing import Callable, List, Optional, Union, overload | ||||
|  | ||||
| from sanic.base.meta import SanicMeta | ||||
| from sanic.exceptions import InvalidUsage | ||||
| from sanic.exceptions import BadRequest | ||||
| from sanic.models.futures import FutureListener | ||||
| from sanic.models.handler_types import ListenerType, Sanic | ||||
|  | ||||
| @@ -86,7 +86,7 @@ class ListenerMixin(metaclass=SanicMeta): | ||||
|  | ||||
|         if callable(listener_or_event): | ||||
|             if event_or_none is None: | ||||
|                 raise InvalidUsage( | ||||
|                 raise BadRequest( | ||||
|                     "Invalid event registration: Missing event name." | ||||
|                 ) | ||||
|             return register_listener(listener_or_event, event_or_none) | ||||
|   | ||||
| @@ -18,10 +18,10 @@ from sanic.compat import stat_async | ||||
| from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE, HTTP_METHODS | ||||
| from sanic.errorpages import RESPONSE_MAPPING | ||||
| from sanic.exceptions import ( | ||||
|     ContentRangeError, | ||||
|     BadRequest, | ||||
|     FileNotFound, | ||||
|     HeaderNotFound, | ||||
|     InvalidUsage, | ||||
|     RangeNotSatisfiable, | ||||
| ) | ||||
| from sanic.handlers import ContentRangeHandler | ||||
| from sanic.log import deprecation, error_logger | ||||
| @@ -778,7 +778,7 @@ class RouteMixin(metaclass=SanicMeta): | ||||
|         # Using this to determine if the URL is trying to break out of the path | ||||
|         # served.  os.path.realpath seems to be very slow | ||||
|         if __file_uri__ and "../" in __file_uri__: | ||||
|             raise InvalidUsage("Invalid URL") | ||||
|             raise BadRequest("Invalid URL") | ||||
|         # Merge served directory and requested file if provided | ||||
|         # Strip all / that in the beginning of the URL to help prevent python | ||||
|         # from herping a derp and treating the uri as an absolute path | ||||
| @@ -865,7 +865,7 @@ class RouteMixin(metaclass=SanicMeta): | ||||
|                             file_path, headers=headers, _range=_range | ||||
|                         ) | ||||
|                 return await file(file_path, headers=headers, _range=_range) | ||||
|         except ContentRangeError: | ||||
|         except RangeNotSatisfiable: | ||||
|             raise | ||||
|         except FileNotFoundError: | ||||
|             raise FileNotFound( | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import sys | ||||
|  | ||||
| from typing import Any, Awaitable, Callable, MutableMapping, Optional, Union | ||||
|  | ||||
| from sanic.exceptions import InvalidUsage | ||||
| from sanic.exceptions import BadRequest | ||||
| from sanic.server.websockets.connection import WebSocketConnection | ||||
|  | ||||
|  | ||||
| @@ -84,7 +84,7 @@ class MockTransport:  # no cov | ||||
|         try: | ||||
|             return self._websocket_connection | ||||
|         except AttributeError: | ||||
|             raise InvalidUsage("Improper websocket connection.") | ||||
|             raise BadRequest("Improper websocket connection.") | ||||
|  | ||||
|     def create_websocket_connection( | ||||
|         self, send: ASGISend, receive: ASGIReceive | ||||
|   | ||||
| @@ -35,7 +35,7 @@ from httptools.parser.errors import HttpParserInvalidURLError  # type: ignore | ||||
|  | ||||
| from sanic.compat import CancelledErrors, Header | ||||
| from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE | ||||
| from sanic.exceptions import BadURL, InvalidUsage, ServerError | ||||
| from sanic.exceptions import BadRequest, BadURL, ServerError | ||||
| from sanic.headers import ( | ||||
|     AcceptContainer, | ||||
|     Options, | ||||
| @@ -379,7 +379,7 @@ class Request: | ||||
|         except Exception: | ||||
|             if not self.body: | ||||
|                 return None | ||||
|             raise InvalidUsage("Failed when parsing body as json") | ||||
|             raise BadRequest("Failed when parsing body as json") | ||||
|  | ||||
|         return self.parsed_json | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ from sanic_routing.route import Route  # type: ignore | ||||
|  | ||||
| from sanic.constants import HTTP_METHODS | ||||
| from sanic.errorpages import check_error_format | ||||
| from sanic.exceptions import MethodNotSupported, NotFound, SanicException | ||||
| from sanic.exceptions import MethodNotAllowed, NotFound, SanicException | ||||
| from sanic.models.handler_types import RouteHandler | ||||
|  | ||||
|  | ||||
| @@ -43,7 +43,7 @@ class Router(BaseRouter): | ||||
|         except RoutingNotFound as e: | ||||
|             raise NotFound("Requested URL {} not found".format(e.path)) | ||||
|         except NoMethod as e: | ||||
|             raise MethodNotSupported( | ||||
|             raise MethodNotAllowed( | ||||
|                 "Method {} not allowed for URL {}".format(method, path), | ||||
|                 method=method, | ||||
|                 allowed_methods=e.allowed_methods, | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import uvicorn | ||||
| from sanic import Sanic | ||||
| from sanic.application.state import Mode | ||||
| from sanic.asgi import MockTransport | ||||
| from sanic.exceptions import Forbidden, InvalidUsage, ServiceUnavailable | ||||
| from sanic.exceptions import Forbidden, BadRequest, ServiceUnavailable | ||||
| from sanic.request import Request | ||||
| from sanic.response import json, text | ||||
| from sanic.server.websockets.connection import WebSocketConnection | ||||
| @@ -392,7 +392,7 @@ async def test_websocket_accept_with_multiple_subprotocols( | ||||
|  | ||||
|  | ||||
| def test_improper_websocket_connection(transport, send, receive): | ||||
|     with pytest.raises(InvalidUsage): | ||||
|     with pytest.raises(BadRequest): | ||||
|         transport.get_websocket_connection() | ||||
|  | ||||
|     transport.create_websocket_connection(send, receive) | ||||
|   | ||||
| @@ -5,7 +5,7 @@ from sanic.blueprint_group import BlueprintGroup | ||||
| from sanic.blueprints import Blueprint | ||||
| from sanic.exceptions import ( | ||||
|     Forbidden, | ||||
|     InvalidUsage, | ||||
|     BadRequest, | ||||
|     SanicException, | ||||
|     ServerError, | ||||
| ) | ||||
| @@ -104,7 +104,7 @@ def test_bp_group(app: Sanic): | ||||
|  | ||||
|     @blueprint_1.route("/invalid") | ||||
|     def blueprint_1_error(request: Request): | ||||
|         raise InvalidUsage("Invalid") | ||||
|         raise BadRequest("Invalid") | ||||
|  | ||||
|     @blueprint_2.route("/") | ||||
|     def blueprint_2_default_route(request): | ||||
| @@ -120,7 +120,7 @@ def test_bp_group(app: Sanic): | ||||
|  | ||||
|     blueprint_3 = Blueprint("blueprint_3", url_prefix="/bp3") | ||||
|  | ||||
|     @blueprint_group_1.exception(InvalidUsage) | ||||
|     @blueprint_group_1.exception(BadRequest) | ||||
|     def handle_group_exception(request, exception): | ||||
|         return text("BP1_ERR_OK") | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ from sanic.app import Sanic | ||||
| from sanic.blueprints import Blueprint | ||||
| from sanic.constants import HTTP_METHODS | ||||
| from sanic.exceptions import ( | ||||
|     InvalidUsage, | ||||
|     BadRequest, | ||||
|     NotFound, | ||||
|     SanicException, | ||||
|     ServerError, | ||||
| @@ -448,7 +448,7 @@ def test_bp_exception_handler(app): | ||||
|  | ||||
|     @blueprint.route("/1") | ||||
|     def handler_1(request): | ||||
|         raise InvalidUsage("OK") | ||||
|         raise BadRequest("OK") | ||||
|  | ||||
|     @blueprint.route("/2") | ||||
|     def handler_2(request): | ||||
|   | ||||
| @@ -6,9 +6,16 @@ from bs4 import BeautifulSoup | ||||
|  | ||||
| from sanic import Sanic | ||||
| from sanic.exceptions import ( | ||||
|     BadRequest, | ||||
|     ContentRangeError, | ||||
|     ExpectationFailed, | ||||
|     Forbidden, | ||||
|     HeaderExpectationFailed, | ||||
|     InvalidUsage, | ||||
|     MethodNotAllowed, | ||||
|     MethodNotSupported, | ||||
|     NotFound, | ||||
|     RangeNotSatisfiable, | ||||
|     SanicException, | ||||
|     ServerError, | ||||
|     Unauthorized, | ||||
| @@ -77,7 +84,7 @@ def exception_app(): | ||||
|  | ||||
|     @app.route("/invalid") | ||||
|     def handler_invalid(request): | ||||
|         raise InvalidUsage("OK") | ||||
|         raise BadRequest("OK") | ||||
|  | ||||
|     @app.route("/abort/401") | ||||
|     def handler_401_error(request): | ||||
| @@ -136,7 +143,7 @@ def test_server_error_exception(exception_app): | ||||
|  | ||||
|  | ||||
| def test_invalid_usage_exception(exception_app): | ||||
|     """Test the built-in InvalidUsage exception works""" | ||||
|     """Test the built-in BadRequest exception works""" | ||||
|     request, response = exception_app.test_client.get("/invalid") | ||||
|     assert response.status == 400 | ||||
|  | ||||
| @@ -375,3 +382,10 @@ def test_contextual_exception_functional_message(override): | ||||
|     assert response.status == 418 | ||||
|     assert response.json["message"] == error_message | ||||
|     assert response.json["context"] == {"foo": "bar"} | ||||
|  | ||||
|  | ||||
| def test_exception_aliases(): | ||||
|     assert InvalidUsage is BadRequest | ||||
|     assert MethodNotSupported is MethodNotAllowed | ||||
|     assert ContentRangeError is RangeNotSatisfiable | ||||
|     assert HeaderExpectationFailed is ExpectationFailed | ||||
|   | ||||
| @@ -10,7 +10,7 @@ from bs4 import BeautifulSoup | ||||
| from pytest import LogCaptureFixture, MonkeyPatch | ||||
|  | ||||
| from sanic import Sanic, handlers | ||||
| from sanic.exceptions import Forbidden, InvalidUsage, NotFound, ServerError | ||||
| from sanic.exceptions import Forbidden, BadRequest, NotFound, ServerError | ||||
| from sanic.handlers import ErrorHandler | ||||
| from sanic.request import Request | ||||
| from sanic.response import stream, text | ||||
| @@ -32,7 +32,7 @@ def exception_handler_app(): | ||||
|  | ||||
|     @exception_handler_app.route("/1", error_format="html") | ||||
|     def handler_1(request): | ||||
|         raise InvalidUsage("OK") | ||||
|         raise BadRequest("OK") | ||||
|  | ||||
|     @exception_handler_app.route("/2", error_format="html") | ||||
|     def handler_2(request): | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import pytest | ||||
|  | ||||
| from sanic_testing.testing import HOST, PORT | ||||
|  | ||||
| from sanic.exceptions import InvalidUsage, SanicException | ||||
| from sanic.exceptions import BadRequest, SanicException | ||||
|  | ||||
|  | ||||
| AVAILABLE_LISTENERS = [ | ||||
| @@ -137,7 +137,7 @@ async def test_trigger_before_events_create_server_missing_event(app): | ||||
|     class MySanicDb: | ||||
|         pass | ||||
|  | ||||
|     with pytest.raises(InvalidUsage): | ||||
|     with pytest.raises(BadRequest): | ||||
|  | ||||
|         @app.listener | ||||
|         async def init_db(app, loop): | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import pytest | ||||
| from sanic_testing.testing import HOST, PORT | ||||
|  | ||||
| from sanic.compat import ctrlc_workaround_for_windows | ||||
| from sanic.exceptions import InvalidUsage | ||||
| from sanic.exceptions import BadRequest | ||||
| from sanic.response import HTTPResponse | ||||
|  | ||||
|  | ||||
| @@ -122,6 +122,6 @@ def test_signals_with_invalid_invocation(app): | ||||
|         return HTTPResponse() | ||||
|  | ||||
|     with pytest.raises( | ||||
|         InvalidUsage, match="Invalid event registration: Missing event name" | ||||
|         BadRequest, match="Invalid event registration: Missing event name" | ||||
|     ): | ||||
|         app.listener(stop) | ||||
|   | ||||
| @@ -2,7 +2,6 @@ import pytest | ||||
|  | ||||
| from sanic.blueprints import Blueprint | ||||
| from sanic.constants import HTTP_METHODS | ||||
| from sanic.exceptions import InvalidUsage | ||||
| from sanic.request import Request | ||||
| from sanic.response import HTTPResponse, text | ||||
| from sanic.views import HTTPMethodView | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Néstor Pérez
					Néstor Pérez