Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flask/sansio/app.py: 71%

235 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-09 07:17 +0000

1from __future__ import annotations 

2 

3import logging 

4import os 

5import sys 

6import typing as t 

7from datetime import timedelta 

8from itertools import chain 

9 

10from werkzeug.exceptions import Aborter 

11from werkzeug.exceptions import BadRequest 

12from werkzeug.exceptions import BadRequestKeyError 

13from werkzeug.routing import BuildError 

14from werkzeug.routing import Map 

15from werkzeug.routing import Rule 

16from werkzeug.sansio.response import Response 

17from werkzeug.utils import cached_property 

18from werkzeug.utils import redirect as _wz_redirect 

19 

20from .. import typing as ft 

21from ..config import Config 

22from ..config import ConfigAttribute 

23from ..ctx import _AppCtxGlobals 

24from ..helpers import _split_blueprint_path 

25from ..helpers import get_debug_flag 

26from ..json.provider import DefaultJSONProvider 

27from ..json.provider import JSONProvider 

28from ..logging import create_logger 

29from ..templating import DispatchingJinjaLoader 

30from ..templating import Environment 

31from .scaffold import _endpoint_from_view_func 

32from .scaffold import find_package 

33from .scaffold import Scaffold 

34from .scaffold import setupmethod 

35 

36if t.TYPE_CHECKING: # pragma: no cover 

37 from werkzeug.wrappers import Response as BaseResponse 

38 from .blueprints import Blueprint 

39 from ..testing import FlaskClient 

40 from ..testing import FlaskCliRunner 

41 

42T_shell_context_processor = t.TypeVar( 

43 "T_shell_context_processor", bound=ft.ShellContextProcessorCallable 

44) 

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

46T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) 

47T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) 

48T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) 

49 

50 

51def _make_timedelta(value: timedelta | int | None) -> timedelta | None: 

52 if value is None or isinstance(value, timedelta): 

53 return value 

54 

55 return timedelta(seconds=value) 

56 

57 

58class App(Scaffold): 

59 """The flask object implements a WSGI application and acts as the central 

60 object. It is passed the name of the module or package of the 

61 application. Once it is created it will act as a central registry for 

62 the view functions, the URL rules, template configuration and much more. 

63 

64 The name of the package is used to resolve resources from inside the 

65 package or the folder the module is contained in depending on if the 

66 package parameter resolves to an actual python package (a folder with 

67 an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). 

68 

69 For more information about resource loading, see :func:`open_resource`. 

70 

71 Usually you create a :class:`Flask` instance in your main module or 

72 in the :file:`__init__.py` file of your package like this:: 

73 

74 from flask import Flask 

75 app = Flask(__name__) 

76 

77 .. admonition:: About the First Parameter 

78 

79 The idea of the first parameter is to give Flask an idea of what 

80 belongs to your application. This name is used to find resources 

81 on the filesystem, can be used by extensions to improve debugging 

82 information and a lot more. 

83 

84 So it's important what you provide there. If you are using a single 

85 module, `__name__` is always the correct value. If you however are 

86 using a package, it's usually recommended to hardcode the name of 

87 your package there. 

88 

89 For example if your application is defined in :file:`yourapplication/app.py` 

90 you should create it with one of the two versions below:: 

91 

92 app = Flask('yourapplication') 

93 app = Flask(__name__.split('.')[0]) 

94 

95 Why is that? The application will work even with `__name__`, thanks 

96 to how resources are looked up. However it will make debugging more 

97 painful. Certain extensions can make assumptions based on the 

98 import name of your application. For example the Flask-SQLAlchemy 

99 extension will look for the code in your application that triggered 

100 an SQL query in debug mode. If the import name is not properly set 

101 up, that debugging information is lost. (For example it would only 

102 pick up SQL queries in `yourapplication.app` and not 

103 `yourapplication.views.frontend`) 

104 

105 .. versionadded:: 0.7 

106 The `static_url_path`, `static_folder`, and `template_folder` 

107 parameters were added. 

108 

109 .. versionadded:: 0.8 

110 The `instance_path` and `instance_relative_config` parameters were 

111 added. 

112 

113 .. versionadded:: 0.11 

114 The `root_path` parameter was added. 

115 

116 .. versionadded:: 1.0 

117 The ``host_matching`` and ``static_host`` parameters were added. 

118 

119 .. versionadded:: 1.0 

120 The ``subdomain_matching`` parameter was added. Subdomain 

121 matching needs to be enabled manually now. Setting 

122 :data:`SERVER_NAME` does not implicitly enable it. 

123 

124 :param import_name: the name of the application package 

125 :param static_url_path: can be used to specify a different path for the 

126 static files on the web. Defaults to the name 

127 of the `static_folder` folder. 

128 :param static_folder: The folder with static files that is served at 

129 ``static_url_path``. Relative to the application ``root_path`` 

130 or an absolute path. Defaults to ``'static'``. 

131 :param static_host: the host to use when adding the static route. 

132 Defaults to None. Required when using ``host_matching=True`` 

133 with a ``static_folder`` configured. 

134 :param host_matching: set ``url_map.host_matching`` attribute. 

135 Defaults to False. 

136 :param subdomain_matching: consider the subdomain relative to 

137 :data:`SERVER_NAME` when matching routes. Defaults to False. 

138 :param template_folder: the folder that contains the templates that should 

139 be used by the application. Defaults to 

140 ``'templates'`` folder in the root path of the 

141 application. 

142 :param instance_path: An alternative instance path for the application. 

143 By default the folder ``'instance'`` next to the 

144 package or module is assumed to be the instance 

145 path. 

146 :param instance_relative_config: if set to ``True`` relative filenames 

147 for loading the config are assumed to 

148 be relative to the instance path instead 

149 of the application root. 

150 :param root_path: The path to the root of the application files. 

151 This should only be set manually when it can't be detected 

152 automatically, such as for namespace packages. 

153 """ 

