Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/werkzeug/exceptions.py: 67%

238 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 06:03 +0000

1"""Implements a number of Python exceptions which can be raised from within 

2a view to trigger a standard HTTP non-200 response. 

3 

4Usage Example 

5------------- 

6 

7.. code-block:: python 

8 

9 from werkzeug.wrappers.request import Request 

10 from werkzeug.exceptions import HTTPException, NotFound 

11 

12 def view(request): 

13 raise NotFound() 

14 

15 @Request.application 

16 def application(request): 

17 try: 

18 return view(request) 

19 except HTTPException as e: 

20 return e 

21 

22As you can see from this example those exceptions are callable WSGI 

23applications. However, they are not Werkzeug response objects. You 

24can get a response object by calling ``get_response()`` on a HTTP 

25exception. 

26 

27Keep in mind that you may have to pass an environ (WSGI) or scope 

28(ASGI) to ``get_response()`` because some errors fetch additional 

29information relating to the request. 

30 

31If you want to hook in a different exception page to say, a 404 status 

32code, you can add a second except for a specific subclass of an error: 

33 

34.. code-block:: python 

35 

36 @Request.application 

37 def application(request): 

38 try: 

39 return view(request) 

40 except NotFound as e: 

41 return not_found(request) 

42 except HTTPException as e: 

43 return e 

44 

45""" 

46import typing as t 

47from datetime import datetime 

48from html import escape 

49 

50from ._internal import _get_environ 

51 

52if t.TYPE_CHECKING: 

53 import typing_extensions as te 

54 from _typeshed.wsgi import StartResponse 

55 from _typeshed.wsgi import WSGIEnvironment 

56 from .datastructures import WWWAuthenticate 

57 from .sansio.response import Response 

58 from .wrappers.request import Request as WSGIRequest # noqa: F401 

59 from .wrappers.response import Response as WSGIResponse # noqa: F401 

60 

61 

62class HTTPException(Exception): 

63 """The base class for all HTTP exceptions. This exception can be called as a WSGI 

64 application to render a default error page or you can catch the subclasses 

65 of it independently and render nicer error messages. 

66 

67 .. versionchanged:: 2.1 

68 Removed the ``wrap`` class method. 

69 """ 

70 

71 code: t.Optional[int] = None 

72 description: t.Optional[str] = None 

73 

74 def __init__( 

75 self, 

76 description: t.Optional[str] = None, 

77 response: t.Optional["Response"] = None, 

78 ) -> None: 

79 super().__init__() 

80 if description is not None: 

81 self.description = description 

82 self.response = response 

83 

84 @property 

85 def name(self) -> str: 

86 """The status name.""" 

87 from .http import HTTP_STATUS_CODES 

88 

89 return HTTP_STATUS_CODES.get(self.code, "Unknown Error") # type: ignore 

90 

91 def get_description( 

92 self, 

93 environ: t.Optional["WSGIEnvironment"] = None, 

94 scope: t.Optional[dict] = None, 

95 ) -> str: 

96 """Get the description.""" 

97 if self.description is None: 

98 description = "" 

99 elif not isinstance(self.description, str): 

100 description = str(self.description) 

101 else: 

102 description = self.description 

103 

104 description = escape(description).replace("\n", "<br>") 

105 return f"<p>{description}</p>" 

106 

107 def get_body( 

108 self, 

109 environ: t.Optional["WSGIEnvironment"] = None, 

110 scope: t.Optional[dict] = None, 

111 ) -> str: 

112 """Get the HTML body.""" 

113 return ( 

114 "<!doctype html>\n" 

115 "<html lang=en>\n" 

116 f"<title>{self.code} {escape(self.name)}</title>\n" 

117 f"<h1>{escape(self.name)}</h1>\n" 

118 f"{self.get_description(environ)}\n" 

119 ) 

120 

121 def get_headers( 

122 self, 

123 environ: t.Optional["WSGIEnvironment"] = None, 

124 scope: t.Optional[dict] = None, 

125 ) -> t.List[t.Tuple[str, str]]: 

