Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flask/scaffold.py: 39%

254 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1import importlib.util 

2import json 

3import os 

4import pathlib 

5import pkgutil 

6import sys 

7import typing as t 

8from collections import defaultdict 

9from datetime import timedelta 

10from functools import update_wrapper 

11 

12from jinja2 import FileSystemLoader 

13from werkzeug.exceptions import default_exceptions 

14from werkzeug.exceptions import HTTPException 

15 

16from . import typing as ft 

17from .cli import AppGroup 

18from .globals import current_app 

19from .helpers import get_root_path 

20from .helpers import locked_cached_property 

21from .helpers import send_from_directory 

22from .templating import _default_template_ctx_processor 

23 

24if t.TYPE_CHECKING: # pragma: no cover 

25 from .wrappers import Response 

26 

27# a singleton sentinel value for parameter defaults 

28_sentinel = object() 

29 

30F = t.TypeVar("F", bound=t.Callable[..., t.Any]) 

31T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable) 

32T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) 

33T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) 

34T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) 

35T_template_context_processor = t.TypeVar( 

36 "T_template_context_processor", bound=ft.TemplateContextProcessorCallable 

37) 

38T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) 

39T_url_value_preprocessor = t.TypeVar( 

40 "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable 

41) 

42T_route = t.TypeVar("T_route", bound=ft.RouteCallable) 

43 

44 

45def setupmethod(f: F) -> F: 

46 f_name = f.__name__ 

47 

48 def wrapper_func(self, *args: t.Any, **kwargs: t.Any) -> t.Any: 

49 self._check_setup_finished(f_name) 

50 return f(self, *args, **kwargs) 

51 

52 return t.cast(F, update_wrapper(wrapper_func, f)) 

53 

54 

55class Scaffold: 

56 """Common behavior shared between :class:`~flask.Flask` and 

57 :class:`~flask.blueprints.Blueprint`. 

58 

59 :param import_name: The import name of the module where this object 

60 is defined. Usually :attr:`__name__` should be used. 

61 :param static_folder: Path to a folder of static files to serve. 

62 If this is set, a static route will be added. 

63 :param static_url_path: URL prefix for the static route. 

64 :param template_folder: Path to a folder containing template files. 

65 for rendering. If this is set, a Jinja loader will be added. 

66 :param root_path: The path that static, template, and resource files 

67 are relative to. Typically not set, it is discovered based on 

68 the ``import_name``. 

69 

70 .. versionadded:: 2.0 

71 """ 

72 

73 name: str 

74 _static_folder: t.Optional[str] = None 

75 _static_url_path: t.Optional[str] = None 

76 

77 #: JSON encoder class used by :func:`flask.json.dumps`. If a 

78 #: blueprint sets this, it will be used instead of the app's value. 

79 #: 

80 #: .. deprecated:: 2.2 

81 #: Will be removed in Flask 2.3. 

82 json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None 

83 

84 #: JSON decoder class used by :func:`flask.json.loads`. If a 

85 #: blueprint sets this, it will be used instead of the app's value. 

86 #: 

87 #: .. deprecated:: 2.2 

88 #: Will be removed in Flask 2.3. 

89 json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None 

90 

91 def __init__( 

92 self, 

93 import_name: str, 

94 static_folder: t.Optional[t.Union[str, os.PathLike]] = None, 

95 static_url_path: t.Optional[str] = None, 

96 template_folder: t.Optional[t.Union[str, os.PathLike]] = None, 

97 root_path: t.Optional[str] = None, 

98 ): 

99 #: The name of the package or module that this object belongs 

100 #: to. Do not change this once it is set by the constructor. 

101 self.import_name = import_name 

102 

103 self.static_folder = static_folder # type: ignore 

104 self.static_url_path = static_url_path 

105 

106 #: The path to the templates folder, relative to 

107 #: :attr:`root_path`, to add to the template loader. ``None`` if 

108 #: templates should not be added. 

109 self.template_folder = template_folder 

110 

111 if root_path is None: 

112 root_path = get_root_path(self.import_name) 

113 

114 #: Absolute path to the package on the filesystem. Used to look 

115 #: up resources contained in the package. 

116 self.root_path = root_path 

117 

118 #: The Click command group for registering CLI commands for this 

119 #: object. The commands are available from the ``flask`` command 