154 

155 #: The class of the object assigned to :attr:`aborter`, created by 

156 #: :meth:`create_aborter`. That object is called by 

157 #: :func:`flask.abort` to raise HTTP errors, and can be 

158 #: called directly as well. 

159 #: 

160 #: Defaults to :class:`werkzeug.exceptions.Aborter`. 

161 #: 

162 #: .. versionadded:: 2.2 

163 aborter_class = Aborter 

164 

165 #: The class that is used for the Jinja environment. 

166 #: 

167 #: .. versionadded:: 0.11 

168 jinja_environment = Environment 

169 

170 #: The class that is used for the :data:`~flask.g` instance. 

171 #: 

172 #: Example use cases for a custom class: 

173 #: 

174 #: 1. Store arbitrary attributes on flask.g. 

175 #: 2. Add a property for lazy per-request database connectors. 

176 #: 3. Return None instead of AttributeError on unexpected attributes. 

177 #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. 

178 #: 

179 #: In Flask 0.9 this property was called `request_globals_class` but it 

180 #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the 

181 #: flask.g object is now application context scoped. 

182 #: 

183 #: .. versionadded:: 0.10 

184 app_ctx_globals_class = _AppCtxGlobals 

185 

186 #: The class that is used for the ``config`` attribute of this app. 

187 #: Defaults to :class:`~flask.Config`. 

188 #: 

189 #: Example use cases for a custom class: 

190 #: 

191 #: 1. Default values for certain config options. 

192 #: 2. Access to config values through attributes in addition to keys. 

193 #: 

194 #: .. versionadded:: 0.11 

195 config_class = Config 

196 

197 #: The testing flag. Set this to ``True`` to enable the test mode of 

198 #: Flask extensions (and in the future probably also Flask itself). 

199 #: For example this might activate test helpers that have an 

200 #: additional runtime cost which should not be enabled by default. 

201 #: 

202 #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the 

203 #: default it's implicitly enabled. 

204 #: 

205 #: This attribute can also be configured from the config with the 

206 #: ``TESTING`` configuration key. Defaults to ``False``. 

207 testing = ConfigAttribute("TESTING") 

208 

209 #: If a secret key is set, cryptographic components can use this to 

210 #: sign cookies and other things. Set this to a complex random value 

211 #: when you want to use the secure cookie for instance. 

212 #: 

213 #: This attribute can also be configured from the config with the 

214 #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. 

215 secret_key = ConfigAttribute("SECRET_KEY") 

216 

217 #: A :class:`~datetime.timedelta` which is used to set the expiration 

218 #: date of a permanent session. The default is 31 days which makes a 

219 #: permanent session survive for roughly one month. 

220 #: 

221 #: This attribute can also be configured from the config with the 

222 #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to 

223 #: ``timedelta(days=31)`` 