126 """Get a list of headers.""" 

127 return [("Content-Type", "text/html; charset=utf-8")] 

128 

129 def get_response( 

130 self, 

131 environ: t.Optional[t.Union["WSGIEnvironment", "WSGIRequest"]] = None, 

132 scope: t.Optional[dict] = None, 

133 ) -> "Response": 

134 """Get a response object. If one was passed to the exception 

135 it's returned directly. 

136 

137 :param environ: the optional environ for the request. This 

138 can be used to modify the response depending 

139 on how the request looked like. 

140 :return: a :class:`Response` object or a subclass thereof. 

141 """ 

142 from .wrappers.response import Response as WSGIResponse # noqa: F811 

143 

144 if self.response is not None: 

145 return self.response 

146 if environ is not None: 

147 environ = _get_environ(environ) 

148 headers = self.get_headers(environ, scope) 

149 return WSGIResponse(self.get_body(environ, scope), self.code, headers) 

150 

151 def __call__( 

152 self, environ: "WSGIEnvironment", start_response: "StartResponse" 

153 ) -> t.Iterable[bytes]: 

154 """Call the exception as WSGI application. 

155 

156 :param environ: the WSGI environment. 

157 :param start_response: the response callable provided by the WSGI 

158 server. 

159 """ 

160 response = t.cast("WSGIResponse", self.get_response(environ)) 

161 return response(environ, start_response) 

162 

163 def __str__(self) -> str: 

164 code = self.code if self.code is not None else "???" 

165 return f"{code} {self.name}: {self.description}" 

166 

167 def __repr__(self) -> str: 

168 code = self.code if self.code is not None else "???" 

169 return f"<{type(self).__name__} '{code}: {self.name}'>" 

170 

171 

172class BadRequest(HTTPException): 

173 """*400* `Bad Request` 

174 

175 Raise if the browser sends something to the application the application 

176 or server cannot handle. 

177 """ 

178 

179 code = 400 

180 description = ( 

181 "The browser (or proxy) sent a request that this server could " 

182 "not understand." 

183 ) 

184 

185 

186class BadRequestKeyError(BadRequest, KeyError): 

187 """An exception that is used to signal both a :exc:`KeyError` and a 

188 :exc:`BadRequest`. Used by many of the datastructures. 

189 """ 

190 

191 _description = BadRequest.description 

192 #: Show the KeyError along with the HTTP error message in the 

193 #: response. This should be disabled in production, but can be 

194 #: useful in a debug mode. 

195 show_exception = False 

196 

197 def __init__(self, arg: t.Optional[str] = None, *args: t.Any, **kwargs: t.Any): 

198 super().__init__(*args, **kwargs) 

199 

200 if arg is None: 

201 KeyError.__init__(self) 

202 else: 

203 KeyError.__init__(self, arg) 

204 

205 @property # type: ignore 

206 def description(self) -> str: # type: ignore 

207 if self.show_exception: 

208 return ( 

209 f"{self._description}\n" 

210 f"{KeyError.__name__}: {KeyError.__str__(self)}" 

211 ) 

212 

213 return self._description 

214 

215 @description.setter 

216 def description(self, value: str) -> None: 

217 self._description = value 

218 

219 

220class ClientDisconnected(BadRequest): 

221 """Internal exception that is raised if Werkzeug detects a disconnected 

222 client. Since the client is already gone at that point attempting to 

223 send the error message to the client might not work and might ultimately 

224 result in another exception in the server. Mainly this is here so that 

225 it is silenced by default as far as Werkzeug is concerned. 

226 

227 Since disconnections cannot be reliably detected and are unspecified 

228 by WSGI to a large extent this might or might not be raised if a client 

229 is gone. 

230 

231 .. versionadded:: 0.8 

232 """ 

233 

234 

235class SecurityError(BadRequest): 

236 """Raised if something triggers a security error. This is otherwise 

237 exactly like a bad request error. 

238 

239 .. versionadded:: 0.9 

240 """ 