120 #: once the application has been discovered and blueprints have 

121 #: been registered. 

122 self.cli = AppGroup() 

123 

124 #: A dictionary mapping endpoint names to view functions. 

125 #: 

126 #: To register a view function, use the :meth:`route` decorator. 

127 #: 

128 #: This data structure is internal. It should not be modified 

129 #: directly and its format may change at any time. 

130 self.view_functions: t.Dict[str, t.Callable] = {} 

131 

132 #: A data structure of registered error handlers, in the format 

133 #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is 

134 #: the name of a blueprint the handlers are active for, or 

135 #: ``None`` for all requests. The ``code`` key is the HTTP 

136 #: status code for ``HTTPException``, or ``None`` for 

137 #: other exceptions. The innermost dictionary maps exception 

138 #: classes to handler functions. 

139 #: 

140 #: To register an error handler, use the :meth:`errorhandler` 

141 #: decorator. 

142 #: 

143 #: This data structure is internal. It should not be modified 

144 #: directly and its format may change at any time. 

145 self.error_handler_spec: t.Dict[ 

146 ft.AppOrBlueprintKey, 

147 t.Dict[t.Optional[int], t.Dict[t.Type[Exception], ft.ErrorHandlerCallable]], 

148 ] = defaultdict(lambda: defaultdict(dict)) 

149 

150 #: A data structure of functions to call at the beginning of 

151 #: each request, in the format ``{scope: [functions]}``. The 

152 #: ``scope`` key is the name of a blueprint the functions are 

153 #: active for, or ``None`` for all requests. 

154 #: 

155 #: To register a function, use the :meth:`before_request` 

156 #: decorator. 

157 #: 

158 #: This data structure is internal. It should not be modified 

159 #: directly and its format may change at any time. 

160 self.before_request_funcs: t.Dict[ 

161 ft.AppOrBlueprintKey, t.List[ft.BeforeRequestCallable] 

162 ] = defaultdict(list) 

163 

164 #: A data structure of functions to call at the end of each 

165 #: request, in the format ``{scope: [functions]}``. The 

166 #: ``scope`` key is the name of a blueprint the functions are 

167 #: active for, or ``None`` for all requests. 

168 #: 

169 #: To register a function, use the :meth:`after_request` 

170 #: decorator. 

171 #: 

172 #: This data structure is internal. It should not be modified 

173 #: directly and its format may change at any time. 

174 self.after_request_funcs: t.Dict[ 

175 ft.AppOrBlueprintKey, t.List[ft.AfterRequestCallable] 

176 ] = defaultdict(list) 

177 

178 #: A data structure of functions to call at the end of each 

179 #: request even if an exception is raised, in the format 

180 #: ``{scope: [functions]}``. The ``scope`` key is the name of a 

181 #: blueprint the functions are active for, or ``None`` for all 

182 #: requests. 

183 #: 

184 #: To register a function, use the :meth:`teardown_request` 

185 #: decorator. 

186 #: 

187 #: This data structure is internal. It should not be modified 

188 #: directly and its format may change at any time. 

189 self.teardown_request_funcs: t.Dict[ 

190 ft.AppOrBlueprintKey, t.List[ft.TeardownCallable] 

191 ] = defaultdict(list) 

192 

193 #: A data structure of functions to call to pass extra context 

194 #: values when rendering templates, in the format 

195 #: ``{scope: [functions]}``. The ``scope`` key is the name of a 

196 #: blueprint the functions are active for, or ``None`` for all 

197 #: requests. 

198 #: 

199 #: To register a function, use the :meth:`context_processor` 

200 #: decorator. 

201 #: 

202 #: This data structure is internal. It should not be modified 

203 #: directly and its format may change at any time. 

204 self.template_context_processors: t.Dict[ 

205 ft.AppOrBlueprintKey, t.List[ft.TemplateContextProcessorCallable] 

206 ] = defaultdict(list, {None: [_default_template_ctx_processor]}) 

207 

208 #: A data structure of functions to call to modify the keyword 

209 #: arguments passed to the view function, in the format 

210 #: ``{scope: [functions]}``. The ``scope`` key is the name of a 

211 #: blueprint the functions are active for, or ``None`` for all 

212 #: requests. 

213 #: 

214 #: To register a function, use the 