224 permanent_session_lifetime = ConfigAttribute( 

225 "PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta 

226 ) 

227 

228 json_provider_class: type[JSONProvider] = DefaultJSONProvider 

229 """A subclass of :class:`~flask.json.provider.JSONProvider`. An 

230 instance is created and assigned to :attr:`app.json` when creating 

231 the app. 

232 

233 The default, :class:`~flask.json.provider.DefaultJSONProvider`, uses 

234 Python's built-in :mod:`json` library. A different provider can use 

235 a different JSON library. 

236 

237 .. versionadded:: 2.2 

238 """ 

239 

240 #: Options that are passed to the Jinja environment in 

241 #: :meth:`create_jinja_environment`. Changing these options after 

242 #: the environment is created (accessing :attr:`jinja_env`) will 

243 #: have no effect. 

244 #: 

245 #: .. versionchanged:: 1.1.0 

246 #: This is a ``dict`` instead of an ``ImmutableDict`` to allow 

247 #: easier configuration. 

248 #: 

249 jinja_options: dict = {} 

250 

251 #: The rule object to use for URL rules created. This is used by 

252 #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. 

253 #: 

254 #: .. versionadded:: 0.7 

255 url_rule_class = Rule 

256 

257 #: The map object to use for storing the URL rules and routing 

258 #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`. 

259 #: 

260 #: .. versionadded:: 1.1.0 

261 url_map_class = Map 

262 

263 #: The :meth:`test_client` method creates an instance of this test 

264 #: client class. Defaults to :class:`~flask.testing.FlaskClient`. 

265 #: 

266 #: .. versionadded:: 0.7 

267 test_client_class: type[FlaskClient] | None = None 

268 

269 #: The :class:`~click.testing.CliRunner` subclass, by default 

270 #: :class:`~flask.testing.FlaskCliRunner` that is used by 

271 #: :meth:`test_cli_runner`. Its ``__init__`` method should take a 

272 #: Flask app object as the first argument. 

273 #: 

274 #: .. versionadded:: 1.0 

275 test_cli_runner_class: type[FlaskCliRunner] | None = None 

276 

277 default_config: dict 

278 response_class: type[Response] 

279 

280 def __init__( 

281 self, 

282 import_name: str, 

283 static_url_path: str | None = None, 

284 static_folder: str | os.PathLike | None = "static", 

285 static_host: str | None = None, 

286 host_matching: bool = False, 

287 subdomain_matching: bool = False, 

288 template_folder: str | os.PathLike | None = "templates", 

289 instance_path: str | None = None, 

290 instance_relative_config: bool = False, 

291 root_path: str | None = None, 

292 ): 

293 super().__init__( 

294 import_name=import_name, 

295 static_folder=static_folder, 

296 static_url_path=static_url_path, 

297 template_folder=template_folder, 

298 root_path=root_path, 

299 ) 

300 

301 if instance_path is None: 

302 instance_path = self.auto_find_instance_path() 

303 elif not os.path.isabs(instance_path): 

304 raise ValueError( 

305 "If an instance path is provided it must be absolute." 

306 " A relative path was given instead." 

307 ) 

308 

309 #: Holds the path to the instance folder. 

310 #: 

311 #: .. versionadded:: 0.8 

312 self.instance_path = instance_path 

313 

314 #: The configuration dictionary as :class:`Config`. This behaves 

315 #: exactly like a regular dictionary but supports additional methods 

316 #: to load a config from files. 

317 self.config = self.make_config(instance_relative_config) 

318 

319 #: An instance of :attr:`aborter_class` created by 

320 #: :meth:`make_aborter`. This is called by :func:`flask.abort` 

321 #: to raise HTTP errors, and can be called directly as well. 

322 #: 

323 #: .. versionadded:: 2.2 

324 #: Moved from ``flask.abort``, which calls this object. 

325 self.aborter = self.make_aborter() 

326 

327 self.json: JSONProvider = self.json_provider_class(self) 

328 """Provides access to JSON methods. Functions in ``flask.json`` 

329 will call methods on this provider when the application context 

330 is active. Used for handling JSON requests and responses. 

331 

332 An instance of :attr:`json_provider_class`. Can be customized by 

333 changing that attribute on a subclass, or by assigning to this 

334 attribute afterwards. 

335 

336 The default, :class:`~flask.json.provider.DefaultJSONProvider`, 

337 uses Python's built-in :mod:`json` library. A different provider 

338 can use a different JSON library. 

339 

340 .. versionadded:: 2.2 

341 """ 