241 

242 

243class BadHost(BadRequest): 

244 """Raised if the submitted host is badly formatted. 

245 

246 .. versionadded:: 0.11.2 

247 """ 

248 

249 

250class Unauthorized(HTTPException): 

251 """*401* ``Unauthorized`` 

252 

253 Raise if the user is not authorized to access a resource. 

254 

255 The ``www_authenticate`` argument should be used to set the 

256 ``WWW-Authenticate`` header. This is used for HTTP basic auth and 

257 other schemes. Use :class:`~werkzeug.datastructures.WWWAuthenticate` 

258 to create correctly formatted values. Strictly speaking a 401 

259 response is invalid if it doesn't provide at least one value for 

260 this header, although real clients typically don't care. 

261 

262 :param description: Override the default message used for the body 

263 of the response. 

264 :param www-authenticate: A single value, or list of values, for the 

265 WWW-Authenticate header(s). 

266 

267 .. versionchanged:: 2.0 

268 Serialize multiple ``www_authenticate`` items into multiple 

269 ``WWW-Authenticate`` headers, rather than joining them 

270 into a single value, for better interoperability. 

271 

272 .. versionchanged:: 0.15.3 

273 If the ``www_authenticate`` argument is not set, the 

274 ``WWW-Authenticate`` header is not set. 

275 

276 .. versionchanged:: 0.15.3 

277 The ``response`` argument was restored. 

278 

279 .. versionchanged:: 0.15.1 

280 ``description`` was moved back as the first argument, restoring 

281 its previous position. 

282 

283 .. versionchanged:: 0.15.0 

284 ``www_authenticate`` was added as the first argument, ahead of 

285 ``description``. 

286 """ 

287 

288 code = 401 

289 description = ( 

290 "The server could not verify that you are authorized to access" 

291 " the URL requested. You either supplied the wrong credentials" 

292 " (e.g. a bad password), or your browser doesn't understand" 

293 " how to supply the credentials required." 

294 ) 

295 

296 def __init__( 

297 self, 

298 description: t.Optional[str] = None, 

299 response: t.Optional["Response"] = None, 

300 www_authenticate: t.Optional[ 

301 t.Union["WWWAuthenticate", t.Iterable["WWWAuthenticate"]] 

302 ] = None, 

303 ) -> None: 

304 super().__init__(description, response) 

305 

306 from .datastructures import WWWAuthenticate 

307 

308 if isinstance(www_authenticate, WWWAuthenticate): 

309 www_authenticate = (www_authenticate,) 

310 

311 self.www_authenticate = www_authenticate 

312 

313 def get_headers( 

314 self, 

315 environ: t.Optional["WSGIEnvironment"] = None, 

316 scope: t.Optional[dict] = None, 

317 ) -> t.List[t.Tuple[str, str]]: 

318 headers = super().get_headers(environ, scope) 

319 if self.www_authenticate: 

320 headers.extend(("WWW-Authenticate", str(x)) for x in self.www_authenticate) 

321 return headers 

322 

323 

324class Forbidden(HTTPException): 

325 """*403* `Forbidden` 

326 

327 Raise if the user doesn't have the permission for the requested resource 

328 but was authenticated. 

329 """ 

330 

331 code = 403 

332 description = ( 

333 "You don't have the permission to access the requested" 

334 " resource. It is either read-protected or not readable by the" 

335 " server." 

336 ) 

337 

338 

339class NotFound(HTTPException): 

340 """*404* `Not Found` 

341 

342 Raise if a resource does not exist and never existed. 

343 """ 

344 

345 code = 404 

346 description = ( 

347 "The requested URL was not found on the server. If you entered" 

348 " the URL manually please check your spelling and try again." 

349 ) 

350 

351 

352class MethodNotAllowed(HTTPException): 

353 """*405* `Method Not Allowed` 

354 

355 Raise if the server used a method the resource does not handle. For 

356 example `POST` if the resource is view only. Especially useful for REST. 

357 

358 The first argument for this exception should be a list of allowed methods. 

359 Strictly speaking the response would be invalid if you don't provide valid 

360 methods in the header which you can do with that list. 

361 """ 