215 #: :meth:`url_value_preprocessor` decorator. 

216 #: 

217 #: This data structure is internal. It should not be modified 

218 #: directly and its format may change at any time. 

219 self.url_value_preprocessors: t.Dict[ 

220 ft.AppOrBlueprintKey, 

221 t.List[ft.URLValuePreprocessorCallable], 

222 ] = defaultdict(list) 

223 

224 #: A data structure of functions to call to modify the keyword 

225 #: arguments when generating URLs, in the format 

226 #: ``{scope: [functions]}``. The ``scope`` key is the name of a 

227 #: blueprint the functions are active for, or ``None`` for all 

228 #: requests. 

229 #: 

230 #: To register a function, use the :meth:`url_defaults` 

231 #: decorator. 

232 #: 

233 #: This data structure is internal. It should not be modified 

234 #: directly and its format may change at any time. 

235 self.url_default_functions: t.Dict[ 

236 ft.AppOrBlueprintKey, t.List[ft.URLDefaultCallable] 

237 ] = defaultdict(list) 

238 

239 def __repr__(self) -> str: 

240 return f"<{type(self).__name__} {self.name!r}>" 

241 

242 def _check_setup_finished(self, f_name: str) -> None: 

243 raise NotImplementedError 

244 

245 @property 

246 def static_folder(self) -> t.Optional[str]: 

247 """The absolute path to the configured static folder. ``None`` 

248 if no static folder is set. 

249 """ 

250 if self._static_folder is not None: 

251 return os.path.join(self.root_path, self._static_folder) 

252 else: 

253 return None 

254 

255 @static_folder.setter 

256 def static_folder(self, value: t.Optional[t.Union[str, os.PathLike]]) -> None: 

257 if value is not None: 

258 value = os.fspath(value).rstrip(r"\/") 

259 

260 self._static_folder = value 

261 

262 @property 

263 def has_static_folder(self) -> bool: 

264 """``True`` if :attr:`static_folder` is set. 

265 

266 .. versionadded:: 0.5 

267 """ 

268 return self.static_folder is not None 

269 

270 @property 

271 def static_url_path(self) -> t.Optional[str]: 

272 """The URL prefix that the static route will be accessible from. 

273 

274 If it was not configured during init, it is derived from 

275 :attr:`static_folder`. 

276 """ 

277 if self._static_url_path is not None: 

278 return self._static_url_path 

279 

280 if self.static_folder is not None: 

281 basename = os.path.basename(self.static_folder) 

282 return f"/{basename}".rstrip("/") 

283 

284 return None 

285 

286 @static_url_path.setter 

287 def static_url_path(self, value: t.Optional[str]) -> None: 

288 if value is not None: 

289 value = value.rstrip("/") 

290 

291 self._static_url_path = value 

292 

293 def get_send_file_max_age(self, filename: t.Optional[str]) -> t.Optional[int]: 

294 """Used by :func:`send_file` to determine the ``max_age`` cache 

295 value for a given file path if it wasn't passed. 

296 

297 By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from 

298 the configuration of :data:`~flask.current_app`. This defaults 

299 to ``None``, which tells the browser to use conditional requests 

300 instead of a timed cache, which is usually preferable. 

301 

302 .. versionchanged:: 2.0 

303 The default configuration is ``None`` instead of 12 hours. 

304 

305 .. versionadded:: 0.9 

306 """ 

307 value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] 

308 

309 if value is None: 

310 return None 

311 

312 if isinstance(value, timedelta): 

313 return int(value.total_seconds()) 

314 

315 return value 

316 

317 def send_static_file(self, filename: str) -> "Response": 

318 """The view function used to serve files from 

319 :attr:`static_folder`. A route is automatically registered for 

320 this view at :attr:`static_url_path` if :attr:`static_folder` is 

321 set. 

322 

323 .. versionadded:: 0.5 

324 """ 

325 if not self.has_static_folder: 

326 raise RuntimeError("'static_folder' must be set to serve static_files.") 

327 

328 # send_file only knows to call get_send_file_max_age on the app, 

329 # call it here so it works for blueprints too. 

330 max_age = self.get_send_file_max_age(filename) 

331 return send_from_directory( 

332 t.cast(str, self.static_folder), filename, max_age=max_age 

333 ) 

334 

335 @locked_cached_property 