342 

343 #: A list of functions that are called by 

344 #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a 

345 #: :exc:`~werkzeug.routing.BuildError`. Each function is called 

346 #: with ``error``, ``endpoint`` and ``values``. If a function 

347 #: returns ``None`` or raises a ``BuildError``, it is skipped. 

348 #: Otherwise, its return value is returned by ``url_for``. 

349 #: 

350 #: .. versionadded:: 0.9 

351 self.url_build_error_handlers: list[ 

352 t.Callable[[Exception, str, dict[str, t.Any]], str] 

353 ] = [] 

354 

355 #: A list of functions that are called when the application context 

356 #: is destroyed. Since the application context is also torn down 

357 #: if the request ends this is the place to store code that disconnects 

358 #: from databases. 

359 #: 

360 #: .. versionadded:: 0.9 

361 self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] 

362 

363 #: A list of shell context processor functions that should be run 

364 #: when a shell context is created. 

365 #: 

366 #: .. versionadded:: 0.11 

367 self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] 

368 

369 #: Maps registered blueprint names to blueprint objects. The 

370 #: dict retains the order the blueprints were registered in. 

371 #: Blueprints can be registered multiple times, this dict does 

372 #: not track how often they were attached. 

373 #: 

374 #: .. versionadded:: 0.7 

375 self.blueprints: dict[str, Blueprint] = {} 

376 

377 #: a place where extensions can store application specific state. For 

378 #: example this is where an extension could store database engines and 

379 #: similar things. 

380 #: 

381 #: The key must match the name of the extension module. For example in 

382 #: case of a "Flask-Foo" extension in `flask_foo`, the key would be 

383 #: ``'foo'``. 

384 #: 

385 #: .. versionadded:: 0.7 

386 self.extensions: dict = {} 

387 

388 #: The :class:`~werkzeug.routing.Map` for this instance. You can use 

389 #: this to change the routing converters after the class was created 

390 #: but before any routes are connected. Example:: 

391 #: 

392 #: from werkzeug.routing import BaseConverter 

393 #: 

394 #: class ListConverter(BaseConverter): 

395 #: def to_python(self, value): 

396 #: return value.split(',') 

397 #: def to_url(self, values): 

398 #: return ','.join(super(ListConverter, self).to_url(value) 

399 #: for value in values) 

400 #: 

401 #: app = Flask(__name__) 

402 #: app.url_map.converters['list'] = ListConverter 

403 self.url_map = self.url_map_class(host_matching=host_matching) 

404 

405 self.subdomain_matching = subdomain_matching 

406 

407 # tracks internally if the application already handled at least one 

408 # request. 

409 self._got_first_request = False 

410 

411 # Set the name of the Click group in case someone wants to add 

412 # the app's commands to another CLI tool. 

413 self.cli.name = self.name 

414 

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

416 if self._got_first_request: 

417 raise AssertionError( 

418 f"The setup method '{f_name}' can no longer be called" 

419 " on the application. It has already handled its first" 

420 " request, any changes will not be applied" 

421 " consistently.\n" 

422 "Make sure all imports, decorators, functions, etc." 

423 " needed to set up the application are done before" 

424 " running it." 

425 ) 

426 

427 @cached_property 

428 def name(self) -> str: # type: ignore 

429 """The name of the application. This is usually the import name 

430 with the difference that it's guessed from the run file if the 

431 import name is main. This name is used as a display name when 

432 Flask needs the name of the application. It can be set and overridden 

433 to change the value. 

434 

435 .. versionadded:: 0.8 

436 """ 

437 if self.import_name == "__main__": 

438 fn = getattr(sys.modules["__main__"], "__file__", None) 

439 if fn is None: 

440 return "__main__" 

441 return os.path.splitext(os.path.basename(fn))[0] 

442 return self.import_name 

443 

444 @cached_property 

445 def logger(self) -> logging.Logger: 

