aboutsummaryrefslogtreecommitdiffstats
path: root/python/flask
diff options
context:
space:
mode:
Diffstat (limited to 'python/flask')
-rw-r--r--python/flask/__init__.py49
-rw-r--r--python/flask/__main__.py14
-rw-r--r--python/flask/_compat.py101
-rw-r--r--python/flask/app.py2334
-rw-r--r--python/flask/blueprints.py447
-rw-r--r--python/flask/cli.py910
-rw-r--r--python/flask/config.py269
-rw-r--r--python/flask/ctx.py457
-rw-r--r--python/flask/debughelpers.py168
-rw-r--r--python/flask/globals.py61
-rw-r--r--python/flask/helpers.py1051
-rw-r--r--python/flask/json/__init__.py357
-rw-r--r--python/flask/json/tag.py300
-rw-r--r--python/flask/logging.py78
-rw-r--r--python/flask/sessions.py385
-rw-r--r--python/flask/signals.py57
-rw-r--r--python/flask/templating.py150
-rw-r--r--python/flask/testing.py246
-rw-r--r--python/flask/views.py158
-rw-r--r--python/flask/wrappers.py216
20 files changed, 0 insertions, 7808 deletions
diff --git a/python/flask/__init__.py b/python/flask/__init__.py
deleted file mode 100644
index 59f0fff..0000000
--- a/python/flask/__init__.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask
- ~~~~~
-
- A microframework based on Werkzeug. It's extensively documented
- and follows best practice patterns.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-__version__ = '1.0.3'
-
-# utilities we import from Werkzeug and Jinja2 that are unused
-# in the module but are exported as public interface.
-from werkzeug.exceptions import abort
-from werkzeug.utils import redirect
-from jinja2 import Markup, escape
-
-from .app import Flask, Request, Response
-from .config import Config
-from .helpers import url_for, flash, send_file, send_from_directory, \
- get_flashed_messages, get_template_attribute, make_response, safe_join, \
- stream_with_context
-from .globals import current_app, g, request, session, _request_ctx_stack, \
- _app_ctx_stack
-from .ctx import has_request_context, has_app_context, \
- after_this_request, copy_current_request_context
-from .blueprints import Blueprint
-from .templating import render_template, render_template_string
-
-# the signals
-from .signals import signals_available, template_rendered, request_started, \
- request_finished, got_request_exception, request_tearing_down, \
- appcontext_tearing_down, appcontext_pushed, \
- appcontext_popped, message_flashed, before_render_template
-
-# We're not exposing the actual json module but a convenient wrapper around
-# it.
-from . import json
-
-# This was the only thing that Flask used to export at one point and it had
-# a more generic name.
-jsonify = json.jsonify
-
-# backwards compat, goes away in 1.0
-from .sessions import SecureCookieSession as Session
-json_available = True
diff --git a/python/flask/__main__.py b/python/flask/__main__.py
deleted file mode 100644
index 4aee654..0000000
--- a/python/flask/__main__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.__main__
- ~~~~~~~~~~~~~~
-
- Alias for flask.run for the command line.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-if __name__ == '__main__':
- from .cli import main
- main(as_module=True)
diff --git a/python/flask/_compat.py b/python/flask/_compat.py
deleted file mode 100644
index dfbaae9..0000000
--- a/python/flask/_compat.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask._compat
- ~~~~~~~~~~~~~
-
- Some py2/py3 compatibility support based on a stripped down
- version of six so we don't have to depend on a specific version
- of it.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import sys
-
-PY2 = sys.version_info[0] == 2
-_identity = lambda x: x
-
-
-if not PY2:
- text_type = str
- string_types = (str,)
- integer_types = (int,)
-
- iterkeys = lambda d: iter(d.keys())
- itervalues = lambda d: iter(d.values())
- iteritems = lambda d: iter(d.items())
-
- from inspect import getfullargspec as getargspec
- from io import StringIO
- import collections.abc as collections_abc
-
- def reraise(tp, value, tb=None):
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
-
- implements_to_string = _identity
-
-else:
- text_type = unicode
- string_types = (str, unicode)
- integer_types = (int, long)
-
- iterkeys = lambda d: d.iterkeys()
- itervalues = lambda d: d.itervalues()
- iteritems = lambda d: d.iteritems()
-
- from inspect import getargspec
- from cStringIO import StringIO
- import collections as collections_abc
-
- exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
-
- def implements_to_string(cls):
- cls.__unicode__ = cls.__str__
- cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
- return cls
-
-
-def with_metaclass(meta, *bases):
- """Create a base class with a metaclass."""
- # This requires a bit of explanation: the basic idea is to make a
- # dummy metaclass for one level of class instantiation that replaces
- # itself with the actual metaclass.
- class metaclass(type):
- def __new__(cls, name, this_bases, d):
- return meta(name, bases, d)
- return type.__new__(metaclass, 'temporary_class', (), {})
-
-
-# Certain versions of pypy have a bug where clearing the exception stack
-# breaks the __exit__ function in a very peculiar way. The second level of
-# exception blocks is necessary because pypy seems to forget to check if an
-# exception happened until the next bytecode instruction?
-#
-# Relevant PyPy bugfix commit:
-# https://bitbucket.org/pypy/pypy/commits/77ecf91c635a287e88e60d8ddb0f4e9df4003301
-# According to ronan on #pypy IRC, it is released in PyPy2 2.3 and later
-# versions.
-#
-# Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug.
-BROKEN_PYPY_CTXMGR_EXIT = False
-if hasattr(sys, 'pypy_version_info'):
- class _Mgr(object):
- def __enter__(self):
- return self
- def __exit__(self, *args):
- if hasattr(sys, 'exc_clear'):
- # Python 3 (PyPy3) doesn't have exc_clear
- sys.exc_clear()
- try:
- try:
- with _Mgr():
- raise AssertionError()
- except:
- raise
- except TypeError:
- BROKEN_PYPY_CTXMGR_EXIT = True
- except AssertionError:
- pass
diff --git a/python/flask/app.py b/python/flask/app.py
deleted file mode 100644
index c570a95..0000000
--- a/python/flask/app.py
+++ /dev/null
@@ -1,2334 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.app
- ~~~~~~~~~
-
- This module implements the central WSGI application object.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import os
-import sys
-import warnings
-from datetime import timedelta
-from functools import update_wrapper
-from itertools import chain
-from threading import Lock
-
-from werkzeug.datastructures import Headers, ImmutableDict
-from werkzeug.exceptions import BadRequest, BadRequestKeyError, HTTPException, \
- InternalServerError, MethodNotAllowed, default_exceptions
-from werkzeug.routing import BuildError, Map, RequestRedirect, \
- RoutingException, Rule
-
-from . import cli, json
-from ._compat import integer_types, reraise, string_types, text_type
-from .config import Config, ConfigAttribute
-from .ctx import AppContext, RequestContext, _AppCtxGlobals
-from .globals import _request_ctx_stack, g, request, session
-from .helpers import (
- _PackageBoundObject,
- _endpoint_from_view_func, find_package, get_env, get_debug_flag,
- get_flashed_messages, locked_cached_property, url_for, get_load_dotenv
-)
-from .logging import create_logger
-from .sessions import SecureCookieSessionInterface
-from .signals import appcontext_tearing_down, got_request_exception, \
- request_finished, request_started, request_tearing_down
-from .templating import DispatchingJinjaLoader, Environment, \
- _default_template_ctx_processor
-from .wrappers import Request, Response
-
-# a singleton sentinel value for parameter defaults
-_sentinel = object()
-
-
-def _make_timedelta(value):
- if not isinstance(value, timedelta):
- return timedelta(seconds=value)
- return value
-
-
-def setupmethod(f):
- """Wraps a method so that it performs a check in debug mode if the
- first request was already handled.
- """
- def wrapper_func(self, *args, **kwargs):
- if self.debug and self._got_first_request:
- raise AssertionError('A setup function was called after the '
- 'first request was handled. This usually indicates a bug '
- 'in the application where a module was not imported '
- 'and decorators or other functionality was called too late.\n'
- 'To fix this make sure to import all your view modules, '
- 'database models and everything related at a central place '
- 'before the application starts serving requests.')
- return f(self, *args, **kwargs)
- return update_wrapper(wrapper_func, f)
-
-
-class Flask(_PackageBoundObject):
- """The flask object implements a WSGI application and acts as the central
- object. It is passed the name of the module or package of the
- application. Once it is created it will act as a central registry for
- the view functions, the URL rules, template configuration and much more.
-
- The name of the package is used to resolve resources from inside the
- package or the folder the module is contained in depending on if the
- package parameter resolves to an actual python package (a folder with
- an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).
-
- For more information about resource loading, see :func:`open_resource`.
-
- Usually you create a :class:`Flask` instance in your main module or
- in the :file:`__init__.py` file of your package like this::
-
- from flask import Flask
- app = Flask(__name__)
-
- .. admonition:: About the First Parameter
-
- The idea of the first parameter is to give Flask an idea of what
- belongs to your application. This name is used to find resources
- on the filesystem, can be used by extensions to improve debugging
- information and a lot more.
-
- So it's important what you provide there. If you are using a single
- module, `__name__` is always the correct value. If you however are
- using a package, it's usually recommended to hardcode the name of
- your package there.
-
- For example if your application is defined in :file:`yourapplication/app.py`
- you should create it with one of the two versions below::
-
- app = Flask('yourapplication')
- app = Flask(__name__.split('.')[0])
-
- Why is that? The application will work even with `__name__`, thanks
- to how resources are looked up. However it will make debugging more
- painful. Certain extensions can make assumptions based on the
- import name of your application. For example the Flask-SQLAlchemy
- extension will look for the code in your application that triggered
- an SQL query in debug mode. If the import name is not properly set
- up, that debugging information is lost. (For example it would only
- pick up SQL queries in `yourapplication.app` and not
- `yourapplication.views.frontend`)
-
- .. versionadded:: 0.7
- The `static_url_path`, `static_folder`, and `template_folder`
- parameters were added.
-
- .. versionadded:: 0.8
- The `instance_path` and `instance_relative_config` parameters were
- added.
-
- .. versionadded:: 0.11
- The `root_path` parameter was added.
-
- .. versionadded:: 1.0
- The ``host_matching`` and ``static_host`` parameters were added.
-
- .. versionadded:: 1.0
- The ``subdomain_matching`` parameter was added. Subdomain
- matching needs to be enabled manually now. Setting
- :data:`SERVER_NAME` does not implicitly enable it.
-
- :param import_name: the name of the application package
- :param static_url_path: can be used to specify a different path for the
- static files on the web. Defaults to the name
- of the `static_folder` folder.
- :param static_folder: the folder with static files that should be served
- at `static_url_path`. Defaults to the ``'static'``
- folder in the root path of the application.
- :param static_host: the host to use when adding the static route.
- Defaults to None. Required when using ``host_matching=True``
- with a ``static_folder`` configured.
- :param host_matching: set ``url_map.host_matching`` attribute.
- Defaults to False.
- :param subdomain_matching: consider the subdomain relative to
- :data:`SERVER_NAME` when matching routes. Defaults to False.
- :param template_folder: the folder that contains the templates that should
- be used by the application. Defaults to
- ``'templates'`` folder in the root path of the
- application.
- :param instance_path: An alternative instance path for the application.
- By default the folder ``'instance'`` next to the
- package or module is assumed to be the instance
- path.
- :param instance_relative_config: if set to ``True`` relative filenames
- for loading the config are assumed to
- be relative to the instance path instead
- of the application root.
- :param root_path: Flask by default will automatically calculate the path
- to the root of the application. In certain situations
- this cannot be achieved (for instance if the package
- is a Python 3 namespace package) and needs to be
- manually defined.
- """
-
- #: The class that is used for request objects. See :class:`~flask.Request`
- #: for more information.
- request_class = Request
-
- #: The class that is used for response objects. See
- #: :class:`~flask.Response` for more information.
- response_class = Response
-
- #: The class that is used for the Jinja environment.
- #:
- #: .. versionadded:: 0.11
- jinja_environment = Environment
-
- #: The class that is used for the :data:`~flask.g` instance.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Store arbitrary attributes on flask.g.
- #: 2. Add a property for lazy per-request database connectors.
- #: 3. Return None instead of AttributeError on unexpected attributes.
- #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
- #:
- #: In Flask 0.9 this property was called `request_globals_class` but it
- #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the
- #: flask.g object is now application context scoped.
- #:
- #: .. versionadded:: 0.10
- app_ctx_globals_class = _AppCtxGlobals
-
- #: The class that is used for the ``config`` attribute of this app.
- #: Defaults to :class:`~flask.Config`.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Default values for certain config options.
- #: 2. Access to config values through attributes in addition to keys.
- #:
- #: .. versionadded:: 0.11
- config_class = Config
-
- #: The testing flag. Set this to ``True`` to enable the test mode of
- #: Flask extensions (and in the future probably also Flask itself).
- #: For example this might activate test helpers that have an
- #: additional runtime cost which should not be enabled by default.
- #:
- #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the
- #: default it's implicitly enabled.
- #:
- #: This attribute can also be configured from the config with the
- #: ``TESTING`` configuration key. Defaults to ``False``.
- testing = ConfigAttribute('TESTING')
-
- #: If a secret key is set, cryptographic components can use this to
- #: sign cookies and other things. Set this to a complex random value
- #: when you want to use the secure cookie for instance.
- #:
- #: This attribute can also be configured from the config with the
- #: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
- secret_key = ConfigAttribute('SECRET_KEY')
-
- #: The secure cookie uses this for the name of the session cookie.
- #:
- #: This attribute can also be configured from the config with the
- #: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
- session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME')
-
- #: A :class:`~datetime.timedelta` which is used to set the expiration
- #: date of a permanent session. The default is 31 days which makes a
- #: permanent session survive for roughly one month.
- #:
- #: This attribute can also be configured from the config with the
- #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to
- #: ``timedelta(days=31)``
- permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME',
- get_converter=_make_timedelta)
-
- #: A :class:`~datetime.timedelta` which is used as default cache_timeout
- #: for the :func:`send_file` functions. The default is 12 hours.
- #:
- #: This attribute can also be configured from the config with the
- #: ``SEND_FILE_MAX_AGE_DEFAULT`` configuration key. This configuration
- #: variable can also be set with an integer value used as seconds.
- #: Defaults to ``timedelta(hours=12)``
- send_file_max_age_default = ConfigAttribute('SEND_FILE_MAX_AGE_DEFAULT',
- get_converter=_make_timedelta)
-
- #: Enable this if you want to use the X-Sendfile feature. Keep in
- #: mind that the server has to support this. This only affects files
- #: sent with the :func:`send_file` method.
- #:
- #: .. versionadded:: 0.2
- #:
- #: This attribute can also be configured from the config with the
- #: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
- use_x_sendfile = ConfigAttribute('USE_X_SENDFILE')
-
- #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`.
- #:
- #: .. versionadded:: 0.10
- json_encoder = json.JSONEncoder
-
- #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`.
- #:
- #: .. versionadded:: 0.10
- json_decoder = json.JSONDecoder
-
- #: Options that are passed directly to the Jinja2 environment.
- jinja_options = ImmutableDict(
- extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
- )
-
- #: Default configuration parameters.
- default_config = ImmutableDict({
- 'ENV': None,
- 'DEBUG': None,
- 'TESTING': False,
- 'PROPAGATE_EXCEPTIONS': None,
- 'PRESERVE_CONTEXT_ON_EXCEPTION': None,
- 'SECRET_KEY': None,
- 'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
- 'USE_X_SENDFILE': False,
- 'SERVER_NAME': None,
- 'APPLICATION_ROOT': '/',
- 'SESSION_COOKIE_NAME': 'session',
- 'SESSION_COOKIE_DOMAIN': None,
- 'SESSION_COOKIE_PATH': None,
- 'SESSION_COOKIE_HTTPONLY': True,
- 'SESSION_COOKIE_SECURE': False,
- 'SESSION_COOKIE_SAMESITE': None,
- 'SESSION_REFRESH_EACH_REQUEST': True,
- 'MAX_CONTENT_LENGTH': None,
- 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
- 'TRAP_BAD_REQUEST_ERRORS': None,
- 'TRAP_HTTP_EXCEPTIONS': False,
- 'EXPLAIN_TEMPLATE_LOADING': False,
- 'PREFERRED_URL_SCHEME': 'http',
- 'JSON_AS_ASCII': True,
- 'JSON_SORT_KEYS': True,
- 'JSONIFY_PRETTYPRINT_REGULAR': False,
- 'JSONIFY_MIMETYPE': 'application/json',
- 'TEMPLATES_AUTO_RELOAD': None,
- 'MAX_COOKIE_SIZE': 4093,
- })
-
- #: The rule object to use for URL rules created. This is used by
- #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`.
- #:
- #: .. versionadded:: 0.7
- url_rule_class = Rule
-
- #: the test client that is used with when `test_client` is used.
- #:
- #: .. versionadded:: 0.7
- test_client_class = None
-
- #: The :class:`~click.testing.CliRunner` subclass, by default
- #: :class:`~flask.testing.FlaskCliRunner` that is used by
- #: :meth:`test_cli_runner`. Its ``__init__`` method should take a
- #: Flask app object as the first argument.
- #:
- #: .. versionadded:: 1.0
- test_cli_runner_class = None
-
- #: the session interface to use. By default an instance of
- #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
- #:
- #: .. versionadded:: 0.8
- 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__(
- self,
- import_name,
- static_url_path=None,
- static_folder='static',
- static_host=None,
- host_matching=False,
- subdomain_matching=False,
- template_folder='templates',
- instance_path=None,
- instance_relative_config=False,
- root_path=None
- ):
- _PackageBoundObject.__init__(
- self,
- import_name,
- template_folder=template_folder,
- root_path=root_path
- )
-
- if static_url_path is not None:
- self.static_url_path = static_url_path
-
- if static_folder is not None:
- self.static_folder = static_folder
-
- if instance_path is None:
- instance_path = self.auto_find_instance_path()
- elif not os.path.isabs(instance_path):
- raise ValueError(
- 'If an instance path is provided it must be absolute.'
- ' A relative path was given instead.'
- )
-
- #: Holds the path to the instance folder.
- #:
- #: .. versionadded:: 0.8
- self.instance_path = instance_path
-
- #: The configuration dictionary as :class:`Config`. This behaves
- #: exactly like a regular dictionary but supports additional methods
- #: to load a config from files.
- self.config = self.make_config(instance_relative_config)
-
- #: A dictionary of all view functions registered. The keys will
- #: 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.
- self.view_functions = {}
-
- #: A dictionary of all registered error handlers. The key is ``None``
- #: for error handlers active on the application, otherwise the key is
- #: the name of the blueprint. Each key points to another dictionary
- #: where the key is the status code of the http exception. The
- #: special key ``None`` points to a list of tuples where the first item
- #: is the class for the instance check and the second the error handler
- #: function.
- #:
- #: To register an error handler, use the :meth:`errorhandler`
- #: decorator.
- self.error_handler_spec = {}
-
- #: A list of functions that are called when :meth:`url_for` raises a
- #: :exc:`~werkzeug.routing.BuildError`. Each function registered here
- #: is called with `error`, `endpoint` and `values`. If a function
- #: returns ``None`` or raises a :exc:`BuildError` the next function is
- #: tried.
- #:
- #: .. versionadded:: 0.9
- self.url_build_error_handlers = []
-
- #: A dictionary with lists of functions that will be called at the
- #: beginning of each request. The key of the dictionary is the name of
- #: the blueprint this function is active for, or ``None`` for all
- #: requests. To register a function, use the :meth:`before_request`
- #: decorator.
- self.before_request_funcs = {}
-
- #: A list of functions that will be called at the beginning of the
- #: first request to this instance. To register a function, use the
- #: :meth:`before_first_request` decorator.
- #:
- #: .. versionadded:: 0.8
- self.before_first_request_funcs = []
-
- #: A dictionary with lists of functions that should be called after
- #: each request. The key of the dictionary is the name of the blueprint
- #: this function is active for, ``None`` for all requests. This can for
- #: example be used to close database connections. To register a function
- #: here, use the :meth:`after_request` decorator.
- self.after_request_funcs = {}
-
- #: A dictionary with lists of functions that are called after
- #: each request, even if an exception has occurred. The key of the
- #: dictionary is the name of the blueprint this function is active for,
- #: ``None`` for all requests. These functions are not allowed to modify
- #: the request, and their return values are ignored. If an exception
- #: 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
- self.teardown_request_funcs = {}
-
- #: A list of functions that are called when the application context
- #: is destroyed. Since the application context is also torn down
- #: if the request ends this is the place to store code that disconnects
- #: from databases.
- #:
- #: .. versionadded:: 0.9
- self.teardown_appcontext_funcs = []
-
- #: A dictionary with lists of functions that are called before the
- #: :attr:`before_request_funcs` functions. The key of the dictionary is
- #: the name of the blueprint this function is active for, or ``None``
- #: for all requests. To register a function, use
- #: :meth:`url_value_preprocessor`.
- #:
- #: .. versionadded:: 0.7
- self.url_value_preprocessors = {}
-
- #: A dictionary with lists of functions that can be used as URL value
- #: preprocessors. The key ``None`` here is used for application wide
- #: callbacks, otherwise the key is the name of the blueprint.
- #: Each of these functions has the chance to modify the dictionary
- #: of URL values before they are used as the keyword arguments of the
- #: 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
- self.url_default_functions = {}
-
- #: A dictionary with list of functions that are called without argument
- #: to populate the template context. The key of the dictionary is the
- #: name of the blueprint this function is active for, ``None`` for all
- #: requests. Each returns a dictionary that the template context is
- #: updated with. To register a function here, use the
- #: :meth:`context_processor` decorator.
- self.template_context_processors = {
- None: [_default_template_ctx_processor]
- }
-
- #: A list of shell context processor functions that should be run
- #: when a shell context is created.
- #:
- #: .. versionadded:: 0.11
- self.shell_context_processors = []
-
- #: all the attached blueprints in a dictionary by name. Blueprints
- #: can be attached multiple times so this dictionary does not tell
- #: you how often they got attached.
- #:
- #: .. versionadded:: 0.7
- self.blueprints = {}
- self._blueprint_order = []
-
- #: a place where extensions can store application specific state. For
- #: example this is where an extension could store database engines and
- #: similar things. For backwards compatibility extensions should register
- #: themselves like this::
- #:
- #: if not hasattr(app, 'extensions'):
- #: app.extensions = {}
- #: app.extensions['extensionname'] = SomeObject()
- #:
- #: The key must match the name of the extension module. For example in
- #: case of a "Flask-Foo" extension in `flask_foo`, the key would be
- #: ``'foo'``.
- #:
- #: .. versionadded:: 0.7
- self.extensions = {}
-
- #: The :class:`~werkzeug.routing.Map` for this instance. You can use
- #: this to change the routing converters after the class was created
- #: but before any routes are connected. Example::
- #:
- #: from werkzeug.routing import BaseConverter
- #:
- #: class ListConverter(BaseConverter):
- #: def to_python(self, value):
- #: return value.split(',')
- #: def to_url(self, values):
- #: return ','.join(super(ListConverter, self).to_url(value)
- #: for value in values)
- #:
- #: app = Flask(__name__)
- #: app.url_map.converters['list'] = ListConverter
- self.url_map = Map()
-
- self.url_map.host_matching = host_matching
- self.subdomain_matching = subdomain_matching
-
- # tracks internally if the application already handled at least one
- # request.
- self._got_first_request = False
- self._before_request_lock = Lock()
-
- # Add a static route using the provided static_url_path, static_host,
- # and static_folder if there is a configured static_folder.
- # Note we do this without checking if static_folder exists.
- # For one, it might be created while the server is running (e.g. during
- # development). Also, Google App Engine stores static files somewhere
- if self.has_static_folder:
- assert bool(static_host) == host_matching, 'Invalid static_host/host_matching combination'
- self.add_url_rule(
- self.static_url_path + '/<path:filename>',
- endpoint='static',
- host=static_host,
- view_func=self.send_static_file
- )
-
- #: The click command line context for this application. Commands
- #: registered here show up in the :command:`flask` command once the
- #: application has been discovered. The default commands are
- #: provided by Flask itself and can be overridden.
- #:
- #: This is an instance of a :class:`click.Group` object.
- self.cli = cli.AppGroup(self.name)
-
- @locked_cached_property
- def name(self):
- """The name of the application. This is usually the import name
- with the difference that it's guessed from the run file if the
- import name is main. This name is used as a display name when
- Flask needs the name of the application. It can be set and overridden
- to change the value.
-
- .. versionadded:: 0.8
- """
- if self.import_name == '__main__':
- fn = getattr(sys.modules['__main__'], '__file__', None)
- if fn is None:
- return '__main__'
- return os.path.splitext(os.path.basename(fn))[0]
- return self.import_name
-
- @property
- def propagate_exceptions(self):
- """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
- value in case it's set, otherwise a sensible default is returned.
-
- .. versionadded:: 0.7
- """
- rv = self.config['PROPAGATE_EXCEPTIONS']
- if rv is not None:
- return rv
- return self.testing or self.debug
-
- @property
- def preserve_context_on_exception(self):
- """Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION``
- configuration value in case it's set, otherwise a sensible default
- is returned.
-
- .. versionadded:: 0.7
- """
- rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION']
- if rv is not None:
- return rv
- return self.debug
-
- @locked_cached_property
- def logger(self):
- """The ``'flask.app'`` logger, a standard Python
- :class:`~logging.Logger`.
-
- In debug mode, the logger's :attr:`~logging.Logger.level` will be set
- to :data:`~logging.DEBUG`.
-
- If there are no handlers configured, a default handler will be added.
- See :ref:`logging` for more information.
-
- .. versionchanged:: 1.0
- Behavior was simplified. The logger is always named
- ``flask.app``. The level is only set during configuration, it
- doesn't check ``app.debug`` each time. Only one format is used,
- not different ones depending on ``app.debug``. No handlers are
- removed, and a handler is only added if no handlers are already
- configured.
-
- .. versionadded:: 0.3
- """
- return create_logger(self)
-
- @locked_cached_property
- def jinja_env(self):
- """The Jinja2 environment used to load templates."""
- return self.create_jinja_environment()
-
- @property
- def got_first_request(self):
- """This attribute is set to ``True`` if the application started
- handling the first request.
-
- .. versionadded:: 0.8
- """
- return self._got_first_request
-
- def make_config(self, instance_relative=False):
- """Used to create the config attribute by the Flask constructor.
- The `instance_relative` parameter is passed in from the constructor
- of Flask (there named `instance_relative_config`) and indicates if
- the config should be relative to the instance path or the root path
- of the application.
-
- .. versionadded:: 0.8
- """
- root_path = self.root_path
- if instance_relative:
- root_path = self.instance_path
- defaults = dict(self.default_config)
- defaults['ENV'] = get_env()
- defaults['DEBUG'] = get_debug_flag()
- return self.config_class(root_path, defaults)
-
- def auto_find_instance_path(self):
- """Tries to locate the instance path if it was not provided to the
- constructor of the application class. It will basically calculate
- the path to a folder named ``instance`` next to your main file or
- the package.
-
- .. versionadded:: 0.8
- """
- prefix, package_path = find_package(self.import_name)
- if prefix is None:
- return os.path.join(package_path, 'instance')
- return os.path.join(prefix, 'var', self.name + '-instance')
-
- def open_instance_resource(self, resource, mode='rb'):
- """Opens a resource from the application's instance folder
- (:attr:`instance_path`). Otherwise works like
- :meth:`open_resource`. Instance resources can also be opened for
- writing.
-
- :param resource: the name of the resource. To access resources within
- subfolders use forward slashes as separator.
- :param mode: resource file opening mode, default is 'rb'.
- """
- return open(os.path.join(self.instance_path, resource), mode)
-
- def _get_templates_auto_reload(self):
- """Reload templates when they are changed. Used by
- :meth:`create_jinja_environment`.
-
- This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If
- not set, it will be enabled in debug mode.
-
- .. versionadded:: 1.0
- This property was added but the underlying config and behavior
- already existed.
- """
- rv = self.config['TEMPLATES_AUTO_RELOAD']
- return rv if rv is not None else self.debug
-
- def _set_templates_auto_reload(self, value):
- self.config['TEMPLATES_AUTO_RELOAD'] = value
-
- templates_auto_reload = property(
- _get_templates_auto_reload, _set_templates_auto_reload
- )
- del _get_templates_auto_reload, _set_templates_auto_reload
-
- def create_jinja_environment(self):
- """Creates the Jinja2 environment based on :attr:`jinja_options`
- and :meth:`select_jinja_autoescape`. Since 0.7 this also adds
- the Jinja2 globals and filters after initialization. Override
- this function to customize the behavior.
-
- .. versionadded:: 0.5
- .. versionchanged:: 0.11
- ``Environment.auto_reload`` set in accordance with
- ``TEMPLATES_AUTO_RELOAD`` configuration option.
- """
- options = dict(self.jinja_options)
-
- if 'autoescape' not in options:
- options['autoescape'] = self.select_jinja_autoescape
-
- if 'auto_reload' not in options:
- options['auto_reload'] = self.templates_auto_reload
-
- rv = self.jinja_environment(self, **options)
- rv.globals.update(
- url_for=url_for,
- get_flashed_messages=get_flashed_messages,
- config=self.config,
- # request, session and g are normally added with the
- # context processor for efficiency reasons but for imported
- # templates we also want the proxies in there.
- request=request,
- session=session,
- g=g
- )
- rv.filters['tojson'] = json.tojson_filter
- return rv
-
- def create_global_jinja_loader(self):
- """Creates the loader for the Jinja2 environment. Can be used to
- override just the loader and keeping the rest unchanged. It's
- discouraged to override this function. Instead one should override
- the :meth:`jinja_loader` function instead.
-
- The global loader dispatches between the loaders of the application
- and the individual blueprints.
-
- .. versionadded:: 0.7
- """
- return DispatchingJinjaLoader(self)
-
- def select_jinja_autoescape(self, filename):
- """Returns ``True`` if autoescaping should be active for the given
- template name. If no template name is given, returns `True`.
-
- .. versionadded:: 0.5
- """
- if filename is None:
- return True
- return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
-
- def update_template_context(self, context):
- """Update the template context with some commonly used variables.
- This injects request, session, config and g into the template
- context as well as everything template context processors want
- to inject. Note that the as of Flask 0.6, the original values
- in the context will not be overridden if a context processor
- decides to return a value with the same key.
-
- :param context: the context as a dictionary that is updated in place
- to add extra variables.
- """
- funcs = self.template_context_processors[None]
- reqctx = _request_ctx_stack.top
- if reqctx is not None:
- bp = reqctx.request.blueprint
- if bp is not None and bp in self.template_context_processors:
- funcs = chain(funcs, self.template_context_processors[bp])
- orig_ctx = context.copy()
- for func in funcs:
- context.update(func())
- # make sure the original values win. This makes it possible to
- # easier add new variables in context processors without breaking
- # existing views.
- context.update(orig_ctx)
-
- def make_shell_context(self):
- """Returns the shell context for an interactive shell for this
- application. This runs all the registered shell context
- processors.
-
- .. versionadded:: 0.11
- """
- rv = {'app': self, 'g': g}
- for processor in self.shell_context_processors:
- rv.update(processor())
- return rv
-
- #: What environment the app is running in. Flask and extensions may
- #: enable behaviors based on the environment, such as enabling debug
- #: mode. This maps to the :data:`ENV` config key. This is set by the
- #: :envvar:`FLASK_ENV` environment variable and may not behave as
- #: expected if set in code.
- #:
- #: **Do not enable development when deploying in production.**
- #:
- #: Default: ``'production'``
- env = ConfigAttribute('ENV')
-
- def _get_debug(self):
- return self.config['DEBUG']
-
- def _set_debug(self, value):
- self.config['DEBUG'] = value
- self.jinja_env.auto_reload = self.templates_auto_reload
-
- #: Whether debug mode is enabled. When using ``flask run`` to start
- #: the development server, an interactive debugger will be shown for
- #: unhandled exceptions, and the server will be reloaded when code
- #: changes. This maps to the :data:`DEBUG` config key. This is
- #: enabled when :attr:`env` is ``'development'`` and is overridden
- #: by the ``FLASK_DEBUG`` environment variable. It may not behave as
- #: expected if set in code.
- #:
- #: **Do not enable debug mode when deploying in production.**
- #:
- #: Default: ``True`` if :attr:`env` is ``'development'``, or
- #: ``False`` otherwise.
- debug = property(_get_debug, _set_debug)
- del _get_debug, _set_debug
-
- def run(self, host=None, port=None, debug=None,
- load_dotenv=True, **options):
- """Runs the application on a local development server.
-
- Do not use ``run()`` in a production setting. It is not intended to
- meet security and performance requirements for a production server.
- Instead, see :ref:`deployment` for WSGI server recommendations.
-
- If the :attr:`debug` flag is set the server will automatically reload
- for code changes and show a debugger in case an exception happened.
-
- If you want to run the application in debug mode, but disable the
- code execution on the interactive debugger, you can pass
- ``use_evalex=False`` as parameter. This will keep the debugger's
- traceback screen active, but disable code execution.
-
- It is not recommended to use this function for development with
- automatic reloading as this is badly supported. Instead you should
- be using the :command:`flask` command line script's ``run`` support.
-
- .. admonition:: Keep in Mind
-
- Flask will suppress any server error with a generic error page
- unless it is in debug mode. As such to enable just the
- interactive debugger without the code reloading, you have to
- invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.
- Setting ``use_debugger`` to ``True`` without being in debug mode
- won't catch any exceptions because there won't be any to
- catch.
-
- :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to
- have the server available externally as well. Defaults to
- ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable
- if present.
- :param port: the port of the webserver. Defaults to ``5000`` or the
- port defined in the ``SERVER_NAME`` config variable if present.
- :param debug: if given, enable or disable debug mode. See
- :attr:`debug`.
- :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
- files to set environment variables. Will also change the working
- directory to the directory containing the first file found.
- :param options: the options to be forwarded to the underlying Werkzeug
- server. See :func:`werkzeug.serving.run_simple` for more
- information.
-
- .. versionchanged:: 1.0
- If installed, python-dotenv will be used to load environment
- variables from :file:`.env` and :file:`.flaskenv` files.
-
- If set, the :envvar:`FLASK_ENV` and :envvar:`FLASK_DEBUG`
- environment variables will override :attr:`env` and
- :attr:`debug`.
-
- Threaded mode is enabled by default.
-
- .. versionchanged:: 0.10
- The default port is now picked from the ``SERVER_NAME``
- variable.
- """
- # Change this into a no-op if the server is invoked from the
- # command line. Have a look at cli.py for more information.
- if os.environ.get('FLASK_RUN_FROM_CLI') == 'true':
- from .debughelpers import explain_ignored_app_run
- explain_ignored_app_run()
- return
-
- if get_load_dotenv(load_dotenv):
- cli.load_dotenv()
-
- # if set, let env vars override previous values
- if 'FLASK_ENV' in os.environ:
- self.env = get_env()
- self.debug = get_debug_flag()
- elif 'FLASK_DEBUG' in os.environ:
- self.debug = get_debug_flag()
-
- # debug passed to method overrides all other sources
- if debug is not None:
- self.debug = bool(debug)
-
- _host = '127.0.0.1'
- _port = 5000
- server_name = self.config.get('SERVER_NAME')
- sn_host, sn_port = None, None
-
- if server_name:
- sn_host, _, sn_port = server_name.partition(':')
-
- host = host or sn_host or _host
- port = int(port or sn_port or _port)
-
- options.setdefault('use_reloader', self.debug)
- options.setdefault('use_debugger', self.debug)
- options.setdefault('threaded', True)
-
- cli.show_server_banner(self.env, self.debug, self.name, False)
-
- from werkzeug.serving import run_simple
-
- try:
- run_simple(host, port, self, **options)
- finally:
- # reset the first request information if the development server
- # reset normally. This makes it possible to restart the server
- # without reloader and that stuff from an interactive shell.
- self._got_first_request = False
-
- def test_client(self, use_cookies=True, **kwargs):
- """Creates a test client for this application. For information
- about unit testing head over to :ref:`testing`.
-
- Note that if you are testing for assertions or exceptions in your
- application code, you must set ``app.testing = True`` in order for the
- exceptions to propagate to the test client. Otherwise, the exception
- will be handled by the application (not visible to the test client) and
- the only indication of an AssertionError or other exception will be a
- 500 status code response to the test client. See the :attr:`testing`
- attribute. For example::
-
- app.testing = True
- client = app.test_client()
-
- The test client can be used in a ``with`` block to defer the closing down
- of the context until the end of the ``with`` block. This is useful if
- you want to access the context locals for testing::
-
- with app.test_client() as c:
- rv = c.get('/?vodka=42')
- assert request.args['vodka'] == '42'
-
- Additionally, you may pass optional keyword arguments that will then
- be passed to the application's :attr:`test_client_class` constructor.
- For example::
-
- from flask.testing import FlaskClient
-
- class CustomClient(FlaskClient):
- def __init__(self, *args, **kwargs):
- self._authentication = kwargs.pop("authentication")
- super(CustomClient,self).__init__( *args, **kwargs)
-
- app.test_client_class = CustomClient
- client = app.test_client(authentication='Basic ....')
-
- See :class:`~flask.testing.FlaskClient` for more information.
-
- .. versionchanged:: 0.4
- added support for ``with`` block usage for the client.
-
- .. versionadded:: 0.7
- The `use_cookies` parameter was added as well as the ability
- to override the client to be used by setting the
- :attr:`test_client_class` attribute.
-
- .. versionchanged:: 0.11
- Added `**kwargs` to support passing additional keyword arguments to
- the constructor of :attr:`test_client_class`.
- """
- cls = self.test_client_class
- if cls is None:
- from flask.testing import FlaskClient as cls
- return cls(self, self.response_class, use_cookies=use_cookies, **kwargs)
-
- def test_cli_runner(self, **kwargs):
- """Create a CLI runner for testing CLI commands.
- See :ref:`testing-cli`.
-
- Returns an instance of :attr:`test_cli_runner_class`, by default
- :class:`~flask.testing.FlaskCliRunner`. The Flask app object is
- passed as the first argument.
-
- .. versionadded:: 1.0
- """
- cls = self.test_cli_runner_class
-
- if cls is None:
- from flask.testing import FlaskCliRunner as cls
-
- return cls(self, **kwargs)
-
- def open_session(self, request):
- """Creates or opens a new session. Default implementation stores all
- session data in a signed cookie. This requires that the
- :attr:`secret_key` is set. Instead of overriding this method
- we recommend replacing the :class:`session_interface`.
-
- .. deprecated: 1.0
- Will be removed in 1.1. Use ``session_interface.open_session``
- instead.
-
- :param request: an instance of :attr:`request_class`.
- """
-
- warnings.warn(DeprecationWarning(
- '"open_session" is deprecated and will be removed in 1.1. Use'
- ' "session_interface.open_session" instead.'
- ))
- return self.session_interface.open_session(self, request)
-
- def save_session(self, session, response):
- """Saves the session if it needs updates. For the default
- implementation, check :meth:`open_session`. Instead of overriding this
- method we recommend replacing the :class:`session_interface`.
-
- .. deprecated: 1.0
- Will be removed in 1.1. Use ``session_interface.save_session``
- instead.
-
- :param session: the session to be saved (a
- :class:`~werkzeug.contrib.securecookie.SecureCookie`
- object)
- :param response: an instance of :attr:`response_class`
- """
-
- warnings.warn(DeprecationWarning(
- '"save_session" is deprecated and will be removed in 1.1. Use'
- ' "session_interface.save_session" instead.'
- ))
- return self.session_interface.save_session(self, session, response)
-
- def make_null_session(self):
- """Creates a new instance of a missing session. Instead of overriding
- this method we recommend replacing the :class:`session_interface`.
-
- .. deprecated: 1.0
- Will be removed in 1.1. Use ``session_interface.make_null_session``
- instead.
-
- .. versionadded:: 0.7
- """
-
- warnings.warn(DeprecationWarning(
- '"make_null_session" is deprecated and will be removed in 1.1. Use'
- ' "session_interface.make_null_session" instead.'
- ))
- return self.session_interface.make_null_session(self)
-
- @setupmethod
- def register_blueprint(self, blueprint, **options):
- """Register a :class:`~flask.Blueprint` on the application. Keyword
- arguments passed to this method will override the defaults set on the
- blueprint.
-
- Calls the blueprint's :meth:`~flask.Blueprint.register` method after
- recording the blueprint in the application's :attr:`blueprints`.
-
- :param blueprint: The blueprint to register.
- :param url_prefix: Blueprint routes will be prefixed with this.
- :param subdomain: Blueprint routes will match on this subdomain.
- :param url_defaults: Blueprint routes will use these default values for
- view arguments.
- :param options: Additional keyword arguments are passed to
- :class:`~flask.blueprints.BlueprintSetupState`. They can be
- accessed in :meth:`~flask.Blueprint.record` callbacks.
-
- .. versionadded:: 0.7
- """
- first_registration = False
-
- if blueprint.name in self.blueprints:
- assert self.blueprints[blueprint.name] is blueprint, (
- 'A name collision occurred between blueprints %r and %r. Both'
- ' share the same name "%s". Blueprints that are created on the'
- ' fly need unique names.' % (
- blueprint, self.blueprints[blueprint.name], blueprint.name
- )
- )
- else:
- self.blueprints[blueprint.name] = blueprint
- self._blueprint_order.append(blueprint)
- first_registration = True
-
- blueprint.register(self, options, first_registration)
-
- def iter_blueprints(self):
- """Iterates over all blueprints by the order they were registered.
-
- .. versionadded:: 0.11
- """
- return iter(self._blueprint_order)
-
- @setupmethod
- def add_url_rule(self, rule, endpoint=None, view_func=None,
- provide_automatic_options=None, **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:
- endpoint = _endpoint_from_view_func(view_func)
- options['endpoint'] = endpoint
- methods = options.pop('methods', None)
-
- # if the methods are not given and the view_func object knows its
- # methods we can use that instead. If neither exists, we go with
- # a tuple of only ``GET`` as default.
- if methods is None:
- methods = getattr(view_func, 'methods', None) or ('GET',)
- if isinstance(methods, string_types):
- raise TypeError('Allowed methods have to be iterables of strings, '
- 'for example: @app.route(..., methods=["POST"])')
- methods = set(item.upper() for item in methods)
-
- # Methods that should always be added
- required_methods = set(getattr(view_func, 'required_methods', ()))
-
- # starting with Flask 0.8 the view_func object can disable and
- # force-enable the automatic options handling.
- if provide_automatic_options is None:
- provide_automatic_options = getattr(view_func,
- 'provide_automatic_options', None)
-
- if provide_automatic_options is None:
- if 'OPTIONS' not in methods:
- provide_automatic_options = True
- required_methods.add('OPTIONS')
- else:
- provide_automatic_options = False
-
- # Add the required methods now.
- methods |= required_methods
-
- rule = self.url_rule_class(rule, methods=methods, **options)
- rule.provide_automatic_options = provide_automatic_options
-
- self.url_map.add(rule)
- if view_func is not None:
- old_func = self.view_functions.get(endpoint)
- if old_func is not None and old_func != view_func:
- raise AssertionError('View function mapping is overwriting an '
- 'existing endpoint function: %s' % endpoint)
- self.view_functions[endpoint] = view_func
-
- def route(self, rule, **options):
- """A decorator that is used to register a view function for a
- given URL rule. This does the same thing as :meth:`add_url_rule`
- but is intended for decorator usage::
-
- @app.route('/')
- def index():
- return 'Hello World'
-
- For more information refer to :ref:`url-route-registrations`.
-
- :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 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.
- """
- def decorator(f):
- endpoint = options.pop('endpoint', None)
- self.add_url_rule(rule, endpoint, f, **options)
- return f
- return decorator
-
- @setupmethod
- def endpoint(self, endpoint):
- """A decorator to register a function as an endpoint.
- Example::
-
- @app.endpoint('example.endpoint')
- def example():
- return "example"
-
- :param endpoint: the name of the endpoint
- """
- def decorator(f):
- self.view_functions[endpoint] = f
- return f
- return decorator
-
- @staticmethod
- def _get_exc_class_and_code(exc_class_or_code):
- """Ensure that we register only exceptions as handler keys"""
- if isinstance(exc_class_or_code, integer_types):
- exc_class = default_exceptions[exc_class_or_code]
- else:
- exc_class = exc_class_or_code
-
- assert issubclass(exc_class, Exception)
-
- if issubclass(exc_class, HTTPException):
- return exc_class, exc_class.code
- else:
- return exc_class, None
-
- @setupmethod
- def errorhandler(self, code_or_exception):
- """Register a function to handle errors by code or exception class.
-
- A decorator that is used to register a function given an
- error code. Example::
-
- @app.errorhandler(404)
- def page_not_found(error):
- return 'This page does not exist', 404
-
- You can also register handlers for arbitrary exceptions::
-
- @app.errorhandler(DatabaseError)
- def special_exception_handler(error):
- return 'Database connection failed', 500
-
- .. versionadded:: 0.7
- Use :meth:`register_error_handler` instead of modifying
- :attr:`error_handler_spec` directly, for application wide error
- handlers.
-
- .. versionadded:: 0.7
- One can now additionally also register custom exception types
- that do not necessarily have to be a subclass of the
- :class:`~werkzeug.exceptions.HTTPException` class.
-
- :param code_or_exception: the code as integer for the handler, or
- an arbitrary exception
- """
- def decorator(f):
- self._register_error_handler(None, code_or_exception, f)
- return f
- return decorator
-
- @setupmethod
- def register_error_handler(self, code_or_exception, f):
- """Alternative error attach function to the :meth:`errorhandler`
- decorator that is more straightforward to use for non decorator
- usage.
-
- .. versionadded:: 0.7
- """
- self._register_error_handler(None, code_or_exception, f)
-
- @setupmethod
- def _register_error_handler(self, key, code_or_exception, f):
- """
- :type key: None|str
- :type code_or_exception: int|T<=Exception
- :type f: callable
- """
- if isinstance(code_or_exception, HTTPException): # old broken behavior
- raise ValueError(
- 'Tried to register a handler for an exception instance {0!r}.'
- ' Handlers can only be registered for exception classes or'
- ' HTTP error codes.'.format(code_or_exception)
- )
-
- try:
- exc_class, code = self._get_exc_class_and_code(code_or_exception)
- except KeyError:
- raise KeyError(
- "'{0}' is not a recognized HTTP error code. Use a subclass of"
- " HTTPException with that code instead.".format(code_or_exception)
- )
-
- handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {})
- handlers[exc_class] = f
-
- @setupmethod
- def template_filter(self, name=None):
- """A decorator that is used to register custom template filter.
- You can specify a name for the filter, otherwise the function
- name will be used. Example::
-
- @app.template_filter()
- def reverse(s):
- return s[::-1]
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_template_filter(f, name=name)
- return f
- return decorator
-
- @setupmethod
- def add_template_filter(self, f, name=None):
- """Register a custom template filter. Works exactly like the
- :meth:`template_filter` decorator.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- self.jinja_env.filters[name or f.__name__] = f
-
- @setupmethod
- def template_test(self, name=None):
- """A decorator that is used to register custom template test.
- You can specify a name for the test, otherwise the function
- name will be used. Example::
-
- @app.template_test()
- def is_prime(n):
- if n == 2:
- return True
- for i in range(2, int(math.ceil(math.sqrt(n))) + 1):
- if n % i == 0:
- return False
- return True
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_template_test(f, name=name)
- return f
- return decorator
-
- @setupmethod
- def add_template_test(self, f, name=None):
- """Register a custom template test. Works exactly like the
- :meth:`template_test` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- self.jinja_env.tests[name or f.__name__] = f
-
- @setupmethod
- def template_global(self, name=None):
- """A decorator that is used to register a custom template global function.
- You can specify a name for the global function, otherwise the function
- name will be used. Example::
-
- @app.template_global()
- def double(n):
- return 2 * n
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_template_global(f, name=name)
- return f
- return decorator
-
- @setupmethod
- def add_template_global(self, f, name=None):
- """Register a custom template global function. Works exactly like the
- :meth:`template_global` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
- self.jinja_env.globals[name or f.__name__] = f
-
- @setupmethod
- def before_request(self, f):
- """Registers a function to run before each request.
-
- For example, this can be used to open a database connection, or to load
- the logged in user from the session.
-
- 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.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def before_first_request(self, f):
- """Registers a function to be run before the first request to this
- instance of the application.
-
- The function will be called without any arguments and its return
- value is ignored.
-
- .. versionadded:: 0.8
- """
- self.before_first_request_funcs.append(f)
- return f
-
- @setupmethod
- def after_request(self, f):
- """Register a function to be run after each request.
-
- Your function must take one parameter, an instance of
- :attr:`response_class` and return a new response object or the
- same (see :meth:`process_response`).
-
- As of Flask 0.7 this function might not be executed at the end of the
- request in case an unhandled exception occurred.
- """
- self.after_request_funcs.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def teardown_request(self, f):
- """Register a function to be run at the end of each request,
- regardless of whether there was an exception or not. These functions
- are executed when the request context is popped, even if not an
- actual request was performed.
-
- Example::
-
- ctx = app.test_request_context()
- ctx.push()
- ...
- ctx.pop()
-
- When ``ctx.pop()`` is executed in the above example, the teardown
- functions are called just before the request context moves from the
- stack of active contexts. This becomes relevant if you are using
- such constructs in tests.
-
- Generally teardown functions must take every necessary step to avoid
- that they will fail. If they do execute code that might fail they
- will have to surround the execution of these code by try/except
- statements and log occurring errors.
-
- When a teardown function was called because of an exception it will
- be passed an error object.
-
- The return values of teardown functions are ignored.
-
- .. admonition:: Debug Note
-
- In debug mode Flask will not tear down a request on an exception
- immediately. Instead it will keep it alive so that the interactive
- debugger can still access it. This behavior can be controlled
- by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable.
- """
- self.teardown_request_funcs.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def teardown_appcontext(self, f):
- """Registers a function to be called when the application context
- ends. These functions are typically also called when the request
- context is popped.
-
- Example::
-
- ctx = app.app_context()
- ctx.push()
- ...
- ctx.pop()
-
- When ``ctx.pop()`` is executed in the above example, the teardown
- functions are called just before the app context moves from the
- stack of active contexts. This becomes relevant if you are using
- such constructs in tests.
-
- Since a request context typically also manages an application
- context it would also be called when you pop a request context.
-
- When a teardown function was called because of an unhandled exception
- it will be passed an error object. If an :meth:`errorhandler` is
- registered, it will handle the exception and the teardown will not
- receive it.
-
- The return values of teardown functions are ignored.
-
- .. versionadded:: 0.9
- """
- self.teardown_appcontext_funcs.append(f)
- return f
-
- @setupmethod
- def context_processor(self, f):
- """Registers a template context processor function."""
- self.template_context_processors[None].append(f)
- return f
-
- @setupmethod
- def shell_context_processor(self, f):
- """Registers a shell context processor function.
-
- .. versionadded:: 0.11
- """
- self.shell_context_processors.append(f)
- return f
-
- @setupmethod
- def url_value_preprocessor(self, f):
- """Register a URL value preprocessor function for all view
- functions in the application. These functions will be called before the
- :meth:`before_request` functions.
-
- The function can modify the values captured from the matched url before
- they are passed to the view. For example, this can be used to pop a
- common language code value and place it in ``g`` rather than pass it to
- every view.
-
- The function is passed the endpoint name and values dict. The return
- value is ignored.
- """
- self.url_value_preprocessors.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def url_defaults(self, f):
- """Callback function for URL defaults for all view functions of the
- application. It's called with the endpoint and values and should
- update the values passed in place.
- """
- self.url_default_functions.setdefault(None, []).append(f)
- return f
-
- def _find_error_handler(self, e):
- """Return a registered error handler for an exception in this order:
- blueprint handler for a specific code, app handler for a specific code,
- blueprint handler for an exception class, app handler for an exception
- class, or ``None`` if a suitable handler is not found.
- """
- exc_class, code = self._get_exc_class_and_code(type(e))
-
- for name, c in (
- (request.blueprint, code), (None, code),
- (request.blueprint, None), (None, None)
- ):
- handler_map = self.error_handler_spec.setdefault(name, {}).get(c)
-
- if not handler_map:
- continue
-
- for cls in exc_class.__mro__:
- handler = handler_map.get(cls)
-
- if handler is not None:
- return handler
-
- def handle_http_exception(self, e):
- """Handles an HTTP exception. By default this will invoke the
- registered error handlers and fall back to returning the
- exception as response.
-
- .. versionchanged:: 1.0.3
- ``RoutingException``, used internally for actions such as
- slash redirects during routing, is not passed to error
- handlers.
-
- .. versionchanged:: 1.0
- Exceptions are looked up by code *and* by MRO, so
- ``HTTPExcpetion`` subclasses can be handled with a catch-all
- handler for the base ``HTTPException``.
-
- .. versionadded:: 0.3
- """
- # Proxy exceptions don't have error codes. We want to always return
- # those unchanged as errors
- if e.code is None:
- return e
-
- # RoutingExceptions are used internally to trigger routing
- # actions, such as slash redirects raising RequestRedirect. They
- # are not raised or handled in user code.
- if isinstance(e, RoutingException):
- return e
-
- handler = self._find_error_handler(e)
- if handler is None:
- return e
- return handler(e)
-
- def trap_http_exception(self, e):
- """Checks if an HTTP exception should be trapped or not. By default
- this will return ``False`` for all exceptions except for a bad request
- key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It
- also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``.
-
- This is called for all HTTP exceptions raised by a view function.
- If it returns ``True`` for any exception the error handler for this
- exception is not called and it shows up as regular exception in the
- traceback. This is helpful for debugging implicitly raised HTTP
- exceptions.
-
- .. versionchanged:: 1.0
- Bad request errors are not trapped by default in debug mode.
-
- .. versionadded:: 0.8
- """
- if self.config['TRAP_HTTP_EXCEPTIONS']:
- return True
-
- trap_bad_request = self.config['TRAP_BAD_REQUEST_ERRORS']
-
- # if unset, trap key errors in debug mode
- if (
- trap_bad_request is None and self.debug
- and isinstance(e, BadRequestKeyError)
- ):
- return True
-
- if trap_bad_request:
- return isinstance(e, BadRequest)
-
- return False
-
- def handle_user_exception(self, e):
- """This method is called whenever an exception occurs that
- should be handled. A special case is :class:`~werkzeug
- .exceptions.HTTPException` which is forwarded to the
- :meth:`handle_http_exception` method. This function will either
- return a response value or reraise the exception with the same
- traceback.
-
- .. versionchanged:: 1.0
- Key errors raised from request data like ``form`` show the
- bad key in debug mode rather than a generic bad request
- message.
-
- .. versionadded:: 0.7
- """
- exc_type, exc_value, tb = sys.exc_info()
- assert exc_value is e
- # ensure not to trash sys.exc_info() at that point in case someone
- # wants the traceback preserved in handle_http_exception. Of course
- # we cannot prevent users from trashing it themselves in a custom
- # trap_http_exception method so that's their fault then.
-
- if isinstance(e, BadRequestKeyError):
- if self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]:
- # Werkzeug < 0.15 doesn't add the KeyError to the 400
- # message, add it in manually.
- description = e.get_description()
-
- if e.args[0] not in description:
- e.description = "KeyError: '{}'".format(*e.args)
- else:
- # Werkzeug >= 0.15 does add it, remove it in production
- e.args = ()
-
- if isinstance(e, HTTPException) and not self.trap_http_exception(e):
- return self.handle_http_exception(e)
-
- handler = self._find_error_handler(e)
-
- if handler is None:
- reraise(exc_type, exc_value, tb)
- return handler(e)
-
- def handle_exception(self, e):
- """Default exception handling that kicks in when an exception
- occurs that is not caught. In debug mode the exception will
- be re-raised immediately, otherwise it is logged and the handler
- for a 500 internal server error is used. If no such handler
- exists, a default 500 internal server error message is displayed.
-
- .. versionadded:: 0.3
- """
- exc_type, exc_value, tb = sys.exc_info()
-
- got_request_exception.send(self, exception=e)
- handler = self._find_error_handler(InternalServerError())
-
- if self.propagate_exceptions:
- # if we want to repropagate the exception, we can attempt to
- # raise it with the whole traceback in case we can do that
- # (the function was actually called from the except part)
- # otherwise, we just raise the error again
- if exc_value is e:
- reraise(exc_type, exc_value, tb)
- else:
- raise e
-
- self.log_exception((exc_type, exc_value, tb))
- if handler is None:
- return InternalServerError()
- return self.finalize_request(handler(e), from_error_handler=True)
-
- def log_exception(self, exc_info):
- """Logs an exception. This is called by :meth:`handle_exception`
- if debugging is disabled and right before the handler is called.
- The default implementation logs the exception as error on the
- :attr:`logger`.
-
- .. versionadded:: 0.8
- """
- self.logger.error('Exception on %s [%s]' % (
- request.path,
- request.method
- ), exc_info=exc_info)
-
- def raise_routing_exception(self, request):
- """Exceptions that are recording during routing are reraised with
- this method. During debug we are not reraising redirect requests
- for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising
- a different error instead to help debug situations.
-
- :internal:
- """
- if not self.debug \
- or not isinstance(request.routing_exception, RequestRedirect) \
- or request.method in ('GET', 'HEAD', 'OPTIONS'):
- raise request.routing_exception
-
- from .debughelpers import FormDataRoutingRedirect
- raise FormDataRoutingRedirect(request)
-
- def dispatch_request(self):
- """Does the request dispatching. Matches the URL and returns the
- return value of the view or error handler. This does not have to
- be a response object. In order to convert the return value to a
- proper response object, call :func:`make_response`.
-
- .. versionchanged:: 0.7
- This no longer does the exception handling, this code was
- moved to the new :meth:`full_dispatch_request`.
- """
- req = _request_ctx_stack.top.request
- if req.routing_exception is not None:
- self.raise_routing_exception(req)
- rule = req.url_rule
- # if we provide automatic options for this URL and the
- # request came with the OPTIONS method, reply automatically
- if getattr(rule, 'provide_automatic_options', False) \
- and req.method == 'OPTIONS':
- return self.make_default_options_response()
- # otherwise dispatch to the handler for that endpoint
- return self.view_functions[rule.endpoint](**req.view_args)
-
- def full_dispatch_request(self):
- """Dispatches the request and on top of that performs request
- pre and postprocessing as well as HTTP exception catching and
- error handling.
-
- .. versionadded:: 0.7
- """
- self.try_trigger_before_first_request_functions()
- try:
- request_started.send(self)
- rv = self.preprocess_request()
- if rv is None:
- rv = self.dispatch_request()
- except Exception as e:
- rv = self.handle_user_exception(e)
- return self.finalize_request(rv)
-
- def finalize_request(self, rv, from_error_handler=False):
- """Given the return value from a view function this finalizes
- the request by converting it into a response and invoking the
- postprocessing functions. This is invoked for both normal
- request dispatching as well as error handlers.
-
- Because this means that it might be called as a result of a
- failure a special safe mode is available which can be enabled
- with the `from_error_handler` flag. If enabled, failures in
- response processing will be logged and otherwise ignored.
-
- :internal:
- """
- response = self.make_response(rv)
- try:
- response = self.process_response(response)
- request_finished.send(self, response=response)
- except Exception:
- if not from_error_handler:
- raise
- self.logger.exception('Request finalizing failed with an '
- 'error while handling an error')
- return response
-
- def try_trigger_before_first_request_functions(self):
- """Called before each request and will ensure that it triggers
- the :attr:`before_first_request_funcs` and only exactly once per
- application instance (which means process usually).
-
- :internal:
- """
- if self._got_first_request:
- return
- with self._before_request_lock:
- if self._got_first_request:
- return
- for func in self.before_first_request_funcs:
- func()
- self._got_first_request = True
-
- def make_default_options_response(self):
- """This method is called to create the default ``OPTIONS`` response.
- This can be changed through subclassing to change the default
- behavior of ``OPTIONS`` responses.
-
- .. versionadded:: 0.7
- """
- adapter = _request_ctx_stack.top.url_adapter
- if hasattr(adapter, 'allowed_methods'):
- methods = adapter.allowed_methods()
- else:
- # fallback for Werkzeug < 0.7
- methods = []
- try:
- adapter.match(method='--')
- except MethodNotAllowed as e:
- methods = e.valid_methods
- except HTTPException as e:
- pass
- rv = self.response_class()
- rv.allow.update(methods)
- return rv
-
- def should_ignore_error(self, error):
- """This is called to figure out if an error should be ignored
- or not as far as the teardown system is concerned. If this
- function returns ``True`` then the teardown handlers will not be
- passed the error.
-
- .. versionadded:: 0.10
- """
- return False
-
- def make_response(self, rv):
- """Convert the return value from a view function to an instance of
- :attr:`response_class`.
-
- :param rv: the return value from the view function. The view function
- must return a response. Returning ``None``, or the view ending
- without returning, is not allowed. The following types are allowed
- for ``view_rv``:
-
- ``str`` (``unicode`` in Python 2)
- A response object is created with the string encoded to UTF-8
- as the body.
-
- ``bytes`` (``str`` in Python 2)
- A response object is created with the bytes as the body.
-
- ``tuple``
- Either ``(body, status, headers)``, ``(body, status)``, or
- ``(body, headers)``, where ``body`` is any of the other types
- allowed here, ``status`` is a string or an integer, and
- ``headers`` is a dictionary or a list of ``(key, value)``
- tuples. If ``body`` is a :attr:`response_class` instance,
- ``status`` overwrites the exiting value and ``headers`` are
- extended.
-
- :attr:`response_class`
- The object is returned unchanged.
-
- other :class:`~werkzeug.wrappers.Response` class
- The object is coerced to :attr:`response_class`.
-
- :func:`callable`
- The function is called as a WSGI application. The result is
- used to create a response object.
-
- .. versionchanged:: 0.9
- Previously a tuple was interpreted as the arguments for the
- response object.
- """
-
- status = headers = None
-
- # unpack tuple returns
- if isinstance(rv, tuple):
- len_rv = len(rv)
-
- # a 3-tuple is unpacked directly
- if len_rv == 3:
- rv, status, headers = rv
- # decide if a 2-tuple has status or headers
- elif len_rv == 2:
- if isinstance(rv[1], (Headers, dict, tuple, list)):
- rv, headers = rv
- else:
- rv, status = rv
- # other sized tuples are not allowed
- else:
- raise TypeError(
- 'The view function did not return a valid response tuple.'
- ' The tuple must have the form (body, status, headers),'
- ' (body, status), or (body, headers).'
- )
-
- # the body must not be None
- if rv is None:
- raise TypeError(
- 'The view function did not return a valid response. The'
- ' function either returned None or ended without a return'
- ' statement.'
- )
-
- # make sure the body is an instance of the response class
- if not isinstance(rv, self.response_class):
- if isinstance(rv, (text_type, bytes, bytearray)):
- # let the response class set the status and headers instead of
- # waiting to do it manually, so that the class can handle any
- # special logic
- rv = self.response_class(rv, status=status, headers=headers)
- status = headers = None
- else:
- # evaluate a WSGI callable, or coerce a different response
- # class to the correct type
- try:
- rv = self.response_class.force_type(rv, request.environ)
- except TypeError as e:
- new_error = TypeError(
- '{e}\nThe view function did not return a valid'
- ' response. The return type must be a string, tuple,'
- ' Response instance, or WSGI callable, but it was a'
- ' {rv.__class__.__name__}.'.format(e=e, rv=rv)
- )
- reraise(TypeError, new_error, sys.exc_info()[2])
-
- # prefer the status if it was provided
- if status is not None:
- if isinstance(status, (text_type, bytes, bytearray)):
- rv.status = status
- else:
- rv.status_code = status
-
- # extend existing headers with provided headers
- if headers:
- rv.headers.extend(headers)
-
- return rv
-
- def create_url_adapter(self, request):
- """Creates a URL adapter for the given request. The URL adapter
- is created at a point where the request context is not yet set
- up so the request is passed explicitly.
-
- .. versionadded:: 0.6
-
- .. versionchanged:: 0.9
- This can now also be called without a request object when the
- URL adapter is created for the application context.
-
- .. versionchanged:: 1.0
- :data:`SERVER_NAME` no longer implicitly enables subdomain
- matching. Use :attr:`subdomain_matching` instead.
- """
- if request is not None:
- # If subdomain matching is disabled (the default), use the
- # default subdomain in all cases. This should be the default
- # in Werkzeug but it currently does not have that feature.
- subdomain = ((self.url_map.default_subdomain or None)
- if not self.subdomain_matching else None)
- return self.url_map.bind_to_environ(
- request.environ,
- server_name=self.config['SERVER_NAME'],
- subdomain=subdomain)
- # We need at the very least the server name to be set for this
- # to work.
- if self.config['SERVER_NAME'] is not None:
- return self.url_map.bind(
- self.config['SERVER_NAME'],
- script_name=self.config['APPLICATION_ROOT'],
- url_scheme=self.config['PREFERRED_URL_SCHEME'])
-
- def inject_url_defaults(self, endpoint, values):
- """Injects the URL defaults for the given endpoint directly into
- the values dictionary passed. This is used internally and
- automatically called on URL building.
-
- .. versionadded:: 0.7
- """
- funcs = self.url_default_functions.get(None, ())
- if '.' in endpoint:
- bp = endpoint.rsplit('.', 1)[0]
- funcs = chain(funcs, self.url_default_functions.get(bp, ()))
- for func in funcs:
- func(endpoint, values)
-
- def handle_url_build_error(self, error, endpoint, values):
- """Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`.
- """
- exc_type, exc_value, tb = sys.exc_info()
- for handler in self.url_build_error_handlers:
- try:
- rv = handler(error, endpoint, values)
- if rv is not None:
- return rv
- except BuildError as e:
- # make error available outside except block (py3)
- error = e
-
- # At this point we want to reraise the exception. If the error is
- # still the same one we can reraise it with the original traceback,
- # otherwise we raise it from here.
- if error is exc_value:
- reraise(exc_type, exc_value, tb)
- raise error
-
- def preprocess_request(self):
- """Called before the request is dispatched. Calls
- :attr:`url_value_preprocessors` registered with the app and the
- current blueprint (if any). Then calls :attr:`before_request_funcs`
- registered with the app and the blueprint.
-
- If any :meth:`before_request` handler 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.
- """
-
- bp = _request_ctx_stack.top.request.blueprint
-
- funcs = self.url_value_preprocessors.get(None, ())
- if bp is not None and bp in self.url_value_preprocessors:
- funcs = chain(funcs, self.url_value_preprocessors[bp])
- for func in funcs:
- func(request.endpoint, request.view_args)
-
- funcs = self.before_request_funcs.get(None, ())
- if bp is not None and bp in self.before_request_funcs:
- funcs = chain(funcs, self.before_request_funcs[bp])
- for func in funcs:
- rv = func()
- if rv is not None:
- return rv
-
- def process_response(self, response):
- """Can be overridden in order to modify the response object
- before it's sent to the WSGI server. By default this will
- call all the :meth:`after_request` decorated functions.
-
- .. versionchanged:: 0.5
- As of Flask 0.5 the functions registered for after request
- execution are called in reverse order of registration.
-
- :param response: a :attr:`response_class` object.
- :return: a new response object or the same, has to be an
- instance of :attr:`response_class`.
- """
- ctx = _request_ctx_stack.top
- bp = ctx.request.blueprint
- funcs = ctx._after_request_functions
- if bp is not None and bp in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
- if None in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[None]))
- for handler in funcs:
- response = handler(response)
- if not self.session_interface.is_null_session(ctx.session):
- self.session_interface.save_session(self, ctx.session, response)
- return response
-
- def do_teardown_request(self, exc=_sentinel):
- """Called after the request is dispatched and the response is
- returned, right before the request context is popped.
-
- This calls all functions decorated with
- :meth:`teardown_request`, and :meth:`Blueprint.teardown_request`
- if a blueprint handled the request. Finally, the
- :data:`request_tearing_down` signal is sent.
-
- This is called by
- :meth:`RequestContext.pop() <flask.ctx.RequestContext.pop>`,
- which may be delayed during testing to maintain access to
- resources.
-
- :param exc: An unhandled exception raised while dispatching the
- request. Detected from the current exception information if
- not passed. Passed to each teardown function.
-
- .. versionchanged:: 0.9
- Added the ``exc`` argument.
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- funcs = reversed(self.teardown_request_funcs.get(None, ()))
- bp = _request_ctx_stack.top.request.blueprint
- if bp is not None and bp in self.teardown_request_funcs:
- funcs = chain(funcs, reversed(self.teardown_request_funcs[bp]))
- for func in funcs:
- func(exc)
- request_tearing_down.send(self, exc=exc)
-
- def do_teardown_appcontext(self, exc=_sentinel):
- """Called right before the application context is popped.
-
- When handling a request, the application context is popped
- after the request context. See :meth:`do_teardown_request`.
-
- This calls all functions decorated with
- :meth:`teardown_appcontext`. Then the
- :data:`appcontext_tearing_down` signal is sent.
-
- This is called by
- :meth:`AppContext.pop() <flask.ctx.AppContext.pop>`.
-
- .. versionadded:: 0.9
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- for func in reversed(self.teardown_appcontext_funcs):
- func(exc)
- appcontext_tearing_down.send(self, exc=exc)
-
- def app_context(self):
- """Create an :class:`~flask.ctx.AppContext`. Use as a ``with``
- block to push the context, which will make :data:`current_app`
- point at this application.
-
- An application context is automatically pushed by
- :meth:`RequestContext.push() <flask.ctx.RequestContext.push>`
- when handling a request, and when running a CLI command. Use
- this to manually create a context outside of these situations.
-
- ::
-
- with app.app_context():
- init_db()
-
- See :doc:`/appcontext`.
-
- .. versionadded:: 0.9
- """
- return AppContext(self)
-
- def request_context(self, environ):
- """Create a :class:`~flask.ctx.RequestContext` representing a
- WSGI environment. Use a ``with`` block to push the context,
- which will make :data:`request` point at this request.
-
- See :doc:`/reqcontext`.
-
- Typically you should not call this from your own code. A request
- context is automatically pushed by the :meth:`wsgi_app` when
- handling a request. Use :meth:`test_request_context` to create
- an environment and context instead of this method.
-
- :param environ: a WSGI environment
- """
- return RequestContext(self, environ)
-
- def test_request_context(self, *args, **kwargs):
- """Create a :class:`~flask.ctx.RequestContext` for a WSGI
- environment created from the given values. This is mostly useful
- during testing, where you may want to run a function that uses
- request data without dispatching a full request.
-
- See :doc:`/reqcontext`.
-
- Use a ``with`` block to push the context, which will make
- :data:`request` point at the request for the created
- environment. ::
-
- with test_request_context(...):
- generate_report()
-
- When using the shell, it may be easier to push and pop the
- context manually to avoid indentation. ::
-
- ctx = app.test_request_context(...)
- ctx.push()
- ...
- ctx.pop()
-
- Takes the same arguments as Werkzeug's
- :class:`~werkzeug.test.EnvironBuilder`, with some defaults from
- the application. See the linked Werkzeug docs for most of the
- available arguments. Flask-specific behavior is listed here.
-
- :param path: URL path being requested.
- :param base_url: Base URL where the app is being served, which
- ``path`` is relative to. If not given, built from
- :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
- :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
- :param subdomain: Subdomain name to append to
- :data:`SERVER_NAME`.
- :param url_scheme: Scheme to use instead of
- :data:`PREFERRED_URL_SCHEME`.
- :param data: The request body, either as a string or a dict of
- form keys and values.
- :param json: If given, this is serialized as JSON and passed as
- ``data``. Also defaults ``content_type`` to
- ``application/json``.
- :param args: other positional arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- :param kwargs: other keyword arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- """
- from flask.testing import make_test_environ_builder
-
- builder = make_test_environ_builder(self, *args, **kwargs)
-
- try:
- return self.request_context(builder.get_environ())
- finally:
- builder.close()
-
- def wsgi_app(self, environ, start_response):
- """The actual WSGI application. This is not implemented in
- :meth:`__call__` so that middlewares can be applied without
- losing a reference to the app object. Instead of doing this::
-
- app = MyMiddleware(app)
-
- It's a better idea to do this instead::
-
- app.wsgi_app = MyMiddleware(app.wsgi_app)
-
- Then you still have the original application object around and
- can continue to call methods on it.
-
- .. versionchanged:: 0.7
- Teardown events for the request and app contexts are called
- even if an unhandled error occurs. Other events may not be
- called depending on when an error occurs during dispatch.
- See :ref:`callbacks-and-errors`.
-
- :param environ: A WSGI environment.
- :param start_response: A callable accepting a status code,
- a list of headers, and an optional exception context to
- start the response.
- """
- ctx = self.request_context(environ)
- error = None
- try:
- try:
- ctx.push()
- response = self.full_dispatch_request()
- except Exception as e:
- error = e
- response = self.handle_exception(e)
- except:
- error = sys.exc_info()[1]
- raise
- return response(environ, start_response)
- finally:
- if self.should_ignore_error(error):
- error = None
- ctx.auto_pop(error)
-
- def __call__(self, environ, start_response):
- """The WSGI server calls the Flask application object as the
- WSGI application. This calls :meth:`wsgi_app` which can be
- wrapped to applying middleware."""
- return self.wsgi_app(environ, start_response)
-
- def __repr__(self):
- return '<%s %r>' % (
- self.__class__.__name__,
- self.name,
- )
diff --git a/python/flask/blueprints.py b/python/flask/blueprints.py
deleted file mode 100644
index c2158fe..0000000
--- a/python/flask/blueprints.py
+++ /dev/null
@@ -1,447 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.blueprints
- ~~~~~~~~~~~~~~~~
-
- Blueprints are the recommended way to implement larger or more
- pluggable applications in Flask 0.7 and later.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-from functools import update_wrapper
-
-from .helpers import _PackageBoundObject, _endpoint_from_view_func
-
-
-class BlueprintSetupState(object):
- """Temporary holder object for registering a blueprint with the
- application. An instance of this class is created by the
- :meth:`~flask.Blueprint.make_setup_state` method and later passed
- to all register callback functions.
- """
-
- def __init__(self, blueprint, app, options, first_registration):
- #: a reference to the current application
- self.app = app
-
- #: a reference to the blueprint that created this setup state.
- self.blueprint = blueprint
-
- #: a dictionary with all options that were passed to the
- #: :meth:`~flask.Flask.register_blueprint` method.
- self.options = options
-
- #: as blueprints can be registered multiple times with the
- #: application and not everything wants to be registered
- #: multiple times on it, this attribute can be used to figure
- #: out if the blueprint was registered in the past already.
- self.first_registration = first_registration
-
- subdomain = self.options.get('subdomain')
- if subdomain is None:
- subdomain = self.blueprint.subdomain
-
- #: The subdomain that the blueprint should be active for, ``None``
- #: otherwise.
- self.subdomain = subdomain
-
- url_prefix = self.options.get('url_prefix')
- if url_prefix is None:
- url_prefix = self.blueprint.url_prefix
- #: The prefix that should be used for all URLs defined on the
- #: blueprint.
- self.url_prefix = url_prefix
-
- #: A dictionary with URL defaults that is added to each and every
- #: URL that was defined with the blueprint.
- self.url_defaults = dict(self.blueprint.url_values_defaults)
- self.url_defaults.update(self.options.get('url_defaults', ()))
-
- def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
- """A helper method to register a rule (and optionally a view function)
- to the application. The endpoint is automatically prefixed with the
- blueprint's name.
- """
- if self.url_prefix is not None:
- if rule:
- rule = '/'.join((
- self.url_prefix.rstrip('/'), rule.lstrip('/')))
- else:
- rule = self.url_prefix
- options.setdefault('subdomain', self.subdomain)
- if endpoint is None:
- endpoint = _endpoint_from_view_func(view_func)
- defaults = self.url_defaults
- if 'defaults' in options:
- defaults = dict(defaults, **options.pop('defaults'))
- self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint),
- view_func, defaults=defaults, **options)
-
-
-class Blueprint(_PackageBoundObject):
- """Represents a blueprint. A blueprint is an object that records
- functions that will be called with the
- :class:`~flask.blueprints.BlueprintSetupState` later to register functions
- or other things on the main application. See :ref:`blueprints` for more
- information.
-
- .. versionadded:: 0.7
- """
-
- warn_on_modifications = False
- _got_registered_once = False
-
- #: Blueprint local JSON decoder class to use.
- #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_encoder`.
- json_encoder = None
- #: Blueprint local JSON decoder class to use.
- #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_decoder`.
- 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__(self, name, import_name, static_folder=None,
- static_url_path=None, template_folder=None,
- url_prefix=None, subdomain=None, url_defaults=None,
- root_path=None):
- _PackageBoundObject.__init__(self, import_name, template_folder,
- root_path=root_path)
- self.name = name
- self.url_prefix = url_prefix
- self.subdomain = subdomain
- self.static_folder = static_folder
- self.static_url_path = static_url_path
- self.deferred_functions = []
- if url_defaults is None:
- url_defaults = {}
- self.url_values_defaults = url_defaults
-
- def record(self, func):
- """Registers a function that is called when the blueprint is
- registered on the application. This function is called with the
- state as argument as returned by the :meth:`make_setup_state`
- method.
- """
- if self._got_registered_once and self.warn_on_modifications:
- from warnings import warn
- warn(Warning('The blueprint was already registered once '
- 'but is getting modified now. These changes '
- 'will not show up.'))
- self.deferred_functions.append(func)
-
- def record_once(self, func):
- """Works like :meth:`record` but wraps the function in another
- function that will ensure the function is only called once. If the
- blueprint is registered a second time on the application, the
- function passed is not called.
- """
- def wrapper(state):
- if state.first_registration:
- func(state)
- return self.record(update_wrapper(wrapper, func))
-
- def make_setup_state(self, app, options, first_registration=False):
- """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState`
- object that is later passed to the register callback functions.
- Subclasses can override this to return a subclass of the setup state.
- """
- return BlueprintSetupState(self, app, options, first_registration)
-
- def register(self, app, options, first_registration=False):
- """Called by :meth:`Flask.register_blueprint` to register all views
- and callbacks registered on the blueprint with the application. Creates
- a :class:`.BlueprintSetupState` and calls each :meth:`record` callback
- with it.
-
- :param app: The application this blueprint is being registered with.
- :param options: Keyword arguments forwarded from
- :meth:`~Flask.register_blueprint`.
- :param first_registration: Whether this is the first time this
- blueprint has been registered on the application.
- """
- self._got_registered_once = True
- state = self.make_setup_state(app, options, first_registration)
-
- if self.has_static_folder:
- state.add_url_rule(
- self.static_url_path + '/<path:filename>',
- view_func=self.send_static_file, endpoint='static'
- )
-
- for deferred in self.deferred_functions:
- deferred(state)
-
- def route(self, rule, **options):
- """Like :meth:`Flask.route` but for a blueprint. The endpoint for the
- :func:`url_for` function is prefixed with the name of the blueprint.
- """
- def decorator(f):
- endpoint = options.pop("endpoint", f.__name__)
- self.add_url_rule(rule, endpoint, f, **options)
- return f
- return decorator
-
- def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
- """Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for
- the :func:`url_for` function is prefixed with the name of the blueprint.
- """
- if endpoint:
- assert '.' not in endpoint, "Blueprint endpoints should not contain dots"
- if view_func and hasattr(view_func, '__name__'):
- assert '.' not in view_func.__name__, "Blueprint view function name should not contain dots"
- self.record(lambda s:
- s.add_url_rule(rule, endpoint, view_func, **options))
-
- def endpoint(self, endpoint):
- """Like :meth:`Flask.endpoint` but for a blueprint. This does not
- prefix the endpoint with the blueprint name, this has to be done
- explicitly by the user of this method. If the endpoint is prefixed
- with a `.` it will be registered to the current blueprint, otherwise
- it's an application independent endpoint.
- """
- def decorator(f):
- def register_endpoint(state):
- state.app.view_functions[endpoint] = f
- self.record_once(register_endpoint)
- return f
- return decorator
-
- def app_template_filter(self, name=None):
- """Register a custom template filter, available application wide. Like
- :meth:`Flask.template_filter` but for a blueprint.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_app_template_filter(f, name=name)
- return f
- return decorator
-
- def add_app_template_filter(self, f, name=None):
- """Register a custom template filter, available application wide. Like
- :meth:`Flask.add_template_filter` but for a blueprint. Works exactly
- like the :meth:`app_template_filter` decorator.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- def register_template(state):
- state.app.jinja_env.filters[name or f.__name__] = f
- self.record_once(register_template)
-
- def app_template_test(self, name=None):
- """Register a custom template test, available application wide. Like
- :meth:`Flask.template_test` but for a blueprint.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_app_template_test(f, name=name)
- return f
- return decorator
-
- def add_app_template_test(self, f, name=None):
- """Register a custom template test, available application wide. Like
- :meth:`Flask.add_template_test` but for a blueprint. Works exactly
- like the :meth:`app_template_test` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- def register_template(state):
- state.app.jinja_env.tests[name or f.__name__] = f
- self.record_once(register_template)
-
- def app_template_global(self, name=None):
- """Register a custom template global, available application wide. Like
- :meth:`Flask.template_global` but for a blueprint.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_app_template_global(f, name=name)
- return f
- return decorator
-
- def add_app_template_global(self, f, name=None):
- """Register a custom template global, available application wide. Like
- :meth:`Flask.add_template_global` but for a blueprint. Works exactly
- like the :meth:`app_template_global` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global, otherwise the
- function name will be used.
- """
- def register_template(state):
- state.app.jinja_env.globals[name or f.__name__] = f
- self.record_once(register_template)
-
- def before_request(self, f):
- """Like :meth:`Flask.before_request` but for a blueprint. This function
- is only executed before each request that is handled by a function of
- that blueprint.
- """
- self.record_once(lambda s: s.app.before_request_funcs
- .setdefault(self.name, []).append(f))
- return f
-
- def before_app_request(self, f):
- """Like :meth:`Flask.before_request`. Such a function is executed
- before each request, even if outside of a blueprint.
- """
- self.record_once(lambda s: s.app.before_request_funcs
- .setdefault(None, []).append(f))
- return f
-
- def before_app_first_request(self, f):
- """Like :meth:`Flask.before_first_request`. Such a function is
- executed before the first request to the application.
- """
- self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
- return f
-
- def after_request(self, f):
- """Like :meth:`Flask.after_request` but for a blueprint. This function
- is only executed after each request that is handled by a function of
- that blueprint.
- """
- self.record_once(lambda s: s.app.after_request_funcs
- .setdefault(self.name, []).append(f))
- return f
-
- def after_app_request(self, f):
- """Like :meth:`Flask.after_request` but for a blueprint. Such a function
- is executed after each request, even if outside of the blueprint.
- """
- self.record_once(lambda s: s.app.after_request_funcs
- .setdefault(None, []).append(f))
- return f
-
- def teardown_request(self, f):
- """Like :meth:`Flask.teardown_request` but for a blueprint. This
- function is only executed when tearing down requests handled by a
- function of that blueprint. Teardown request functions are executed
- when the request context is popped, even when no actual request was
- performed.
- """
- self.record_once(lambda s: s.app.teardown_request_funcs
- .setdefault(self.name, []).append(f))
- return f
-
- def teardown_app_request(self, f):
- """Like :meth:`Flask.teardown_request` but for a blueprint. Such a
- function is executed when tearing down each request, even if outside of
- the blueprint.
- """
- self.record_once(lambda s: s.app.teardown_request_funcs
- .setdefault(None, []).append(f))
- return f
-
- def context_processor(self, f):
- """Like :meth:`Flask.context_processor` but for a blueprint. This
- function is only executed for requests handled by a blueprint.
- """
- self.record_once(lambda s: s.app.template_context_processors
- .setdefault(self.name, []).append(f))
- return f
-
- def app_context_processor(self, f):
- """Like :meth:`Flask.context_processor` but for a blueprint. Such a
- function is executed each request, even if outside of the blueprint.
- """
- self.record_once(lambda s: s.app.template_context_processors
- .setdefault(None, []).append(f))
- return f
-
- def app_errorhandler(self, code):
- """Like :meth:`Flask.errorhandler` but for a blueprint. This
- handler is used for all requests, even if outside of the blueprint.
- """
- def decorator(f):
- self.record_once(lambda s: s.app.errorhandler(code)(f))
- return f
- return decorator
-
- def url_value_preprocessor(self, f):
- """Registers a function as URL value preprocessor for this
- blueprint. It's called before the view functions are called and
- can modify the url values provided.
- """
- self.record_once(lambda s: s.app.url_value_preprocessors
- .setdefault(self.name, []).append(f))
- return f
-
- def url_defaults(self, f):
- """Callback function for URL defaults for this blueprint. It's called
- with the endpoint and values and should update the values passed
- in place.
- """
- self.record_once(lambda s: s.app.url_default_functions
- .setdefault(self.name, []).append(f))
- return f
-
- def app_url_value_preprocessor(self, f):
- """Same as :meth:`url_value_preprocessor` but application wide.
- """
- self.record_once(lambda s: s.app.url_value_preprocessors
- .setdefault(None, []).append(f))
- return f
-
- def app_url_defaults(self, f):
- """Same as :meth:`url_defaults` but application wide.
- """
- self.record_once(lambda s: s.app.url_default_functions
- .setdefault(None, []).append(f))
- return f
-
- def errorhandler(self, code_or_exception):
- """Registers an error handler that becomes active for this blueprint
- only. Please be aware that routing does not happen local to a
- blueprint so an error handler for 404 usually is not handled by
- a blueprint unless it is caused inside a view function. Another
- special case is the 500 internal server error which is always looked
- up from the application.
-
- Otherwise works as the :meth:`~flask.Flask.errorhandler` decorator
- of the :class:`~flask.Flask` object.
- """
- def decorator(f):
- self.record_once(lambda s: s.app._register_error_handler(
- self.name, code_or_exception, f))
- return f
- return decorator
-
- def register_error_handler(self, code_or_exception, f):
- """Non-decorator version of the :meth:`errorhandler` error attach
- function, akin to the :meth:`~flask.Flask.register_error_handler`
- application-wide function of the :class:`~flask.Flask` object but
- for error handlers limited to this blueprint.
-
- .. versionadded:: 0.11
- """
- self.record_once(lambda s: s.app._register_error_handler(
- self.name, code_or_exception, f))
diff --git a/python/flask/cli.py b/python/flask/cli.py
deleted file mode 100644
index 3eb93b3..0000000
--- a/python/flask/cli.py
+++ /dev/null
@@ -1,910 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.cli
- ~~~~~~~~~
-
- A simple command line application to run flask apps.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-from __future__ import print_function
-
-import ast
-import inspect
-import os
-import platform
-import re
-import ssl
-import sys
-import traceback
-from functools import update_wrapper
-from operator import attrgetter
-from threading import Lock, Thread
-
-import click
-from werkzeug.utils import import_string
-
-from . import __version__
-from ._compat import getargspec, iteritems, reraise, text_type
-from .globals import current_app
-from .helpers import get_debug_flag, get_env, get_load_dotenv
-
-try:
- import dotenv
-except ImportError:
- dotenv = None
-
-
-class NoAppException(click.UsageError):
- """Raised if an application cannot be found or loaded."""
-
-
-def find_best_app(script_info, module):
- """Given a module instance this tries to find the best possible
- application in the module or raises an exception.
- """
- from . import Flask
-
- # Search for the most common names first.
- for attr_name in ('app', 'application'):
- app = getattr(module, attr_name, None)
-
- if isinstance(app, Flask):
- return app
-
- # Otherwise find the only object that is a Flask instance.
- matches = [
- v for k, v in iteritems(module.__dict__) if isinstance(v, Flask)
- ]
-
- if len(matches) == 1:
- return matches[0]
- elif len(matches) > 1:
- raise NoAppException(
- 'Detected multiple Flask applications in module "{module}". Use '
- '"FLASK_APP={module}:name" to specify the correct '
- 'one.'.format(module=module.__name__)
- )
-
- # Search for app factory functions.
- for attr_name in ('create_app', 'make_app'):
- app_factory = getattr(module, attr_name, None)
-
- if inspect.isfunction(app_factory):
- try:
- app = call_factory(script_info, app_factory)
-
- if isinstance(app, Flask):
- return app
- except TypeError:
- if not _called_with_wrong_args(app_factory):
- raise
- raise NoAppException(
- 'Detected factory "{factory}" in module "{module}", but '
- 'could not call it without arguments. Use '
- '"FLASK_APP=\'{module}:{factory}(args)\'" to specify '
- 'arguments.'.format(
- factory=attr_name, module=module.__name__
- )
- )
-
- raise NoAppException(
- 'Failed to find Flask application or factory in module "{module}". '
- 'Use "FLASK_APP={module}:name to specify one.'.format(
- module=module.__name__
- )
- )
-
-
-def call_factory(script_info, app_factory, arguments=()):
- """Takes an app factory, a ``script_info` object and optionally a tuple
- of arguments. Checks for the existence of a script_info argument and calls
- the app_factory depending on that and the arguments provided.
- """
- args_spec = getargspec(app_factory)
- arg_names = args_spec.args
- arg_defaults = args_spec.defaults
-
- if 'script_info' in arg_names:
- return app_factory(*arguments, script_info=script_info)
- elif arguments:
- return app_factory(*arguments)
- elif not arguments and len(arg_names) == 1 and arg_defaults is None:
- return app_factory(script_info)
-
- return app_factory()
-
-
-def _called_with_wrong_args(factory):
- """Check whether calling a function raised a ``TypeError`` because
- the call failed or because something in the factory raised the
- error.
-
- :param factory: the factory function that was called
- :return: true if the call failed
- """
- tb = sys.exc_info()[2]
-
- try:
- while tb is not None:
- if tb.tb_frame.f_code is factory.__code__:
- # in the factory, it was called successfully
- return False
-
- tb = tb.tb_next
-
- # didn't reach the factory
- return True
- finally:
- del tb
-
-
-def find_app_by_string(script_info, module, app_name):
- """Checks if the given string is a variable name or a function. If it is a
- function, it checks for specified arguments and whether it takes a
- ``script_info`` argument and calls the function with the appropriate
- arguments.
- """
- from flask import Flask
- match = re.match(r'^ *([^ ()]+) *(?:\((.*?) *,? *\))? *$', app_name)
-
- if not match:
- raise NoAppException(
- '"{name}" is not a valid variable name or function '
- 'expression.'.format(name=app_name)
- )
-
- name, args = match.groups()
-
- try:
- attr = getattr(module, name)
- except AttributeError as e:
- raise NoAppException(e.args[0])
-
- if inspect.isfunction(attr):
- if args:
- try:
- args = ast.literal_eval('({args},)'.format(args=args))
- except (ValueError, SyntaxError)as e:
- raise NoAppException(
- 'Could not parse the arguments in '
- '"{app_name}".'.format(e=e, app_name=app_name)
- )
- else:
- args = ()
-
- try:
- app = call_factory(script_info, attr, args)
- except TypeError as e:
- if not _called_with_wrong_args(attr):
- raise
-
- raise NoAppException(
- '{e}\nThe factory "{app_name}" in module "{module}" could not '
- 'be called with the specified arguments.'.format(
- e=e, app_name=app_name, module=module.__name__
- )
- )
- else:
- app = attr
-
- if isinstance(app, Flask):
- return app
-
- raise NoAppException(
- 'A valid Flask application was not obtained from '
- '"{module}:{app_name}".'.format(
- module=module.__name__, app_name=app_name
- )
- )
-
-
-def prepare_import(path):
- """Given a filename this will try to calculate the python path, add it
- to the search path and return the actual module name that is expected.
- """
- path = os.path.realpath(path)
-
- if os.path.splitext(path)[1] == '.py':
- path = os.path.splitext(path)[0]
-
- if os.path.basename(path) == '__init__':
- path = os.path.dirname(path)
-
- module_name = []
-
- # move up until outside package structure (no __init__.py)
- while True:
- path, name = os.path.split(path)
- module_name.append(name)
-
- if not os.path.exists(os.path.join(path, '__init__.py')):
- break
-
- if sys.path[0] != path:
- sys.path.insert(0, path)
-
- return '.'.join(module_name[::-1])
-
-
-def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
- __traceback_hide__ = True
-
- try:
- __import__(module_name)
- except ImportError:
- # Reraise the ImportError if it occurred within the imported module.
- # Determine this by checking whether the trace has a depth > 1.
- if sys.exc_info()[-1].tb_next:
- raise NoAppException(
- 'While importing "{name}", an ImportError was raised:'
- '\n\n{tb}'.format(name=module_name, tb=traceback.format_exc())
- )
- elif raise_if_not_found:
- raise NoAppException(
- 'Could not import "{name}".'.format(name=module_name)
- )
- else:
- return
-
- module = sys.modules[module_name]
-
- if app_name is None:
- return find_best_app(script_info, module)
- else:
- return find_app_by_string(script_info, module, app_name)
-
-
-def get_version(ctx, param, value):
- if not value or ctx.resilient_parsing:
- return
- import werkzeug
- message = (
- 'Python %(python)s\n'
- 'Flask %(flask)s\n'
- 'Werkzeug %(werkzeug)s'
- )
- click.echo(message % {
- 'python': platform.python_version(),
- 'flask': __version__,
- 'werkzeug': werkzeug.__version__,
- }, color=ctx.color)
- ctx.exit()
-
-
-version_option = click.Option(
- ['--version'],
- help='Show the flask version',
- expose_value=False,
- callback=get_version,
- is_flag=True,
- is_eager=True
-)
-
-
-class DispatchingApp(object):
- """Special application that dispatches to a Flask application which
- is imported by name in a background thread. If an error happens
- it is recorded and shown as part of the WSGI handling which in case
- of the Werkzeug debugger means that it shows up in the browser.
- """
-
- def __init__(self, loader, use_eager_loading=False):
- self.loader = loader
- self._app = None
- self._lock = Lock()
- self._bg_loading_exc_info = None
- if use_eager_loading:
- self._load_unlocked()
- else:
- self._load_in_background()
-
- def _load_in_background(self):
- def _load_app():
- __traceback_hide__ = True
- with self._lock:
- try:
- self._load_unlocked()
- except Exception:
- self._bg_loading_exc_info = sys.exc_info()
- t = Thread(target=_load_app, args=())
- t.start()
-
- def _flush_bg_loading_exception(self):
- __traceback_hide__ = True
- exc_info = self._bg_loading_exc_info
- if exc_info is not None:
- self._bg_loading_exc_info = None
- reraise(*exc_info)
-
- def _load_unlocked(self):
- __traceback_hide__ = True
- self._app = rv = self.loader()
- self._bg_loading_exc_info = None
- return rv
-
- def __call__(self, environ, start_response):
- __traceback_hide__ = True
- if self._app is not None:
- return self._app(environ, start_response)
- self._flush_bg_loading_exception()
- with self._lock:
- if self._app is not None:
- rv = self._app
- else:
- rv = self._load_unlocked()
- return rv(environ, start_response)
-
-
-class ScriptInfo(object):
- """Helper object to deal with Flask applications. This is usually not
- necessary to interface with as it's used internally in the dispatching
- to click. In future versions of Flask this object will most likely play
- a bigger role. Typically it's created automatically by the
- :class:`FlaskGroup` but you can also manually create it and pass it
- onwards as click object.
- """
-
- def __init__(self, app_import_path=None, create_app=None,
- set_debug_flag=True):
- #: Optionally the import path for the Flask application.
- self.app_import_path = app_import_path or os.environ.get('FLASK_APP')
- #: Optionally a function that is passed the script info to create
- #: the instance of the application.
- self.create_app = create_app
- #: A dictionary with arbitrary data that can be associated with
- #: this script info.
- self.data = {}
- self.set_debug_flag = set_debug_flag
- self._loaded_app = None
-
- def load_app(self):
- """Loads the Flask app (if not yet loaded) and returns it. Calling
- this multiple times will just result in the already loaded app to
- be returned.
- """
- __traceback_hide__ = True
-
- if self._loaded_app is not None:
- return self._loaded_app
-
- app = None
-
- if self.create_app is not None:
- app = call_factory(self, self.create_app)
- else:
- if self.app_import_path:
- path, name = (re.split(r':(?![\\/])', self.app_import_path, 1) + [None])[:2]
- import_name = prepare_import(path)
- app = locate_app(self, import_name, name)
- else:
- for path in ('wsgi.py', 'app.py'):
- import_name = prepare_import(path)
- app = locate_app(self, import_name, None,
- raise_if_not_found=False)
-
- if app:
- break
-
- if not app:
- raise NoAppException(
- 'Could not locate a Flask application. You did not provide '
- 'the "FLASK_APP" environment variable, and a "wsgi.py" or '
- '"app.py" module was not found in the current directory.'
- )
-
- if self.set_debug_flag:
- # Update the app's debug flag through the descriptor so that
- # other values repopulate as well.
- app.debug = get_debug_flag()
-
- self._loaded_app = app
- return app
-
-
-pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True)
-
-
-def with_appcontext(f):
- """Wraps a callback so that it's guaranteed to be executed with the
- script's application context. If callbacks are registered directly
- to the ``app.cli`` object then they are wrapped with this function
- by default unless it's disabled.
- """
- @click.pass_context
- def decorator(__ctx, *args, **kwargs):
- with __ctx.ensure_object(ScriptInfo).load_app().app_context():
- return __ctx.invoke(f, *args, **kwargs)
- return update_wrapper(decorator, f)
-
-
-class AppGroup(click.Group):
- """This works similar to a regular click :class:`~click.Group` but it
- changes the behavior of the :meth:`command` decorator so that it
- automatically wraps the functions in :func:`with_appcontext`.
-
- Not to be confused with :class:`FlaskGroup`.
- """
-
- def command(self, *args, **kwargs):
- """This works exactly like the method of the same name on a regular
- :class:`click.Group` but it wraps callbacks in :func:`with_appcontext`
- unless it's disabled by passing ``with_appcontext=False``.
- """
- wrap_for_ctx = kwargs.pop('with_appcontext', True)
- def decorator(f):
- if wrap_for_ctx:
- f = with_appcontext(f)
- return click.Group.command(self, *args, **kwargs)(f)
- return decorator
-
- def group(self, *args, **kwargs):
- """This works exactly like the method of the same name on a regular
- :class:`click.Group` but it defaults the group class to
- :class:`AppGroup`.
- """
- kwargs.setdefault('cls', AppGroup)
- return click.Group.group(self, *args, **kwargs)
-
-
-class FlaskGroup(AppGroup):
- """Special subclass of the :class:`AppGroup` group that supports
- loading more commands from the configured Flask app. Normally a
- developer does not have to interface with this class but there are
- some very advanced use cases for which it makes sense to create an
- instance of this.
-
- For information as of why this is useful see :ref:`custom-scripts`.
-
- :param add_default_commands: if this is True then the default run and
- shell commands wil be added.
- :param add_version_option: adds the ``--version`` option.
- :param create_app: an optional callback that is passed the script info and
- returns the loaded app.
- :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
- files to set environment variables. Will also change the working
- directory to the directory containing the first file found.
- :param set_debug_flag: Set the app's debug flag based on the active
- environment
-
- .. versionchanged:: 1.0
- If installed, python-dotenv will be used to load environment variables
- from :file:`.env` and :file:`.flaskenv` files.
- """
-
- def __init__(self, add_default_commands=True, create_app=None,
- add_version_option=True, load_dotenv=True,
- set_debug_flag=True, **extra):
- params = list(extra.pop('params', None) or ())
-
- if add_version_option:
- params.append(version_option)
-
- AppGroup.__init__(self, params=params, **extra)
- self.create_app = create_app
- self.load_dotenv = load_dotenv
- self.set_debug_flag = set_debug_flag
-
- if add_default_commands:
- self.add_command(run_command)
- self.add_command(shell_command)
- self.add_command(routes_command)
-
- self._loaded_plugin_commands = False
-
- def _load_plugin_commands(self):
- if self._loaded_plugin_commands:
- return
- try:
- import pkg_resources
- except ImportError:
- self._loaded_plugin_commands = True
- return
-
- for ep in pkg_resources.iter_entry_points('flask.commands'):
- self.add_command(ep.load(), ep.name)
- self._loaded_plugin_commands = True
-
- def get_command(self, ctx, name):
- self._load_plugin_commands()
-
- # We load built-in commands first as these should always be the
- # same no matter what the app does. If the app does want to
- # override this it needs to make a custom instance of this group
- # and not attach the default commands.
- #
- # This also means that the script stays functional in case the
- # application completely fails.
- rv = AppGroup.get_command(self, ctx, name)
- if rv is not None:
- return rv
-
- info = ctx.ensure_object(ScriptInfo)
- try:
- rv = info.load_app().cli.get_command(ctx, name)
- if rv is not None:
- return rv
- except NoAppException:
- pass
-
- def list_commands(self, ctx):
- self._load_plugin_commands()
-
- # The commands available is the list of both the application (if
- # available) plus the builtin commands.
- rv = set(click.Group.list_commands(self, ctx))
- info = ctx.ensure_object(ScriptInfo)
- try:
- rv.update(info.load_app().cli.list_commands(ctx))
- except Exception:
- # Here we intentionally swallow all exceptions as we don't
- # want the help page to break if the app does not exist.
- # If someone attempts to use the command we try to create
- # the app again and this will give us the error.
- # However, we will not do so silently because that would confuse
- # users.
- traceback.print_exc()
- return sorted(rv)
-
- def main(self, *args, **kwargs):
- # Set a global flag that indicates that we were invoked from the
- # command line interface. This is detected by Flask.run to make the
- # call into a no-op. This is necessary to avoid ugly errors when the
- # script that is loaded here also attempts to start a server.
- os.environ['FLASK_RUN_FROM_CLI'] = 'true'
-
- if get_load_dotenv(self.load_dotenv):
- load_dotenv()
-
- obj = kwargs.get('obj')
-
- if obj is None:
- obj = ScriptInfo(create_app=self.create_app,
- set_debug_flag=self.set_debug_flag)
-
- kwargs['obj'] = obj
- kwargs.setdefault('auto_envvar_prefix', 'FLASK')
- return super(FlaskGroup, self).main(*args, **kwargs)
-
-
-def _path_is_ancestor(path, other):
- """Take ``other`` and remove the length of ``path`` from it. Then join it
- to ``path``. If it is the original value, ``path`` is an ancestor of
- ``other``."""
- return os.path.join(path, other[len(path):].lstrip(os.sep)) == other
-
-
-def load_dotenv(path=None):
- """Load "dotenv" files in order of precedence to set environment variables.
-
- If an env var is already set it is not overwritten, so earlier files in the
- list are preferred over later files.
-
- Changes the current working directory to the location of the first file
- found, with the assumption that it is in the top level project directory
- and will be where the Python path should import local packages from.
-
- This is a no-op if `python-dotenv`_ is not installed.
-
- .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
-
- :param path: Load the file at this location instead of searching.
- :return: ``True`` if a file was loaded.
-
- .. versionadded:: 1.0
- """
- if dotenv is None:
- if path or os.path.exists('.env') or os.path.exists('.flaskenv'):
- click.secho(
- ' * Tip: There are .env files present.'
- ' Do "pip install python-dotenv" to use them.',
- fg='yellow')
- return
-
- if path is not None:
- return dotenv.load_dotenv(path)
-
- new_dir = None
-
- for name in ('.env', '.flaskenv'):
- path = dotenv.find_dotenv(name, usecwd=True)
-
- if not path:
- continue
-
- if new_dir is None:
- new_dir = os.path.dirname(path)
-
- dotenv.load_dotenv(path)
-
- if new_dir and os.getcwd() != new_dir:
- os.chdir(new_dir)
-
- return new_dir is not None # at least one file was located and loaded
-
-
-def show_server_banner(env, debug, app_import_path, eager_loading):
- """Show extra startup messages the first time the server is run,
- ignoring the reloader.
- """
- if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
- return
-
- if app_import_path is not None:
- message = ' * Serving Flask app "{0}"'.format(app_import_path)
-
- if not eager_loading:
- message += ' (lazy loading)'
-
- click.echo(message)
-
- click.echo(' * Environment: {0}'.format(env))
-
- if env == 'production':
- click.secho(
- ' WARNING: This is a development server. '
- 'Do not use it in a production deployment.', fg='red')
- click.secho(' Use a production WSGI server instead.', dim=True)
-
- if debug is not None:
- click.echo(' * Debug mode: {0}'.format('on' if debug else 'off'))
-
-
-class CertParamType(click.ParamType):
- """Click option type for the ``--cert`` option. Allows either an
- existing file, the string ``'adhoc'``, or an import for a
- :class:`~ssl.SSLContext` object.
- """
-
- name = 'path'
-
- def __init__(self):
- self.path_type = click.Path(
- exists=True, dir_okay=False, resolve_path=True)
-
- def convert(self, value, param, ctx):
- try:
- return self.path_type(value, param, ctx)
- except click.BadParameter:
- value = click.STRING(value, param, ctx).lower()
-
- if value == 'adhoc':
- try:
- import OpenSSL
- except ImportError:
- raise click.BadParameter(
- 'Using ad-hoc certificates requires pyOpenSSL.',
- ctx, param)
-
- return value
-
- obj = import_string(value, silent=True)
-
- if sys.version_info < (2, 7, 9):
- if obj:
- return obj
- else:
- if isinstance(obj, ssl.SSLContext):
- return obj
-
- raise
-
-
-def _validate_key(ctx, param, value):
- """The ``--key`` option must be specified when ``--cert`` is a file.
- Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed.
- """
- cert = ctx.params.get('cert')
- is_adhoc = cert == 'adhoc'
-
- if sys.version_info < (2, 7, 9):
- is_context = cert and not isinstance(cert, (text_type, bytes))
- else:
- is_context = isinstance(cert, ssl.SSLContext)
-
- if value is not None:
- if is_adhoc:
- raise click.BadParameter(
- 'When "--cert" is "adhoc", "--key" is not used.',
- ctx, param)
-
- if is_context:
- raise click.BadParameter(
- 'When "--cert" is an SSLContext object, "--key is not used.',
- ctx, param)
-
- if not cert:
- raise click.BadParameter(
- '"--cert" must also be specified.',
- ctx, param)
-
- ctx.params['cert'] = cert, value
-
- else:
- if cert and not (is_adhoc or is_context):
- raise click.BadParameter(
- 'Required when using "--cert".',
- ctx, param)
-
- return value
-
-
-@click.command('run', short_help='Run a development server.')
-@click.option('--host', '-h', default='127.0.0.1',
- help='The interface to bind to.')
-@click.option('--port', '-p', default=5000,
- help='The port to bind to.')
-@click.option('--cert', type=CertParamType(),
- help='Specify a certificate file to use HTTPS.')
-@click.option('--key',
- type=click.Path(exists=True, dir_okay=False, resolve_path=True),
- callback=_validate_key, expose_value=False,
- help='The key file to use when specifying a certificate.')
-@click.option('--reload/--no-reload', default=None,
- help='Enable or disable the reloader. By default the reloader '
- 'is active if debug is enabled.')
-@click.option('--debugger/--no-debugger', default=None,
- help='Enable or disable the debugger. By default the debugger '
- 'is active if debug is enabled.')
-@click.option('--eager-loading/--lazy-loader', default=None,
- help='Enable or disable eager loading. By default eager '
- 'loading is enabled if the reloader is disabled.')
-@click.option('--with-threads/--without-threads', default=True,
- help='Enable or disable multithreading.')
-@pass_script_info
-def run_command(info, host, port, reload, debugger, eager_loading,
- with_threads, cert):
- """Run a local development server.
-
- This server is for development purposes only. It does not provide
- the stability, security, or performance of production WSGI servers.
-
- The reloader and debugger are enabled by default if
- FLASK_ENV=development or FLASK_DEBUG=1.
- """
- debug = get_debug_flag()
-
- if reload is None:
- reload = debug
-
- if debugger is None:
- debugger = debug
-
- if eager_loading is None:
- eager_loading = not reload
-
- show_server_banner(get_env(), debug, info.app_import_path, eager_loading)
- app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
-
- from werkzeug.serving import run_simple
- run_simple(host, port, app, use_reloader=reload, use_debugger=debugger,
- threaded=with_threads, ssl_context=cert)
-
-
-@click.command('shell', short_help='Run a shell in the app context.')
-@with_appcontext
-def shell_command():
- """Run an interactive Python shell in the context of a given
- Flask application. The application will populate the default
- namespace of this shell according to it's configuration.
-
- This is useful for executing small snippets of management code
- without having to manually configure the application.
- """
- import code
- from flask.globals import _app_ctx_stack
- app = _app_ctx_stack.top.app
- banner = 'Python %s on %s\nApp: %s [%s]\nInstance: %s' % (
- sys.version,
- sys.platform,
- app.import_name,
- app.env,
- app.instance_path,
- )
- ctx = {}
-
- # Support the regular Python interpreter startup script if someone
- # is using it.
- startup = os.environ.get('PYTHONSTARTUP')
- if startup and os.path.isfile(startup):
- with open(startup, 'r') as f:
- eval(compile(f.read(), startup, 'exec'), ctx)
-
- ctx.update(app.make_shell_context())
-
- code.interact(banner=banner, local=ctx)
-
-
-@click.command('routes', short_help='Show the routes for the app.')
-@click.option(
- '--sort', '-s',
- type=click.Choice(('endpoint', 'methods', 'rule', 'match')),
- default='endpoint',
- help=(
- 'Method to sort routes by. "match" is the order that Flask will match '
- 'routes when dispatching a request.'
- )
-)
-@click.option(
- '--all-methods',
- is_flag=True,
- help="Show HEAD and OPTIONS methods."
-)
-@with_appcontext
-def routes_command(sort, all_methods):
- """Show all registered routes with endpoints and methods."""
-
- rules = list(current_app.url_map.iter_rules())
- if not rules:
- click.echo('No routes were registered.')
- return
-
- ignored_methods = set(() if all_methods else ('HEAD', 'OPTIONS'))
-
- if sort in ('endpoint', 'rule'):
- rules = sorted(rules, key=attrgetter(sort))
- elif sort == 'methods':
- rules = sorted(rules, key=lambda rule: sorted(rule.methods))
-
- rule_methods = [
- ', '.join(sorted(rule.methods - ignored_methods)) for rule in rules
- ]
-
- headers = ('Endpoint', 'Methods', 'Rule')
- widths = (
- max(len(rule.endpoint) for rule in rules),
- max(len(methods) for methods in rule_methods),
- max(len(rule.rule) for rule in rules),
- )
- widths = [max(len(h), w) for h, w in zip(headers, widths)]
- row = '{{0:<{0}}} {{1:<{1}}} {{2:<{2}}}'.format(*widths)
-
- click.echo(row.format(*headers).strip())
- click.echo(row.format(*('-' * width for width in widths)))
-
- for rule, methods in zip(rules, rule_methods):
- click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip())
-
-
-cli = FlaskGroup(help="""\
-A general utility script for Flask applications.
-
-Provides commands from Flask, extensions, and the application. Loads the
-application defined in the FLASK_APP environment variable, or from a wsgi.py
-file. Setting the FLASK_ENV environment variable to 'development' will enable
-debug mode.
-
-\b
- {prefix}{cmd} FLASK_APP=hello.py
- {prefix}{cmd} FLASK_ENV=development
- {prefix}flask run
-""".format(
- cmd='export' if os.name == 'posix' else 'set',
- prefix='$ ' if os.name == 'posix' else '> '
-))
-
-
-def main(as_module=False):
- args = sys.argv[1:]
-
- if as_module:
- this_module = 'flask'
-
- if sys.version_info < (2, 7):
- this_module += '.cli'
-
- name = 'python -m ' + this_module
-
- # Python rewrites "python -m flask" to the path to the file in argv.
- # Restore the original command so that the reloader works.
- sys.argv = ['-m', this_module] + args
- else:
- name = None
-
- cli.main(args=args, prog_name=name)
-
-
-if __name__ == '__main__':
- main(as_module=True)
diff --git a/python/flask/config.py b/python/flask/config.py
deleted file mode 100644
index a5475ed..0000000
--- a/python/flask/config.py
+++ /dev/null
@@ -1,269 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.config
- ~~~~~~~~~~~~
-
- Implements the configuration related objects.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import os
-import types
-import errno
-
-from werkzeug.utils import import_string
-from ._compat import string_types, iteritems
-from . import json
-
-
-class ConfigAttribute(object):
- """Makes an attribute forward to the config"""
-
- def __init__(self, name, get_converter=None):
- self.__name__ = name
- self.get_converter = get_converter
-
- def __get__(self, obj, type=None):
- if obj is None:
- return self
- rv = obj.config[self.__name__]
- if self.get_converter is not None:
- rv = self.get_converter(rv)
- return rv
-
- def __set__(self, obj, value):
- obj.config[self.__name__] = value
-
-
-class Config(dict):
- """Works exactly like a dict but provides ways to fill it from files
- or special dictionaries. There are two common patterns to populate the
- config.
-
- Either you can fill the config from a config file::
-
- app.config.from_pyfile('yourconfig.cfg')
-
- Or alternatively you can define the configuration options in the
- module that calls :meth:`from_object` or provide an import path to
- a module that should be loaded. It is also possible to tell it to
- use the same module and with that provide the configuration values
- just before the call::
-
- DEBUG = True
- SECRET_KEY = 'development key'
- app.config.from_object(__name__)
-
- In both cases (loading from any Python file or loading from modules),
- only uppercase keys are added to the config. This makes it possible to use
- lowercase values in the config file for temporary values that are not added
- to the config or to define the config keys in the same file that implements
- the application.
-
- Probably the most interesting way to load configurations is from an
- environment variable pointing to a file::
-
- app.config.from_envvar('YOURAPPLICATION_SETTINGS')
-
- In this case before launching the application you have to set this
- environment variable to the file you want to use. On Linux and OS X
- use the export statement::
-
- export YOURAPPLICATION_SETTINGS='/path/to/config/file'
-
- On windows use `set` instead.
-
- :param root_path: path to which files are read relative from. When the
- config object is created by the application, this is
- the application's :attr:`~flask.Flask.root_path`.
- :param defaults: an optional dictionary of default values
- """
-
- def __init__(self, root_path, defaults=None):
- dict.__init__(self, defaults or {})
- self.root_path = root_path
-
- def from_envvar(self, variable_name, silent=False):
- """Loads a configuration from an environment variable pointing to
- a configuration file. This is basically just a shortcut with nicer
- error messages for this line of code::
-
- app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
-
- :param variable_name: name of the environment variable
- :param silent: set to ``True`` if you want silent failure for missing
- files.
- :return: bool. ``True`` if able to load config, ``False`` otherwise.
- """
- rv = os.environ.get(variable_name)
- if not rv:
- if silent:
- return False
- raise RuntimeError('The environment variable %r is not set '
- 'and as such configuration could not be '
- 'loaded. Set this variable and make it '
- 'point to a configuration file' %
- variable_name)
- return self.from_pyfile(rv, silent=silent)
-
- def from_pyfile(self, filename, silent=False):
- """Updates the values in the config from a Python file. This function
- behaves as if the file was imported as module with the
- :meth:`from_object` function.
-
- :param filename: the filename of the config. This can either be an
- absolute filename or a filename relative to the
- root path.
- :param silent: set to ``True`` if you want silent failure for missing
- files.
-
- .. versionadded:: 0.7
- `silent` parameter.
- """
- filename = os.path.join(self.root_path, filename)
- d = types.ModuleType('config')
- d.__file__ = filename
- try:
- with open(filename, mode='rb') as config_file:
- exec(compile(config_file.read(), filename, 'exec'), d.__dict__)
- except IOError as e:
- if silent and e.errno in (
- errno.ENOENT, errno.EISDIR, errno.ENOTDIR
- ):
- return False
- e.strerror = 'Unable to load configuration file (%s)' % e.strerror
- raise
- self.from_object(d)
- return True
-
- def from_object(self, obj):
- """Updates the values from the given object. An object can be of one
- of the following two types:
-
- - a string: in this case the object with that name will be imported
- - an actual object reference: that object is used directly
-
- Objects are usually either modules or classes. :meth:`from_object`
- loads only the uppercase attributes of the module/class. A ``dict``
- object will not work with :meth:`from_object` because the keys of a
- ``dict`` are not attributes of the ``dict`` class.
-
- Example of module-based configuration::
-
- app.config.from_object('yourapplication.default_config')
- from yourapplication import default_config
- app.config.from_object(default_config)
-
- Nothing is done to the object before loading. If the object is a
- class and has ``@property`` attributes, it needs to be
- instantiated before being passed to this method.
-
- You should not use this function to load the actual configuration but
- rather configuration defaults. The actual config should be loaded
- with :meth:`from_pyfile` and ideally from a location not within the
- package because the package might be installed system wide.
-
- See :ref:`config-dev-prod` for an example of class-based configuration
- using :meth:`from_object`.
-
- :param obj: an import name or object
- """
- if isinstance(obj, string_types):
- obj = import_string(obj)
- for key in dir(obj):
- if key.isupper():
- self[key] = getattr(obj, key)
-
- def from_json(self, filename, silent=False):
- """Updates the values in the config from a JSON file. This function
- behaves as if the JSON object was a dictionary and passed to the
- :meth:`from_mapping` function.
-
- :param filename: the filename of the JSON file. This can either be an
- absolute filename or a filename relative to the
- root path.
- :param silent: set to ``True`` if you want silent failure for missing
- files.
-
- .. versionadded:: 0.11
- """
- filename = os.path.join(self.root_path, filename)
-
- try:
- with open(filename) as json_file:
- obj = json.loads(json_file.read())
- except IOError as e:
- if silent and e.errno in (errno.ENOENT, errno.EISDIR):
- return False
- e.strerror = 'Unable to load configuration file (%s)' % e.strerror
- raise
- return self.from_mapping(obj)
-
- def from_mapping(self, *mapping, **kwargs):
- """Updates the config like :meth:`update` ignoring items with non-upper
- keys.
-
- .. versionadded:: 0.11
- """
- mappings = []
- if len(mapping) == 1:
- if hasattr(mapping[0], 'items'):
- mappings.append(mapping[0].items())
- else:
- mappings.append(mapping[0])
- elif len(mapping) > 1:
- raise TypeError(
- 'expected at most 1 positional argument, got %d' % len(mapping)
- )
- mappings.append(kwargs.items())
- for mapping in mappings:
- for (key, value) in mapping:
- if key.isupper():
- self[key] = value
- return True
-
- def get_namespace(self, namespace, lowercase=True, trim_namespace=True):
- """Returns a dictionary containing a subset of configuration options
- that match the specified namespace/prefix. Example usage::
-
- app.config['IMAGE_STORE_TYPE'] = 'fs'
- app.config['IMAGE_STORE_PATH'] = '/var/app/images'
- app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com'
- image_store_config = app.config.get_namespace('IMAGE_STORE_')
-
- The resulting dictionary `image_store_config` would look like::
-
- {
- 'type': 'fs',
- 'path': '/var/app/images',
- 'base_url': 'http://img.website.com'
- }
-
- This is often useful when configuration options map directly to
- keyword arguments in functions or class constructors.
-
- :param namespace: a configuration namespace
- :param lowercase: a flag indicating if the keys of the resulting
- dictionary should be lowercase
- :param trim_namespace: a flag indicating if the keys of the resulting
- dictionary should not include the namespace
-
- .. versionadded:: 0.11
- """
- rv = {}
- for k, v in iteritems(self):
- if not k.startswith(namespace):
- continue
- if trim_namespace:
- key = k[len(namespace):]
- else:
- key = k
- if lowercase:
- key = key.lower()
- rv[key] = v
- return rv
-
- def __repr__(self):
- return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self))
diff --git a/python/flask/ctx.py b/python/flask/ctx.py
deleted file mode 100644
index ec8e787..0000000
--- a/python/flask/ctx.py
+++ /dev/null
@@ -1,457 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.ctx
- ~~~~~~~~~
-
- Implements the objects required to keep the context.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import sys
-from functools import update_wrapper
-
-from werkzeug.exceptions import HTTPException
-
-from .globals import _request_ctx_stack, _app_ctx_stack
-from .signals import appcontext_pushed, appcontext_popped
-from ._compat import BROKEN_PYPY_CTXMGR_EXIT, reraise
-
-
-# a singleton sentinel value for parameter defaults
-_sentinel = object()
-
-
-class _AppCtxGlobals(object):
- """A plain object. Used as a namespace for storing data during an
- application context.
-
- Creating an app context automatically creates this object, which is
- made available as the :data:`g` proxy.
-
- .. describe:: 'key' in g
-
- Check whether an attribute is present.
-
- .. versionadded:: 0.10
-
- .. describe:: iter(g)
-
- Return an iterator over the attribute names.
-
- .. versionadded:: 0.10
- """
-
- def get(self, name, default=None):
- """Get an attribute by name, or a default value. Like
- :meth:`dict.get`.
-
- :param name: Name of attribute to get.
- :param default: Value to return if the attribute is not present.
-
- .. versionadded:: 0.10
- """
- return self.__dict__.get(name, default)
-
- def pop(self, name, default=_sentinel):
- """Get and remove an attribute by name. Like :meth:`dict.pop`.
-
- :param name: Name of attribute to pop.
- :param default: Value to return if the attribute is not present,
- instead of raise a ``KeyError``.
-
- .. versionadded:: 0.11
- """
- if default is _sentinel:
- return self.__dict__.pop(name)
- else:
- return self.__dict__.pop(name, default)
-
- def setdefault(self, name, default=None):
- """Get the value of an attribute if it is present, otherwise
- set and return a default value. Like :meth:`dict.setdefault`.
-
- :param name: Name of attribute to get.
- :param: default: Value to set and return if the attribute is not
- present.
-
- .. versionadded:: 0.11
- """
- return self.__dict__.setdefault(name, default)
-
- def __contains__(self, item):
- return item in self.__dict__
-
- def __iter__(self):
- return iter(self.__dict__)
-
- def __repr__(self):
- top = _app_ctx_stack.top
- if top is not None:
- return '<flask.g of %r>' % top.app.name
- return object.__repr__(self)
-
-
-def after_this_request(f):
- """Executes a function after this request. This is useful to modify
- response objects. The function is passed the response object and has
- to return the same or a new one.
-
- Example::
-
- @app.route('/')
- def index():
- @after_this_request
- def add_header(response):
- response.headers['X-Foo'] = 'Parachute'
- return response
- return 'Hello World!'
-
- This is more useful if a function other than the view function wants to
- modify a response. For instance think of a decorator that wants to add
- some headers without converting the return value into a response object.
-
- .. versionadded:: 0.9
- """
- _request_ctx_stack.top._after_request_functions.append(f)
- return f
-
-
-def copy_current_request_context(f):
- """A helper function that decorates a function to retain the current
- request context. This is useful when working with greenlets. The moment
- the function is decorated a copy of the request context is created and
- then pushed when the function is called.
-
- Example::
-
- import gevent
- from flask import copy_current_request_context
-
- @app.route('/')
- def index():
- @copy_current_request_context
- def do_some_work():
- # do some work here, it can access flask.request like you
- # would otherwise in the view function.
- ...
- gevent.spawn(do_some_work)
- return 'Regular response'
-
- .. versionadded:: 0.10
- """
- top = _request_ctx_stack.top
- if top is None:
- raise RuntimeError('This decorator can only be used at local scopes '
- 'when a request context is on the stack. For instance within '
- 'view functions.')
- reqctx = top.copy()
- def wrapper(*args, **kwargs):
- with reqctx:
- return f(*args, **kwargs)
- return update_wrapper(wrapper, f)
-
-
-def has_request_context():
- """If you have code that wants to test if a request context is there or
- not this function can be used. For instance, you may want to take advantage
- of request information if the request object is available, but fail
- silently if it is unavailable.
-
- ::
-
- class User(db.Model):
-
- def __init__(self, username, remote_addr=None):
- self.username = username
- if remote_addr is None and has_request_context():
- remote_addr = request.remote_addr
- self.remote_addr = remote_addr
-
- Alternatively you can also just test any of the context bound objects
- (such as :class:`request` or :class:`g`) for truthness::
-
- class User(db.Model):
-
- def __init__(self, username, remote_addr=None):
- self.username = username
- if remote_addr is None and request:
- remote_addr = request.remote_addr
- self.remote_addr = remote_addr
-
- .. versionadded:: 0.7
- """
- return _request_ctx_stack.top is not None
-
-
-def has_app_context():
- """Works like :func:`has_request_context` but for the application
- context. You can also just do a boolean check on the
- :data:`current_app` object instead.
-
- .. versionadded:: 0.9
- """
- return _app_ctx_stack.top is not None
-
-
-class AppContext(object):
- """The application context binds an application object implicitly
- to the current thread or greenlet, similar to how the
- :class:`RequestContext` binds request information. The application
- context is also implicitly created if a request context is created
- but the application is not on top of the individual application
- context.
- """
-
- def __init__(self, app):
- self.app = app
- self.url_adapter = app.create_url_adapter(None)
- self.g = app.app_ctx_globals_class()
-
- # Like request context, app contexts can be pushed multiple times
- # but there a basic "refcount" is enough to track them.
- self._refcnt = 0
-
- def push(self):
- """Binds the app context to the current context."""
- self._refcnt += 1
- if hasattr(sys, 'exc_clear'):
- sys.exc_clear()
- _app_ctx_stack.push(self)
- appcontext_pushed.send(self.app)
-
- def pop(self, exc=_sentinel):
- """Pops the app context."""
- try:
- self._refcnt -= 1
- if self._refcnt <= 0:
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- self.app.do_teardown_appcontext(exc)
- finally:
- rv = _app_ctx_stack.pop()
- assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
- % (rv, self)
- appcontext_popped.send(self.app)
-
- def __enter__(self):
- self.push()
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- self.pop(exc_value)
-
- if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
- reraise(exc_type, exc_value, tb)
-
-
-class RequestContext(object):
- """The request context contains all request relevant information. It is
- created at the beginning of the request and pushed to the
- `_request_ctx_stack` and removed at the end of it. It will create the
- URL adapter and request object for the WSGI environment provided.
-
- Do not attempt to use this class directly, instead use
- :meth:`~flask.Flask.test_request_context` and
- :meth:`~flask.Flask.request_context` to create this object.
-
- When the request context is popped, it will evaluate all the
- functions registered on the application for teardown execution
- (:meth:`~flask.Flask.teardown_request`).
-
- The request context is automatically popped at the end of the request
- for you. In debug mode the request context is kept around if
- exceptions happen so that interactive debuggers have a chance to
- introspect the data. With 0.4 this can also be forced for requests
- that did not fail and outside of ``DEBUG`` mode. By setting
- ``'flask._preserve_context'`` to ``True`` on the WSGI environment the
- context will not pop itself at the end of the request. This is used by
- the :meth:`~flask.Flask.test_client` for example to implement the
- deferred cleanup functionality.
-
- You might find this helpful for unittests where you need the
- information from the context local around for a little longer. Make
- sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in
- that situation, otherwise your unittests will leak memory.
- """
-
- def __init__(self, app, environ, request=None):
- self.app = app
- if request is None:
- request = app.request_class(environ)
- self.request = request
- self.url_adapter = app.create_url_adapter(self.request)
- self.flashes = None
- self.session = None
-
- # Request contexts can be pushed multiple times and interleaved with
- # other request contexts. Now only if the last level is popped we
- # get rid of them. Additionally if an application context is missing
- # one is created implicitly so for each level we add this information
- self._implicit_app_ctx_stack = []
-
- # indicator if the context was preserved. Next time another context
- # is pushed the preserved context is popped.
- self.preserved = False
-
- # remembers the exception for pop if there is one in case the context
- # preservation kicks in.
- self._preserved_exc = None
-
- # Functions that should be executed after the request on the response
- # object. These will be called before the regular "after_request"
- # functions.
- self._after_request_functions = []
-
- self.match_request()
-
- def _get_g(self):
- return _app_ctx_stack.top.g
- def _set_g(self, value):
- _app_ctx_stack.top.g = value
- g = property(_get_g, _set_g)
- del _get_g, _set_g
-
- def copy(self):
- """Creates a copy of this request context with the same request object.
- This can be used to move a request context to a different greenlet.
- Because the actual request object is the same this cannot be used to
- move a request context to a different thread unless access to the
- request object is locked.
-
- .. versionadded:: 0.10
- """
- return self.__class__(self.app,
- environ=self.request.environ,
- request=self.request
- )
-
- def match_request(self):
- """Can be overridden by a subclass to hook into the matching
- of the request.
- """
- try:
- url_rule, self.request.view_args = \
- self.url_adapter.match(return_rule=True)
- self.request.url_rule = url_rule
- except HTTPException as e:
- self.request.routing_exception = e
-
- def push(self):
- """Binds the request context to the current context."""
- # If an exception occurs in debug mode or if context preservation is
- # activated under exception situations exactly one context stays
- # on the stack. The rationale is that you want to access that
- # information under debug situations. However if someone forgets to
- # pop that context again we want to make sure that on the next push
- # it's invalidated, otherwise we run at risk that something leaks
- # memory. This is usually only a problem in test suite since this
- # functionality is not active in production environments.
- top = _request_ctx_stack.top
- if top is not None and top.preserved:
- top.pop(top._preserved_exc)
-
- # Before we push the request context we have to ensure that there
- # is an application context.
- app_ctx = _app_ctx_stack.top
- if app_ctx is None or app_ctx.app != self.app:
- app_ctx = self.app.app_context()
- app_ctx.push()
- self._implicit_app_ctx_stack.append(app_ctx)
- else:
- self._implicit_app_ctx_stack.append(None)
-
- if hasattr(sys, 'exc_clear'):
- sys.exc_clear()
-
- _request_ctx_stack.push(self)
-
- # Open the session at the moment that the request context is available.
- # This allows a custom open_session method to use the request context.
- # Only open a new session if this is the first time the request was
- # pushed, otherwise stream_with_context loses the session.
- if self.session is None:
- session_interface = self.app.session_interface
- self.session = session_interface.open_session(
- self.app, self.request
- )
-
- if self.session is None:
- self.session = session_interface.make_null_session(self.app)
-
- def pop(self, exc=_sentinel):
- """Pops the request context and unbinds it by doing that. This will
- also trigger the execution of functions registered by the
- :meth:`~flask.Flask.teardown_request` decorator.
-
- .. versionchanged:: 0.9
- Added the `exc` argument.
- """
- app_ctx = self._implicit_app_ctx_stack.pop()
-
- try:
- clear_request = False
- if not self._implicit_app_ctx_stack:
- self.preserved = False
- self._preserved_exc = None
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- self.app.do_teardown_request(exc)
-
- # If this interpreter supports clearing the exception information
- # we do that now. This will only go into effect on Python 2.x,
- # on 3.x it disappears automatically at the end of the exception
- # stack.
- if hasattr(sys, 'exc_clear'):
- sys.exc_clear()
-
- request_close = getattr(self.request, 'close', None)
- if request_close is not None:
- request_close()
- clear_request = True
- finally:
- rv = _request_ctx_stack.pop()
-
- # get rid of circular dependencies at the end of the request
- # so that we don't require the GC to be active.
- if clear_request:
- rv.request.environ['werkzeug.request'] = None
-
- # Get rid of the app as well if necessary.
- if app_ctx is not None:
- app_ctx.pop(exc)
-
- assert rv is self, 'Popped wrong request context. ' \
- '(%r instead of %r)' % (rv, self)
-
- def auto_pop(self, exc):
- if self.request.environ.get('flask._preserve_context') or \
- (exc is not None and self.app.preserve_context_on_exception):
- self.preserved = True
- self._preserved_exc = exc
- else:
- self.pop(exc)
-
- def __enter__(self):
- self.push()
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- # do not pop the request stack if we are in debug mode and an
- # exception happened. This will allow the debugger to still
- # access the request object in the interactive shell. Furthermore
- # the context can be force kept alive for the test client.
- # See flask.testing for how this works.
- self.auto_pop(exc_value)
-
- if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
- reraise(exc_type, exc_value, tb)
-
- def __repr__(self):
- return '<%s \'%s\' [%s] of %s>' % (
- self.__class__.__name__,
- self.request.url,
- self.request.method,
- self.app.name,
- )
diff --git a/python/flask/debughelpers.py b/python/flask/debughelpers.py
deleted file mode 100644
index e9765f2..0000000
--- a/python/flask/debughelpers.py
+++ /dev/null
@@ -1,168 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.debughelpers
- ~~~~~~~~~~~~~~~~~~
-
- Various helpers to make the development experience better.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import os
-from warnings import warn
-
-from ._compat import implements_to_string, text_type
-from .app import Flask
-from .blueprints import Blueprint
-from .globals import _request_ctx_stack
-
-
-class UnexpectedUnicodeError(AssertionError, UnicodeError):
- """Raised in places where we want some better error reporting for
- unexpected unicode or binary data.
- """
-
-
-@implements_to_string
-class DebugFilesKeyError(KeyError, AssertionError):
- """Raised from request.files during debugging. The idea is that it can
- provide a better error message than just a generic KeyError/BadRequest.
- """
-
- def __init__(self, request, key):
- form_matches = request.form.getlist(key)
- buf = ['You tried to access the file "%s" in the request.files '
- 'dictionary but it does not exist. The mimetype for the request '
- 'is "%s" instead of "multipart/form-data" which means that no '
- 'file contents were transmitted. To fix this error you should '
- 'provide enctype="multipart/form-data" in your form.' %
- (key, request.mimetype)]
- if form_matches:
- buf.append('\n\nThe browser instead transmitted some file names. '
- 'This was submitted: %s' % ', '.join('"%s"' % x
- for x in form_matches))
- self.msg = ''.join(buf)
-
- def __str__(self):
- return self.msg
-
-
-class FormDataRoutingRedirect(AssertionError):
- """This exception is raised by Flask in debug mode if it detects a
- redirect caused by the routing system when the request method is not
- GET, HEAD or OPTIONS. Reasoning: form data will be dropped.
- """
-
- def __init__(self, request):
- exc = request.routing_exception
- buf = ['A request was sent to this URL (%s) but a redirect was '
- 'issued automatically by the routing system to "%s".'
- % (request.url, exc.new_url)]
-
- # In case just a slash was appended we can be extra helpful
- if request.base_url + '/' == exc.new_url.split('?')[0]:
- buf.append(' The URL was defined with a trailing slash so '
- 'Flask will automatically redirect to the URL '
- 'with the trailing slash if it was accessed '
- 'without one.')
-
- buf.append(' Make sure to directly send your %s-request to this URL '
- 'since we can\'t make browsers or HTTP clients redirect '
- 'with form data reliably or without user interaction.' %
- request.method)
- buf.append('\n\nNote: this exception is only raised in debug mode')
- AssertionError.__init__(self, ''.join(buf).encode('utf-8'))
-
-
-def attach_enctype_error_multidict(request):
- """Since Flask 0.8 we're monkeypatching the files object in case a
- request is detected that does not use multipart form data but the files
- object is accessed.
- """
- oldcls = request.files.__class__
- class newcls(oldcls):
- def __getitem__(self, key):
- try:
- return oldcls.__getitem__(self, key)
- except KeyError:
- if key not in request.form:
- raise
- raise DebugFilesKeyError(request, key)
- newcls.__name__ = oldcls.__name__
- newcls.__module__ = oldcls.__module__
- request.files.__class__ = newcls
-
-
-def _dump_loader_info(loader):
- yield 'class: %s.%s' % (type(loader).__module__, type(loader).__name__)
- for key, value in sorted(loader.__dict__.items()):
- if key.startswith('_'):
- continue
- if isinstance(value, (tuple, list)):
- if not all(isinstance(x, (str, text_type)) for x in value):
- continue
- yield '%s:' % key
- for item in value:
- yield ' - %s' % item
- continue
- elif not isinstance(value, (str, text_type, int, float, bool)):
- continue
- yield '%s: %r' % (key, value)
-
-
-def explain_template_loading_attempts(app, template, attempts):
- """This should help developers understand what failed"""
- info = ['Locating template "%s":' % template]
- total_found = 0
- blueprint = None
- reqctx = _request_ctx_stack.top
- if reqctx is not None and reqctx.request.blueprint is not None:
- blueprint = reqctx.request.blueprint
-
- for idx, (loader, srcobj, triple) in enumerate(attempts):
- if isinstance(srcobj, Flask):
- src_info = 'application "%s"' % srcobj.import_name
- elif isinstance(srcobj, Blueprint):
- src_info = 'blueprint "%s" (%s)' % (srcobj.name,
- srcobj.import_name)
- else:
- src_info = repr(srcobj)
-
- info.append('% 5d: trying loader of %s' % (
- idx + 1, src_info))
-
- for line in _dump_loader_info(loader):
- info.append(' %s' % line)
-
- if triple is None:
- detail = 'no match'
- else:
- detail = 'found (%r)' % (triple[1] or '<string>')
- total_found += 1
- info.append(' -> %s' % detail)
-
- seems_fishy = False
- if total_found == 0:
- info.append('Error: the template could not be found.')
- seems_fishy = True
- elif total_found > 1:
- info.append('Warning: multiple loaders returned a match for the template.')
- seems_fishy = True
-
- if blueprint is not None and seems_fishy:
- info.append(' The template was looked up from an endpoint that '
- 'belongs to the blueprint "%s".' % blueprint)
- info.append(' Maybe you did not place a template in the right folder?')
- info.append(' See http://flask.pocoo.org/docs/blueprints/#templates')
-
- app.logger.info('\n'.join(info))
-
-
-def explain_ignored_app_run():
- if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
- warn(Warning('Silently ignoring app.run() because the '
- 'application is run from the flask command line '
- 'executable. Consider putting app.run() behind an '
- 'if __name__ == "__main__" guard to silence this '
- 'warning.'), stacklevel=3)
diff --git a/python/flask/globals.py b/python/flask/globals.py
deleted file mode 100644
index 7d50a6f..0000000
--- a/python/flask/globals.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.globals
- ~~~~~~~~~~~~~
-
- Defines all the global objects that are proxies to the current
- active context.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-from functools import partial
-from werkzeug.local import LocalStack, LocalProxy
-
-
-_request_ctx_err_msg = '''\
-Working outside of request context.
-
-This typically means that you attempted to use functionality that needed
-an active HTTP request. Consult the documentation on testing for
-information about how to avoid this problem.\
-'''
-_app_ctx_err_msg = '''\
-Working outside of application context.
-
-This typically means that you attempted to use functionality that needed
-to interface with the current application object in some way. To solve
-this, set up an application context with app.app_context(). See the
-documentation for more information.\
-'''
-
-
-def _lookup_req_object(name):
- top = _request_ctx_stack.top
- if top is None:
- raise RuntimeError(_request_ctx_err_msg)
- return getattr(top, name)
-
-
-def _lookup_app_object(name):
- top = _app_ctx_stack.top
- if top is None:
- raise RuntimeError(_app_ctx_err_msg)
- return getattr(top, name)
-
-
-def _find_app():
- top = _app_ctx_stack.top
- if top is None:
- raise RuntimeError(_app_ctx_err_msg)
- return top.app
-
-
-# context locals
-_request_ctx_stack = LocalStack()
-_app_ctx_stack = LocalStack()
-current_app = LocalProxy(_find_app)
-request = LocalProxy(partial(_lookup_req_object, 'request'))
-session = LocalProxy(partial(_lookup_req_object, 'session'))
-g = LocalProxy(partial(_lookup_app_object, 'g'))
diff --git a/python/flask/helpers.py b/python/flask/helpers.py
deleted file mode 100644
index 158edc5..0000000
--- a/python/flask/helpers.py
+++ /dev/null
@@ -1,1051 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.helpers
- ~~~~~~~~~~~~~
-
- Implements various helpers.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import os
-import socket
-import sys
-import pkgutil
-import posixpath
-import mimetypes
-from time import time
-from zlib import adler32
-from threading import RLock
-import unicodedata
-from werkzeug.routing import BuildError
-from functools import update_wrapper
-
-from werkzeug.urls import url_quote
-from werkzeug.datastructures import Headers, Range
-from werkzeug.exceptions import BadRequest, NotFound, \
- RequestedRangeNotSatisfiable
-
-from werkzeug.wsgi import wrap_file
-from jinja2 import FileSystemLoader
-
-from .signals import message_flashed
-from .globals import session, _request_ctx_stack, _app_ctx_stack, \
- current_app, request
-from ._compat import string_types, text_type, PY2
-
-# sentinel
-_missing = object()
-
-
-# what separators does this operating system provide that are not a slash?
-# this is used by the send_from_directory function to ensure that nobody is
-# able to access files from outside the filesystem.
-_os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep]
- if sep not in (None, '/'))
-
-
-def get_env():
- """Get the environment the app is running in, indicated by the
- :envvar:`FLASK_ENV` environment variable. The default is
- ``'production'``.
- """
- return os.environ.get('FLASK_ENV') or 'production'
-
-
-def get_debug_flag():
- """Get whether debug mode should be enabled for the app, indicated
- by the :envvar:`FLASK_DEBUG` environment variable. The default is
- ``True`` if :func:`.get_env` returns ``'development'``, or ``False``
- otherwise.
- """
- val = os.environ.get('FLASK_DEBUG')
-
- if not val:
- return get_env() == 'development'
-
- return val.lower() not in ('0', 'false', 'no')
-
-
-def get_load_dotenv(default=True):
- """Get whether the user has disabled loading dotenv files by setting
- :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load the
- files.
-
- :param default: What to return if the env var isn't set.
- """
- val = os.environ.get('FLASK_SKIP_DOTENV')
-
- if not val:
- return default
-
- return val.lower() in ('0', 'false', 'no')
-
-
-def _endpoint_from_view_func(view_func):
- """Internal helper that returns the default endpoint for a given
- function. This always is the function name.
- """
- assert view_func is not None, 'expected view func if endpoint ' \
- 'is not provided.'
- return view_func.__name__
-
-
-def stream_with_context(generator_or_function):
- """Request contexts disappear when the response is started on the server.
- This is done for efficiency reasons and to make it less likely to encounter
- memory leaks with badly written WSGI middlewares. The downside is that if
- you are using streamed responses, the generator cannot access request bound
- information any more.
-
- This function however can help you keep the context around for longer::
-
- from flask import stream_with_context, request, Response
-
- @app.route('/stream')
- def streamed_response():
- @stream_with_context
- def generate():
- yield 'Hello '
- yield request.args['name']
- yield '!'
- return Response(generate())
-
- Alternatively it can also be used around a specific generator::
-
- from flask import stream_with_context, request, Response
-
- @app.route('/stream')
- def streamed_response():
- def generate():
- yield 'Hello '
- yield request.args['name']
- yield '!'
- return Response(stream_with_context(generate()))
-
- .. versionadded:: 0.9
- """
- try:
- gen = iter(generator_or_function)
- except TypeError:
- def decorator(*args, **kwargs):
- gen = generator_or_function(*args, **kwargs)
- return stream_with_context(gen)
- return update_wrapper(decorator, generator_or_function)
-
- def generator():
- ctx = _request_ctx_stack.top
- if ctx is None:
- raise RuntimeError('Attempted to stream with context but '
- 'there was no context in the first place to keep around.')
- with ctx:
- # Dummy sentinel. Has to be inside the context block or we're
- # not actually keeping the context around.
- yield None
-
- # The try/finally is here so that if someone passes a WSGI level
- # iterator in we're still running the cleanup logic. Generators
- # don't need that because they are closed on their destruction
- # automatically.
- try:
- for item in gen:
- yield item
- finally:
- if hasattr(gen, 'close'):
- gen.close()
-
- # The trick is to start the generator. Then the code execution runs until
- # the first dummy None is yielded at which point the context was already
- # pushed. This item is discarded. Then when the iteration continues the
- # real generator is executed.
- wrapped_g = generator()
- next(wrapped_g)
- return wrapped_g
-
-
-def make_response(*args):
- """Sometimes it is necessary to set additional headers in a view. Because
- views do not have to return response objects but can return a value that
- is converted into a response object by Flask itself, it becomes tricky to
- add headers to it. This function can be called instead of using a return
- and you will get a response object which you can use to attach headers.
-
- If view looked like this and you want to add a new header::
-
- def index():
- return render_template('index.html', foo=42)
-
- You can now do something like this::
-
- def index():
- response = make_response(render_template('index.html', foo=42))
- response.headers['X-Parachutes'] = 'parachutes are cool'
- return response
-
- This function accepts the very same arguments you can return from a
- view function. This for example creates a response with a 404 error
- code::
-
- response = make_response(render_template('not_found.html'), 404)
-
- The other use case of this function is to force the return value of a
- view function into a response which is helpful with view
- decorators::
-
- response = make_response(view_function())
- response.headers['X-Parachutes'] = 'parachutes are cool'
-
- Internally this function does the following things:
-
- - if no arguments are passed, it creates a new response argument
- - if one argument is passed, :meth:`flask.Flask.make_response`
- is invoked with it.
- - if more than one argument is passed, the arguments are passed
- to the :meth:`flask.Flask.make_response` function as tuple.
-
- .. versionadded:: 0.6
- """
- if not args:
- return current_app.response_class()
- if len(args) == 1:
- args = args[0]
- return current_app.make_response(args)
-
-
-def url_for(endpoint, **values):
- """Generates a URL to the given endpoint with the method provided.
-
- Variable arguments that are unknown to the target endpoint are appended
- to the generated URL as query arguments. If the value of a query argument
- is ``None``, the whole pair is skipped. In case blueprints are active
- you can shortcut references to the same blueprint by prefixing the
- local endpoint with a dot (``.``).
-
- This will reference the index function local to the current blueprint::
-
- url_for('.index')
-
- For more information, head over to the :ref:`Quickstart <url-building>`.
-
- To integrate applications, :class:`Flask` has a hook to intercept URL build
- errors through :attr:`Flask.url_build_error_handlers`. The `url_for`
- function results in a :exc:`~werkzeug.routing.BuildError` when the current
- app does not have a URL for the given endpoint and values. When it does, the
- :data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if
- it is not ``None``, which can return a string to use as the result of
- `url_for` (instead of `url_for`'s default to raise the
- :exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception.
- An example::
-
- def external_url_handler(error, endpoint, values):
- "Looks up an external URL when `url_for` cannot build a URL."
- # This is an example of hooking the build_error_handler.
- # Here, lookup_url is some utility function you've built
- # which looks up the endpoint in some external URL registry.
- url = lookup_url(endpoint, **values)
- if url is None:
- # External lookup did not have a URL.
- # Re-raise the BuildError, in context of original traceback.
- exc_type, exc_value, tb = sys.exc_info()
- if exc_value is error:
- raise exc_type, exc_value, tb
- else:
- raise error
- # url_for will use this result, instead of raising BuildError.
- return url
-
- app.url_build_error_handlers.append(external_url_handler)
-
- Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and
- `endpoint` and `values` are the arguments passed into `url_for`. Note
- that this is for building URLs outside the current application, and not for
- handling 404 NotFound errors.
-
- .. versionadded:: 0.10
- The `_scheme` parameter was added.
-
- .. versionadded:: 0.9
- The `_anchor` and `_method` parameters were added.
-
- .. versionadded:: 0.9
- Calls :meth:`Flask.handle_build_error` on
- :exc:`~werkzeug.routing.BuildError`.
-
- :param endpoint: the endpoint of the URL (name of the function)
- :param values: the variable arguments of the URL rule
- :param _external: if set to ``True``, an absolute URL is generated. Server
- address can be changed via ``SERVER_NAME`` configuration variable which
- falls back to the `Host` header, then to the IP and port of the request.
- :param _scheme: a string specifying the desired URL scheme. The `_external`
- parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default
- behavior uses the same scheme as the current request, or
- ``PREFERRED_URL_SCHEME`` from the :ref:`app configuration <config>` if no
- request context is available. As of Werkzeug 0.10, this also can be set
- to an empty string to build protocol-relative URLs.
- :param _anchor: if provided this is added as anchor to the URL.
- :param _method: if provided this explicitly specifies an HTTP method.
- """
- appctx = _app_ctx_stack.top
- reqctx = _request_ctx_stack.top
-
- if appctx is None:
- raise RuntimeError(
- 'Attempted to generate a URL without the application context being'
- ' pushed. This has to be executed when application context is'
- ' available.'
- )
-
- # If request specific information is available we have some extra
- # features that support "relative" URLs.
- if reqctx is not None:
- url_adapter = reqctx.url_adapter
- blueprint_name = request.blueprint
-
- if endpoint[:1] == '.':
- if blueprint_name is not None:
- endpoint = blueprint_name + endpoint
- else:
- endpoint = endpoint[1:]
-
- external = values.pop('_external', False)
-
- # Otherwise go with the url adapter from the appctx and make
- # the URLs external by default.
- else:
- url_adapter = appctx.url_adapter
-
- if url_adapter is None:
- raise RuntimeError(
- 'Application was not able to create a URL adapter for request'
- ' independent URL generation. You might be able to fix this by'
- ' setting the SERVER_NAME config variable.'
- )
-
- external = values.pop('_external', True)
-
- anchor = values.pop('_anchor', None)
- method = values.pop('_method', None)
- scheme = values.pop('_scheme', None)
- appctx.app.inject_url_defaults(endpoint, values)
-
- # This is not the best way to deal with this but currently the
- # underlying Werkzeug router does not support overriding the scheme on
- # a per build call basis.
- old_scheme = None
- if scheme is not None:
- if not external:
- raise ValueError('When specifying _scheme, _external must be True')
- old_scheme = url_adapter.url_scheme
- url_adapter.url_scheme = scheme
-
- try:
- try:
- rv = url_adapter.build(endpoint, values, method=method,
- force_external=external)
- finally:
- if old_scheme is not None:
- url_adapter.url_scheme = old_scheme
- except BuildError as error:
- # We need to inject the values again so that the app callback can
- # deal with that sort of stuff.
- values['_external'] = external
- values['_anchor'] = anchor
- values['_method'] = method
- values['_scheme'] = scheme
- return appctx.app.handle_url_build_error(error, endpoint, values)
-
- if anchor is not None:
- rv += '#' + url_quote(anchor)
- return rv
-
-
-def get_template_attribute(template_name, attribute):
- """Loads a macro (or variable) a template exports. This can be used to
- invoke a macro from within Python code. If you for example have a
- template named :file:`_cider.html` with the following contents:
-
- .. sourcecode:: html+jinja
-
- {% macro hello(name) %}Hello {{ name }}!{% endmacro %}
-
- You can access this from Python code like this::
-
- hello = get_template_attribute('_cider.html', 'hello')
- return hello('World')
-
- .. versionadded:: 0.2
-
- :param template_name: the name of the template
- :param attribute: the name of the variable of macro to access
- """
- return getattr(current_app.jinja_env.get_template(template_name).module,
- attribute)
-
-
-def flash(message, category='message'):
- """Flashes a message to the next request. In order to remove the
- flashed message from the session and to display it to the user,
- the template has to call :func:`get_flashed_messages`.
-
- .. versionchanged:: 0.3
- `category` parameter added.
-
- :param message: the message to be flashed.
- :param category: the category for the message. The following values
- are recommended: ``'message'`` for any kind of message,
- ``'error'`` for errors, ``'info'`` for information
- messages and ``'warning'`` for warnings. However any
- kind of string can be used as category.
- """
- # Original implementation:
- #
- # session.setdefault('_flashes', []).append((category, message))
- #
- # This assumed that changes made to mutable structures in the session are
- # always in sync with the session object, which is not true for session
- # implementations that use external storage for keeping their keys/values.
- flashes = session.get('_flashes', [])
- flashes.append((category, message))
- session['_flashes'] = flashes
- message_flashed.send(current_app._get_current_object(),
- message=message, category=category)
-
-
-def get_flashed_messages(with_categories=False, category_filter=[]):
- """Pulls all flashed messages from the session and returns them.
- Further calls in the same request to the function will return
- the same messages. By default just the messages are returned,
- but when `with_categories` is set to ``True``, the return value will
- be a list of tuples in the form ``(category, message)`` instead.
-
- Filter the flashed messages to one or more categories by providing those
- categories in `category_filter`. This allows rendering categories in
- separate html blocks. The `with_categories` and `category_filter`
- arguments are distinct:
-
- * `with_categories` controls whether categories are returned with message
- text (``True`` gives a tuple, where ``False`` gives just the message text).
- * `category_filter` filters the messages down to only those matching the
- provided categories.
-
- See :ref:`message-flashing-pattern` for examples.
-
- .. versionchanged:: 0.3
- `with_categories` parameter added.
-
- .. versionchanged:: 0.9
- `category_filter` parameter added.
-
- :param with_categories: set to ``True`` to also receive categories.
- :param category_filter: whitelist of categories to limit return values
- """
- flashes = _request_ctx_stack.top.flashes
- if flashes is None:
- _request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \
- if '_flashes' in session else []
- if category_filter:
- flashes = list(filter(lambda f: f[0] in category_filter, flashes))
- if not with_categories:
- return [x[1] for x in flashes]
- return flashes
-
-
-def send_file(filename_or_fp, mimetype=None, as_attachment=False,
- attachment_filename=None, add_etags=True,
- cache_timeout=None, conditional=False, last_modified=None):
- """Sends the contents of a file to the client. This will use the
- most efficient method available and configured. By default it will
- try to use the WSGI server's file_wrapper support. Alternatively
- you can set the application's :attr:`~Flask.use_x_sendfile` attribute
- to ``True`` to directly emit an ``X-Sendfile`` header. This however
- requires support of the underlying webserver for ``X-Sendfile``.
-
- By default it will try to guess the mimetype for you, but you can
- also explicitly provide one. For extra security you probably want
- to send certain files as attachment (HTML for instance). The mimetype
- guessing requires a `filename` or an `attachment_filename` to be
- provided.
-
- ETags will also be attached automatically if a `filename` is provided. You
- can turn this off by setting `add_etags=False`.
-
- If `conditional=True` and `filename` is provided, this method will try to
- upgrade the response stream to support range requests. This will allow
- the request to be answered with partial content response.
-
- Please never pass filenames to this function from user sources;
- you should use :func:`send_from_directory` instead.
-
- .. versionadded:: 0.2
-
- .. versionadded:: 0.5
- The `add_etags`, `cache_timeout` and `conditional` parameters were
- added. The default behavior is now to attach etags.
-
- .. versionchanged:: 0.7
- mimetype guessing and etag support for file objects was
- deprecated because it was unreliable. Pass a filename if you are
- able to, otherwise attach an etag yourself. This functionality
- will be removed in Flask 1.0
-
- .. versionchanged:: 0.9
- cache_timeout pulls its default from application config, when None.
-
- .. versionchanged:: 0.12
- The filename is no longer automatically inferred from file objects. If
- you want to use automatic mimetype and etag support, pass a filepath via
- `filename_or_fp` or `attachment_filename`.
-
- .. versionchanged:: 0.12
- The `attachment_filename` is preferred over `filename` for MIME-type
- detection.
-
- .. versionchanged:: 1.0
- UTF-8 filenames, as specified in `RFC 2231`_, are supported.
-
- .. _RFC 2231: https://tools.ietf.org/html/rfc2231#section-4
-
- .. versionchanged:: 1.0.3
- Filenames are encoded with ASCII instead of Latin-1 for broader
- compatibility with WSGI servers.
-
- :param filename_or_fp: the filename of the file to send.
- This is relative to the :attr:`~Flask.root_path`
- if a relative path is specified.
- Alternatively a file object might be provided in
- which case ``X-Sendfile`` might not work and fall
- back to the traditional method. Make sure that the
- file pointer is positioned at the start of data to
- send before calling :func:`send_file`.
- :param mimetype: the mimetype of the file if provided. If a file path is
- given, auto detection happens as fallback, otherwise an
- error will be raised.
- :param as_attachment: set to ``True`` if you want to send this file with
- a ``Content-Disposition: attachment`` header.
- :param attachment_filename: the filename for the attachment if it
- differs from the file's filename.
- :param add_etags: set to ``False`` to disable attaching of etags.
- :param conditional: set to ``True`` to enable conditional responses.
-
- :param cache_timeout: the timeout in seconds for the headers. When ``None``
- (default), this value is set by
- :meth:`~Flask.get_send_file_max_age` of
- :data:`~flask.current_app`.
- :param last_modified: set the ``Last-Modified`` header to this value,
- a :class:`~datetime.datetime` or timestamp.
- If a file was passed, this overrides its mtime.
- """
- mtime = None
- fsize = None
- if isinstance(filename_or_fp, string_types):
- filename = filename_or_fp
- if not os.path.isabs(filename):
- filename = os.path.join(current_app.root_path, filename)
- file = None
- if attachment_filename is None:
- attachment_filename = os.path.basename(filename)
- else:
- file = filename_or_fp
- filename = None
-
- if mimetype is None:
- if attachment_filename is not None:
- mimetype = mimetypes.guess_type(attachment_filename)[0] \
- or 'application/octet-stream'
-
- if mimetype is None:
- raise ValueError(
- 'Unable to infer MIME-type because no filename is available. '
- 'Please set either `attachment_filename`, pass a filepath to '
- '`filename_or_fp` or set your own MIME-type via `mimetype`.'
- )
-
- headers = Headers()
- if as_attachment:
- if attachment_filename is None:
- raise TypeError('filename unavailable, required for '
- 'sending as attachment')
-
- if not isinstance(attachment_filename, text_type):
- attachment_filename = attachment_filename.decode('utf-8')
-
- try:
- attachment_filename = attachment_filename.encode('ascii')
- except UnicodeEncodeError:
- filenames = {
- 'filename': unicodedata.normalize(
- 'NFKD', attachment_filename).encode('ascii', 'ignore'),
- 'filename*': "UTF-8''%s" % url_quote(attachment_filename),
- }
- else:
- filenames = {'filename': attachment_filename}
-
- headers.add('Content-Disposition', 'attachment', **filenames)
-
- if current_app.use_x_sendfile and filename:
- if file is not None:
- file.close()
- headers['X-Sendfile'] = filename
- fsize = os.path.getsize(filename)
- headers['Content-Length'] = fsize
- data = None
- else:
- if file is None:
- file = open(filename, 'rb')
- mtime = os.path.getmtime(filename)
- fsize = os.path.getsize(filename)
- headers['Content-Length'] = fsize
- data = wrap_file(request.environ, file)
-
- rv = current_app.response_class(data, mimetype=mimetype, headers=headers,
- direct_passthrough=True)
-
- if last_modified is not None:
- rv.last_modified = last_modified
- elif mtime is not None:
- rv.last_modified = mtime
-
- rv.cache_control.public = True
- if cache_timeout is None:
- cache_timeout = current_app.get_send_file_max_age(filename)
- if cache_timeout is not None:
- rv.cache_control.max_age = cache_timeout
- rv.expires = int(time() + cache_timeout)
-
- if add_etags and filename is not None:
- from warnings import warn
-
- try:
- rv.set_etag('%s-%s-%s' % (
- os.path.getmtime(filename),
- os.path.getsize(filename),
- adler32(
- filename.encode('utf-8') if isinstance(filename, text_type)
- else filename
- ) & 0xffffffff
- ))
- except OSError:
- warn('Access %s failed, maybe it does not exist, so ignore etags in '
- 'headers' % filename, stacklevel=2)
-
- if conditional:
- try:
- rv = rv.make_conditional(request, accept_ranges=True,
- complete_length=fsize)
- except RequestedRangeNotSatisfiable:
- if file is not None:
- file.close()
- raise
- # make sure we don't send x-sendfile for servers that
- # ignore the 304 status code for x-sendfile.
- if rv.status_code == 304:
- rv.headers.pop('x-sendfile', None)
- return rv
-
-
-def safe_join(directory, *pathnames):
- """Safely join `directory` and zero or more untrusted `pathnames`
- components.
-
- Example usage::
-
- @app.route('/wiki/<path:filename>')
- def wiki_page(filename):
- filename = safe_join(app.config['WIKI_FOLDER'], filename)
- with open(filename, 'rb') as fd:
- content = fd.read() # Read and process the file content...
-
- :param directory: the trusted base directory.
- :param pathnames: the untrusted pathnames relative to that directory.
- :raises: :class:`~werkzeug.exceptions.NotFound` if one or more passed
- paths fall out of its boundaries.
- """
-
- parts = [directory]
-
- for filename in pathnames:
- if filename != '':
- filename = posixpath.normpath(filename)
-
- if (
- any(sep in filename for sep in _os_alt_seps)
- or os.path.isabs(filename)
- or filename == '..'
- or filename.startswith('../')
- ):
- raise NotFound()
-
- parts.append(filename)
-
- return posixpath.join(*parts)
-
-
-def send_from_directory(directory, filename, **options):
- """Send a file from a given directory with :func:`send_file`. This
- is a secure way to quickly expose static files from an upload folder
- or something similar.
-
- Example usage::
-
- @app.route('/uploads/<path:filename>')
- def download_file(filename):
- return send_from_directory(app.config['UPLOAD_FOLDER'],
- filename, as_attachment=True)
-
- .. admonition:: Sending files and Performance
-
- It is strongly recommended to activate either ``X-Sendfile`` support in
- your webserver or (if no authentication happens) to tell the webserver
- to serve files for the given path on its own without calling into the
- web application for improved performance.
-
- .. versionadded:: 0.5
-
- :param directory: the directory where all the files are stored.
- :param filename: the filename relative to that directory to
- download.
- :param options: optional keyword arguments that are directly
- forwarded to :func:`send_file`.
- """
- filename = safe_join(directory, filename)
- if not os.path.isabs(filename):
- filename = os.path.join(current_app.root_path, filename)
- try:
- if not os.path.isfile(filename):
- raise NotFound()
- except (TypeError, ValueError):
- raise BadRequest()
- options.setdefault('conditional', True)
- return send_file(filename, **options)
-
-
-def get_root_path(import_name):
- """Returns the path to a package or cwd if that cannot be found. This
- returns the path of a package or the folder that contains a module.
-
- Not to be confused with the package path returned by :func:`find_package`.
- """
- # Module already imported and has a file attribute. Use that first.
- mod = sys.modules.get(import_name)
- if mod is not None and hasattr(mod, '__file__'):
- return os.path.dirname(os.path.abspath(mod.__file__))
-
- # Next attempt: check the loader.
- loader = pkgutil.get_loader(import_name)
-
- # Loader does not exist or we're referring to an unloaded main module
- # or a main module without path (interactive sessions), go with the
- # current working directory.
- if loader is None or import_name == '__main__':
- return os.getcwd()
-
- # For .egg, zipimporter does not have get_filename until Python 2.7.
- # Some other loaders might exhibit the same behavior.
- if hasattr(loader, 'get_filename'):
- filepath = loader.get_filename(import_name)
- else:
- # Fall back to imports.
- __import__(import_name)
- mod = sys.modules[import_name]
- filepath = getattr(mod, '__file__', None)
-
- # If we don't have a filepath it might be because we are a
- # namespace package. In this case we pick the root path from the
- # first module that is contained in our package.
- if filepath is None:
- raise RuntimeError('No root path can be found for the provided '
- 'module "%s". This can happen because the '
- 'module came from an import hook that does '
- 'not provide file name information or because '
- 'it\'s a namespace package. In this case '
- 'the root path needs to be explicitly '
- 'provided.' % import_name)
-
- # filepath is import_name.py for a module, or __init__.py for a package.
- return os.path.dirname(os.path.abspath(filepath))
-
-
-def _matching_loader_thinks_module_is_package(loader, mod_name):
- """Given the loader that loaded a module and the module this function
- attempts to figure out if the given module is actually a package.
- """
- # If the loader can tell us if something is a package, we can
- # directly ask the loader.
- if hasattr(loader, 'is_package'):
- return loader.is_package(mod_name)
- # importlib's namespace loaders do not have this functionality but
- # all the modules it loads are packages, so we can take advantage of
- # this information.
- elif (loader.__class__.__module__ == '_frozen_importlib' and
- loader.__class__.__name__ == 'NamespaceLoader'):
- return True
- # Otherwise we need to fail with an error that explains what went
- # wrong.
- raise AttributeError(
- ('%s.is_package() method is missing but is required by Flask of '
- 'PEP 302 import hooks. If you do not use import hooks and '
- 'you encounter this error please file a bug against Flask.') %
- loader.__class__.__name__)
-
-
-def find_package(import_name):
- """Finds a package and returns the prefix (or None if the package is
- not installed) as well as the folder that contains the package or
- module as a tuple. The package path returned is the module that would
- have to be added to the pythonpath in order to make it possible to
- import the module. The prefix is the path below which a UNIX like
- folder structure exists (lib, share etc.).
- """
- root_mod_name = import_name.split('.')[0]
- loader = pkgutil.get_loader(root_mod_name)
- if loader is None or import_name == '__main__':
- # import name is not found, or interactive/main module
- package_path = os.getcwd()
- else:
- # For .egg, zipimporter does not have get_filename until Python 2.7.
- if hasattr(loader, 'get_filename'):
- filename = loader.get_filename(root_mod_name)
- elif hasattr(loader, 'archive'):
- # zipimporter's loader.archive points to the .egg or .zip
- # archive filename is dropped in call to dirname below.
- filename = loader.archive
- else:
- # At least one loader is missing both get_filename and archive:
- # Google App Engine's HardenedModulesHook
- #
- # Fall back to imports.
- __import__(import_name)
- filename = sys.modules[import_name].__file__
- package_path = os.path.abspath(os.path.dirname(filename))
-
- # In case the root module is a package we need to chop of the
- # rightmost part. This needs to go through a helper function
- # because of python 3.3 namespace packages.
- if _matching_loader_thinks_module_is_package(
- loader, root_mod_name):
- package_path = os.path.dirname(package_path)
-
- site_parent, site_folder = os.path.split(package_path)
- py_prefix = os.path.abspath(sys.prefix)
- if package_path.startswith(py_prefix):
- return py_prefix, package_path
- elif site_folder.lower() == 'site-packages':
- parent, folder = os.path.split(site_parent)
- # Windows like installations
- if folder.lower() == 'lib':
- base_dir = parent
- # UNIX like installations
- elif os.path.basename(parent).lower() == 'lib':
- base_dir = os.path.dirname(parent)
- else:
- base_dir = site_parent
- return base_dir, package_path
- return None, package_path
-
-
-class locked_cached_property(object):
- """A decorator that converts a function into a lazy property. The
- function wrapped is called the first time to retrieve the result
- and then that calculated result is used the next time you access
- the value. Works like the one in Werkzeug but has a lock for
- thread safety.
- """
-
- def __init__(self, func, name=None, doc=None):
- self.__name__ = name or func.__name__
- self.__module__ = func.__module__
- self.__doc__ = doc or func.__doc__
- self.func = func
- self.lock = RLock()
-
- def __get__(self, obj, type=None):
- if obj is None:
- return self
- with self.lock:
- value = obj.__dict__.get(self.__name__, _missing)
- if value is _missing:
- value = self.func(obj)
- obj.__dict__[self.__name__] = value
- return value
-
-
-class _PackageBoundObject(object):
- #: 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__(self, import_name, template_folder=None, root_path=None):
- self.import_name = import_name
- self.template_folder = template_folder
-
- if root_path is None:
- root_path = get_root_path(self.import_name)
-
- self.root_path = root_path
- self._static_folder = None
- self._static_url_path = None
-
- def _get_static_folder(self):
- if self._static_folder is not None:
- return os.path.join(self.root_path, self._static_folder)
-
- def _set_static_folder(self, value):
- self._static_folder = value
-
- static_folder = property(
- _get_static_folder, _set_static_folder,
- doc='The absolute path to the configured static folder.'
- )
- del _get_static_folder, _set_static_folder
-
- def _get_static_url_path(self):
- if self._static_url_path is not None:
- return self._static_url_path
-
- if self.static_folder is not None:
- return '/' + os.path.basename(self.static_folder)
-
- def _set_static_url_path(self, value):
- self._static_url_path = value
-
- static_url_path = property(
- _get_static_url_path, _set_static_url_path,
- doc='The URL prefix that the static route will be registered for.'
- )
- del _get_static_url_path, _set_static_url_path
-
- @property
- def has_static_folder(self):
- """This is ``True`` if the package bound object's container has a
- folder for static files.
-
- .. versionadded:: 0.5
- """
- return self.static_folder is not None
-
- @locked_cached_property
- def jinja_loader(self):
- """The Jinja loader for this package bound object.
-
- .. versionadded:: 0.5
- """
- if self.template_folder is not None:
- return FileSystemLoader(os.path.join(self.root_path,
- self.template_folder))
-
- def get_send_file_max_age(self, filename):
- """Provides default cache_timeout for the :func:`send_file` functions.
-
- By default, this function returns ``SEND_FILE_MAX_AGE_DEFAULT`` from
- the configuration of :data:`~flask.current_app`.
-
- Static file functions such as :func:`send_from_directory` use this
- function, and :func:`send_file` calls this function on
- :data:`~flask.current_app` when the given cache_timeout is ``None``. If a
- cache_timeout is given in :func:`send_file`, that timeout is used;
- otherwise, this method is called.
-
- This allows subclasses to change the behavior when sending files based
- on the filename. For example, to set the cache timeout for .js files
- to 60 seconds::
-
- class MyFlask(flask.Flask):
- def get_send_file_max_age(self, name):
- if name.lower().endswith('.js'):
- return 60
- return flask.Flask.get_send_file_max_age(self, name)
-
- .. versionadded:: 0.9
- """
- return total_seconds(current_app.send_file_max_age_default)
-
- def send_static_file(self, filename):
- """Function used internally to send static files from the static
- folder to the browser.
-
- .. versionadded:: 0.5
- """
- if not self.has_static_folder:
- raise RuntimeError('No static folder for this object')
- # Ensure get_send_file_max_age is called in all cases.
- # Here, we ensure get_send_file_max_age is called for Blueprints.
- cache_timeout = self.get_send_file_max_age(filename)
- return send_from_directory(self.static_folder, filename,
- cache_timeout=cache_timeout)
-
- def open_resource(self, resource, mode='rb'):
- """Opens a resource from the application's resource folder. To see
- how this works, consider the following folder structure::
-
- /myapplication.py
- /schema.sql
- /static
- /style.css
- /templates
- /layout.html
- /index.html
-
- If you want to open the :file:`schema.sql` file you would do the
- following::
-
- with app.open_resource('schema.sql') as f:
- contents = f.read()
- do_something_with(contents)
-
- :param resource: the name of the resource. To access resources within
- subfolders use forward slashes as separator.
- :param mode: resource file opening mode, default is 'rb'.
- """
- if mode not in ('r', 'rb'):
- raise ValueError('Resources can only be opened for reading')
- return open(os.path.join(self.root_path, resource), mode)
-
-
-def total_seconds(td):
- """Returns the total seconds from a timedelta object.
-
- :param timedelta td: the timedelta to be converted in seconds
-
- :returns: number of seconds
- :rtype: int
- """
- return td.days * 60 * 60 * 24 + td.seconds
-
-
-def is_ip(value):
- """Determine if the given string is an IP address.
-
- Python 2 on Windows doesn't provide ``inet_pton``, so this only
- checks IPv4 addresses in that environment.
-
- :param value: value to check
- :type value: str
-
- :return: True if string is an IP address
- :rtype: bool
- """
- if PY2 and os.name == 'nt':
- try:
- socket.inet_aton(value)
- return True
- except socket.error:
- return False
-
- for family in (socket.AF_INET, socket.AF_INET6):
- try:
- socket.inet_pton(family, value)
- except socket.error:
- pass
- else:
- return True
-
- return False
diff --git a/python/flask/json/__init__.py b/python/flask/json/__init__.py
deleted file mode 100644
index c24286c..0000000
--- a/python/flask/json/__init__.py
+++ /dev/null
@@ -1,357 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-flask.json
-~~~~~~~~~~
-
-:copyright: © 2010 by the Pallets team.
-:license: BSD, see LICENSE for more details.
-"""
-import codecs
-import io
-import uuid
-from datetime import date, datetime
-from flask.globals import current_app, request
-from flask._compat import text_type, PY2
-
-from werkzeug.http import http_date
-from jinja2 import Markup
-
-# Use the same json implementation as itsdangerous on which we
-# depend anyways.
-from itsdangerous import json as _json
-
-
-# Figure out if simplejson escapes slashes. This behavior was changed
-# from one version to another without reason.
-_slash_escape = '\\/' not in _json.dumps('/')
-
-
-__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump',
- 'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder',
- 'jsonify']
-
-
-def _wrap_reader_for_text(fp, encoding):
- if isinstance(fp.read(0), bytes):
- fp = io.TextIOWrapper(io.BufferedReader(fp), encoding)
- return fp
-
-
-def _wrap_writer_for_text(fp, encoding):
- try:
- fp.write('')
- except TypeError:
- fp = io.TextIOWrapper(fp, encoding)
- return fp
-
-
-class JSONEncoder(_json.JSONEncoder):
- """The default Flask JSON encoder. This one extends the default simplejson
- encoder by also supporting ``datetime`` objects, ``UUID`` as well as
- ``Markup`` objects which are serialized as RFC 822 datetime strings (same
- as the HTTP date format). In order to support more data types override the
- :meth:`default` method.
- """
-
- def default(self, o):
- """Implement this method in a subclass such that it returns a
- serializable object for ``o``, or calls the base implementation (to
- raise a :exc:`TypeError`).
-
- For example, to support arbitrary iterators, you could implement
- default like this::
-
- def default(self, o):
- try:
- iterable = iter(o)
- except TypeError:
- pass
- else:
- return list(iterable)
- return JSONEncoder.default(self, o)
- """
- if isinstance(o, datetime):
- return http_date(o.utctimetuple())
- if isinstance(o, date):
- return http_date(o.timetuple())
- if isinstance(o, uuid.UUID):
- return str(o)
- if hasattr(o, '__html__'):
- return text_type(o.__html__())
- return _json.JSONEncoder.default(self, o)
-
-
-class JSONDecoder(_json.JSONDecoder):
- """The default JSON decoder. This one does not change the behavior from
- the default simplejson decoder. Consult the :mod:`json` documentation
- for more information. This decoder is not only used for the load
- functions of this module but also :attr:`~flask.Request`.
- """
-
-
-def _dump_arg_defaults(kwargs, app=None):
- """Inject default arguments for dump functions."""
- if app is None:
- app = current_app
-
- if app:
- bp = app.blueprints.get(request.blueprint) if request else None
- kwargs.setdefault(
- 'cls', bp.json_encoder if bp and bp.json_encoder else app.json_encoder
- )
-
- if not app.config['JSON_AS_ASCII']:
- kwargs.setdefault('ensure_ascii', False)
-
- kwargs.setdefault('sort_keys', app.config['JSON_SORT_KEYS'])
- else:
- kwargs.setdefault('sort_keys', True)
- kwargs.setdefault('cls', JSONEncoder)
-
-
-def _load_arg_defaults(kwargs, app=None):
- """Inject default arguments for load functions."""
- if app is None:
- app = current_app
-
- if app:
- bp = app.blueprints.get(request.blueprint) if request else None
- kwargs.setdefault(
- 'cls',
- bp.json_decoder if bp and bp.json_decoder
- else app.json_decoder
- )
- else:
- kwargs.setdefault('cls', JSONDecoder)
-
-
-def detect_encoding(data):
- """Detect which UTF codec was used to encode the given bytes.
-
- The latest JSON standard (:rfc:`8259`) suggests that only UTF-8 is
- accepted. Older documents allowed 8, 16, or 32. 16 and 32 can be big
- or little endian. Some editors or libraries may prepend a BOM.
-
- :param data: Bytes in unknown UTF encoding.
- :return: UTF encoding name
- """
- head = data[:4]
-
- if head[:3] == codecs.BOM_UTF8:
- return 'utf-8-sig'
-
- if b'\x00' not in head:
- return 'utf-8'
-
- if head in (codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE):
- return 'utf-32'
-
- if head[:2] in (codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE):
- return 'utf-16'
-
- if len(head) == 4:
- if head[:3] == b'\x00\x00\x00':
- return 'utf-32-be'
-
- if head[::2] == b'\x00\x00':
- return 'utf-16-be'
-
- if head[1:] == b'\x00\x00\x00':
- return 'utf-32-le'
-
- if head[1::2] == b'\x00\x00':
- return 'utf-16-le'
-
- if len(head) == 2:
- return 'utf-16-be' if head.startswith(b'\x00') else 'utf-16-le'
-
- return 'utf-8'
-
-
-def dumps(obj, app=None, **kwargs):
- """Serialize ``obj`` to a JSON-formatted string. If there is an
- app context pushed, use the current app's configured encoder
- (:attr:`~flask.Flask.json_encoder`), or fall back to the default
- :class:`JSONEncoder`.
-
- Takes the same arguments as the built-in :func:`json.dumps`, and
- does some extra configuration based on the application. If the
- simplejson package is installed, it is preferred.
-
- :param obj: Object to serialize to JSON.
- :param app: App instance to use to configure the JSON encoder.
- Uses ``current_app`` if not given, and falls back to the default
- encoder when not in an app context.
- :param kwargs: Extra arguments passed to :func:`json.dumps`.
-
- .. versionchanged:: 1.0.3
-
- ``app`` can be passed directly, rather than requiring an app
- context for configuration.
- """
- _dump_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop('encoding', None)
- rv = _json.dumps(obj, **kwargs)
- if encoding is not None and isinstance(rv, text_type):
- rv = rv.encode(encoding)
- return rv
-
-
-def dump(obj, fp, app=None, **kwargs):
- """Like :func:`dumps` but writes into a file object."""
- _dump_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop('encoding', None)
- if encoding is not None:
- fp = _wrap_writer_for_text(fp, encoding)
- _json.dump(obj, fp, **kwargs)
-
-
-def loads(s, app=None, **kwargs):
- """Deserialize an object from a JSON-formatted string ``s``. If
- there is an app context pushed, use the current app's configured
- decoder (:attr:`~flask.Flask.json_decoder`), or fall back to the
- default :class:`JSONDecoder`.
-
- Takes the same arguments as the built-in :func:`json.loads`, and
- does some extra configuration based on the application. If the
- simplejson package is installed, it is preferred.
-
- :param s: JSON string to deserialize.
- :param app: App instance to use to configure the JSON decoder.
- Uses ``current_app`` if not given, and falls back to the default
- encoder when not in an app context.
- :param kwargs: Extra arguments passed to :func:`json.dumps`.
-
- .. versionchanged:: 1.0.3
-
- ``app`` can be passed directly, rather than requiring an app
- context for configuration.
- """
- _load_arg_defaults(kwargs, app=app)
- if isinstance(s, bytes):
- encoding = kwargs.pop('encoding', None)
- if encoding is None:
- encoding = detect_encoding(s)
- s = s.decode(encoding)
- return _json.loads(s, **kwargs)
-
-
-def load(fp, app=None, **kwargs):
- """Like :func:`loads` but reads from a file object."""
- _load_arg_defaults(kwargs, app=app)
- if not PY2:
- fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8')
- return _json.load(fp, **kwargs)
-
-
-def htmlsafe_dumps(obj, **kwargs):
- """Works exactly like :func:`dumps` but is safe for use in ``<script>``
- tags. It accepts the same arguments and returns a JSON string. Note that
- this is available in templates through the ``|tojson`` filter which will
- also mark the result as safe. Due to how this function escapes certain
- characters this is safe even if used outside of ``<script>`` tags.
-
- The following characters are escaped in strings:
-
- - ``<``
- - ``>``
- - ``&``
- - ``'``
-
- This makes it safe to embed such strings in any place in HTML with the
- notable exception of double quoted attributes. In that case single
- quote your attributes or HTML escape it in addition.
-
- .. versionchanged:: 0.10
- This function's return value is now always safe for HTML usage, even
- if outside of script tags or if used in XHTML. This rule does not
- hold true when using this function in HTML attributes that are double
- quoted. Always single quote attributes if you use the ``|tojson``
- filter. Alternatively use ``|tojson|forceescape``.
- """
- rv = dumps(obj, **kwargs) \
- .replace(u'<', u'\\u003c') \
- .replace(u'>', u'\\u003e') \
- .replace(u'&', u'\\u0026') \
- .replace(u"'", u'\\u0027')
- if not _slash_escape:
- rv = rv.replace('\\/', '/')
- return rv
-
-
-def htmlsafe_dump(obj, fp, **kwargs):
- """Like :func:`htmlsafe_dumps` but writes into a file object."""
- fp.write(text_type(htmlsafe_dumps(obj, **kwargs)))
-
-
-def jsonify(*args, **kwargs):
- """This function wraps :func:`dumps` to add a few enhancements that make
- life easier. It turns the JSON output into a :class:`~flask.Response`
- object with the :mimetype:`application/json` mimetype. For convenience, it
- also converts multiple arguments into an array or multiple keyword arguments
- into a dict. This means that both ``jsonify(1,2,3)`` and
- ``jsonify([1,2,3])`` serialize to ``[1,2,3]``.
-
- For clarity, the JSON serialization behavior has the following differences
- from :func:`dumps`:
-
- 1. Single argument: Passed straight through to :func:`dumps`.
- 2. Multiple arguments: Converted to an array before being passed to
- :func:`dumps`.
- 3. Multiple keyword arguments: Converted to a dict before being passed to
- :func:`dumps`.
- 4. Both args and kwargs: Behavior undefined and will throw an exception.
-
- Example usage::
-
- from flask import jsonify
-
- @app.route('/_get_current_user')
- def get_current_user():
- return jsonify(username=g.user.username,
- email=g.user.email,
- id=g.user.id)
-
- This will send a JSON response like this to the browser::
-
- {
- "username": "admin",
- "email": "admin@localhost",
- "id": 42
- }
-
-
- .. versionchanged:: 0.11
- Added support for serializing top-level arrays. This introduces a
- security risk in ancient browsers. See :ref:`json-security` for details.
-
- This function's response will be pretty printed if the
- ``JSONIFY_PRETTYPRINT_REGULAR`` config parameter is set to True or the
- Flask app is running in debug mode. Compressed (not pretty) formatting
- currently means no indents and no spaces after separators.
-
- .. versionadded:: 0.2
- """
-
- indent = None
- separators = (',', ':')
-
- if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] or current_app.debug:
- indent = 2
- separators = (', ', ': ')
-
- if args and kwargs:
- raise TypeError('jsonify() behavior undefined when passed both args and kwargs')
- elif len(args) == 1: # single args are passed directly to dumps()
- data = args[0]
- else:
- data = args or kwargs
-
- return current_app.response_class(
- dumps(data, indent=indent, separators=separators) + '\n',
- mimetype=current_app.config['JSONIFY_MIMETYPE']
- )
-
-
-def tojson_filter(obj, **kwargs):
- return Markup(htmlsafe_dumps(obj, **kwargs))
diff --git a/python/flask/json/tag.py b/python/flask/json/tag.py
deleted file mode 100644
index 11c966c..0000000
--- a/python/flask/json/tag.py
+++ /dev/null
@@ -1,300 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Tagged JSON
-~~~~~~~~~~~
-
-A compact representation for lossless serialization of non-standard JSON types.
-:class:`~flask.sessions.SecureCookieSessionInterface` uses this to serialize
-the session data, but it may be useful in other places. It can be extended to
-support other types.
-
-.. autoclass:: TaggedJSONSerializer
- :members:
-
-.. autoclass:: JSONTag
- :members:
-
-Let's seen an example that adds support for :class:`~collections.OrderedDict`.
-Dicts don't have an order in Python or JSON, so to handle this we will dump
-the items as a list of ``[key, value]`` pairs. Subclass :class:`JSONTag` and
-give it the new key ``' od'`` to identify the type. The session serializer
-processes dicts first, so insert the new tag at the front of the order since
-``OrderedDict`` must be processed before ``dict``. ::
-
- from flask.json.tag import JSONTag
-
- class TagOrderedDict(JSONTag):
- __slots__ = ('serializer',)
- key = ' od'
-
- def check(self, value):
- return isinstance(value, OrderedDict)
-
- def to_json(self, value):
- return [[k, self.serializer.tag(v)] for k, v in iteritems(value)]
-
- def to_python(self, value):
- return OrderedDict(value)
-
- app.session_interface.serializer.register(TagOrderedDict, index=0)
-
-:copyright: © 2010 by the Pallets team.
-:license: BSD, see LICENSE for more details.
-"""
-
-from base64 import b64decode, b64encode
-from datetime import datetime
-from uuid import UUID
-
-from jinja2 import Markup
-from werkzeug.http import http_date, parse_date
-
-from flask._compat import iteritems, text_type
-from flask.json import dumps, loads
-
-
-class JSONTag(object):
- """Base class for defining type tags for :class:`TaggedJSONSerializer`."""
-
- __slots__ = ('serializer',)
-
- #: The tag to mark the serialized object with. If ``None``, this tag is
- #: only used as an intermediate step during tagging.
- key = None
-
- def __init__(self, serializer):
- """Create a tagger for the given serializer."""
- self.serializer = serializer
-
- def check(self, value):
- """Check if the given value should be tagged by this tag."""
- raise NotImplementedError
-
- def to_json(self, value):
- """Convert the Python object to an object that is a valid JSON type.
- The tag will be added later."""
- raise NotImplementedError
-
- def to_python(self, value):
- """Convert the JSON representation back to the correct type. The tag
- will already be removed."""
- raise NotImplementedError
-
- def tag(self, value):
- """Convert the value to a valid JSON type and add the tag structure
- around it."""
- return {self.key: self.to_json(value)}
-
-
-class TagDict(JSONTag):
- """Tag for 1-item dicts whose only key matches a registered tag.
-
- Internally, the dict key is suffixed with `__`, and the suffix is removed
- when deserializing.
- """
-
- __slots__ = ()
- key = ' di'
-
- def check(self, value):
- return (
- isinstance(value, dict)
- and len(value) == 1
- and next(iter(value)) in self.serializer.tags
- )
-
- def to_json(self, value):
- key = next(iter(value))
- return {key + '__': self.serializer.tag(value[key])}
-
- def to_python(self, value):
- key = next(iter(value))
- return {key[:-2]: value[key]}
-
-
-class PassDict(JSONTag):
- __slots__ = ()
-
- def check(self, value):
- return isinstance(value, dict)
-
- def to_json(self, value):
- # JSON objects may only have string keys, so don't bother tagging the
- # key here.
- return dict((k, self.serializer.tag(v)) for k, v in iteritems(value))
-
- tag = to_json
-
-
-class TagTuple(JSONTag):
- __slots__ = ()
- key = ' t'
-
- def check(self, value):
- return isinstance(value, tuple)
-
- def to_json(self, value):
- return [self.serializer.tag(item) for item in value]
-
- def to_python(self, value):
- return tuple(value)
-
-
-class PassList(JSONTag):
- __slots__ = ()
-
- def check(self, value):
- return isinstance(value, list)
-
- def to_json(self, value):
- return [self.serializer.tag(item) for item in value]
-
- tag = to_json
-
-
-class TagBytes(JSONTag):
- __slots__ = ()
- key = ' b'
-
- def check(self, value):
- return isinstance(value, bytes)
-
- def to_json(self, value):
- return b64encode(value).decode('ascii')
-
- def to_python(self, value):
- return b64decode(value)
-
-
-class TagMarkup(JSONTag):
- """Serialize anything matching the :class:`~flask.Markup` API by
- having a ``__html__`` method to the result of that method. Always
- deserializes to an instance of :class:`~flask.Markup`."""
-
- __slots__ = ()
- key = ' m'
-
- def check(self, value):
- return callable(getattr(value, '__html__', None))
-
- def to_json(self, value):
- return text_type(value.__html__())
-
- def to_python(self, value):
- return Markup(value)
-
-
-class TagUUID(JSONTag):
- __slots__ = ()
- key = ' u'
-
- def check(self, value):
- return isinstance(value, UUID)
-
- def to_json(self, value):
- return value.hex
-
- def to_python(self, value):
- return UUID(value)
-
-
-class TagDateTime(JSONTag):
- __slots__ = ()
- key = ' d'
-
- def check(self, value):
- return isinstance(value, datetime)
-
- def to_json(self, value):
- return http_date(value)
-
- def to_python(self, value):
- return parse_date(value)
-
-
-class TaggedJSONSerializer(object):
- """Serializer that uses a tag system to compactly represent objects that
- are not JSON types. Passed as the intermediate serializer to
- :class:`itsdangerous.Serializer`.
-
- The following extra types are supported:
-
- * :class:`dict`
- * :class:`tuple`
- * :class:`bytes`
- * :class:`~flask.Markup`
- * :class:`~uuid.UUID`
- * :class:`~datetime.datetime`
- """
-
- __slots__ = ('tags', 'order')
-
- #: Tag classes to bind when creating the serializer. Other tags can be
- #: added later using :meth:`~register`.
- default_tags = [
- TagDict, PassDict, TagTuple, PassList, TagBytes, TagMarkup, TagUUID,
- TagDateTime,
- ]
-
- def __init__(self):
- self.tags = {}
- self.order = []
-
- for cls in self.default_tags:
- self.register(cls)
-
- def register(self, tag_class, force=False, index=None):
- """Register a new tag with this serializer.
-
- :param tag_class: tag class to register. Will be instantiated with this
- serializer instance.
- :param force: overwrite an existing tag. If false (default), a
- :exc:`KeyError` is raised.
- :param index: index to insert the new tag in the tag order. Useful when
- the new tag is a special case of an existing tag. If ``None``
- (default), the tag is appended to the end of the order.
-
- :raise KeyError: if the tag key is already registered and ``force`` is
- not true.
- """
- tag = tag_class(self)
- key = tag.key
-
- if key is not None:
- if not force and key in self.tags:
- raise KeyError("Tag '{0}' is already registered.".format(key))
-
- self.tags[key] = tag
-
- if index is None:
- self.order.append(tag)
- else:
- self.order.insert(index, tag)
-
- def tag(self, value):
- """Convert a value to a tagged representation if necessary."""
- for tag in self.order:
- if tag.check(value):
- return tag.tag(value)
-
- return value
-
- def untag(self, value):
- """Convert a tagged representation back to the original type."""
- if len(value) != 1:
- return value
-
- key = next(iter(value))
-
- if key not in self.tags:
- return value
-
- return self.tags[key].to_python(value[key])
-
- def dumps(self, value):
- """Tag the value and dump it to a compact JSON string."""
- return dumps(self.tag(value), separators=(',', ':'))
-
- def loads(self, value):
- """Load data from a JSON string and deserialized any tagged objects."""
- return loads(value, object_hook=self.untag)
diff --git a/python/flask/logging.py b/python/flask/logging.py
deleted file mode 100644
index 389c2c2..0000000
--- a/python/flask/logging.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-flask.logging
-~~~~~~~~~~~~~
-
-:copyright: © 2010 by the Pallets team.
-:license: BSD, see LICENSE for more details.
-"""
-
-from __future__ import absolute_import
-
-import logging
-import sys
-
-from werkzeug.local import LocalProxy
-
-from .globals import request
-
-
-@LocalProxy
-def wsgi_errors_stream():
- """Find the most appropriate error stream for the application. If a request
- is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``.
-
- If you configure your own :class:`logging.StreamHandler`, you may want to
- use this for the stream. If you are using file or dict configuration and
- can't import this directly, you can refer to it as
- ``ext://flask.logging.wsgi_errors_stream``.
- """
- return request.environ['wsgi.errors'] if request else sys.stderr
-
-
-def has_level_handler(logger):
- """Check if there is a handler in the logging chain that will handle the
- given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`.
- """
- level = logger.getEffectiveLevel()
- current = logger
-
- while current:
- if any(handler.level <= level for handler in current.handlers):
- return True
-
- if not current.propagate:
- break
-
- current = current.parent
-
- return False
-
-
-#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format
-#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``.
-default_handler = logging.StreamHandler(wsgi_errors_stream)
-default_handler.setFormatter(logging.Formatter(
- '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
-))
-
-
-def create_logger(app):
- """Get the ``'flask.app'`` logger and configure it if needed.
-
- When :attr:`~flask.Flask.debug` is enabled, set the logger level to
- :data:`logging.DEBUG` if it is not set.
-
- If there is no handler for the logger's effective level, add a
- :class:`~logging.StreamHandler` for
- :func:`~flask.logging.wsgi_errors_stream` with a basic format.
- """
- logger = logging.getLogger('flask.app')
-
- if app.debug and logger.level == logging.NOTSET:
- logger.setLevel(logging.DEBUG)
-
- if not has_level_handler(logger):
- logger.addHandler(default_handler)
-
- return logger
diff --git a/python/flask/sessions.py b/python/flask/sessions.py
deleted file mode 100644
index c8b7d4e..0000000
--- a/python/flask/sessions.py
+++ /dev/null
@@ -1,385 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.sessions
- ~~~~~~~~~~~~~~
-
- Implements cookie based sessions based on itsdangerous.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import hashlib
-import warnings
-from datetime import datetime
-
-from itsdangerous import BadSignature, URLSafeTimedSerializer
-from werkzeug.datastructures import CallbackDict
-
-from flask._compat import collections_abc
-from flask.helpers import is_ip, total_seconds
-from flask.json.tag import TaggedJSONSerializer
-
-
-class SessionMixin(collections_abc.MutableMapping):
- """Expands a basic dictionary with session attributes."""
-
- @property
- def permanent(self):
- """This reflects the ``'_permanent'`` key in the dict."""
- return self.get('_permanent', False)
-
- @permanent.setter
- def permanent(self, value):
- self['_permanent'] = bool(value)
-
- #: Some implementations can detect whether a session is newly
- #: created, but that is not guaranteed. Use with caution. The mixin
- # default is hard-coded ``False``.
- new = False
-
- #: Some implementations can detect changes to the session and set
- #: this when that happens. The mixin default is hard coded to
- #: ``True``.
- modified = True
-
- #: Some implementations can detect when session data is read or
- #: written and set this when that happens. The mixin default is hard
- #: coded to ``True``.
- accessed = True
-
-
-class SecureCookieSession(CallbackDict, SessionMixin):
- """Base class for sessions based on signed cookies.
-
- This session backend will set the :attr:`modified` and
- :attr:`accessed` attributes. It cannot reliably track whether a
- session is new (vs. empty), so :attr:`new` remains hard coded to
- ``False``.
- """
-
- #: When data is changed, this is set to ``True``. Only the session
- #: dictionary itself is tracked; if the session contains mutable
- #: data (for example a nested dict) then this must be set to
- #: ``True`` manually when modifying that data. The session cookie
- #: will only be written to the response if this is ``True``.
- modified = False
-
- #: When data is read or written, this is set to ``True``. Used by
- # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie``
- #: header, which allows caching proxies to cache different pages for
- #: different users.
- accessed = False
-
- def __init__(self, initial=None):
- def on_update(self):
- self.modified = True
- self.accessed = True
-
- super(SecureCookieSession, self).__init__(initial, on_update)
-
- def __getitem__(self, key):
- self.accessed = True
- return super(SecureCookieSession, self).__getitem__(key)
-
- def get(self, key, default=None):
- self.accessed = True
- return super(SecureCookieSession, self).get(key, default)
-
- def setdefault(self, key, default=None):
- self.accessed = True
- return super(SecureCookieSession, self).setdefault(key, default)
-
-
-class NullSession(SecureCookieSession):
- """Class used to generate nicer error messages if sessions are not
- available. Will still allow read-only access to the empty session
- but fail on setting.
- """
-
- def _fail(self, *args, **kwargs):
- raise RuntimeError('The session is unavailable because no secret '
- 'key was set. Set the secret_key on the '
- 'application to something unique and secret.')
- __setitem__ = __delitem__ = clear = pop = popitem = \
- update = setdefault = _fail
- del _fail
-
-
-class SessionInterface(object):
- """The basic interface you have to implement in order to replace the
- default session interface which uses werkzeug's securecookie
- implementation. The only methods you have to implement are
- :meth:`open_session` and :meth:`save_session`, the others have
- useful defaults which you don't need to change.
-
- The session object returned by the :meth:`open_session` method has to
- provide a dictionary like interface plus the properties and methods
- from the :class:`SessionMixin`. We recommend just subclassing a dict
- and adding that mixin::
-
- class Session(dict, SessionMixin):
- pass
-
- If :meth:`open_session` returns ``None`` Flask will call into
- :meth:`make_null_session` to create a session that acts as replacement
- if the session support cannot work because some requirement is not
- fulfilled. The default :class:`NullSession` class that is created
- will complain that the secret key was not set.
-
- To replace the session interface on an application all you have to do
- is to assign :attr:`flask.Flask.session_interface`::
-
- app = Flask(__name__)
- app.session_interface = MySessionInterface()
-
- .. versionadded:: 0.8
- """
-
- #: :meth:`make_null_session` will look here for the class that should
- #: be created when a null session is requested. Likewise the
- #: :meth:`is_null_session` method will perform a typecheck against
- #: this type.
- null_session_class = NullSession
-
- #: A flag that indicates if the session interface is pickle based.
- #: This can be used by Flask extensions to make a decision in regards
- #: to how to deal with the session object.
- #:
- #: .. versionadded:: 0.10
- pickle_based = False
-
- def make_null_session(self, app):
- """Creates a null session which acts as a replacement object if the
- real session support could not be loaded due to a configuration
- error. This mainly aids the user experience because the job of the
- null session is to still support lookup without complaining but
- modifications are answered with a helpful error message of what
- failed.
-
- This creates an instance of :attr:`null_session_class` by default.
- """
- return self.null_session_class()
-
- def is_null_session(self, obj):
- """Checks if a given object is a null session. Null sessions are
- not asked to be saved.
-
- This checks if the object is an instance of :attr:`null_session_class`
- by default.
- """
- return isinstance(obj, self.null_session_class)
-
- def get_cookie_domain(self, app):
- """Returns the domain that should be set for the session cookie.
-
- Uses ``SESSION_COOKIE_DOMAIN`` if it is configured, otherwise
- falls back to detecting the domain based on ``SERVER_NAME``.
-
- Once detected (or if not set at all), ``SESSION_COOKIE_DOMAIN`` is
- updated to avoid re-running the logic.
- """
-
- rv = app.config['SESSION_COOKIE_DOMAIN']
-
- # set explicitly, or cached from SERVER_NAME detection
- # if False, return None
- if rv is not None:
- return rv if rv else None
-
- rv = app.config['SERVER_NAME']
-
- # server name not set, cache False to return none next time
- if not rv:
- app.config['SESSION_COOKIE_DOMAIN'] = False
- return None
-
- # chop off the port which is usually not supported by browsers
- # remove any leading '.' since we'll add that later
- rv = rv.rsplit(':', 1)[0].lstrip('.')
-
- if '.' not in rv:
- # Chrome doesn't allow names without a '.'
- # this should only come up with localhost
- # hack around this by not setting the name, and show a warning
- warnings.warn(
- '"{rv}" is not a valid cookie domain, it must contain a ".".'
- ' Add an entry to your hosts file, for example'
- ' "{rv}.localdomain", and use that instead.'.format(rv=rv)
- )
- app.config['SESSION_COOKIE_DOMAIN'] = False
- return None
-
- ip = is_ip(rv)
-
- if ip:
- warnings.warn(
- 'The session cookie domain is an IP address. This may not work'
- ' as intended in some browsers. Add an entry to your hosts'
- ' file, for example "localhost.localdomain", and use that'
- ' instead.'
- )
-
- # if this is not an ip and app is mounted at the root, allow subdomain
- # matching by adding a '.' prefix
- if self.get_cookie_path(app) == '/' and not ip:
- rv = '.' + rv
-
- app.config['SESSION_COOKIE_DOMAIN'] = rv
- return rv
-
- def get_cookie_path(self, app):
- """Returns the path for which the cookie should be valid. The
- default implementation uses the value from the ``SESSION_COOKIE_PATH``
- config var if it's set, and falls back to ``APPLICATION_ROOT`` or
- uses ``/`` if it's ``None``.
- """
- return app.config['SESSION_COOKIE_PATH'] \
- or app.config['APPLICATION_ROOT']
-
- def get_cookie_httponly(self, app):
- """Returns True if the session cookie should be httponly. This
- currently just returns the value of the ``SESSION_COOKIE_HTTPONLY``
- config var.
- """
- return app.config['SESSION_COOKIE_HTTPONLY']
-
- def get_cookie_secure(self, app):
- """Returns True if the cookie should be secure. This currently
- just returns the value of the ``SESSION_COOKIE_SECURE`` setting.
- """
- return app.config['SESSION_COOKIE_SECURE']
-
- def get_cookie_samesite(self, app):
- """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the
- ``SameSite`` attribute. This currently just returns the value of
- the :data:`SESSION_COOKIE_SAMESITE` setting.
- """
- return app.config['SESSION_COOKIE_SAMESITE']
-
- def get_expiration_time(self, app, session):
- """A helper method that returns an expiration date for the session
- or ``None`` if the session is linked to the browser session. The
- default implementation returns now + the permanent session
- lifetime configured on the application.
- """
- if session.permanent:
- return datetime.utcnow() + app.permanent_session_lifetime
-
- def should_set_cookie(self, app, session):
- """Used by session backends to determine if a ``Set-Cookie`` header
- should be set for this session cookie for this response. If the session
- has been modified, the cookie is set. If the session is permanent and
- the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is
- always set.
-
- This check is usually skipped if the session was deleted.
-
- .. versionadded:: 0.11
- """
-
- return session.modified or (
- session.permanent and app.config['SESSION_REFRESH_EACH_REQUEST']
- )
-
- def open_session(self, app, request):
- """This method has to be implemented and must either return ``None``
- in case the loading failed because of a configuration error or an
- instance of a session object which implements a dictionary like
- interface + the methods and attributes on :class:`SessionMixin`.
- """
- raise NotImplementedError()
-
- def save_session(self, app, session, response):
- """This is called for actual sessions returned by :meth:`open_session`
- at the end of the request. This is still called during a request
- context so if you absolutely need access to the request you can do
- that.
- """
- raise NotImplementedError()
-
-
-session_json_serializer = TaggedJSONSerializer()
-
-
-class SecureCookieSessionInterface(SessionInterface):
- """The default session interface that stores sessions in signed cookies
- through the :mod:`itsdangerous` module.
- """
- #: the salt that should be applied on top of the secret key for the
- #: signing of cookie based sessions.
- salt = 'cookie-session'
- #: the hash function to use for the signature. The default is sha1
- digest_method = staticmethod(hashlib.sha1)
- #: the name of the itsdangerous supported key derivation. The default
- #: is hmac.
- key_derivation = 'hmac'
- #: A python serializer for the payload. The default is a compact
- #: JSON derived serializer with support for some extra Python types
- #: such as datetime objects or tuples.
- serializer = session_json_serializer
- session_class = SecureCookieSession
-
- def get_signing_serializer(self, app):
- if not app.secret_key:
- return None
- signer_kwargs = dict(
- key_derivation=self.key_derivation,
- digest_method=self.digest_method
- )
- return URLSafeTimedSerializer(app.secret_key, salt=self.salt,
- serializer=self.serializer,
- signer_kwargs=signer_kwargs)
-
- def open_session(self, app, request):
- s = self.get_signing_serializer(app)
- if s is None:
- return None
- val = request.cookies.get(app.session_cookie_name)
- if not val:
- return self.session_class()
- max_age = total_seconds(app.permanent_session_lifetime)
- try:
- data = s.loads(val, max_age=max_age)
- return self.session_class(data)
- except BadSignature:
- return self.session_class()
-
- def save_session(self, app, session, response):
- domain = self.get_cookie_domain(app)
- path = self.get_cookie_path(app)
-
- # If the session is modified to be empty, remove the cookie.
- # If the session is empty, return without setting the cookie.
- if not session:
- if session.modified:
- response.delete_cookie(
- app.session_cookie_name,
- domain=domain,
- path=path
- )
-
- return
-
- # Add a "Vary: Cookie" header if the session was accessed at all.
- if session.accessed:
- response.vary.add('Cookie')
-
- if not self.should_set_cookie(app, session):
- return
-
- httponly = self.get_cookie_httponly(app)
- secure = self.get_cookie_secure(app)
- samesite = self.get_cookie_samesite(app)
- expires = self.get_expiration_time(app, session)
- val = self.get_signing_serializer(app).dumps(dict(session))
- response.set_cookie(
- app.session_cookie_name,
- val,
- expires=expires,
- httponly=httponly,
- domain=domain,
- path=path,
- secure=secure,
- samesite=samesite
- )
diff --git a/python/flask/signals.py b/python/flask/signals.py
deleted file mode 100644
index 18f2630..0000000
--- a/python/flask/signals.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.signals
- ~~~~~~~~~~~~~
-
- Implements signals based on blinker if available, otherwise
- falls silently back to a noop.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-signals_available = False
-try:
- from blinker import Namespace
- signals_available = True
-except ImportError:
- class Namespace(object):
- def signal(self, name, doc=None):
- return _FakeSignal(name, doc)
-
- class _FakeSignal(object):
- """If blinker is unavailable, create a fake class with the same
- interface that allows sending of signals but will fail with an
- error on anything else. Instead of doing anything on send, it
- will just ignore the arguments and do nothing instead.
- """
-
- def __init__(self, name, doc=None):
- self.name = name
- self.__doc__ = doc
- def _fail(self, *args, **kwargs):
- raise RuntimeError('signalling support is unavailable '
- 'because the blinker library is '
- 'not installed.')
- send = lambda *a, **kw: None
- connect = disconnect = has_receivers_for = receivers_for = \
- temporarily_connected_to = connected_to = _fail
- del _fail
-
-# The namespace for code signals. If you are not Flask code, do
-# not put signals in here. Create your own namespace instead.
-_signals = Namespace()
-
-
-# Core signals. For usage examples grep the source code or consult
-# the API documentation in docs/api.rst as well as docs/signals.rst
-template_rendered = _signals.signal('template-rendered')
-before_render_template = _signals.signal('before-render-template')
-request_started = _signals.signal('request-started')
-request_finished = _signals.signal('request-finished')
-request_tearing_down = _signals.signal('request-tearing-down')
-got_request_exception = _signals.signal('got-request-exception')
-appcontext_tearing_down = _signals.signal('appcontext-tearing-down')
-appcontext_pushed = _signals.signal('appcontext-pushed')
-appcontext_popped = _signals.signal('appcontext-popped')
-message_flashed = _signals.signal('message-flashed')
diff --git a/python/flask/templating.py b/python/flask/templating.py
deleted file mode 100644
index 0240200..0000000
--- a/python/flask/templating.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.templating
- ~~~~~~~~~~~~~~~~
-
- Implements the bridge to Jinja2.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-from jinja2 import BaseLoader, Environment as BaseEnvironment, \
- TemplateNotFound
-
-from .globals import _request_ctx_stack, _app_ctx_stack
-from .signals import template_rendered, before_render_template
-
-
-def _default_template_ctx_processor():
- """Default template context processor. Injects `request`,
- `session` and `g`.
- """
- reqctx = _request_ctx_stack.top
- appctx = _app_ctx_stack.top
- rv = {}
- if appctx is not None:
- rv['g'] = appctx.g
- if reqctx is not None:
- rv['request'] = reqctx.request
- rv['session'] = reqctx.session
- return rv
-
-
-class Environment(BaseEnvironment):
- """Works like a regular Jinja2 environment but has some additional
- knowledge of how Flask's blueprint works so that it can prepend the
- name of the blueprint to referenced templates if necessary.
- """
-
- def __init__(self, app, **options):
- if 'loader' not in options:
- options['loader'] = app.create_global_jinja_loader()
- BaseEnvironment.__init__(self, **options)
- self.app = app
-
-
-class DispatchingJinjaLoader(BaseLoader):
- """A loader that looks for templates in the application and all
- the blueprint folders.
- """
-
- def __init__(self, app):
- self.app = app
-
- def get_source(self, environment, template):
- if self.app.config['EXPLAIN_TEMPLATE_LOADING']:
- return self._get_source_explained(environment, template)
- return self._get_source_fast(environment, template)
-
- def _get_source_explained(self, environment, template):
- attempts = []
- trv = None
-
- for srcobj, loader in self._iter_loaders(template):
- try:
- rv = loader.get_source(environment, template)
- if trv is None:
- trv = rv
- except TemplateNotFound:
- rv = None
- attempts.append((loader, srcobj, rv))
-
- from .debughelpers import explain_template_loading_attempts
- explain_template_loading_attempts(self.app, template, attempts)
-
- if trv is not None:
- return trv
- raise TemplateNotFound(template)
-
- def _get_source_fast(self, environment, template):
- for srcobj, loader in self._iter_loaders(template):
- try:
- return loader.get_source(environment, template)
- except TemplateNotFound:
- continue
- raise TemplateNotFound(template)
-
- def _iter_loaders(self, template):
- loader = self.app.jinja_loader
- if loader is not None:
- yield self.app, loader
-
- for blueprint in self.app.iter_blueprints():
- loader = blueprint.jinja_loader
- if loader is not None:
- yield blueprint, loader
-
- def list_templates(self):
- result = set()
- loader = self.app.jinja_loader
- if loader is not None:
- result.update(loader.list_templates())
-
- for blueprint in self.app.iter_blueprints():
- loader = blueprint.jinja_loader
- if loader is not None:
- for template in loader.list_templates():
- result.add(template)
-
- return list(result)
-
-
-def _render(template, context, app):
- """Renders the template and fires the signal"""
-
- before_render_template.send(app, template=template, context=context)
- rv = template.render(context)
- template_rendered.send(app, template=template, context=context)
- return rv
-
-
-def render_template(template_name_or_list, **context):
- """Renders a template from the template folder with the given
- context.
-
- :param template_name_or_list: the name of the template to be
- rendered, or an iterable with template names
- the first one existing will be rendered
- :param context: the variables that should be available in the
- context of the template.
- """
- ctx = _app_ctx_stack.top
- ctx.app.update_template_context(context)
- return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
- context, ctx.app)
-
-
-def render_template_string(source, **context):
- """Renders a template from the given template source string
- with the given context. Template variables will be autoescaped.
-
- :param source: the source code of the template to be
- rendered
- :param context: the variables that should be available in the
- context of the template.
- """
- ctx = _app_ctx_stack.top
- ctx.app.update_template_context(context)
- return _render(ctx.app.jinja_env.from_string(source),
- context, ctx.app)
diff --git a/python/flask/testing.py b/python/flask/testing.py
deleted file mode 100644
index 114c5cc..0000000
--- a/python/flask/testing.py
+++ /dev/null
@@ -1,246 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.testing
- ~~~~~~~~~~~~~
-
- Implements test support helpers. This module is lazily imported
- and usually not used in production environments.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-import werkzeug
-from contextlib import contextmanager
-
-from click.testing import CliRunner
-from flask.cli import ScriptInfo
-from werkzeug.test import Client, EnvironBuilder
-from flask import _request_ctx_stack
-from flask.json import dumps as json_dumps
-from werkzeug.urls import url_parse
-
-
-def make_test_environ_builder(
- app, path='/', base_url=None, subdomain=None, url_scheme=None,
- *args, **kwargs
-):
- """Create a :class:`~werkzeug.test.EnvironBuilder`, taking some
- defaults from the application.
-
- :param app: The Flask application to configure the environment from.
- :param path: URL path being requested.
- :param base_url: Base URL where the app is being served, which
- ``path`` is relative to. If not given, built from
- :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
- :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
- :param subdomain: Subdomain name to append to :data:`SERVER_NAME`.
- :param url_scheme: Scheme to use instead of
- :data:`PREFERRED_URL_SCHEME`.
- :param json: If given, this is serialized as JSON and passed as
- ``data``. Also defaults ``content_type`` to
- ``application/json``.
- :param args: other positional arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- :param kwargs: other keyword arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- """
-
- assert (
- not (base_url or subdomain or url_scheme)
- or (base_url is not None) != bool(subdomain or url_scheme)
- ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".'
-
- if base_url is None:
- http_host = app.config.get('SERVER_NAME') or 'localhost'
- app_root = app.config['APPLICATION_ROOT']
-
- if subdomain:
- http_host = '{0}.{1}'.format(subdomain, http_host)
-
- if url_scheme is None:
- url_scheme = app.config['PREFERRED_URL_SCHEME']
-
- url = url_parse(path)
- base_url = '{scheme}://{netloc}/{path}'.format(
- scheme=url.scheme or url_scheme,
- netloc=url.netloc or http_host,
- path=app_root.lstrip('/')
- )
- path = url.path
-
- if url.query:
- sep = b'?' if isinstance(url.query, bytes) else '?'
- path += sep + url.query
-
- # TODO use EnvironBuilder.json_dumps once we require Werkzeug 0.15
- if 'json' in kwargs:
- assert 'data' not in kwargs, "Client cannot provide both 'json' and 'data'."
- kwargs['data'] = json_dumps(kwargs.pop('json'), app=app)
-
- if 'content_type' not in kwargs:
- kwargs['content_type'] = 'application/json'
-
- return EnvironBuilder(path, base_url, *args, **kwargs)
-
-
-class FlaskClient(Client):
- """Works like a regular Werkzeug test client but has some knowledge about
- how Flask works to defer the cleanup of the request context stack to the
- end of a ``with`` body when used in a ``with`` statement. For general
- information about how to use this class refer to
- :class:`werkzeug.test.Client`.
-
- .. versionchanged:: 0.12
- `app.test_client()` includes preset default environment, which can be
- set after instantiation of the `app.test_client()` object in
- `client.environ_base`.
-
- Basic usage is outlined in the :ref:`testing` chapter.
- """
-
- preserve_context = False
-
- def __init__(self, *args, **kwargs):
- super(FlaskClient, self).__init__(*args, **kwargs)
- self.environ_base = {
- "REMOTE_ADDR": "127.0.0.1",
- "HTTP_USER_AGENT": "werkzeug/" + werkzeug.__version__
- }
-
- @contextmanager
- def session_transaction(self, *args, **kwargs):
- """When used in combination with a ``with`` statement this opens a
- session transaction. This can be used to modify the session that
- the test client uses. Once the ``with`` block is left the session is
- stored back.
-
- ::
-
- with client.session_transaction() as session:
- session['value'] = 42
-
- Internally this is implemented by going through a temporary test
- request context and since session handling could depend on
- request variables this function accepts the same arguments as
- :meth:`~flask.Flask.test_request_context` which are directly
- passed through.
- """
- if self.cookie_jar is None:
- raise RuntimeError('Session transactions only make sense '
- 'with cookies enabled.')
- app = self.application
- environ_overrides = kwargs.setdefault('environ_overrides', {})
- self.cookie_jar.inject_wsgi(environ_overrides)
- outer_reqctx = _request_ctx_stack.top
- with app.test_request_context(*args, **kwargs) as c:
- session_interface = app.session_interface
- sess = session_interface.open_session(app, c.request)
- if sess is None:
- raise RuntimeError('Session backend did not open a session. '
- 'Check the configuration')
-
- # Since we have to open a new request context for the session
- # handling we want to make sure that we hide out own context
- # from the caller. By pushing the original request context
- # (or None) on top of this and popping it we get exactly that
- # behavior. It's important to not use the push and pop
- # methods of the actual request context object since that would
- # mean that cleanup handlers are called
- _request_ctx_stack.push(outer_reqctx)
- try:
- yield sess
- finally:
- _request_ctx_stack.pop()
-
- resp = app.response_class()
- if not session_interface.is_null_session(sess):
- session_interface.save_session(app, sess, resp)
- headers = resp.get_wsgi_headers(c.request.environ)
- self.cookie_jar.extract_wsgi(c.request.environ, headers)
-
- def open(self, *args, **kwargs):
- as_tuple = kwargs.pop('as_tuple', False)
- buffered = kwargs.pop('buffered', False)
- follow_redirects = kwargs.pop('follow_redirects', False)
-
- if (
- not kwargs and len(args) == 1
- and isinstance(args[0], (EnvironBuilder, dict))
- ):
- environ = self.environ_base.copy()
-
- if isinstance(args[0], EnvironBuilder):
- environ.update(args[0].get_environ())
- else:
- environ.update(args[0])
-
- environ['flask._preserve_context'] = self.preserve_context
- else:
- kwargs.setdefault('environ_overrides', {}) \
- ['flask._preserve_context'] = self.preserve_context
- kwargs.setdefault('environ_base', self.environ_base)
- builder = make_test_environ_builder(
- self.application, *args, **kwargs
- )
-
- try:
- environ = builder.get_environ()
- finally:
- builder.close()
-
- return Client.open(
- self, environ,
- as_tuple=as_tuple,
- buffered=buffered,
- follow_redirects=follow_redirects
- )
-
- def __enter__(self):
- if self.preserve_context:
- raise RuntimeError('Cannot nest client invocations')
- self.preserve_context = True
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- self.preserve_context = False
-
- # on exit we want to clean up earlier. Normally the request context
- # stays preserved until the next request in the same thread comes
- # in. See RequestGlobals.push() for the general behavior.
- top = _request_ctx_stack.top
- if top is not None and top.preserved:
- top.pop()
-
-
-class FlaskCliRunner(CliRunner):
- """A :class:`~click.testing.CliRunner` for testing a Flask app's
- CLI commands. Typically created using
- :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`.
- """
- def __init__(self, app, **kwargs):
- self.app = app
- super(FlaskCliRunner, self).__init__(**kwargs)
-
- def invoke(self, cli=None, args=None, **kwargs):
- """Invokes a CLI command in an isolated environment. See
- :meth:`CliRunner.invoke <click.testing.CliRunner.invoke>` for
- full method documentation. See :ref:`testing-cli` for examples.
-
- If the ``obj`` argument is not given, passes an instance of
- :class:`~flask.cli.ScriptInfo` that knows how to load the Flask
- app being tested.
-
- :param cli: Command object to invoke. Default is the app's
- :attr:`~flask.app.Flask.cli` group.
- :param args: List of strings to invoke the command with.
-
- :return: a :class:`~click.testing.Result` object.
- """
- if cli is None:
- cli = self.app.cli
-
- if 'obj' not in kwargs:
- kwargs['obj'] = ScriptInfo(create_app=lambda: self.app)
-
- return super(FlaskCliRunner, self).invoke(cli, args, **kwargs)
diff --git a/python/flask/views.py b/python/flask/views.py
deleted file mode 100644
index 1f2c997..0000000
--- a/python/flask/views.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.views
- ~~~~~~~~~~~
-
- This module provides class-based views inspired by the ones in Django.
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-from .globals import request
-from ._compat import with_metaclass
-
-
-http_method_funcs = frozenset(['get', 'post', 'head', 'options',
- 'delete', 'put', 'trace', 'patch'])
-
-
-class View(object):
- """Alternative way to use view functions. A subclass has to implement
- :meth:`dispatch_request` which is called with the view arguments from
- the URL routing system. If :attr:`methods` is provided the methods
- do not have to be passed to the :meth:`~flask.Flask.add_url_rule`
- method explicitly::
-
- class MyView(View):
- methods = ['GET']
-
- def dispatch_request(self, name):
- return 'Hello %s!' % name
-
- app.add_url_rule('/hello/<name>', view_func=MyView.as_view('myview'))
-
- When you want to decorate a pluggable view you will have to either do that
- when the view function is created (by wrapping the return value of
- :meth:`as_view`) or you can use the :attr:`decorators` attribute::
-
- class SecretView(View):
- methods = ['GET']
- decorators = [superuser_required]
-
- def dispatch_request(self):
- ...
-
- The decorators stored in the decorators list are applied one after another
- when the view function is created. Note that you can *not* use the class
- based decorators since those would decorate the view class and not the
- generated view function!
- """
-
- #: A list of methods this view can handle.
- methods = None
-
- #: Setting this disables or force-enables the automatic options handling.
- provide_automatic_options = None
-
- #: The canonical way to decorate class-based views is to decorate the
- #: return value of as_view(). However since this moves parts of the
- #: logic from the class declaration to the place where it's hooked
- #: into the routing system.
- #:
- #: You can place one or more decorators in this list and whenever the
- #: view function is created the result is automatically decorated.
- #:
- #: .. versionadded:: 0.8
- decorators = ()
-
- def dispatch_request(self):
- """Subclasses have to override this method to implement the
- actual view function code. This method is called with all
- the arguments from the URL rule.
- """
- raise NotImplementedError()
-
- @classmethod
- def as_view(cls, name, *class_args, **class_kwargs):
- """Converts the class into an actual view function that can be used
- with the routing system. Internally this generates a function on the
- fly which will instantiate the :class:`View` on each request and call
- the :meth:`dispatch_request` method on it.
-
- The arguments passed to :meth:`as_view` are forwarded to the
- constructor of the class.
- """
- def view(*args, **kwargs):
- self = view.view_class(*class_args, **class_kwargs)
- return self.dispatch_request(*args, **kwargs)
-
- if cls.decorators:
- view.__name__ = name
- view.__module__ = cls.__module__
- for decorator in cls.decorators:
- view = decorator(view)
-
- # We attach the view class to the view function for two reasons:
- # first of all it allows us to easily figure out what class-based
- # view this thing came from, secondly it's also used for instantiating
- # the view class so you can actually replace it with something else
- # for testing purposes and debugging.
- view.view_class = cls
- view.__name__ = name
- view.__doc__ = cls.__doc__
- view.__module__ = cls.__module__
- view.methods = cls.methods
- view.provide_automatic_options = cls.provide_automatic_options
- return view
-
-
-class MethodViewType(type):
- """Metaclass for :class:`MethodView` that determines what methods the view
- defines.
- """
-
- def __init__(cls, name, bases, d):
- super(MethodViewType, cls).__init__(name, bases, d)
-
- if 'methods' not in d:
- methods = set()
-
- for key in http_method_funcs:
- if hasattr(cls, key):
- methods.add(key.upper())
-
- # If we have no method at all in there we don't want to add a
- # method list. This is for instance the case for the base class
- # or another subclass of a base method view that does not introduce
- # new methods.
- if methods:
- cls.methods = methods
-
-
-class MethodView(with_metaclass(MethodViewType, View)):
- """A class-based view that dispatches request methods to the corresponding
- class methods. For example, if you implement a ``get`` method, it will be
- used to handle ``GET`` requests. ::
-
- class CounterAPI(MethodView):
- def get(self):
- return session.get('counter', 0)
-
- def post(self):
- session['counter'] = session.get('counter', 0) + 1
- return 'OK'
-
- app.add_url_rule('/counter', view_func=CounterAPI.as_view('counter'))
- """
-
- def dispatch_request(self, *args, **kwargs):
- meth = getattr(self, request.method.lower(), None)
-
- # If the request method is HEAD and we don't have a handler for it
- # retry with GET.
- if meth is None and request.method == 'HEAD':
- meth = getattr(self, 'get', None)
-
- assert meth is not None, 'Unimplemented method %r' % request.method
- return meth(*args, **kwargs)
diff --git a/python/flask/wrappers.py b/python/flask/wrappers.py
deleted file mode 100644
index 12eff2c..0000000
--- a/python/flask/wrappers.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.wrappers
- ~~~~~~~~~~~~~~
-
- Implements the WSGI wrappers (request and response).
-
- :copyright: © 2010 by the Pallets team.
- :license: BSD, see LICENSE for more details.
-"""
-
-from werkzeug.exceptions import BadRequest
-from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase
-
-from flask import json
-from flask.globals import current_app
-
-
-class JSONMixin(object):
- """Common mixin for both request and response objects to provide JSON
- parsing capabilities.
-
- .. versionadded:: 1.0
- """
-
- _cached_json = (Ellipsis, Ellipsis)
-
- @property
- def is_json(self):
- """Check if the mimetype indicates JSON data, either
- :mimetype:`application/json` or :mimetype:`application/*+json`.
-
- .. versionadded:: 0.11
- """
- mt = self.mimetype
- return (
- mt == 'application/json'
- or (mt.startswith('application/')) and mt.endswith('+json')
- )
-
- @property
- def json(self):
- """This will contain the parsed JSON data if the mimetype indicates
- JSON (:mimetype:`application/json`, see :meth:`is_json`), otherwise it
- will be ``None``.
- """
- return self.get_json()
-
- def _get_data_for_json(self, cache):
- return self.get_data(cache=cache)
-
- def get_json(self, force=False, silent=False, cache=True):
- """Parse and return the data as JSON. If the mimetype does not
- indicate JSON (:mimetype:`application/json`, see
- :meth:`is_json`), this returns ``None`` unless ``force`` is
- true. If parsing fails, :meth:`on_json_loading_failed` is called
- and its return value is used as the return value.
-
- :param force: Ignore the mimetype and always try to parse JSON.
- :param silent: Silence parsing errors and return ``None``
- instead.
- :param cache: Store the parsed JSON to return for subsequent
- calls.
- """
- if cache and self._cached_json[silent] is not Ellipsis:
- return self._cached_json[silent]
-
- if not (force or self.is_json):
- return None
-
- data = self._get_data_for_json(cache=cache)
-
- try:
- rv = json.loads(data)
- except ValueError as e:
- if silent:
- rv = None
- if cache:
- normal_rv, _ = self._cached_json
- self._cached_json = (normal_rv, rv)
- else:
- rv = self.on_json_loading_failed(e)
- if cache:
- _, silent_rv = self._cached_json
- self._cached_json = (rv, silent_rv)
- else:
- if cache:
- self._cached_json = (rv, rv)
-
- return rv
-
- def on_json_loading_failed(self, e):
- """Called if :meth:`get_json` parsing fails and isn't silenced. If
- this method returns a value, it is used as the return value for
- :meth:`get_json`. The default implementation raises a
- :class:`BadRequest` exception.
-
- .. versionchanged:: 0.10
- Raise a :exc:`BadRequest` error instead of returning an error
- message as JSON. If you want that behavior you can add it by
- subclassing.
-
- .. versionadded:: 0.8
- """
- if current_app is not None and current_app.debug:
- raise BadRequest('Failed to decode JSON object: {0}'.format(e))
-
- raise BadRequest()
-
-
-class Request(RequestBase, JSONMixin):
- """The request object used by default in Flask. Remembers the
- matched endpoint and view arguments.
-
- It is what ends up as :class:`~flask.request`. If you want to replace
- the request object used you can subclass this and set
- :attr:`~flask.Flask.request_class` to your subclass.
-
- The request object is a :class:`~werkzeug.wrappers.Request` subclass and
- provides all of the attributes Werkzeug defines plus a few Flask
- specific ones.
- """
-
- #: The internal URL rule that matched the request. This can be
- #: useful to inspect which methods are allowed for the URL from
- #: a before/after handler (``request.url_rule.methods``) etc.
- #: Though if the request's method was invalid for the URL rule,
- #: the valid list is available in ``routing_exception.valid_methods``
- #: instead (an attribute of the Werkzeug exception :exc:`~werkzeug.exceptions.MethodNotAllowed`)
- #: because the request was never internally bound.
- #:
- #: .. versionadded:: 0.6
- url_rule = None
-
- #: A dict of view arguments that matched the request. If an exception
- #: happened when matching, this will be ``None``.
- view_args = None
-
- #: If matching the URL failed, this is the exception that will be
- #: raised / was raised as part of the request handling. This is
- #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
- #: something similar.
- routing_exception = None
-
- @property
- def max_content_length(self):
- """Read-only view of the ``MAX_CONTENT_LENGTH`` config key."""
- if current_app:
- return current_app.config['MAX_CONTENT_LENGTH']
-
- @property
- def endpoint(self):
- """The endpoint that matched the request. This in combination with
- :attr:`view_args` can be used to reconstruct the same or a
- modified URL. If an exception happened when matching, this will
- be ``None``.
- """
- if self.url_rule is not None:
- return self.url_rule.endpoint
-
- @property
- def blueprint(self):
- """The name of the current blueprint"""
- if self.url_rule and '.' in self.url_rule.endpoint:
- return self.url_rule.endpoint.rsplit('.', 1)[0]
-
- def _load_form_data(self):
- RequestBase._load_form_data(self)
-
- # In debug mode we're replacing the files multidict with an ad-hoc
- # subclass that raises a different error for key errors.
- if (
- current_app
- and current_app.debug
- and self.mimetype != 'multipart/form-data'
- and not self.files
- ):
- from .debughelpers import attach_enctype_error_multidict
- attach_enctype_error_multidict(self)
-
-
-class Response(ResponseBase, JSONMixin):
- """The response object that is used by default in Flask. Works like the
- response object from Werkzeug but is set to have an HTML mimetype by
- default. Quite often you don't have to create this object yourself because
- :meth:`~flask.Flask.make_response` will take care of that for you.
-
- If you want to replace the response object used you can subclass this and
- set :attr:`~flask.Flask.response_class` to your subclass.
-
- .. versionchanged:: 1.0
- JSON support is added to the response, like the request. This is useful
- when testing to get the test client response data as JSON.
-
- .. versionchanged:: 1.0
-
- Added :attr:`max_cookie_size`.
- """
-
- default_mimetype = 'text/html'
-
- def _get_data_for_json(self, cache):
- return self.get_data()
-
- @property
- def max_cookie_size(self):
- """Read-only view of the :data:`MAX_COOKIE_SIZE` config key.
-
- See :attr:`~werkzeug.wrappers.BaseResponse.max_cookie_size` in
- Werkzeug's docs.
- """
- if current_app:
- return current_app.config['MAX_COOKIE_SIZE']
-
- # return Werkzeug's default when not in an app context
- return super(Response, self).max_cookie_size