336 def jinja_loader(self) -> t.Optional[FileSystemLoader]: 

337 """The Jinja loader for this object's templates. By default this 

338 is a class :class:`jinja2.loaders.FileSystemLoader` to 

339 :attr:`template_folder` if it is set. 

340 

341 .. versionadded:: 0.5 

342 """ 

343 if self.template_folder is not None: 

344 return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) 

345 else: 

346 return None 

347 

348 def open_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: 

349 """Open a resource file relative to :attr:`root_path` for 

350 reading. 

351 

352 For example, if the file ``schema.sql`` is next to the file 

353 ``app.py`` where the ``Flask`` app is defined, it can be opened 

354 with: 

355 

356 .. code-block:: python 

357 

358 with app.open_resource("schema.sql") as f: 

359 conn.executescript(f.read()) 

360 

361 :param resource: Path to the resource relative to 

362 :attr:`root_path`. 

363 :param mode: Open the file in this mode. Only reading is 

364 supported, valid values are "r" (or "rt") and "rb". 

365 """ 

366 if mode not in {"r", "rt", "rb"}: 

367 raise ValueError("Resources can only be opened for reading.") 

368 

369 return open(os.path.join(self.root_path, resource), mode) 

370 

371 def _method_route( 

372 self, 

373 method: str, 

374 rule: str, 

375 options: dict, 

376 ) -> t.Callable[[T_route], T_route]: 

377 if "methods" in options: 

378 raise TypeError("Use the 'route' decorator to use the 'methods' argument.") 

379 

380 return self.route(rule, methods=[method], **options) 

381 

382 @setupmethod 

383 def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 

384 """Shortcut for :meth:`route` with ``methods=["GET"]``. 

385 

386 .. versionadded:: 2.0 

387 """ 

388 return self._method_route("GET", rule, options) 

389 

390 @setupmethod 

391 def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 

392 """Shortcut for :meth:`route` with ``methods=["POST"]``. 

393 

394 .. versionadded:: 2.0 

395 """ 

396 return self._method_route("POST", rule, options) 

397 

398 @setupmethod 

399 def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 

400 """Shortcut for :meth:`route` with ``methods=["PUT"]``. 

401 

402 .. versionadded:: 2.0 

403 """ 

404 return self._method_route("PUT", rule, options) 

405 

406 @setupmethod 

407 def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 

408 """Shortcut for :meth:`route` with ``methods=["DELETE"]``. 

409 

410 .. versionadded:: 2.0 

411 """ 

412 return self._method_route("DELETE", rule, options) 

413 

414 @setupmethod 

415 def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 

416 """Shortcut for :meth:`route` with ``methods=["PATCH"]``. 

417 

418 .. versionadded:: 2.0 

419 """ 

420 return self._method_route("PATCH", rule, options) 

421 

422 @setupmethod 

423 def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: 

424 """Decorate a view function to register it with the given URL 

425 rule and options. Calls :meth:`add_url_rule`, which has more 

426 details about the implementation. 

427 

428 .. code-block:: python 

429 

430 @app.route("/") 

431 def index(): 

432 return "Hello, World!" 

433 

434 See :ref:`url-route-registrations`. 

435 

436 The endpoint name for the route defaults to the name of the view 

437 function if the ``endpoint`` parameter isn't passed. 

438 

439 The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and 

440 ``OPTIONS`` are added automatically. 

441 

442 :param rule: The URL rule string. 

443 :param options: Extra options passed to the 

444 :class:`~werkzeug.routing.Rule` object. 

445 """ 

446 

447 def decorator(f: T_route) -> T_route: 

448 endpoint = options.pop("endpoint", None) 

449 self.add_url_rule(rule, endpoint, f, **options) 

450 return f 

451 

452 return decorator 

453 

454 @setupmethod 

455 def add_url_rule( 

456 self, 

457 rule: str, 

458 endpoint: t.Optional[str] = None, 

459 view_func: t.Optional[ft.RouteCallable] = None, 

460 provide_automatic_options: t.Optional[bool] = None, 

461 **options: t.Any, 

462 ) -> None: 