446 """A standard Python :class:`~logging.Logger` for the app, with 

447 the same name as :attr:`name`. 

448 

449 In debug mode, the logger's :attr:`~logging.Logger.level` will 

450 be set to :data:`~logging.DEBUG`. 

451 

452 If there are no handlers configured, a default handler will be 

453 added. See :doc:`/logging` for more information. 

454 

455 .. versionchanged:: 1.1.0 

456 The logger takes the same name as :attr:`name` rather than 

457 hard-coding ``"flask.app"``. 

458 

459 .. versionchanged:: 1.0.0 

460 Behavior was simplified. The logger is always named 

461 ``"flask.app"``. The level is only set during configuration, 

462 it doesn't check ``app.debug`` each time. Only one format is 

463 used, not different ones depending on ``app.debug``. No 

464 handlers are removed, and a handler is only added if no 

465 handlers are already configured. 

466 

467 .. versionadded:: 0.3 

468 """ 

469 return create_logger(self) 

470 

471 @cached_property 

472 def jinja_env(self) -> Environment: 

473 """The Jinja environment used to load templates. 

474 

475 The environment is created the first time this property is 

476 accessed. Changing :attr:`jinja_options` after that will have no 

477 effect. 

478 """ 

479 return self.create_jinja_environment() 

480 

481 def create_jinja_environment(self) -> Environment: 

482 raise NotImplementedError() 

483 

484 def make_config(self, instance_relative: bool = False) -> Config: 

485 """Used to create the config attribute by the Flask constructor. 

486 The `instance_relative` parameter is passed in from the constructor 

487 of Flask (there named `instance_relative_config`) and indicates if 

488 the config should be relative to the instance path or the root path 

489 of the application. 

490 

491 .. versionadded:: 0.8 

492 """ 

493 root_path = self.root_path 

494 if instance_relative: 

495 root_path = self.instance_path 

496 defaults = dict(self.default_config) 

497 defaults["DEBUG"] = get_debug_flag() 

498 return self.config_class(root_path, defaults) 

499 

500 def make_aborter(self) -> Aborter: 

501 """Create the object to assign to :attr:`aborter`. That object 

502 is called by :func:`flask.abort` to raise HTTP errors, and can 

503 be called directly as well. 

504 

505 By default, this creates an instance of :attr:`aborter_class`, 

506 which defaults to :class:`werkzeug.exceptions.Aborter`. 

507 

508 .. versionadded:: 2.2 

509 """ 

510 return self.aborter_class() 

511 

512 def auto_find_instance_path(self) -> str: 

513 """Tries to locate the instance path if it was not provided to the 

514 constructor of the application class. It will basically calculate 

515 the path to a folder named ``instance`` next to your main file or 

516 the package. 

517 

518 .. versionadded:: 0.8 

519 """ 

520 prefix, package_path = find_package(self.import_name) 

521 if prefix is None: 

522 return os.path.join(package_path, "instance") 

523 return os.path.join(prefix, "var", f"{self.name}-instance") 

524 

525 def create_global_jinja_loader(self) -> DispatchingJinjaLoader: 

526 """Creates the loader for the Jinja2 environment. Can be used to 

527 override just the loader and keeping the rest unchanged. It's 

528 discouraged to override this function. Instead one should override 

529 the :meth:`jinja_loader` function instead. 

530 

531 The global loader dispatches between the loaders of the application 

532 and the individual blueprints. 

533 

534 .. versionadded:: 0.7 

535 """ 

536 return DispatchingJinjaLoader(self) 

537 

538 def select_jinja_autoescape(self, filename: str) -> bool: 

539 """Returns ``True`` if autoescaping should be active for the given 

540 template name. If no template name is given, returns `True`. 

541 

542 .. versionchanged:: 2.2 

543 Autoescaping is now enabled by default for ``.svg`` files. 

544 

545 .. versionadded:: 0.5 

546 """ 

547 if filename is None: 

548 return True 

549 return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) 

550 

551 @property 

552 def debug(self) -> bool: 

553 """Whether debug mode is enabled. When using ``flask run`` to start the 

554 development server, an interactive debugger will be shown for unhandled 

555 exceptions, and the server will be reloaded when code changes. This maps to the 

556 :data:`DEBUG` config key. It may not behave as expected if set late. 

557 

558 **Do not enable debug mode when deploying in production.** 

559 

560 Default: ``False`` 

561 """ 

562 return self.config["DEBUG"] 

563 

564 @debug.setter 

565 def debug(self, value: bool) -> None: 

566 self.config["DEBUG"] = value 

567 

568 if self.config["TEMPLATES_AUTO_RELOAD"] is None: 

569 self.jinja_env.auto_reload = value 

570 

571 @setupmethod 

572 def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: 