362 

363 code = 405 

364 description = "The method is not allowed for the requested URL." 

365 

366 def __init__( 

367 self, 

368 valid_methods: t.Optional[t.Iterable[str]] = None, 

369 description: t.Optional[str] = None, 

370 response: t.Optional["Response"] = None, 

371 ) -> None: 

372 """Takes an optional list of valid http methods 

373 starting with werkzeug 0.3 the list will be mandatory.""" 

374 super().__init__(description=description, response=response) 

375 self.valid_methods = valid_methods 

376 

377 def get_headers( 

378 self, 

379 environ: t.Optional["WSGIEnvironment"] = None, 

380 scope: t.Optional[dict] = None, 

381 ) -> t.List[t.Tuple[str, str]]: 

382 headers = super().get_headers(environ, scope) 

383 if self.valid_methods: 

384 headers.append(("Allow", ", ".join(self.valid_methods))) 

385 return headers 

386 

387 

388class NotAcceptable(HTTPException): 

389 """*406* `Not Acceptable` 

390 

391 Raise if the server can't return any content conforming to the 

392 `Accept` headers of the client. 

393 """ 

394 

395 code = 406 

396 description = ( 

397 "The resource identified by the request is only capable of" 

398 " generating response entities which have content" 

399 " characteristics not acceptable according to the accept" 

400 " headers sent in the request." 

401 ) 

402 

403 

404class RequestTimeout(HTTPException): 

405 """*408* `Request Timeout` 

406 

407 Raise to signalize a timeout. 

408 """ 

409 

410 code = 408 

411 description = ( 

412 "The server closed the network connection because the browser" 

413 " didn't finish the request within the specified time." 

414 ) 

415 

416 

417class Conflict(HTTPException): 

418 """*409* `Conflict` 

419 

420 Raise to signal that a request cannot be completed because it conflicts 

421 with the current state on the server. 

422 

423 .. versionadded:: 0.7 

424 """ 

425 

426 code = 409 

427 description = ( 

428 "A conflict happened while processing the request. The" 

429 " resource might have been modified while the request was being" 

430 " processed." 

431 ) 

432 

433 

434class Gone(HTTPException): 

435 """*410* `Gone` 

436 

437 Raise if a resource existed previously and went away without new location. 

438 """ 

439 

440 code = 410 

441 description = ( 

442 "The requested URL is no longer available on this server and" 

443 " there is no forwarding address. If you followed a link from a" 

444 " foreign page, please contact the author of this page." 

445 ) 

446 

447 

448class LengthRequired(HTTPException): 

449 """*411* `Length Required` 

450 

451 Raise if the browser submitted data but no ``Content-Length`` header which 

452 is required for the kind of processing the server does. 

453 """ 

454 

455 code = 411 

456 description = ( 

457 "A request with this method requires a valid <code>Content-" 

458 "Length</code> header." 

459 ) 

460 

461 

462class PreconditionFailed(HTTPException): 

463 """*412* `Precondition Failed` 

464 

465 Status code used in combination with ``If-Match``, ``If-None-Match``, or 

466 ``If-Unmodified-Since``. 

467 """ 

468 

469 code = 412 

470 description = ( 

471 "The precondition on the request for the URL failed positive evaluation." 

472 ) 

473 

474 

475class RequestEntityTooLarge(HTTPException): 

476 """*413* `Request Entity Too Large` 

477 

478 The status code one should return if the data submitted exceeded a given 

479 limit. 

480 """ 

481 

482 code = 413 

483 description = "The data value transmitted exceeds the capacity limit." 

484 

485 

486class RequestURITooLarge(HTTPException): 

487 """*414* `Request URI Too Large` 

488 

489 Like *413* but for too long URLs. 

490 """ 

491 

492 code = 414 

493 description = ( 

494 "The length of the requested URL exceeds the capacity limit for" 

495 " this server. The request cannot be processed." 

496 ) 