463 """Register a rule for routing incoming requests and building 

464 URLs. The :meth:`route` decorator is a shortcut to call this 

465 with the ``view_func`` argument. These are equivalent: 

466 

467 .. code-block:: python 

468 

469 @app.route("/") 

470 def index(): 

471 ... 

472 

473 .. code-block:: python 

474 

475 def index(): 

476 ... 

477 

478 app.add_url_rule("/", view_func=index) 

479 

480 See :ref:`url-route-registrations`. 

481 

482 The endpoint name for the route defaults to the name of the view 

483 function if the ``endpoint`` parameter isn't passed. An error 

484 will be raised if a function has already been registered for the 

485 endpoint. 

486 

487 The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is 

488 always added automatically, and ``OPTIONS`` is added 

489 automatically by default. 

490 

491 ``view_func`` does not necessarily need to be passed, but if the 

492 rule should participate in routing an endpoint name must be 

493 associated with a view function at some point with the 

494 :meth:`endpoint` decorator. 

495 

496 .. code-block:: python 

497 

498 app.add_url_rule("/", endpoint="index") 

499 

500 @app.endpoint("index") 

501 def index(): 

502 ... 

503 

504 If ``view_func`` has a ``required_methods`` attribute, those 

505 methods are added to the passed and automatic methods. If it 

506 has a ``provide_automatic_methods`` attribute, it is used as the 

507 default if the parameter is not passed. 

508 

509 :param rule: The URL rule string. 

510 :param endpoint: The endpoint name to associate with the rule 

511 and view function. Used when routing and building URLs. 

512 Defaults to ``view_func.__name__``. 

513 :param view_func: The view function to associate with the 

514 endpoint name. 

515 :param provide_automatic_options: Add the ``OPTIONS`` method and 

516 respond to ``OPTIONS`` requests automatically. 

517 :param options: Extra options passed to the 

518 :class:`~werkzeug.routing.Rule` object. 

519 """ 

520 raise NotImplementedError 

521 

522 @setupmethod 

523 def endpoint(self, endpoint: str) -> t.Callable[[F], F]: 

524 """Decorate a view function to register it for the given 

525 endpoint. Used if a rule is added without a ``view_func`` with 

526 :meth:`add_url_rule`. 

527 

528 .. code-block:: python 

529 

530 app.add_url_rule("/ex", endpoint="example") 

531 

532 @app.endpoint("example") 

533 def example(): 

534 ... 

535 

536 :param endpoint: The endpoint name to associate with the view 

537 function. 

538 """ 

539 

540 def decorator(f: F) -> F: 

541 self.view_functions[endpoint] = f 

542 return f 

543 

544 return decorator 

545 

546 @setupmethod 

547 def before_request(self, f: T_before_request) -> T_before_request: 

548 """Register a function to run before each request. 

549 

550 For example, this can be used to open a database connection, or 

551 to load the logged in user from the session. 

552 

553 .. code-block:: python 

554 

555 @app.before_request 

556 def load_user(): 

557 if "user_id" in session: 

558 g.user = db.session.get(session["user_id"]) 

559 

560 The function will be called without any arguments. If it returns 

561 a non-``None`` value, the value is handled as if it was the 

562 return value from the view, and further request handling is 

563 stopped. 

564 

565 This is available on both app and blueprint objects. When used on an app, this 

566 executes before every request. When used on a blueprint, this executes before 

567 every request that the blueprint handles. To register with a blueprint and 

568 execute before every request, use :meth:`.Blueprint.before_app_request`. 

569 """ 

570 self.before_request_funcs.setdefault(None, []).append(f) 

571 return f 

572 

573 @setupmethod 

574 def after_request(self, f: T_after_request) -> T_after_request: 

575 """Register a function to run after each request to this object. 

576 

577 The function is called with the response object, and must return 

578 a response object. This allows the functions to modify or 

579 replace the response before it is sent. 

580 

581 If a function raises an exception, any remaining 

582 ``after_request`` functions will not be called. Therefore, this 

583 should not be used for actions that must execute, such as to 

584 close resources. Use :meth:`teardown_request` for that. 

585 

586 This is available on both app and blueprint objects. When used on an app, this 

587 executes after every request. When used on a blueprint, this executes after 

588 every request that the blueprint handles. To register with a blueprint and 

589 execute after every request, use :meth:`.Blueprint.after_app_request`. 

590 """ 

591 self.after_request_funcs.setdefault(None, []).append(f) 

592 return f 

593 

594 @setupmethod 