573 """Register a :class:`~flask.Blueprint` on the application. Keyword 

574 arguments passed to this method will override the defaults set on the 

575 blueprint. 

576 

577 Calls the blueprint's :meth:`~flask.Blueprint.register` method after 

578 recording the blueprint in the application's :attr:`blueprints`. 

579 

580 :param blueprint: The blueprint to register. 

581 :param url_prefix: Blueprint routes will be prefixed with this. 

582 :param subdomain: Blueprint routes will match on this subdomain. 

583 :param url_defaults: Blueprint routes will use these default values for 

584 view arguments. 

585 :param options: Additional keyword arguments are passed to 

586 :class:`~flask.blueprints.BlueprintSetupState`. They can be 

587 accessed in :meth:`~flask.Blueprint.record` callbacks. 

588 

589 .. versionchanged:: 2.0.1 

590 The ``name`` option can be used to change the (pre-dotted) 

591 name the blueprint is registered with. This allows the same 

592 blueprint to be registered multiple times with unique names 

593 for ``url_for``. 

594 

595 .. versionadded:: 0.7 

596 """ 

597 blueprint.register(self, options) 

598 

599 def iter_blueprints(self) -> t.ValuesView[Blueprint]: 

600 """Iterates over all blueprints by the order they were registered. 

601 

602 .. versionadded:: 0.11 

603 """ 

604 return self.blueprints.values() 

605 

606 @setupmethod 

607 def add_url_rule( 

608 self, 

609 rule: str, 

610 endpoint: str | None = None, 

611 view_func: ft.RouteCallable | None = None, 

612 provide_automatic_options: bool | None = None, 

613 **options: t.Any, 

614 ) -> None: 

615 if endpoint is None: 

616 endpoint = _endpoint_from_view_func(view_func) # type: ignore 

617 options["endpoint"] = endpoint 

618 methods = options.pop("methods", None) 

619 

620 # if the methods are not given and the view_func object knows its 

621 # methods we can use that instead. If neither exists, we go with 

622 # a tuple of only ``GET`` as default. 

623 if methods is None: 

624 methods = getattr(view_func, "methods", None) or ("GET",) 

625 if isinstance(methods, str): 

626 raise TypeError( 

627 "Allowed methods must be a list of strings, for" 

628 ' example: @app.route(..., methods=["POST"])' 

629 ) 

630 methods = {item.upper() for item in methods} 

631 

632 # Methods that should always be added 

633 required_methods = set(getattr(view_func, "required_methods", ())) 

634 

635 # starting with Flask 0.8 the view_func object can disable and 

636 # force-enable the automatic options handling. 

637 if provide_automatic_options is None: 

638 provide_automatic_options = getattr( 

639 view_func, "provide_automatic_options", None 

640 ) 

641 

642 if provide_automatic_options is None: 

643 if "OPTIONS" not in methods: 

644 provide_automatic_options = True 

645 required_methods.add("OPTIONS") 

646 else: 

647 provide_automatic_options = False 

648 

649 # Add the required methods now. 

650 methods |= required_methods 

651 

652 rule = self.url_rule_class(rule, methods=methods, **options) 

653 rule.provide_automatic_options = provide_automatic_options # type: ignore 

654 

655 self.url_map.add(rule) 

656 if view_func is not None: 

657 old_func = self.view_functions.get(endpoint) 

658 if old_func is not None and old_func != view_func: 

659 raise AssertionError( 

660 "View function mapping is overwriting an existing" 

661 f" endpoint function: {endpoint}" 

662 ) 

663 self.view_functions[endpoint] = view_func 

664 

665 @setupmethod 

666 def template_filter( 

667 self, name: str | None = None 

668 ) -> t.Callable[[T_template_filter], T_template_filter]: 

669 """A decorator that is used to register custom template filter. 

670 You can specify a name for the filter, otherwise the function 

671 name will be used. Example:: 

672 

673 @app.template_filter() 

674 def reverse(s): 

675 return s[::-1] 

676 

677 :param name: the optional name of the filter, otherwise the 

678 function name will be used. 

679 """ 

680 

681 def decorator(f: T_template_filter) -> T_template_filter: 

682 self.add_template_filter(f, name=name) 

683 return f 

684 

685 return decorator 

686 

687 @setupmethod 

688 def add_template_filter( 

689 self, f: ft.TemplateFilterCallable, name: str | None = None 

690 ) -> None: 

