⚡ Added Flask module
This commit is contained in:
		
							parent
							
								
									a6a6febe5f
								
							
						
					
					
						commit
						2fb7fd3244
					
				| 
						 | 
				
			
			@ -4,9 +4,13 @@ Project: Analyse worldwide COVID-19 Data and provide graphs etc.
 | 
			
		|||
 | 
			
		||||
@author Patrick Müller
 | 
			
		||||
"""
 | 
			
		||||
import socketserver
 | 
			
		||||
from http.server import BaseHTTPRequestHandler
 | 
			
		||||
from modules import flask
 | 
			
		||||
 | 
			
		||||
class HttpRequestHandler(BaseHTTPRequestHandler):
 | 
			
		||||
	def do_GET(self):
 | 
			
		||||
		print('hello')
 | 
			
		||||
app = flask.Flask(__name__)
 | 
			
		||||
app.config['DEBUG'] = True
 | 
			
		||||
 | 
			
		||||
@app.route('/', methods=['GET'])
 | 
			
		||||
def home():
 | 
			
		||||
	return "<h1>Distant Reading Archive</h1><p>This site is a prototype API for distant reading of science fiction novels.</p>"
 | 
			
		||||
 | 
			
		||||
app.run()
 | 
			
		||||
							
								
								
									
										0
									
								
								modules/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										60
									
								
								modules/flask/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								modules/flask/__init__.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask
 | 
			
		||||
    ~~~~~
 | 
			
		||||
 | 
			
		||||
    A microframework based on Werkzeug.  It's extensively documented
 | 
			
		||||
    and follows best practice patterns.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
# utilities we import from Werkzeug and Jinja2 that are unused
 | 
			
		||||
# in the module but are exported as public interface.
 | 
			
		||||
from jinja2 import escape
 | 
			
		||||
from jinja2 import Markup
 | 
			
		||||
from werkzeug.exceptions import abort
 | 
			
		||||
from werkzeug.utils import redirect
 | 
			
		||||
 | 
			
		||||
from . import json
 | 
			
		||||
from ._compat import json_available
 | 
			
		||||
from .app import Flask
 | 
			
		||||
from .app import Request
 | 
			
		||||
from .app import Response
 | 
			
		||||
from .blueprints import Blueprint
 | 
			
		||||
from .config import Config
 | 
			
		||||
from .ctx import after_this_request
 | 
			
		||||
from .ctx import copy_current_request_context
 | 
			
		||||
from .ctx import has_app_context
 | 
			
		||||
from .ctx import has_request_context
 | 
			
		||||
from .globals import _app_ctx_stack
 | 
			
		||||
from .globals import _request_ctx_stack
 | 
			
		||||
from .globals import current_app
 | 
			
		||||
from .globals import g
 | 
			
		||||
from .globals import request
 | 
			
		||||
from .globals import session
 | 
			
		||||
from .helpers import flash
 | 
			
		||||
from .helpers import get_flashed_messages
 | 
			
		||||
from .helpers import get_template_attribute
 | 
			
		||||
from .helpers import make_response
 | 
			
		||||
from .helpers import safe_join
 | 
			
		||||
from .helpers import send_file
 | 
			
		||||
from .helpers import send_from_directory
 | 
			
		||||
from .helpers import stream_with_context
 | 
			
		||||
from .helpers import url_for
 | 
			
		||||
from .json import jsonify
 | 
			
		||||
from .signals import appcontext_popped
 | 
			
		||||
from .signals import appcontext_pushed
 | 
			
		||||
from .signals import appcontext_tearing_down
 | 
			
		||||
from .signals import before_render_template
 | 
			
		||||
from .signals import got_request_exception
 | 
			
		||||
from .signals import message_flashed
 | 
			
		||||
from .signals import request_finished
 | 
			
		||||
from .signals import request_started
 | 
			
		||||
from .signals import request_tearing_down
 | 
			
		||||
from .signals import signals_available
 | 
			
		||||
from .signals import template_rendered
 | 
			
		||||
from .templating import render_template
 | 
			
		||||
from .templating import render_template_string
 | 
			
		||||
 | 
			
		||||
__version__ = "1.2.0.dev0"
 | 
			
		||||
							
								
								
									
										15
									
								
								modules/flask/__main__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								modules/flask/__main__.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.__main__
 | 
			
		||||
    ~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Alias for flask.run for the command line.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    from .cli import main
 | 
			
		||||
 | 
			
		||||
    main(as_module=True)
 | 
			
		||||
							
								
								
									
										145
									
								
								modules/flask/_compat.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								modules/flask/_compat.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,145 @@
 | 
			
		|||
# -*- 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 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
PY2 = sys.version_info[0] == 2
 | 
			
		||||
_identity = lambda x: x
 | 
			
		||||
 | 
			
		||||
try:  # Python 2
 | 
			
		||||
    text_type = unicode
 | 
			
		||||
    string_types = (str, unicode)
 | 
			
		||||
    integer_types = (int, long)
 | 
			
		||||
except NameError:  # Python 3
 | 
			
		||||
    text_type = str
 | 
			
		||||
    string_types = (str,)
 | 
			
		||||
    integer_types = (int,)
 | 
			
		||||
 | 
			
		||||
if not PY2:
 | 
			
		||||
    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:
 | 
			
		||||
    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__(metacls, 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:  # noqa: B001
 | 
			
		||||
            # We intentionally use a bare except here. See the comment above
 | 
			
		||||
            # regarding a pypy bug as to why.
 | 
			
		||||
            raise
 | 
			
		||||
    except TypeError:
 | 
			
		||||
        BROKEN_PYPY_CTXMGR_EXIT = True
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    from os import fspath
 | 
			
		||||
except ImportError:
 | 
			
		||||
    # Backwards compatibility as proposed in PEP 0519:
 | 
			
		||||
    # https://www.python.org/dev/peps/pep-0519/#backwards-compatibility
 | 
			
		||||
    def fspath(path):
 | 
			
		||||
        return path.__fspath__() if hasattr(path, "__fspath__") else path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _DeprecatedBool(object):
 | 
			
		||||
    def __init__(self, name, version, value):
 | 
			
		||||
        self.message = "'{}' is deprecated and will be removed in version {}.".format(
 | 
			
		||||
            name, version
 | 
			
		||||
        )
 | 
			
		||||
        self.value = value
 | 
			
		||||
 | 
			
		||||
    def _warn(self):
 | 
			
		||||
        import warnings
 | 
			
		||||
 | 
			
		||||
        warnings.warn(self.message, DeprecationWarning, stacklevel=2)
 | 
			
		||||
 | 
			
		||||
    def __eq__(self, other):
 | 
			
		||||
        self._warn()
 | 
			
		||||
        return other == self.value
 | 
			
		||||
 | 
			
		||||
    def __ne__(self, other):
 | 
			
		||||
        self._warn()
 | 
			
		||||
        return other != self.value
 | 
			
		||||
 | 
			
		||||
    def __bool__(self):
 | 
			
		||||
        self._warn()
 | 
			
		||||
        return self.value
 | 
			
		||||
 | 
			
		||||
    __nonzero__ = __bool__
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
json_available = _DeprecatedBool("flask.json_available", "2.0.0", True)
 | 
			
		||||
							
								
								
									
										2457
									
								
								modules/flask/app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2457
									
								
								modules/flask/app.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										569
									
								
								modules/flask/blueprints.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										569
									
								
								modules/flask/blueprints.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,569 @@
 | 
			
		|||
# -*- 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 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
from functools import update_wrapper
 | 
			
		||||
 | 
			
		||||
from .helpers import _endpoint_from_view_func
 | 
			
		||||
from .helpers import _PackageBoundObject
 | 
			
		||||
 | 
			
		||||
# a singleton sentinel value for parameter defaults
 | 
			
		||||
_sentinel = object()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 collection of routes and other
 | 
			
		||||
    app-related functions that can be registered on a real application
 | 
			
		||||
    later.
 | 
			
		||||
 | 
			
		||||
    A blueprint is an object that allows defining application functions
 | 
			
		||||
    without requiring an application object ahead of time. It uses the
 | 
			
		||||
    same decorators as :class:`~flask.Flask`, but defers the need for an
 | 
			
		||||
    application by recording them for later registration.
 | 
			
		||||
 | 
			
		||||
    Decorating a function with a blueprint creates a deferred function
 | 
			
		||||
    that is called with :class:`~flask.blueprints.BlueprintSetupState`
 | 
			
		||||
    when the blueprint is registered on an application.
 | 
			
		||||
 | 
			
		||||
    See :ref:`blueprints` for more information.
 | 
			
		||||
 | 
			
		||||
    .. versionchanged:: 1.1.0
 | 
			
		||||
        Blueprints have a ``cli`` group to register nested CLI commands.
 | 
			
		||||
        The ``cli_group`` parameter controls the name of the group under
 | 
			
		||||
        the ``flask`` command.
 | 
			
		||||
 | 
			
		||||
    .. versionadded:: 0.7
 | 
			
		||||
 | 
			
		||||
    :param name: The name of the blueprint. Will be prepended to each
 | 
			
		||||
        endpoint name.
 | 
			
		||||
    :param import_name: The name of the blueprint package, usually
 | 
			
		||||
        ``__name__``. This helps locate the ``root_path`` for the
 | 
			
		||||
        blueprint.
 | 
			
		||||
    :param static_folder: A folder with static files that should be
 | 
			
		||||
        served by the blueprint's static route. The path is relative to
 | 
			
		||||
        the blueprint's root path. Blueprint static files are disabled
 | 
			
		||||
        by default.
 | 
			
		||||
    :param static_url_path: The url to serve static files from.
 | 
			
		||||
        Defaults to ``static_folder``. If the blueprint does not have
 | 
			
		||||
        a ``url_prefix``, the app's static route will take precedence,
 | 
			
		||||
        and the blueprint's static files won't be accessible.
 | 
			
		||||
    :param template_folder: A folder with templates that should be added
 | 
			
		||||
        to the app's template search path. The path is relative to the
 | 
			
		||||
        blueprint's root path. Blueprint templates are disabled by
 | 
			
		||||
        default. Blueprint templates have a lower precedence than those
 | 
			
		||||
        in the app's templates folder.
 | 
			
		||||
    :param url_prefix: A path to prepend to all of the blueprint's URLs,
 | 
			
		||||
        to make them distinct from the rest of the app's routes.
 | 
			
		||||
    :param subdomain: A subdomain that blueprint routes will match on by
 | 
			
		||||
        default.
 | 
			
		||||
    :param url_defaults: A dict of default values that blueprint routes
 | 
			
		||||
        will receive by default.
 | 
			
		||||
    :param root_path: By default, the blueprint will automatically this
 | 
			
		||||
        based on ``import_name``. In certain situations this automatic
 | 
			
		||||
        detection can fail, so the path can be specified manually
 | 
			
		||||
        instead.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
        cli_group=_sentinel,
 | 
			
		||||
    ):
 | 
			
		||||
        _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
 | 
			
		||||
        self.cli_group = cli_group
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
        cli_resolved_group = options.get("cli_group", self.cli_group)
 | 
			
		||||
 | 
			
		||||
        if not self.cli.commands:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if cli_resolved_group is None:
 | 
			
		||||
            app.cli.commands.update(self.cli.commands)
 | 
			
		||||
        elif cli_resolved_group is _sentinel:
 | 
			
		||||
            self.cli.name = self.name
 | 
			
		||||
            app.cli.add_command(self.cli)
 | 
			
		||||
        else:
 | 
			
		||||
            self.cli.name = cli_resolved_group
 | 
			
		||||
            app.cli.add_command(self.cli)
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
        )
 | 
			
		||||
							
								
								
									
										974
									
								
								modules/flask/cli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										974
									
								
								modules/flask/cli.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,974 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.cli
 | 
			
		||||
    ~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    A simple command line application to run flask apps.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
from __future__ import print_function
 | 
			
		||||
 | 
			
		||||
import ast
 | 
			
		||||
import inspect
 | 
			
		||||
import os
 | 
			
		||||
import platform
 | 
			
		||||
import re
 | 
			
		||||
import sys
 | 
			
		||||
import traceback
 | 
			
		||||
from functools import update_wrapper
 | 
			
		||||
from operator import attrgetter
 | 
			
		||||
from threading import Lock
 | 
			
		||||
from threading import Thread
 | 
			
		||||
 | 
			
		||||
import click
 | 
			
		||||
from werkzeug.utils import import_string
 | 
			
		||||
 | 
			
		||||
from ._compat import getargspec
 | 
			
		||||
from ._compat import itervalues
 | 
			
		||||
from ._compat import reraise
 | 
			
		||||
from ._compat import text_type
 | 
			
		||||
from .globals import current_app
 | 
			
		||||
from .helpers import get_debug_flag
 | 
			
		||||
from .helpers import get_env
 | 
			
		||||
from .helpers import get_load_dotenv
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    import dotenv
 | 
			
		||||
except ImportError:
 | 
			
		||||
    dotenv = None
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    import ssl
 | 
			
		||||
except ImportError:
 | 
			
		||||
    ssl = 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 v in itervalues(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:
 | 
			
		||||
        # explicitly delete tb as it is circular referenced
 | 
			
		||||
        # https://docs.python.org/2/library/sys.html#sys.exc_info
 | 
			
		||||
        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 . 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)
 | 
			
		||||
 | 
			
		||||
    fname, ext = os.path.splitext(path)
 | 
			
		||||
    if ext == ".py":
 | 
			
		||||
        path = fname
 | 
			
		||||
 | 
			
		||||
    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  # noqa: F841
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    from . import __version__
 | 
			
		||||
 | 
			
		||||
    message = "Python %(python)s\nFlask %(flask)s\nWerkzeug %(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=None):
 | 
			
		||||
        self.loader = loader
 | 
			
		||||
        self._app = None
 | 
			
		||||
        self._lock = Lock()
 | 
			
		||||
        self._bg_loading_exc_info = None
 | 
			
		||||
 | 
			
		||||
        if use_eager_loading is None:
 | 
			
		||||
            use_eager_loading = os.environ.get("WERKZEUG_RUN_MAIN") != "true"
 | 
			
		||||
 | 
			
		||||
        if use_eager_loading:
 | 
			
		||||
            self._load_unlocked()
 | 
			
		||||
        else:
 | 
			
		||||
            self._load_in_background()
 | 
			
		||||
 | 
			
		||||
    def _load_in_background(self):
 | 
			
		||||
        def _load_app():
 | 
			
		||||
            __traceback_hide__ = True  # noqa: F841
 | 
			
		||||
            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  # noqa: F841
 | 
			
		||||
        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  # noqa: F841
 | 
			
		||||
        self._app = rv = self.loader()
 | 
			
		||||
        self._bg_loading_exc_info = None
 | 
			
		||||
        return rv
 | 
			
		||||
 | 
			
		||||
    def __call__(self, environ, start_response):
 | 
			
		||||
        __traceback_hide__ = True  # noqa: F841
 | 
			
		||||
        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  # noqa: F841
 | 
			
		||||
 | 
			
		||||
        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 will 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.
 | 
			
		||||
 | 
			
		||||
    .. versionchanged:: 1.1.0
 | 
			
		||||
        Returns ``False`` when python-dotenv is not installed, or when
 | 
			
		||||
        the given path isn't a file.
 | 
			
		||||
 | 
			
		||||
    .. versionadded:: 1.0
 | 
			
		||||
    """
 | 
			
		||||
    if dotenv is None:
 | 
			
		||||
        if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"):
 | 
			
		||||
            click.secho(
 | 
			
		||||
                " * Tip: There are .env or .flaskenv files present."
 | 
			
		||||
                ' Do "pip install python-dotenv" to use them.',
 | 
			
		||||
                fg="yellow",
 | 
			
		||||
                err=True,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    # if the given path specifies the actual file then return True,
 | 
			
		||||
    # else False
 | 
			
		||||
    if path is not None:
 | 
			
		||||
        if os.path.isfile(path):
 | 
			
		||||
            return dotenv.load_dotenv(path)
 | 
			
		||||
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    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):
 | 
			
		||||
        if ssl is None:
 | 
			
		||||
            raise click.BadParameter(
 | 
			
		||||
                'Using "--cert" requires Python to be compiled with SSL support.',
 | 
			
		||||
                ctx,
 | 
			
		||||
                param,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            return self.path_type(value, param, ctx)
 | 
			
		||||
        except click.BadParameter:
 | 
			
		||||
            value = click.STRING(value, param, ctx).lower()
 | 
			
		||||
 | 
			
		||||
            if value == "adhoc":
 | 
			
		||||
                try:
 | 
			
		||||
                    import cryptography  # noqa: F401
 | 
			
		||||
                except ImportError:
 | 
			
		||||
                    raise click.BadParameter(
 | 
			
		||||
                        "Using ad-hoc certificates requires the cryptography library.",
 | 
			
		||||
                        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 = ssl and 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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SeparatedPathType(click.Path):
 | 
			
		||||
    """Click option type that accepts a list of values separated by the
 | 
			
		||||
    OS's path separator (``:``, ``;`` on Windows). Each value is
 | 
			
		||||
    validated as a :class:`click.Path` type.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def convert(self, value, param, ctx):
 | 
			
		||||
        items = self.split_envvar_value(value)
 | 
			
		||||
        super_convert = super(SeparatedPathType, self).convert
 | 
			
		||||
        return [super_convert(item, param, ctx) for item in items]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@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-loading",
 | 
			
		||||
    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.",
 | 
			
		||||
)
 | 
			
		||||
@click.option(
 | 
			
		||||
    "--extra-files",
 | 
			
		||||
    default=None,
 | 
			
		||||
    type=SeparatedPathType(),
 | 
			
		||||
    help=(
 | 
			
		||||
        "Extra files that trigger a reload on change. Multiple paths"
 | 
			
		||||
        " are separated by '{}'.".format(os.path.pathsep)
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
@pass_script_info
 | 
			
		||||
def run_command(
 | 
			
		||||
    info, host, port, reload, debugger, eager_loading, with_threads, cert, extra_files
 | 
			
		||||
):
 | 
			
		||||
    """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
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
        extra_files=extra_files,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@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 .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):
 | 
			
		||||
    # TODO omit sys.argv once https://github.com/pallets/click/issues/536 is fixed
 | 
			
		||||
    cli.main(args=sys.argv[1:], prog_name="python -m flask" if as_module else None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main(as_module=True)
 | 
			
		||||
							
								
								
									
										301
									
								
								modules/flask/config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								modules/flask/config.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,301 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.config
 | 
			
		||||
    ~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Implements the configuration related objects.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
import errno
 | 
			
		||||
import os
 | 
			
		||||
import types
 | 
			
		||||
import warnings
 | 
			
		||||
 | 
			
		||||
from werkzeug.utils import import_string
 | 
			
		||||
 | 
			
		||||
from ._compat import iteritems
 | 
			
		||||
from ._compat import string_types
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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_file(self, filename, load, silent=False):
 | 
			
		||||
        """Update the values in the config from a file that is loaded
 | 
			
		||||
        using the ``load`` parameter. The loaded data is passed to the
 | 
			
		||||
        :meth:`from_mapping` method.
 | 
			
		||||
 | 
			
		||||
        .. code-block:: python
 | 
			
		||||
 | 
			
		||||
            import toml
 | 
			
		||||
            app.config.from_file("config.toml", load=toml.load)
 | 
			
		||||
 | 
			
		||||
        :param filename: The path to the data file. This can be an
 | 
			
		||||
            absolute path or relative to the config root path.
 | 
			
		||||
        :param load: A callable that takes a file handle and returns a
 | 
			
		||||
            mapping of loaded data from the file.
 | 
			
		||||
        :type load: ``Callable[[Reader], Mapping]`` where ``Reader``
 | 
			
		||||
            implements a ``read`` method.
 | 
			
		||||
        :param silent: Ignore the file if it doesn't exist.
 | 
			
		||||
 | 
			
		||||
        .. versionadded:: 2.0
 | 
			
		||||
        """
 | 
			
		||||
        filename = os.path.join(self.root_path, filename)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            with open(filename) as f:
 | 
			
		||||
                obj = load(f)
 | 
			
		||||
        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_json(self, filename, silent=False):
 | 
			
		||||
        """Update the values in the config from a JSON file. The loaded
 | 
			
		||||
        data is passed to the :meth:`from_mapping` method.
 | 
			
		||||
 | 
			
		||||
        :param filename: The path to the JSON file. This can be an
 | 
			
		||||
            absolute path or relative to the config root path.
 | 
			
		||||
        :param silent: Ignore the file if it doesn't exist.
 | 
			
		||||
 | 
			
		||||
        .. deprecated:: 1.2
 | 
			
		||||
            Use :meth:`from_file` with :meth:`json.load` instead.
 | 
			
		||||
 | 
			
		||||
        .. versionadded:: 0.11
 | 
			
		||||
        """
 | 
			
		||||
        warnings.warn(
 | 
			
		||||
            "'from_json' is deprecated and will be removed in 2.0."
 | 
			
		||||
            " Use 'from_file(filename, load=json.load)' instead.",
 | 
			
		||||
            DeprecationWarning,
 | 
			
		||||
            stacklevel=2,
 | 
			
		||||
        )
 | 
			
		||||
        from .json import load
 | 
			
		||||
 | 
			
		||||
        return self.from_file(filename, load, silent=silent)
 | 
			
		||||
 | 
			
		||||
    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))
 | 
			
		||||
							
								
								
									
										475
									
								
								modules/flask/ctx.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										475
									
								
								modules/flask/ctx.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,475 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.ctx
 | 
			
		||||
    ~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Implements the objects required to keep the context.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