595 def teardown_request(self, f: T_teardown) -> T_teardown: 

596 """Register a function to be called when the request context is 

597 popped. Typically this happens at the end of each request, but 

598 contexts may be pushed manually as well during testing. 

599 

600 .. code-block:: python 

601 

602 with app.test_request_context(): 

603 ... 

604 

605 When the ``with`` block exits (or ``ctx.pop()`` is called), the 

606 teardown functions are called just before the request context is 

607 made inactive. 

608 

609 When a teardown function was called because of an unhandled 

610 exception it will be passed an error object. If an 

611 :meth:`errorhandler` is registered, it will handle the exception 

612 and the teardown will not receive it. 

613 

614 Teardown functions must avoid raising exceptions. If they 

615 execute code that might fail they must surround that code with a 

616 ``try``/``except`` block and log any errors. 

617 

618 The return values of teardown functions are ignored. 

619 

620 This is available on both app and blueprint objects. When used on an app, this 

621 executes after every request. When used on a blueprint, this executes after 

622 every request that the blueprint handles. To register with a blueprint and 

623 execute after every request, use :meth:`.Blueprint.teardown_app_request`. 

624 """ 

625 self.teardown_request_funcs.setdefault(None, []).append(f) 

626 return f 

627 

628 @setupmethod 

629 def context_processor( 

630 self, 

631 f: T_template_context_processor, 

632 ) -> T_template_context_processor: 

633 """Registers a template context processor function. These functions run before 

634 rendering a template. The keys of the returned dict are added as variables 

635 available in the template. 

636 

637 This is available on both app and blueprint objects. When used on an app, this 

638 is called for every rendered template. When used on a blueprint, this is called 

639 for templates rendered from the blueprint's views. To register with a blueprint 

640 and affect every template, use :meth:`.Blueprint.app_context_processor`. 

641 """ 

642 self.template_context_processors[None].append(f) 

643 return f 

644 

645 @setupmethod 

646 def url_value_preprocessor( 

647 self, 

648 f: T_url_value_preprocessor, 

649 ) -> T_url_value_preprocessor: 

650 """Register a URL value preprocessor function for all view 

651 functions in the application. These functions will be called before the 

652 :meth:`before_request` functions. 

653 

654 The function can modify the values captured from the matched url before 

655 they are passed to the view. For example, this can be used to pop a 

656 common language code value and place it in ``g`` rather than pass it to 

657 every view. 

658 

659 The function is passed the endpoint name and values dict. The return 

660 value is ignored. 

661 

662 This is available on both app and blueprint objects. When used on an app, this 

663 is called for every request. When used on a blueprint, this is called for 

664 requests that the blueprint handles. To register with a blueprint and affect 

665 every request, use :meth:`.Blueprint.app_url_value_preprocessor`. 

666 """ 

667 self.url_value_preprocessors[None].append(f) 

668 return f 

669 

670 @setupmethod 

671 def url_defaults(self, f: T_url_defaults) -> T_url_defaults: 

672 """Callback function for URL defaults for all view functions of the 

673 application. It's called with the endpoint and values and should 

674 update the values passed in place. 

675 

676 This is available on both app and blueprint objects. When used on an app, this 

677 is called for every request. When used on a blueprint, this is called for 

678 requests that the blueprint handles. To register with a blueprint and affect 

679 every request, use :meth:`.Blueprint.app_url_defaults`. 

680 """ 

681 self.url_default_functions[None].append(f) 

682 return f 

683 

684 @setupmethod 

685 def errorhandler( 

686 self, code_or_exception: t.Union[t.Type[Exception], int] 

687 ) -> t.Callable[[T_error_handler], T_error_handler]: 