691 """Register a custom template filter. Works exactly like the 

692 :meth:`template_filter` decorator. 

693 

694 :param name: the optional name of the filter, otherwise the 

695 function name will be used. 

696 """ 

697 self.jinja_env.filters[name or f.__name__] = f 

698 

699 @setupmethod 

700 def template_test( 

701 self, name: str | None = None 

702 ) -> t.Callable[[T_template_test], T_template_test]: 

703 """A decorator that is used to register custom template test. 

704 You can specify a name for the test, otherwise the function 

705 name will be used. Example:: 

706 

707 @app.template_test() 

708 def is_prime(n): 

709 if n == 2: 

710 return True 

711 for i in range(2, int(math.ceil(math.sqrt(n))) + 1): 

712 if n % i == 0: 

713 return False 

714 return True 

715 

716 .. versionadded:: 0.10 

717 

718 :param name: the optional name of the test, otherwise the 

719 function name will be used. 

720 """ 

721 

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

723 self.add_template_test(f, name=name) 

724 return f 

725 

726 return decorator 

727 

728 @setupmethod 

729 def add_template_test( 

730 self, f: ft.TemplateTestCallable, name: str | None = None 

731 ) -> None: 

732 """Register a custom template test. Works exactly like the 

733 :meth:`template_test` decorator. 

734 

735 .. versionadded:: 0.10 

736 

737 :param name: the optional name of the test, otherwise the 

738 function name will be used. 

739 """ 

740 self.jinja_env.tests[name or f.__name__] = f 

741 

742 @setupmethod 

743 def template_global( 

744 self, name: str | None = None 

745 ) -> t.Callable[[T_template_global], T_template_global]: 

746 """A decorator that is used to register a custom template global function. 

747 You can specify a name for the global function, otherwise the function 

748 name will be used. Example:: 

749 

750 @app.template_global() 

751 def double(n): 

752 return 2 * n 

753 

754 .. versionadded:: 0.10 

755 

756 :param name: the optional name of the global function, otherwise the 

757 function name will be used. 

758 """ 

759 

760 def decorator(f: T_template_global) -> T_template_global: 

761 self.add_template_global(f, name=name) 

762 return f 

763 

764 return decorator 

765 

766 @setupmethod 

767 def add_template_global( 

768 self, f: ft.TemplateGlobalCallable, name: str | None = None 

769 ) -> None: 

770 """Register a custom template global function. Works exactly like the 

771 :meth:`template_global` decorator. 

772 

773 .. versionadded:: 0.10 

774 

775 :param name: the optional name of the global function, otherwise the 

776 function name will be used. 

777 """ 

778 self.jinja_env.globals[name or f.__name__] = f 

779 

780 @setupmethod 

781 def teardown_appcontext(self, f: T_teardown) -> T_teardown: 

782 """Registers a function to be called when the application 

783 context is popped. The application context is typically popped 

784 after the request context for each request, at the end of CLI 

785 commands, or after a manually pushed context ends. 

786 

787 .. code-block:: python 

788 

789 with app.app_context(): 

790 ... 

791 

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

793 teardown functions are called just before the app context is 

794 made inactive. Since a request context typically also manages an 

795 application context it would also be called when you pop a 

796 request context. 

797 

798 When a teardown function was called because of an unhandled 

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

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

801 and the teardown will not receive it. 

802 

803 Teardown functions must avoid raising exceptions. If they 

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

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

806 

807 The return values of teardown functions are ignored. 

808 

809 .. versionadded:: 0.9 

810 """ 

811 self.teardown_appcontext_funcs.append(f) 

812 return f 

813 

814 @setupmethod 

815 def shell_context_processor( 

816 self, f: T_shell_context_processor 

817 ) -> T_shell_context_processor: 

818 """Registers a shell context processor function. 

819 

820 .. versionadded:: 0.11 

821 """ 

822 self.shell_context_processors.append(f) 

823 return f 

824 

825 def _find_error_handler( 

826 self, e: Exception, blueprints: list[str] 

827 ) -> ft.ErrorHandlerCallable | None: 

828 """Return a registered error handler for an exception in this order: 

829 blueprint handler for a specific code, app handler for a specific code, 

830 blueprint handler for an exception class, app handler for an exception 

831 class, or ``None`` if a suitable handler is not found. 

832 """ 

833 exc_class, code = self._get_exc_class_and_code(type(e)) 