497 

498 

499class UnsupportedMediaType(HTTPException): 

500 """*415* `Unsupported Media Type` 

501 

502 The status code returned if the server is unable to handle the media type 

503 the client transmitted. 

504 """ 

505 

506 code = 415 

507 description = ( 

508 "The server does not support the media type transmitted in the request." 

509 ) 

510 

511 

512class RequestedRangeNotSatisfiable(HTTPException): 

513 """*416* `Requested Range Not Satisfiable` 

514 

515 The client asked for an invalid part of the file. 

516 

517 .. versionadded:: 0.7 

518 """ 

519 

520 code = 416 

521 description = "The server cannot provide the requested range." 

522 

523 def __init__( 

524 self, 

525 length: t.Optional[int] = None, 

526 units: str = "bytes", 

527 description: t.Optional[str] = None, 

528 response: t.Optional["Response"] = None, 

529 ) -> None: 

530 """Takes an optional `Content-Range` header value based on ``length`` 

531 parameter. 

532 """ 

533 super().__init__(description=description, response=response) 

534 self.length = length 

535 self.units = units 

536 

537 def get_headers( 

538 self, 

539 environ: t.Optional["WSGIEnvironment"] = None, 

540 scope: t.Optional[dict] = None, 

541 ) -> t.List[t.Tuple[str, str]]: 

542 headers = super().get_headers(environ, scope) 

543 if self.length is not None: 

544 headers.append(("Content-Range", f"{self.units} */{self.length}")) 

545 return headers 

546 

547 

548class ExpectationFailed(HTTPException): 

549 """*417* `Expectation Failed` 

550 

551 The server cannot meet the requirements of the Expect request-header. 

552 

553 .. versionadded:: 0.7 

554 """ 

555 

556 code = 417 

557 description = "The server could not meet the requirements of the Expect header" 

558 

559 

560class ImATeapot(HTTPException): 

561 """*418* `I'm a teapot` 

562 

563 The server should return this if it is a teapot and someone attempted 

564 to brew coffee with it. 

565 

566 .. versionadded:: 0.7 

567 """ 

568 

569 code = 418 

570 description = "This server is a teapot, not a coffee machine" 

571 

572 

573class UnprocessableEntity(HTTPException): 

574 """*422* `Unprocessable Entity` 

575 

576 Used if the request is well formed, but the instructions are otherwise 

577 incorrect. 

578 """ 

579 

580 code = 422 

581 description = ( 

582 "The request was well-formed but was unable to be followed due" 

583 " to semantic errors." 

584 ) 

585 

586 

587class Locked(HTTPException): 

588 """*423* `Locked` 

589 

590 Used if the resource that is being accessed is locked. 

591 """ 

592 

593 code = 423 

594 description = "The resource that is being accessed is locked." 

595 

596 

597class FailedDependency(HTTPException): 

598 """*424* `Failed Dependency` 

599 

600 Used if the method could not be performed on the resource 

601 because the requested action depended on another action and that action failed. 

602 """ 

603 

604 code = 424 

605 description = ( 

606 "The method could not be performed on the resource because the" 

607 " requested action depended on another action and that action" 

608 " failed." 

609 ) 

610 

611 

612class PreconditionRequired(HTTPException): 

613 """*428* `Precondition Required` 

614 

615 The server requires this request to be conditional, typically to prevent 

616 the lost update problem, which is a race condition between two or more 

617 clients attempting to update a resource through PUT or DELETE. By requiring 

618 each client to include a conditional header ("If-Match" or "If-Unmodified- 

619 Since") with the proper value retained from a recent GET request, the 

620 server ensures that each client has at least seen the previous revision of 

621 the resource. 

622 """ 

623 

624 code = 428 

625 description = ( 

626 "This request is required to be conditional; try using" 

627 ' "If-Match" or "If-Unmodified-Since".' 

628 ) 

629 

630 

631class _RetryAfter(HTTPException): 