688 """Register a function to handle errors by code or exception class. 

689 

690 A decorator that is used to register a function given an 

691 error code. Example:: 

692 

693 @app.errorhandler(404) 

694 def page_not_found(error): 

695 return 'This page does not exist', 404 

696 

697 You can also register handlers for arbitrary exceptions:: 

698 

699 @app.errorhandler(DatabaseError) 

700 def special_exception_handler(error): 

701 return 'Database connection failed', 500 

702 

703 This is available on both app and blueprint objects. When used on an app, this 

704 can handle errors from every request. When used on a blueprint, this can handle 

705 errors from requests that the blueprint handles. To register with a blueprint 

706 and affect every request, use :meth:`.Blueprint.app_errorhandler`. 

707 

708 .. versionadded:: 0.7 

709 Use :meth:`register_error_handler` instead of modifying 

710 :attr:`error_handler_spec` directly, for application wide error 

711 handlers. 

712 

713 .. versionadded:: 0.7 

714 One can now additionally also register custom exception types 

715 that do not necessarily have to be a subclass of the 

716 :class:`~werkzeug.exceptions.HTTPException` class. 

717 

718 :param code_or_exception: the code as integer for the handler, or 

719 an arbitrary exception 

720 """ 

721 

722 def decorator(f: T_error_handler) -> T_error_handler: 

723 self.register_error_handler(code_or_exception, f) 

724 return f 

725 

726 return decorator 

727 

728 @setupmethod 

729 def register_error_handler( 

730 self, 

731 code_or_exception: t.Union[t.Type[Exception], int], 

732 f: ft.ErrorHandlerCallable, 

733 ) -> None: 

734 """Alternative error attach function to the :meth:`errorhandler` 

735 decorator that is more straightforward to use for non decorator 

736 usage. 

737 

738 .. versionadded:: 0.7 

739 """ 

740 exc_class, code = self._get_exc_class_and_code(code_or_exception) 

741 self.error_handler_spec[None][code][exc_class] = f 

742 

743 @staticmethod 

744 def _get_exc_class_and_code( 

745 exc_class_or_code: t.Union[t.Type[Exception], int] 

746 ) -> t.Tuple[t.Type[Exception], t.Optional[int]]: 

747 """Get the exception class being handled. For HTTP status codes 

748 or ``HTTPException`` subclasses, return both the exception and 

749 status code. 

750 

751 :param exc_class_or_code: Any exception class, or an HTTP status 

752 code as an integer. 

753 """ 

754 exc_class: t.Type[Exception] 

755 

756 if isinstance(exc_class_or_code, int): 

757 try: 

758 exc_class = default_exceptions[exc_class_or_code] 

759 except KeyError: 

760 raise ValueError( 

761 f"'{exc_class_or_code}' is not a recognized HTTP" 

762 " error code. Use a subclass of HTTPException with" 

763 " that code instead." 

764 ) from None 

765 else: 

766 exc_class = exc_class_or_code 

767 

768 if isinstance(exc_class, Exception): 

769 raise TypeError( 

770 f"{exc_class!r} is an instance, not a class. Handlers" 

771 " can only be registered for Exception classes or HTTP" 

772 " error codes." 

773 ) 

774 

775 if not issubclass(exc_class, Exception): 

776 raise ValueError( 

777 f"'{exc_class.__name__}' is not a subclass of Exception." 

778 " Handlers can only be registered for Exception classes" 

779 " or HTTP error codes." 

780 ) 

781 

782 if issubclass(exc_class, HTTPException): 

783 return exc_class, exc_class.code 

784 else: 

785 return exc_class, None 

786 

787 

788def _endpoint_from_view_func(view_func: t.Callable) -> str: 

789 """Internal helper that returns the default endpoint for a given 

790 function. This always is the function name. 

791 """ 

792 assert view_func is not None, "expected view func if endpoint is not provided." 

793 return view_func.__name__ 

794 

795 

796def _matching_loader_thinks_module_is_package(loader, mod_name): 

797 """Attempt to figure out if the given name is a package or a module. 

798 

799 :param: loader: The loader that handled the name. 

800 :param mod_name: The name of the package or module. 

801 """ 

802 # Use loader.is_package if it's available. 

803 if hasattr(loader, "is_package"): 

804 return loader.is_package(mod_name) 

805 

806 cls = type(loader) 

807 

808 # NamespaceLoader doesn't implement is_package, but all names it 

809 # loads must be packages. 

810 if cls.__module__ == "_frozen_importlib" and cls.__name__ == "NamespaceLoader": 

811 return True 

812 

813 # Otherwise we need to fail with an error that explains what went 

814 # wrong. 

815 raise AttributeError( 

816 f"'{cls.__name__}.is_package()' must be implemented for PEP 302" 

817 f" import hooks." 

818 ) 

819 

820 

821def _path_is_relative_to(path: pathlib.PurePath, base: str) -> bool: 