834 names = (*blueprints, None) 

835 

836 for c in (code, None) if code is not None else (None,): 

837 for name in names: 

838 handler_map = self.error_handler_spec[name][c] 

839 

840 if not handler_map: 

841 continue 

842 

843 for cls in exc_class.__mro__: 

844 handler = handler_map.get(cls) 

845 

846 if handler is not None: 

847 return handler 

848 return None 

849 

850 def trap_http_exception(self, e: Exception) -> bool: 

851 """Checks if an HTTP exception should be trapped or not. By default 

852 this will return ``False`` for all exceptions except for a bad request 

853 key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It 

854 also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. 

855 

856 This is called for all HTTP exceptions raised by a view function. 

857 If it returns ``True`` for any exception the error handler for this 

858 exception is not called and it shows up as regular exception in the 

859 traceback. This is helpful for debugging implicitly raised HTTP 

860 exceptions. 

861 

862 .. versionchanged:: 1.0 

863 Bad request errors are not trapped by default in debug mode. 

864 

865 .. versionadded:: 0.8 

866 """ 

867 if self.config["TRAP_HTTP_EXCEPTIONS"]: 

868 return True 

869 

870 trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] 

871 

872 # if unset, trap key errors in debug mode 

873 if ( 

874 trap_bad_request is None 

875 and self.debug 

876 and isinstance(e, BadRequestKeyError) 

877 ): 

878 return True 

879 

880 if trap_bad_request: 

881 return isinstance(e, BadRequest) 

882 

883 return False 

884 

885 def should_ignore_error(self, error: BaseException | None) -> bool: 

886 """This is called to figure out if an error should be ignored 

887 or not as far as the teardown system is concerned. If this 

888 function returns ``True`` then the teardown handlers will not be 

889 passed the error. 

890 

891 .. versionadded:: 0.10 

892 """ 

893 return False 

894 

895 def redirect(self, location: str, code: int = 302) -> BaseResponse: 

896 """Create a redirect response object. 

897 

898 This is called by :func:`flask.redirect`, and can be called 

899 directly as well. 

900 

901 :param location: The URL to redirect to. 

902 :param code: The status code for the redirect. 

903 

904 .. versionadded:: 2.2 

905 Moved from ``flask.redirect``, which calls this method. 

906 """ 

907 return _wz_redirect( 

908 location, code=code, Response=self.response_class # type: ignore[arg-type] 

909 ) 

910 

911 def inject_url_defaults(self, endpoint: str, values: dict) -> None: 

912 """Injects the URL defaults for the given endpoint directly into 

913 the values dictionary passed. This is used internally and 

914 automatically called on URL building. 

915 

916 .. versionadded:: 0.7 

917 """ 

918 names: t.Iterable[str | None] = (None,) 

919 

920 # url_for may be called outside a request context, parse the 

921 # passed endpoint instead of using request.blueprints. 

922 if "." in endpoint: 

923 names = chain( 

924 names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) 

925 ) 

926 

927 for name in names: 

928 if name in self.url_default_functions: 

929 for func in self.url_default_functions[name]: 

930 func(endpoint, values) 

931 

932 def handle_url_build_error( 

933 self, error: BuildError, endpoint: str, values: dict[str, t.Any] 

934 ) -> str: 

935 """Called by :meth:`.url_for` if a 

936 :exc:`~werkzeug.routing.BuildError` was raised. If this returns 

937 a value, it will be returned by ``url_for``, otherwise the error 

938 will be re-raised. 

939 

940 Each function in :attr:`url_build_error_handlers` is called with 

941 ``error``, ``endpoint`` and ``values``. If a function returns 

942 ``None`` or raises a ``BuildError``, it is skipped. Otherwise, 

943 its return value is returned by ``url_for``. 

944 

945 :param error: The active ``BuildError`` being handled. 

946 :param endpoint: The endpoint being built. 

947 :param values: The keyword arguments passed to ``url_for``. 

948 """ 

949 for handler in self.url_build_error_handlers: 

950 try: 

951 rv = handler(error, endpoint, values) 

952 except BuildError as e: 

953 # make error available outside except block 

954 error = e 

955 else: 

956 if rv is not None: 

957 return rv 

958 

959 # Re-raise if called with an active exception, otherwise raise 

960 # the passed in exception. 

961 if error is sys.exc_info()[1]: 

962 raise 

963 

964 raise error