632 """Adds an optional ``retry_after`` parameter which will set the 

633 ``Retry-After`` header. May be an :class:`int` number of seconds or 

634 a :class:`~datetime.datetime`. 

635 """ 

636 

637 def __init__( 

638 self, 

639 description: t.Optional[str] = None, 

640 response: t.Optional["Response"] = None, 

641 retry_after: t.Optional[t.Union[datetime, int]] = None, 

642 ) -> None: 

643 super().__init__(description, response) 

644 self.retry_after = retry_after 

645 

646 def get_headers( 

647 self, 

648 environ: t.Optional["WSGIEnvironment"] = None, 

649 scope: t.Optional[dict] = None, 

650 ) -> t.List[t.Tuple[str, str]]: 

651 headers = super().get_headers(environ, scope) 

652 

653 if self.retry_after: 

654 if isinstance(self.retry_after, datetime): 

655 from .http import http_date 

656 

657 value = http_date(self.retry_after) 

658 else: 

659 value = str(self.retry_after) 

660 

661 headers.append(("Retry-After", value)) 

662 

663 return headers 

664 

665 

666class TooManyRequests(_RetryAfter): 

667 """*429* `Too Many Requests` 

668 

669 The server is limiting the rate at which this user receives 

670 responses, and this request exceeds that rate. (The server may use 

671 any convenient method to identify users and their request rates). 

672 The server may include a "Retry-After" header to indicate how long 

673 the user should wait before retrying. 

674 

675 :param retry_after: If given, set the ``Retry-After`` header to this 

676 value. May be an :class:`int` number of seconds or a 

677 :class:`~datetime.datetime`. 

678 

679 .. versionchanged:: 1.0 

680 Added ``retry_after`` parameter. 

681 """ 

682 

683 code = 429 

684 description = "This user has exceeded an allotted request count. Try again later." 

685 

686 

687class RequestHeaderFieldsTooLarge(HTTPException): 

688 """*431* `Request Header Fields Too Large` 

689 

690 The server refuses to process the request because the header fields are too 

691 large. One or more individual fields may be too large, or the set of all 

692 headers is too large. 

693 """ 

694 

695 code = 431 

696 description = "One or more header fields exceeds the maximum size." 

697 

698 

699class UnavailableForLegalReasons(HTTPException): 

700 """*451* `Unavailable For Legal Reasons` 

701 

702 This status code indicates that the server is denying access to the 

703 resource as a consequence of a legal demand. 

704 """ 

705 

706 code = 451 

707 description = "Unavailable for legal reasons." 

708 

709 

710class InternalServerError(HTTPException): 

711 """*500* `Internal Server Error` 

712 

713 Raise if an internal server error occurred. This is a good fallback if an 

714 unknown error occurred in the dispatcher. 

715 

716 .. versionchanged:: 1.0.0 

717 Added the :attr:`original_exception` attribute. 

718 """ 

719 

720 code = 500 

721 description = ( 

722 "The server encountered an internal error and was unable to" 

723 " complete your request. Either the server is overloaded or" 

724 " there is an error in the application." 

725 ) 

726 

727 def __init__( 

728 self, 

729 description: t.Optional[str] = None, 

730 response: t.Optional["Response"] = None, 

731 original_exception: t.Optional[BaseException] = None, 

732 ) -> None: 

733 #: The original exception that caused this 500 error. Can be 

734 #: used by frameworks to provide context when handling 

735 #: unexpected errors. 

736 self.original_exception = original_exception 

737 super().__init__(description=description, response=response) 

738 

739 

740class NotImplemented(HTTPException): 

741 """*501* `Not Implemented` 

742 

743 Raise if the application does not support the action requested by the 

744 browser. 

745 """ 

746 

747 code = 501 

748 description = "The server does not support the action requested by the browser." 

749 

750 

751class BadGateway(HTTPException): 

752 """*502* `Bad Gateway` 

753 

754 If you do proxying in your application you should return this status code 

755 if you received an invalid response from the upstream server it accessed 

756 in attempting to fulfill the request. 

757 """ 