822 # Path.is_relative_to doesn't exist until Python 3.9 

823 try: 

824 path.relative_to(base) 

825 return True 

826 except ValueError: 

827 return False 

828 

829 

830def _find_package_path(import_name): 

831 """Find the path that contains the package or module.""" 

832 root_mod_name, _, _ = import_name.partition(".") 

833 

834 try: 

835 root_spec = importlib.util.find_spec(root_mod_name) 

836 

837 if root_spec is None: 

838 raise ValueError("not found") 

839 # ImportError: the machinery told us it does not exist 

840 # ValueError: 

841 # - the module name was invalid 

842 # - the module name is __main__ 

843 # - *we* raised `ValueError` due to `root_spec` being `None` 

844 except (ImportError, ValueError): 

845 pass # handled below 

846 else: 

847 # namespace package 

848 if root_spec.origin in {"namespace", None}: 

849 package_spec = importlib.util.find_spec(import_name) 

850 if package_spec is not None and package_spec.submodule_search_locations: 

851 # Pick the path in the namespace that contains the submodule. 

852 package_path = pathlib.Path( 

853 os.path.commonpath(package_spec.submodule_search_locations) 

854 ) 

855 search_locations = ( 

856 location 

857 for location in root_spec.submodule_search_locations 

858 if _path_is_relative_to(package_path, location) 

859 ) 

860 else: 

861 # Pick the first path. 

862 search_locations = iter(root_spec.submodule_search_locations) 

863 return os.path.dirname(next(search_locations)) 

864 # a package (with __init__.py) 

865 elif root_spec.submodule_search_locations: 

866 return os.path.dirname(os.path.dirname(root_spec.origin)) 

867 # just a normal module 

868 else: 

869 return os.path.dirname(root_spec.origin) 

870 

871 # we were unable to find the `package_path` using PEP 451 loaders 

872 loader = pkgutil.get_loader(root_mod_name) 

873 

874 if loader is None or root_mod_name == "__main__": 

875 # import name is not found, or interactive/main module 

876 return os.getcwd() 

877 

878 if hasattr(loader, "get_filename"): 

879 filename = loader.get_filename(root_mod_name) 

880 elif hasattr(loader, "archive"): 

881 # zipimporter's loader.archive points to the .egg or .zip file. 

882 filename = loader.archive 

883 else: 

884 # At least one loader is missing both get_filename and archive: 

885 # Google App Engine's HardenedModulesHook, use __file__. 

886 filename = importlib.import_module(root_mod_name).__file__ 

887 

888 package_path = os.path.abspath(os.path.dirname(filename)) 

889 

890 # If the imported name is a package, filename is currently pointing 

891 # to the root of the package, need to get the current directory. 

892 if _matching_loader_thinks_module_is_package(loader, root_mod_name): 

893 package_path = os.path.dirname(package_path) 

894 

895 return package_path 

896 

897 

898def find_package(import_name: str): 

899 """Find the prefix that a package is installed under, and the path 

900 that it would be imported from. 

901 

902 The prefix is the directory containing the standard directory 

903 hierarchy (lib, bin, etc.). If the package is not installed to the 

904 system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), 

905 ``None`` is returned. 

906 

907 The path is the entry in :attr:`sys.path` that contains the package 

908 for import. If the package is not installed, it's assumed that the 

909 package was imported from the current working directory. 

910 """ 

911 package_path = _find_package_path(import_name) 

912 py_prefix = os.path.abspath(sys.prefix) 

913 

914 # installed to the system 

915 if _path_is_relative_to(pathlib.PurePath(package_path), py_prefix): 

916 return py_prefix, package_path 

917 

918 site_parent, site_folder = os.path.split(package_path) 

919 

920 # installed to a virtualenv 

921 if site_folder.lower() == "site-packages": 

922 parent, folder = os.path.split(site_parent) 

923 

924 # Windows (prefix/lib/site-packages) 

925 if folder.lower() == "lib": 

926 return parent, package_path 

927 

928 # Unix (prefix/lib/pythonX.Y/site-packages) 

929 if os.path.basename(parent).lower() == "lib": 

930 return os.path.dirname(parent), package_path 

931 

932 # something else (prefix/site-packages) 

933 return site_parent, package_path 

934 

935 # not installed 

936 return None, package_path