import sys
 | 
			
		||||
from functools import update_wrapper
 | 
			
		||||
 | 
			
		||||
from werkzeug.exceptions import HTTPException
 | 
			
		||||
 | 
			
		||||
from ._compat import BROKEN_PYPY_CTXMGR_EXIT
 | 
			
		||||
from ._compat import reraise
 | 
			
		||||
from .globals import _app_ctx_stack
 | 
			
		||||
from .globals import _request_ctx_stack
 | 
			
		||||
from .signals import appcontext_popped
 | 
			
		||||
from .signals import appcontext_pushed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 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 raising 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.  The current session is also
 | 
			
		||||
    included in the copied request context.
 | 
			
		||||
 | 
			
		||||
    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 or
 | 
			
		||||
                # flask.session 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, session=None):
 | 
			
		||||
        self.app = app
 | 
			
		||||
        if request is None:
 | 
			
		||||
            request = app.request_class(environ)
 | 
			
		||||
        self.request = request
 | 
			
		||||
        self.url_adapter = None
 | 
			
		||||
        try:
 | 
			
		||||
            self.url_adapter = app.create_url_adapter(self.request)
 | 
			
		||||
        except HTTPException as e:
 | 
			
		||||
            self.request.routing_exception = e
 | 
			
		||||
        self.flashes = None
 | 
			
		||||
        self.session = session
 | 
			
		||||
 | 
			
		||||
        # 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 = []
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def g(self):
 | 
			
		||||
        return _app_ctx_stack.top.g
 | 
			
		||||
 | 
			
		||||
    @g.setter
 | 
			
		||||
    def g(self, value):
 | 
			
		||||
        _app_ctx_stack.top.g = value
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
        .. versionchanged:: 1.1
 | 
			
		||||
           The current session object is used instead of reloading the original
 | 
			
		||||
           data. This prevents `flask.session` pointing to an out-of-date object.
 | 
			
		||||
        """
 | 
			
		||||
        return self.__class__(
 | 
			
		||||
            self.app,
 | 
			
		||||
            environ=self.request.environ,
 | 
			
		||||
            request=self.request,
 | 
			
		||||
            session=self.session,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def match_request(self):
 | 
			
		||||
        """Can be overridden by a subclass to hook into the matching
 | 
			
		||||
        of the request.
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            result = self.url_adapter.match(return_rule=True)
 | 
			
		||||
            self.request.url_rule, self.request.view_args = result
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
        if self.url_adapter is not None:
 | 
			
		||||
            self.match_request()
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
        )
 | 
			
		||||
							
								
								
									
										183
									
								
								modules/flask/debughelpers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								modules/flask/debughelpers.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,183 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.debughelpers
 | 
			
		||||
    ~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Various helpers to make the development experience better.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