758 

759 code = 502 

760 description = ( 

761 "The proxy server received an invalid response from an upstream server." 

762 ) 

763 

764 

765class ServiceUnavailable(_RetryAfter): 

766 """*503* `Service Unavailable` 

767 

768 Status code you should return if a service is temporarily 

769 unavailable. 

770 

771 :param retry_after: If given, set the ``Retry-After`` header to this 

772 value. May be an :class:`int` number of seconds or a 

773 :class:`~datetime.datetime`. 

774 

775 .. versionchanged:: 1.0 

776 Added ``retry_after`` parameter. 

777 """ 

778 

779 code = 503 

780 description = ( 

781 "The server is temporarily unable to service your request due" 

782 " to maintenance downtime or capacity problems. Please try" 

783 " again later." 

784 ) 

785 

786 

787class GatewayTimeout(HTTPException): 

788 """*504* `Gateway Timeout` 

789 

790 Status code you should return if a connection to an upstream server 

791 times out. 

792 """ 

793 

794 code = 504 

795 description = "The connection to an upstream server timed out." 

796 

797 

798class HTTPVersionNotSupported(HTTPException): 

799 """*505* `HTTP Version Not Supported` 

800 

801 The server does not support the HTTP protocol version used in the request. 

802 """ 

803 

804 code = 505 

805 description = ( 

806 "The server does not support the HTTP protocol version used in the request." 

807 ) 

808 

809 

810default_exceptions: t.Dict[int, t.Type[HTTPException]] = {} 

811 

812 

813def _find_exceptions() -> None: 

814 for obj in globals().values(): 

815 try: 

816 is_http_exception = issubclass(obj, HTTPException) 

817 except TypeError: 

818 is_http_exception = False 

819 if not is_http_exception or obj.code is None: 

820 continue 

821 old_obj = default_exceptions.get(obj.code, None) 

822 if old_obj is not None and issubclass(obj, old_obj): 

823 continue 

824 default_exceptions[obj.code] = obj 

825 

826 

827_find_exceptions() 

828del _find_exceptions 

829 

830 

831class Aborter: 

832 """When passed a dict of code -> exception items it can be used as 

833 callable that raises exceptions. If the first argument to the 

834 callable is an integer it will be looked up in the mapping, if it's 

835 a WSGI application it will be raised in a proxy exception. 

836 

837 The rest of the arguments are forwarded to the exception constructor. 

838 """ 

839 

840 def __init__( 

841 self, 

842 mapping: t.Optional[t.Dict[int, t.Type[HTTPException]]] = None, 

843 extra: t.Optional[t.Dict[int, t.Type[HTTPException]]] = None, 

844 ) -> None: 

845 if mapping is None: 

846 mapping = default_exceptions 

847 self.mapping = dict(mapping) 

848 if extra is not None: 

849 self.mapping.update(extra) 

850 

851 def __call__( 

852 self, code: t.Union[int, "Response"], *args: t.Any, **kwargs: t.Any 

853 ) -> "te.NoReturn": 

854 from .sansio.response import Response 

855 

856 if isinstance(code, Response): 

857 raise HTTPException(response=code) 

858 

859 if code not in self.mapping: 

860 raise LookupError(f"no exception for {code!r}") 

861 

862 raise self.mapping[code](*args, **kwargs) 

863 

864 

865def abort( 

866 status: t.Union[int, "Response"], *args: t.Any, **kwargs: t.Any 

867) -> "te.NoReturn": 

868 """Raises an :py:exc:`HTTPException` for the given status code or WSGI 

869 application. 

870 

871 If a status code is given, it will be looked up in the list of 

872 exceptions and will raise that exception. If passed a WSGI application, 

873 it will wrap it in a proxy WSGI exception and raise that:: 

874 

875 abort(404) # 404 Not Found 

876 abort(Response('Hello World')) 

877 

878 """ 

879 _aborter(status, *args, **kwargs) 

880 

881 

882_aborter: Aborter = Aborter()