rewrite Scaffold docs

This commit is contained in:
David Lord 2021-03-08 15:05:47 -08:00
parent 9f7c602a84
commit 7029674775
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
3 changed files with 208 additions and 169 deletions

View file

@ -346,21 +346,6 @@ class Flask(Scaffold):
#: .. versionadded:: 0.8 #: .. versionadded:: 0.8
session_interface = SecureCookieSessionInterface() session_interface = SecureCookieSessionInterface()
# TODO remove the next three attrs when Sphinx :inherited-members: works
# https://github.com/sphinx-doc/sphinx/issues/741
#: The name of the package or module that this app belongs to. Do not
#: change this once it is set by the constructor.
import_name = None
#: Location of the template files to be added to the template lookup.
#: ``None`` if templates should not be added.
template_folder = None
#: Absolute path to the package on the filesystem. Used to look up
#: resources contained in the package.
root_path = None
def __init__( def __init__(
self, self,
import_name, import_name,
@ -1017,58 +1002,6 @@ class Flask(Scaffold):
provide_automatic_options=None, provide_automatic_options=None,
**options, **options,
): ):
"""Connects a URL rule. Works exactly like the :meth:`route`
decorator. If a view_func is provided it will be registered with the
endpoint.
Basically this example::
@app.route('/')
def index():
pass
Is equivalent to the following::
def index():
pass
app.add_url_rule('/', 'index', index)
If the view_func is not provided you will need to connect the endpoint
to a view function like so::
app.view_functions['index'] = index
Internally :meth:`route` invokes :meth:`add_url_rule` so if you want
to customize the behavior via subclassing you only need to change
this method.
For more information refer to :ref:`url-route-registrations`.
.. versionchanged:: 0.2
`view_func` parameter added.
.. versionchanged:: 0.6
``OPTIONS`` is added automatically as method.
:param rule: the URL rule as string
:param endpoint: the endpoint for the registered URL rule. Flask
itself assumes the name of the view function as
endpoint
:param view_func: the function to call when serving a request to the
provided endpoint
:param provide_automatic_options: controls whether the ``OPTIONS``
method should be added automatically. This can also be controlled
by setting the ``view_func.provide_automatic_options = False``
before adding the rule.
:param options: the options to be forwarded to the underlying
:class:`~werkzeug.routing.Rule` object. A change
to Werkzeug is handling of method options. methods
is a list of methods this rule should be limited
to (``GET``, ``POST`` etc.). By default a rule
just listens for ``GET`` (and implicitly ``HEAD``).
Starting with Flask 0.6, ``OPTIONS`` is implicitly
added and handled by the standard request handling.
"""
if endpoint is None: if endpoint is None:
endpoint = _endpoint_from_view_func(view_func) endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint options["endpoint"] = endpoint
@ -2023,6 +1956,7 @@ class Flask(Scaffold):
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the """The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be WSGI application. This calls :meth:`wsgi_app`, which can be
wrapped to applying middleware.""" wrapped to apply middleware.
"""
return self.wsgi_app(environ, start_response) return self.wsgi_app(environ, start_response)

View file

@ -130,28 +130,13 @@ class Blueprint(Scaffold):
warn_on_modifications = False warn_on_modifications = False
_got_registered_once = False _got_registered_once = False
#: Blueprint local JSON encoder class to use. #: Blueprint local JSON encoder class to use. Set to ``None`` to use
#: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_encoder`. #: the app's :class:`~flask.Flask.json_encoder`.
json_encoder = None json_encoder = None
#: Blueprint local JSON decoder class to use. #: Blueprint local JSON decoder class to use. Set to ``None`` to use
#: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_decoder`. #: the app's :class:`~flask.Flask.json_decoder`.
json_decoder = None json_decoder = None
# TODO remove the next three attrs when Sphinx :inherited-members: works
# https://github.com/sphinx-doc/sphinx/issues/741
#: The name of the package or module that this app belongs to. Do not
#: change this once it is set by the constructor.
import_name = None
#: Location of the template files to be added to the template lookup.
#: ``None`` if templates should not be added.
template_folder = None
#: Absolute path to the package on the filesystem. Used to look up
#: resources contained in the package.
root_path = None
def __init__( def __init__(
self, self,
name, name,

View file

@ -1,3 +1,4 @@
import importlib.util
import os import os
import pkgutil import pkgutil
import sys import sys
@ -41,26 +42,39 @@ def setupmethod(f):
class Scaffold: class Scaffold:
"""A common base for :class:`~flask.app.Flask` and """Common behavior shared between :class:`~flask.Flask` and
:class:`~flask.blueprints.Blueprint`. :class:`~flask.blueprints.Blueprint`.
:param import_name: The import name of the module where this object
is defined. Usually :attr:`__name__` should be used.
:param static_folder: Path to a folder of static files to serve.
If this is set, a static route will be added.
:param static_url_path: URL prefix for the static route.
:param template_folder: Path to a folder containing template files.
for rendering. If this is set, a Jinja loader will be added.
:param root_path: The path that static, template, and resource files
are relative to. Typically not set, it is discovered based on
the ``import_name``.
.. versionadded:: 2.0.0
""" """
name: str name: str
_static_folder = None _static_folder = None
_static_url_path = None _static_url_path = None
#: Skeleton local JSON decoder class to use. #: JSON encoder class used by :func:`flask.json.dumps`. If a
#: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_encoder`. #: blueprint sets this, it will be used instead of the app's value.
json_encoder = None json_encoder = None
#: Skeleton local JSON decoder class to use. #: JSON decoder class used by :func:`flask.json.loads`. If a
#: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_decoder`. #: blueprint sets this, it will be used instead of the app's value.
json_decoder = None json_decoder = None
def __init__( def __init__(
self, self,
import_name, import_name,
static_folder="static", static_folder=None,
static_url_path=None, static_url_path=None,
template_folder=None, template_folder=None,
root_path=None, root_path=None,
@ -90,79 +104,105 @@ class Scaffold:
#: been registered. #: been registered.
self.cli = AppGroup() self.cli = AppGroup()
#: A dictionary of all view functions registered. The keys will #: A dictionary mapping endpoint names to view functions.
#: be function names which are also used to generate URLs and #:
#: the values are the function objects themselves.
#: To register a view function, use the :meth:`route` decorator. #: To register a view function, use the :meth:`route` decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.view_functions = {} self.view_functions = {}
#: A dictionary of all registered error handlers. The key is ``None`` #: A data structure of registered error handlers, in the format
#: for error handlers active on the application, otherwise the key is #: ``{scope: {code: {class: handler}}}```. The ``scope`` key is
#: the name of the blueprint. Each key points to another dictionary #: the name of a blueprint the handlers are active for, or
#: where the key is the status code of the http exception. The #: ``None`` for all requests. The ``code`` key is the HTTP
#: special key ``None`` points to a list of tuples where the first item #: status code for ``HTTPException``, or ``None`` for
#: is the class for the instance check and the second the error handler #: other exceptions. The innermost dictionary maps exception
#: function. #: classes to handler functions.
#: #:
#: To register an error handler, use the :meth:`errorhandler` #: To register an error handler, use the :meth:`errorhandler`
#: decorator. #: decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.error_handler_spec = defaultdict(lambda: defaultdict(dict)) self.error_handler_spec = defaultdict(lambda: defaultdict(dict))
#: A dictionary with lists of functions that will be called at the #: A data structure of functions to call at the beginning of
#: beginning of each request. The key of the dictionary is the name of #: each request, in the format ``{scope: [functions]}``. The
#: the blueprint this function is active for, or ``None`` for all #: ``scope`` key is the name of a blueprint the functions are
#: requests. To register a function, use the :meth:`before_request` #: active for, or ``None`` for all requests.
#:
#: To register a function, use the :meth:`before_request`
#: decorator. #: decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.before_request_funcs = defaultdict(list) self.before_request_funcs = defaultdict(list)
#: A dictionary with lists of functions that should be called after #: A data structure of functions to call at the end of each
#: each request. The key of the dictionary is the name of the blueprint #: request, in the format ``{scope: [functions]}``. The
#: this function is active for, ``None`` for all requests. This can for #: ``scope`` key is the name of a blueprint the functions are
#: example be used to close database connections. To register a function #: active for, or ``None`` for all requests.
#: here, use the :meth:`after_request` decorator. #:
#: To register a function, use the :meth:`after_request`
#: decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.after_request_funcs = defaultdict(list) self.after_request_funcs = defaultdict(list)
#: A dictionary with lists of functions that are called after #: A data structure of functions to call at the end of each
#: each request, even if an exception has occurred. The key of the #: request even if an exception is raised, in the format
#: dictionary is the name of the blueprint this function is active for, #: ``{scope: [functions]}``. The ``scope`` key is the name of a
#: ``None`` for all requests. These functions are not allowed to modify #: blueprint the functions are active for, or ``None`` for all
#: the request, and their return values are ignored. If an exception #: requests.
#: occurred while processing the request, it gets passed to each
#: teardown_request function. To register a function here, use the
#: :meth:`teardown_request` decorator.
#: #:
#: .. versionadded:: 0.7 #: To register a function, use the :meth:`teardown_request`
#: decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.teardown_request_funcs = defaultdict(list) self.teardown_request_funcs = defaultdict(list)
#: A dictionary with list of functions that are called without argument #: A data structure of functions to call to pass extra context
#: to populate the template context. The key of the dictionary is the #: values when rendering templates, in the format
#: name of the blueprint this function is active for, ``None`` for all #: ``{scope: [functions]}``. The ``scope`` key is the name of a
#: requests. Each returns a dictionary that the template context is #: blueprint the functions are active for, or ``None`` for all
#: updated with. To register a function here, use the #: requests.
#: :meth:`context_processor` decorator. #:
#: To register a function, use the :meth:`context_processor`
#: decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.template_context_processors = defaultdict( self.template_context_processors = defaultdict(
list, {None: [_default_template_ctx_processor]} list, {None: [_default_template_ctx_processor]}
) )
#: A dictionary with lists of functions that are called before the #: A data structure of functions to call to modify the keyword
#: :attr:`before_request_funcs` functions. The key of the dictionary is #: arguments passed to the view function, in the format
#: the name of the blueprint this function is active for, or ``None`` #: ``{scope: [functions]}``. The ``scope`` key is the name of a
#: for all requests. To register a function, use #: blueprint the functions are active for, or ``None`` for all
#: :meth:`url_value_preprocessor`. #: requests.
#: #:
#: .. versionadded:: 0.7 #: To register a function, use the
#: :meth:`url_value_preprocessor` decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.url_value_preprocessors = defaultdict(list) self.url_value_preprocessors = defaultdict(list)
#: A dictionary with lists of functions that can be used as URL value #: A data structure of functions to call to modify the keyword
#: preprocessors. The key ``None`` here is used for application wide #: arguments when generating URLs, in the format
#: callbacks, otherwise the key is the name of the blueprint. #: ``{scope: [functions]}``. The ``scope`` key is the name of a
#: Each of these functions has the chance to modify the dictionary #: blueprint the functions are active for, or ``None`` for all
#: of URL values before they are used as the keyword arguments of the #: requests.
#: view function. For each function registered this one should also
#: provide a :meth:`url_defaults` function that adds the parameters
#: automatically again that were removed that way.
#: #:
#: .. versionadded:: 0.7 #: To register a function, use the :meth:`url_defaults`
#: decorator.
#:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.url_default_functions = defaultdict(list) self.url_default_functions = defaultdict(list)
def __repr__(self): def __repr__(self):
@ -328,19 +368,26 @@ class Scaffold:
return self._method_route("PATCH", rule, options) return self._method_route("PATCH", rule, options)
def route(self, rule, **options): def route(self, rule, **options):
"""A decorator that is used to register a view function for a """Decorate a view function to register it with the given URL
given URL rule. This does the same thing as :meth:`add_url_rule` rule and options. Calls :meth:`add_url_rule`, which has more
but is used as a decorator. See :meth:`add_url_rule` and details about the implementation.
:ref:`url-route-registrations` for more information.
.. code-block:: python .. code-block:: python
@app.route("/") @app.route("/")
def index(): def index():
return "Hello World" return "Hello, World!"
:param rule: The URL rule as a string. See :ref:`url-route-registrations`.
:param options: The options to be forwarded to the underlying
The endpoint name for the route defaults to the name of the view
function if the ``endpoint`` parameter isn't passed.
The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and
``OPTIONS`` are added automatically.
:param rule: The URL rule string.
:param options: Extra options passed to the
:class:`~werkzeug.routing.Rule` object. :class:`~werkzeug.routing.Rule` object.
""" """
@ -360,17 +407,80 @@ class Scaffold:
provide_automatic_options=None, provide_automatic_options=None,
**options, **options,
): ):
"""Register a rule for routing incoming requests and building
URLs. The :meth:`route` decorator is a shortcut to call this
with the ``view_func`` argument. These are equivalent:
.. code-block:: python
@app.route("/")
def index():
...
.. code-block:: python
def index():
...
app.add_url_rule("/", view_func=index)
See :ref:`url-route-registrations`.
The endpoint name for the route defaults to the name of the view
function if the ``endpoint`` parameter isn't passed. An error
will be raised if a function has already been registered for the
endpoint.
The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is
always added automatically, and ``OPTIONS`` is added
automatically by default.
``view_func`` does not necessarily need to be passed, but if the
rule should participate in routing an endpoint name must be
associated with a view function at some point with the
:meth:`endpoint` decorator.
.. code-block:: python
app.add_url_rule("/", endpoint="index")
@app.endpoint("index")
def index():
...
If ``view_func`` has a ``required_methods`` attribute, those
methods are added to the passed and automatic methods. If it
has a ``provide_automatic_methods`` attribute, it is used as the
default if the parameter is not passed.
:param rule: The URL rule string.
:param endpoint: The endpoint name to associate with the rule
and view function. Used when routing and building URLs.
Defaults to ``view_func.__name__``.
:param view_func: The view function to associate with the
endpoint name.
:param provide_automatic_options: Add the ``OPTIONS`` method and
respond to ``OPTIONS`` requests automatically.
:param options: Extra options passed to the
:class:`~werkzeug.routing.Rule` object.
"""
raise NotImplementedError raise NotImplementedError
def endpoint(self, endpoint): def endpoint(self, endpoint):
"""A decorator to register a function as an endpoint. """Decorate a view function to register it for the given
Example:: endpoint. Used if a rule is added without a ``view_func`` with
:meth:`add_url_rule`.
@app.endpoint('example.endpoint') .. code-block:: python
app.add_url_rule("/ex", endpoint="example")
@app.endpoint("example")
def example(): def example():
return "example" ...
:param endpoint: the name of the endpoint :param endpoint: The endpoint name to associate with the view
function.
""" """
def decorator(f): def decorator(f):
@ -381,28 +491,38 @@ class Scaffold:
@setupmethod @setupmethod
def before_request(self, f): def before_request(self, f):
"""Registers a function to run before each request. """Register a function to run before each request.
For example, this can be used to open a database connection, or to load For example, this can be used to open a database connection, or
the logged in user from the session. to load the logged in user from the session.
The function will be called without any arguments. If it returns a .. code-block:: python
non-None value, the value is handled as if it was the return value from
the view, and further request handling is stopped. @app.before_request
def load_user():
if "user_id" in session:
g.user = db.session.get(session["user_id"])
The function will be called without any arguments. If it returns
a non-``None`` value, the value is handled as if it was the
return value from the view, and further request handling is
stopped.
""" """
self.before_request_funcs[None].append(f) self.before_request_funcs[None].append(f)
return f return f
@setupmethod @setupmethod
def after_request(self, f): def after_request(self, f):
"""Register a function to be run after each request. """Register a function to run after each request to this object.
Your function must take one parameter, an instance of The function is called with the response object, and must return
:attr:`response_class` and return a new response object or the a response object. This allows the functions to modify or
same (see :meth:`process_response`). replace the response before it is sent.
As of Flask 0.7 this function might not be executed at the end of the If a function raises an exception, any remaining
request in case an unhandled exception occurred. ``after_request`` functions will not be called. Therefore, this
should not be used for actions that must execute, such as to
close resources. Use :meth:`teardown_request` for that.
""" """
self.after_request_funcs[None].append(f) self.after_request_funcs[None].append(f)
return f return f
@ -426,8 +546,8 @@ class Scaffold:
stack of active contexts. This becomes relevant if you are using stack of active contexts. This becomes relevant if you are using
such constructs in tests. such constructs in tests.
Generally teardown functions must take every necessary step to avoid Teardown functions must avoid raising exceptions, since they . If they
that they will fail. If they do execute code that might fail they execute code that might fail they
will have to surround the execution of these code by try/except will have to surround the execution of these code by try/except
statements and log occurring errors. statements and log occurring errors.