import os
 | 
			
		||||
from warnings import warn
 | 
			
		||||
 | 
			
		||||
from ._compat import implements_to_string
 | 
			
		||||
from ._compat import 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 https://flask.palletsprojects.com/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,
 | 
			
		||||
        )
 | 
			
		||||
							
								
								
									
										62
									
								
								modules/flask/globals.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								modules/flask/globals.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.globals
 | 
			
		||||
    ~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Defines all the global objects that are proxies to the current
 | 
			
		||||
    active context.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
from functools import partial
 | 
			
		||||
 | 
			
		||||
from werkzeug.local import LocalProxy
 | 
			
		||||
from werkzeug.local import LocalStack
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_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"))
 | 
			
		||||
							
								
								
									
										1167
									
								
								modules/flask/helpers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1167
									
								
								modules/flask/helpers.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										109
									
								
								modules/flask/logging.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								modules/flask/logging.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,109 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
flask.logging
 | 
			
		||||
~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
:copyright: 2010 Pallets
 | 
			
		||||
:license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
from __future__ import absolute_import
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
import sys
 | 
			
		||||
import warnings
 | 
			
		||||
 | 
			
		||||
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 _has_config(logger):
 | 
			
		||||
    """Decide if a logger has direct configuration applied by checking
 | 
			
		||||
    its properties against the defaults.
 | 
			
		||||
 | 
			
		||||
    :param logger: The :class:`~logging.Logger` to inspect.
 | 
			
		||||
    """
 | 
			
		||||
    return (
 | 
			
		||||
        logger.level != logging.NOTSET
 | 
			
		||||
        or logger.handlers
 | 
			
		||||
        or logger.filters
 | 
			
		||||
        or not logger.propagate
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_logger(app):
 | 
			
		||||
    """Get the Flask app's logger and configure it if needed.
 | 
			
		||||
 | 
			
		||||
    The logger name will be the same as
 | 
			
		||||
    :attr:`app.import_name <flask.Flask.name>`.
 | 
			
		||||
 | 
			
		||||
    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(app.name)
 | 
			
		||||
 | 
			
		||||
    # 1.1.0 changes name of logger, warn if config is detected for old
 | 
			
		||||
    # name and not new name
 | 
			
		||||
    for old_name in ("flask.app", "flask"):
 | 
			
		||||
        old_logger = logging.getLogger(old_name)
 | 
			
		||||
 | 
			
		||||
        if _has_config(old_logger) and not _has_config(logger):
 | 
			
		||||
            warnings.warn(
 | 
			
		||||
                "'app.logger' is named '{name}' for this application,"
 | 
			
		||||
                " but configuration was found for '{old_name}', which"
 | 
			
		||||
                " no longer has an effect. The logging configuration"
 | 
			
		||||
                " should be moved to '{name}'.".format(name=app.name, old_name=old_name)
 | 
			
		||||
            )
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
    if app.debug and not logger.level:
 | 
			
		||||
        logger.setLevel(logging.DEBUG)
 | 
			
		||||
 | 
			
		||||
    if not has_level_handler(logger):
 | 
			
		||||
        logger.addHandler(default_handler)
 | 
			
		||||
 | 
			
		||||
    return logger
 | 
			
		||||
							
								
								
									
										394
									
								
								modules/flask/sessions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								modules/flask/sessions.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,394 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.sessions
 | 
			
		||||
    ~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Implements cookie based sessions based on itsdangerous.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
import hashlib
 | 
			
		||||
import warnings
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
from itsdangerous import BadSignature
 | 
			
		||||
from itsdangerous import URLSafeTimedSerializer
 | 
			
		||||
from werkzeug.datastructures import CallbackDict
 | 
			
		||||
 | 
			
		||||
from ._compat import collections_abc
 | 
			
		||||
from .helpers import is_ip
 | 
			
		||||
from .helpers import total_seconds
 | 
			
		||||
from .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_name(self, app):
 | 
			
		||||
        """Returns the name of the session cookie.
 | 
			
		||||
 | 
			
		||||
        Uses ``app.session_cookie_name`` which is set to ``SESSION_COOKIE_NAME``
 | 
			
		||||
        """
 | 
			
		||||
        return app.session_cookie_name
 | 
			
		||||
 | 
			
		||||
    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(self.get_cookie_name(app))
 | 
			
		||||
        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):
 | 
			
		||||
        name = self.get_cookie_name(app)
 | 
			
		||||
        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(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(
 | 
			
		||||
            name,
 | 
			
		||||
            val,
 | 
			
		||||
            expires=expires,
 | 
			
		||||
            httponly=httponly,
 | 
			
		||||
            domain=domain,
 | 
			
		||||
            path=path,
 | 
			
		||||
            secure=secure,
 | 
			
		||||
            samesite=samesite,
 | 
			
		||||
        )
 | 
			
		||||
							
								
								
									
										65
									
								
								modules/flask/signals.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								modules/flask/signals.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.signals
 | 
			
		||||
    ~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Implements signals based on blinker if available, otherwise
 | 
			
		||||
    falls silently back to a noop.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
try:
 | 
			
		||||
    from blinker import Namespace
 | 
			
		||||
 | 
			
		||||
    signals_available = True
 | 
			
		||||
except ImportError:
 | 
			
		||||
    signals_available = False
 | 
			
		||||
 | 
			
		||||
    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 send(self, *args, **kwargs):
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        def _fail(self, *args, **kwargs):
 | 
			
		||||
            raise RuntimeError(
 | 
			
		||||
                "Signalling support is unavailable because the blinker"
 | 
			
		||||
                " library is not installed."
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        connect = connect_via = connected_to = temporarily_connected_to = _fail
 | 
			
		||||
        disconnect = _fail
 | 
			
		||||
        has_receivers_for = receivers_for = _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")
 | 
			
		||||
							
								
								
									
										155
									
								
								modules/flask/templating.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								modules/flask/templating.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,155 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.templating
 | 
			
		||||
    ~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Implements the bridge to Jinja2.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
from jinja2 import BaseLoader
 | 
			
		||||
from jinja2 import Environment as BaseEnvironment
 | 
			
		||||
from jinja2 import TemplateNotFound
 | 
			
		||||
 | 
			
		||||
from .globals import _app_ctx_stack
 | 
			
		||||
from .globals import _request_ctx_stack
 | 
			
		||||
from .signals import before_render_template
 | 
			
		||||
from .signals import template_rendered
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
							
								
								
									
										283
									
								
								modules/flask/testing.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								modules/flask/testing.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,283 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.testing
 | 
			
		||||
    ~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Implements test support helpers.  This module is lazily imported
 | 
			
		||||
    and usually not used in production environments.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
import warnings
 | 
			
		||||
from contextlib import contextmanager
 | 
			
		||||
 | 
			
		||||
import werkzeug.test
 | 
			
		||||
from click.testing import CliRunner
 | 
			
		||||
from werkzeug.test import Client
 | 
			
		||||
from werkzeug.urls import url_parse
 | 
			
		||||
 | 
			
		||||
from . import _request_ctx_stack
 | 
			
		||||
from .cli import ScriptInfo
 | 
			
		||||
from .json import dumps as json_dumps
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EnvironBuilder(werkzeug.test.EnvironBuilder):
 | 
			
		||||
    """An :class:`~werkzeug.test.EnvironBuilder`, that takes 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`.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        app,
 | 
			
		||||
        path="/",
 | 
			
		||||
        base_url=None,
 | 
			
		||||
        subdomain=None,
 | 
			
		||||
        url_scheme=None,
 | 
			
		||||
        *args,
 | 
			
		||||
        **kwargs
 | 
			
		||||
    ):
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
        self.app = app
 | 
			
		||||
        super(EnvironBuilder, self).__init__(path, base_url, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def json_dumps(self, obj, **kwargs):
 | 
			
		||||
        """Serialize ``obj`` to a JSON-formatted string.
 | 
			
		||||
 | 
			
		||||
        The serialization will be configured according to the config associated
 | 
			
		||||
        with this EnvironBuilder's ``app``.
 | 
			
		||||
        """
 | 
			
		||||
        kwargs.setdefault("app", self.app)
 | 
			
		||||
        return json_dumps(obj, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def make_test_environ_builder(*args, **kwargs):
 | 
			
		||||
    """Create a :class:`flask.testing.EnvironBuilder`.
 | 
			
		||||
 | 
			
		||||
    .. deprecated: 1.1
 | 
			
		||||
        Will be removed in 1.2. Construct ``flask.testing.EnvironBuilder``
 | 
			
		||||
        directly instead.
 | 
			
		||||
    """
 | 
			
		||||
    warnings.warn(
 | 
			
		||||
        DeprecationWarning(
 | 
			
		||||
            '"make_test_environ_builder()" is deprecated and will be removed '
 | 
			
		||||
            'in 1.2. Construct "flask.testing.EnvironBuilder" directly '
 | 
			
		||||
            "instead."
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    return EnvironBuilder(*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], (werkzeug.test.EnvironBuilder, dict))
 | 
			
		||||
        ):
 | 
			
		||||
            environ = self.environ_base.copy()
 | 
			
		||||
 | 
			
		||||
            if isinstance(args[0], werkzeug.test.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 = EnvironBuilder(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
 | 
			
		||||
 | 
			
		||||
        # Normally the request context is preserved until the next
 | 
			
		||||
        # request in the same thread comes. When the client exits we
 | 
			
		||||
        # want to clean up earlier. Pop request contexts until the stack
 | 
			
		||||
        # is empty or a non-preserved one is found.
 | 
			
		||||
        while True:
 | 
			
		||||
            top = _request_ctx_stack.top
 | 
			
		||||
 | 
			
		||||
            if top is not None and top.preserved:
 | 
			
		||||
                top.pop()
 | 
			
		||||
            else:
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
							
								
								
									
										163
									
								
								modules/flask/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								modules/flask/views.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,163 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.views
 | 
			
		||||
    ~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    This module provides class-based views inspired by the ones in Django.
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
from ._compat import with_metaclass
 | 
			
		||||
from .globals import request
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 base in bases:
 | 
			
		||||
                if getattr(base, "methods", None):
 | 
			
		||||
                    methods.update(base.methods)
 | 
			
		||||
 | 
			
		||||
            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)
 | 
			
		||||
							
								
								
									
										137
									
								
								modules/flask/wrappers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								modules/flask/wrappers.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,137 @@
 | 
			
		|||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""
 | 
			
		||||
    flask.wrappers
 | 
			
		||||
    ~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
    Implements the WSGI wrappers (request and response).
 | 
			
		||||
 | 
			
		||||
    :copyright: 2010 Pallets
 | 
			
		||||
    :license: BSD-3-Clause
 | 
			
		||||
"""
 | 
			
		||||
from werkzeug.exceptions import BadRequest
 | 
			
		||||
from werkzeug.wrappers import Request as RequestBase
 | 
			
		||||
from werkzeug.wrappers import Response as ResponseBase
 | 
			
		||||
from werkzeug.wrappers.json import JSONMixin as _JSONMixin
 | 
			
		||||
 | 
			
		||||
from . import json
 | 
			
		||||
from .globals import current_app
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JSONMixin(_JSONMixin):
 | 
			
		||||
    json_module = json
 | 
			
		||||
 | 
			
		||||
    def on_json_loading_failed(self, e):
 | 
			
		||||
        if current_app 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
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user