Reformat with black

https://github.com/python/black
This commit is contained in:
David Baumgold 2019-05-06 15:39:41 -04:00
parent 5b309831ec
commit 025589ee76
63 changed files with 3784 additions and 3459 deletions

View file

@ -10,7 +10,7 @@
:license: BSD, see LICENSE for more details.
"""
__version__ = '1.1.dev'
__version__ = "1.1.dev"
# utilities we import from Werkzeug and Jinja2 that are unused
# in the module but are exported as public interface.
@ -20,21 +20,48 @@ from jinja2 import Markup, escape
from .app import Flask, Request, Response
from .config import Config
from .helpers import url_for, flash, send_file, send_from_directory, \
get_flashed_messages, get_template_attribute, make_response, safe_join, \
stream_with_context
from .globals import current_app, g, request, session, _request_ctx_stack, \
_app_ctx_stack
from .ctx import has_request_context, has_app_context, \
after_this_request, copy_current_request_context
from .helpers import (
url_for,
flash,
send_file,
send_from_directory,
get_flashed_messages,
get_template_attribute,
make_response,
safe_join,
stream_with_context,
)
from .globals import (
current_app,
g,
request,
session,
_request_ctx_stack,
_app_ctx_stack,
)
from .ctx import (
has_request_context,
has_app_context,
after_this_request,
copy_current_request_context,
)
from .blueprints import Blueprint
from .templating import render_template, render_template_string
# the signals
from .signals import signals_available, template_rendered, request_started, \
request_finished, got_request_exception, request_tearing_down, \
appcontext_tearing_down, appcontext_pushed, \
appcontext_popped, message_flashed, before_render_template
from .signals import (
signals_available,
template_rendered,
request_started,
request_finished,
got_request_exception,
request_tearing_down,
appcontext_tearing_down,
appcontext_pushed,
appcontext_popped,
message_flashed,
before_render_template,
)
# We're not exposing the actual json module but a convenient wrapper around
# it.

View file

@ -9,6 +9,7 @@
:license: BSD, see LICENSE for more details.
"""
if __name__ == '__main__':
if __name__ == "__main__":
from .cli import main
main(as_module=True)

View file

@ -50,11 +50,11 @@ else:
from cStringIO import StringIO
import collections as collections_abc
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
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')
cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
return cls
@ -66,7 +66,8 @@ def with_metaclass(meta, *bases):
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})
return type.__new__(metaclass, "temporary_class", (), {})
# Certain versions of pypy have a bug where clearing the exception stack
@ -81,14 +82,17 @@ def with_metaclass(meta, *bases):
#
# Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug.
BROKEN_PYPY_CTXMGR_EXIT = False
if hasattr(sys, 'pypy_version_info'):
if hasattr(sys, "pypy_version_info"):
class _Mgr(object):
def __enter__(self):
return self
def __exit__(self, *args):
if hasattr(sys, 'exc_clear'):
if hasattr(sys, "exc_clear"):
# Python 3 (PyPy3) doesn't have exc_clear
sys.exc_clear()
try:
try:
with _Mgr():
@ -107,4 +111,4 @@ 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
return path.__fspath__() if hasattr(path, "__fspath__") else path

View file

@ -18,10 +18,15 @@ from itertools import chain
from threading import Lock
from werkzeug.datastructures import Headers, ImmutableDict
from werkzeug.exceptions import BadRequest, BadRequestKeyError, HTTPException, \
InternalServerError, MethodNotAllowed, default_exceptions
from werkzeug.routing import BuildError, Map, RequestRedirect, \
RoutingException, Rule
from werkzeug.exceptions import (
BadRequest,
BadRequestKeyError,
HTTPException,
InternalServerError,
MethodNotAllowed,
default_exceptions,
)
from werkzeug.routing import BuildError, Map, RequestRedirect, RoutingException, Rule
from . import cli, json
from ._compat import integer_types, reraise, string_types, text_type
@ -30,15 +35,29 @@ from .ctx import AppContext, RequestContext, _AppCtxGlobals
from .globals import _request_ctx_stack, g, request, session
from .helpers import (
_PackageBoundObject,
_endpoint_from_view_func, find_package, get_env, get_debug_flag,
get_flashed_messages, locked_cached_property, url_for, get_load_dotenv
_endpoint_from_view_func,
find_package,
get_env,
get_debug_flag,
get_flashed_messages,
locked_cached_property,
url_for,
get_load_dotenv,
)
from .logging import create_logger
from .sessions import SecureCookieSessionInterface
from .signals import appcontext_tearing_down, got_request_exception, \
request_finished, request_started, request_tearing_down
from .templating import DispatchingJinjaLoader, Environment, \
_default_template_ctx_processor
from .signals import (
appcontext_tearing_down,
got_request_exception,
request_finished,
request_started,
request_tearing_down,
)
from .templating import (
DispatchingJinjaLoader,
Environment,
_default_template_ctx_processor,
)
from .wrappers import Request, Response
# a singleton sentinel value for parameter defaults
@ -55,16 +74,20 @@ def setupmethod(f):
"""Wraps a method so that it performs a check in debug mode if the
first request was already handled.
"""
def wrapper_func(self, *args, **kwargs):
if self.debug and self._got_first_request:
raise AssertionError('A setup function was called after the '
'first request was handled. This usually indicates a bug '
'in the application where a module was not imported '
'and decorators or other functionality was called too late.\n'
'To fix this make sure to import all your view modules, '
'database models and everything related at a central place '
'before the application starts serving requests.')
raise AssertionError(
"A setup function was called after the "
"first request was handled. This usually indicates a bug "
"in the application where a module was not imported "
"and decorators or other functionality was called too late.\n"
"To fix this make sure to import all your view modules, "
"database models and everything related at a central place "
"before the application starts serving requests."
)
return f(self, *args, **kwargs)
return update_wrapper(wrapper_func, f)
@ -217,7 +240,7 @@ class Flask(_PackageBoundObject):
#:
#: This attribute can also be configured from the config with the
#: ``TESTING`` configuration key. Defaults to ``False``.
testing = ConfigAttribute('TESTING')
testing = ConfigAttribute("TESTING")
#: If a secret key is set, cryptographic components can use this to
#: sign cookies and other things. Set this to a complex random value
@ -225,13 +248,13 @@ class Flask(_PackageBoundObject):
#:
#: This attribute can also be configured from the config with the
#: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
secret_key = ConfigAttribute('SECRET_KEY')
secret_key = ConfigAttribute("SECRET_KEY")
#: The secure cookie uses this for the name of the session cookie.
#:
#: This attribute can also be configured from the config with the
#: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME')
session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME")
#: A :class:`~datetime.timedelta` which is used to set the expiration
#: date of a permanent session. The default is 31 days which makes a
@ -240,8 +263,9 @@ class Flask(_PackageBoundObject):
#: This attribute can also be configured from the config with the
#: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to
#: ``timedelta(days=31)``
permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME',
get_converter=_make_timedelta)
permanent_session_lifetime = ConfigAttribute(
"PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
)
#: A :class:`~datetime.timedelta` which is used as default cache_timeout
#: for the :func:`send_file` functions. The default is 12 hours.
@ -250,8 +274,9 @@ class Flask(_PackageBoundObject):
#: ``SEND_FILE_MAX_AGE_DEFAULT`` configuration key. This configuration
#: variable can also be set with an integer value used as seconds.
#: Defaults to ``timedelta(hours=12)``
send_file_max_age_default = ConfigAttribute('SEND_FILE_MAX_AGE_DEFAULT',
get_converter=_make_timedelta)
send_file_max_age_default = ConfigAttribute(
"SEND_FILE_MAX_AGE_DEFAULT", get_converter=_make_timedelta
)
#: Enable this if you want to use the X-Sendfile feature. Keep in
#: mind that the server has to support this. This only affects files
@ -261,7 +286,7 @@ class Flask(_PackageBoundObject):
#:
#: This attribute can also be configured from the config with the
#: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
use_x_sendfile = ConfigAttribute('USE_X_SENDFILE')
use_x_sendfile = ConfigAttribute("USE_X_SENDFILE")
#: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`.
#:
@ -275,41 +300,43 @@ class Flask(_PackageBoundObject):
#: Options that are passed directly to the Jinja2 environment.
jinja_options = ImmutableDict(
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
extensions=["jinja2.ext.autoescape", "jinja2.ext.with_"]
)
#: Default configuration parameters.
default_config = ImmutableDict({
'ENV': None,
'DEBUG': None,
'TESTING': False,
'PROPAGATE_EXCEPTIONS': None,
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
'USE_X_SENDFILE': False,
'SERVER_NAME': None,
'APPLICATION_ROOT': '/',
'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_COOKIE_SAMESITE': None,
'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
'TRAP_BAD_REQUEST_ERRORS': None,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': False,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None,
'MAX_COOKIE_SIZE': 4093,
})
default_config = ImmutableDict(
{
"ENV": None,
"DEBUG": None,
"TESTING": False,
"PROPAGATE_EXCEPTIONS": None,
"PRESERVE_CONTEXT_ON_EXCEPTION": None,
"SECRET_KEY": None,
"PERMANENT_SESSION_LIFETIME": timedelta(days=31),
"USE_X_SENDFILE": False,
"SERVER_NAME": None,
"APPLICATION_ROOT": "/",
"SESSION_COOKIE_NAME": "session",
"SESSION_COOKIE_DOMAIN": None,
"SESSION_COOKIE_PATH": None,
"SESSION_COOKIE_HTTPONLY": True,
"SESSION_COOKIE_SECURE": False,
"SESSION_COOKIE_SAMESITE": None,
"SESSION_REFRESH_EACH_REQUEST": True,
"MAX_CONTENT_LENGTH": None,
"SEND_FILE_MAX_AGE_DEFAULT": timedelta(hours=12),
"TRAP_BAD_REQUEST_ERRORS": None,
"TRAP_HTTP_EXCEPTIONS": False,
"EXPLAIN_TEMPLATE_LOADING": False,
"PREFERRED_URL_SCHEME": "http",
"JSON_AS_ASCII": True,
"JSON_SORT_KEYS": True,
"JSONIFY_PRETTYPRINT_REGULAR": False,
"JSONIFY_MIMETYPE": "application/json",
"TEMPLATES_AUTO_RELOAD": None,
"MAX_COOKIE_SIZE": 4093,
}
)
#: The rule object to use for URL rules created. This is used by
#: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`.
@ -355,20 +382,17 @@ class Flask(_PackageBoundObject):
self,
import_name,
static_url_path=None,
static_folder='static',
static_folder="static",
static_host=None,
host_matching=False,
subdomain_matching=False,
template_folder='templates',
template_folder="templates",
instance_path=None,
instance_relative_config=False,
root_path=None
root_path=None,
):
_PackageBoundObject.__init__(
self,
import_name,
template_folder=template_folder,
root_path=root_path
self, import_name, template_folder=template_folder, root_path=root_path
)
if static_url_path is not None:
@ -381,8 +405,8 @@ class Flask(_PackageBoundObject):
instance_path = self.auto_find_instance_path()
elif not os.path.isabs(instance_path):
raise ValueError(
'If an instance path is provided it must be absolute.'
' A relative path was given instead.'
"If an instance path is provided it must be absolute."
" A relative path was given instead."
)
#: Holds the path to the instance folder.
@ -490,9 +514,7 @@ class Flask(_PackageBoundObject):
#: requests. Each returns a dictionary that the template context is
#: updated with. To register a function here, use the
#: :meth:`context_processor` decorator.
self.template_context_processors = {
None: [_default_template_ctx_processor]
}
self.template_context_processors = {None: [_default_template_ctx_processor]}
#: A list of shell context processor functions that should be run
#: when a shell context is created.
@ -555,12 +577,14 @@ class Flask(_PackageBoundObject):
# For one, it might be created while the server is running (e.g. during
# development). Also, Google App Engine stores static files somewhere
if self.has_static_folder:
assert bool(static_host) == host_matching, 'Invalid static_host/host_matching combination'
assert (
bool(static_host) == host_matching
), "Invalid static_host/host_matching combination"
self.add_url_rule(
self.static_url_path + '/<path:filename>',
endpoint='static',
self.static_url_path + "/<path:filename>",
endpoint="static",
host=static_host,
view_func=self.send_static_file
view_func=self.send_static_file,
)
#: The click command line context for this application. Commands
@ -581,10 +605,10 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.8
"""
if self.import_name == '__main__':
fn = getattr(sys.modules['__main__'], '__file__', None)
if self.import_name == "__main__":
fn = getattr(sys.modules["__main__"], "__file__", None)
if fn is None:
return '__main__'
return "__main__"
return os.path.splitext(os.path.basename(fn))[0]
return self.import_name
@ -595,7 +619,7 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.7
"""
rv = self.config['PROPAGATE_EXCEPTIONS']
rv = self.config["PROPAGATE_EXCEPTIONS"]
if rv is not None:
return rv
return self.testing or self.debug
@ -608,7 +632,7 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.7
"""
rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION']
rv = self.config["PRESERVE_CONTEXT_ON_EXCEPTION"]
if rv is not None:
return rv
return self.debug
@ -663,8 +687,8 @@ class Flask(_PackageBoundObject):
if instance_relative:
root_path = self.instance_path
defaults = dict(self.default_config)
defaults['ENV'] = get_env()
defaults['DEBUG'] = get_debug_flag()
defaults["ENV"] = get_env()
defaults["DEBUG"] = get_debug_flag()
return self.config_class(root_path, defaults)
def auto_find_instance_path(self):
@ -677,10 +701,10 @@ class Flask(_PackageBoundObject):
"""
prefix, package_path = find_package(self.import_name)
if prefix is None:
return os.path.join(package_path, 'instance')
return os.path.join(prefix, 'var', self.name + '-instance')
return os.path.join(package_path, "instance")
return os.path.join(prefix, "var", self.name + "-instance")
def open_instance_resource(self, resource, mode='rb'):
def open_instance_resource(self, resource, mode="rb"):
"""Opens a resource from the application's instance folder
(:attr:`instance_path`). Otherwise works like
:meth:`open_resource`. Instance resources can also be opened for
@ -703,11 +727,11 @@ class Flask(_PackageBoundObject):
This property was added but the underlying config and behavior
already existed.
"""
rv = self.config['TEMPLATES_AUTO_RELOAD']
rv = self.config["TEMPLATES_AUTO_RELOAD"]
return rv if rv is not None else self.debug
def _set_templates_auto_reload(self, value):
self.config['TEMPLATES_AUTO_RELOAD'] = value
self.config["TEMPLATES_AUTO_RELOAD"] = value
templates_auto_reload = property(
_get_templates_auto_reload, _set_templates_auto_reload
@ -727,11 +751,11 @@ class Flask(_PackageBoundObject):
"""
options = dict(self.jinja_options)
if 'autoescape' not in options:
options['autoescape'] = self.select_jinja_autoescape
if "autoescape" not in options:
options["autoescape"] = self.select_jinja_autoescape
if 'auto_reload' not in options:
options['auto_reload'] = self.templates_auto_reload
if "auto_reload" not in options:
options["auto_reload"] = self.templates_auto_reload
rv = self.jinja_environment(self, **options)
rv.globals.update(
@ -743,9 +767,9 @@ class Flask(_PackageBoundObject):
# templates we also want the proxies in there.
request=request,
session=session,
g=g
g=g,
)
rv.filters['tojson'] = json.tojson_filter
rv.filters["tojson"] = json.tojson_filter
return rv
def create_global_jinja_loader(self):
@ -769,7 +793,7 @@ class Flask(_PackageBoundObject):
"""
if filename is None:
return True
return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
return filename.endswith((".html", ".htm", ".xml", ".xhtml"))
def update_template_context(self, context):
"""Update the template context with some commonly used variables.
@ -803,7 +827,7 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.11
"""
rv = {'app': self, 'g': g}
rv = {"app": self, "g": g}
for processor in self.shell_context_processors:
rv.update(processor())
return rv
@ -817,13 +841,13 @@ class Flask(_PackageBoundObject):
#: **Do not enable development when deploying in production.**
#:
#: Default: ``'production'``
env = ConfigAttribute('ENV')
env = ConfigAttribute("ENV")
def _get_debug(self):
return self.config['DEBUG']
return self.config["DEBUG"]
def _set_debug(self, value):
self.config['DEBUG'] = value
self.config["DEBUG"] = value
self.jinja_env.auto_reload = self.templates_auto_reload
#: Whether debug mode is enabled. When using ``flask run`` to start
@ -841,8 +865,7 @@ class Flask(_PackageBoundObject):
debug = property(_get_debug, _set_debug)
del _get_debug, _set_debug
def run(self, host=None, port=None, debug=None,
load_dotenv=True, **options):
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
"""Runs the application on a local development server.
Do not use ``run()`` in a production setting. It is not intended to
@ -902,8 +925,9 @@ class Flask(_PackageBoundObject):
"""
# Change this into a no-op if the server is invoked from the
# command line. Have a look at cli.py for more information.
if os.environ.get('FLASK_RUN_FROM_CLI') == 'true':
if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
from .debughelpers import explain_ignored_app_run
explain_ignored_app_run()
return
@ -911,30 +935,30 @@ class Flask(_PackageBoundObject):
cli.load_dotenv()
# if set, let env vars override previous values
if 'FLASK_ENV' in os.environ:
if "FLASK_ENV" in os.environ:
self.env = get_env()
self.debug = get_debug_flag()
elif 'FLASK_DEBUG' in os.environ:
elif "FLASK_DEBUG" in os.environ:
self.debug = get_debug_flag()
# debug passed to method overrides all other sources
if debug is not None:
self.debug = bool(debug)
_host = '127.0.0.1'
_host = "127.0.0.1"
_port = 5000
server_name = self.config.get('SERVER_NAME')
server_name = self.config.get("SERVER_NAME")
sn_host, sn_port = None, None
if server_name:
sn_host, _, sn_port = server_name.partition(':')
sn_host, _, sn_port = server_name.partition(":")
host = host or sn_host or _host
port = int(port or sn_port or _port)
options.setdefault('use_reloader', self.debug)
options.setdefault('use_debugger', self.debug)
options.setdefault('threaded', True)
options.setdefault("use_reloader", self.debug)
options.setdefault("use_debugger", self.debug)
options.setdefault("threaded", True)
cli.show_server_banner(self.env, self.debug, self.name, False)
@ -1034,10 +1058,12 @@ class Flask(_PackageBoundObject):
:param request: an instance of :attr:`request_class`.
"""
warnings.warn(DeprecationWarning(
'"open_session" is deprecated and will be removed in 1.1. Use'
' "session_interface.open_session" instead.'
))
warnings.warn(
DeprecationWarning(
'"open_session" is deprecated and will be removed in 1.1. Use'
' "session_interface.open_session" instead.'
)
)
return self.session_interface.open_session(self, request)
def save_session(self, session, response):
@ -1055,10 +1081,12 @@ class Flask(_PackageBoundObject):
:param response: an instance of :attr:`response_class`
"""
warnings.warn(DeprecationWarning(
'"save_session" is deprecated and will be removed in 1.1. Use'
' "session_interface.save_session" instead.'
))
warnings.warn(
DeprecationWarning(
'"save_session" is deprecated and will be removed in 1.1. Use'
' "session_interface.save_session" instead.'
)
)
return self.session_interface.save_session(self, session, response)
def make_null_session(self):
@ -1072,10 +1100,12 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.7
"""
warnings.warn(DeprecationWarning(
'"make_null_session" is deprecated and will be removed in 1.1. Use'
' "session_interface.make_null_session" instead.'
))
warnings.warn(
DeprecationWarning(
'"make_null_session" is deprecated and will be removed in 1.1. Use'
' "session_interface.make_null_session" instead.'
)
)
return self.session_interface.make_null_session(self)
@setupmethod
@ -1102,11 +1132,10 @@ class Flask(_PackageBoundObject):
if blueprint.name in self.blueprints:
assert self.blueprints[blueprint.name] is blueprint, (
'A name collision occurred between blueprints %r and %r. Both'
"A name collision occurred between blueprints %r and %r. Both"
' share the same name "%s". Blueprints that are created on the'
' fly need unique names.' % (
blueprint, self.blueprints[blueprint.name], blueprint.name
)
" fly need unique names."
% (blueprint, self.blueprints[blueprint.name], blueprint.name)
)
else:
self.blueprints[blueprint.name] = blueprint
@ -1123,8 +1152,14 @@ class Flask(_PackageBoundObject):
return iter(self._blueprint_order)
@setupmethod
def add_url_rule(self, rule, endpoint=None, view_func=None,
provide_automatic_options=None, **options):
def add_url_rule(
self,
rule,
endpoint=None,
view_func=None,
provide_automatic_options=None,
**options
):
"""Connects a URL rule. Works exactly like the :meth:`route`
decorator. If a view_func is provided it will be registered with the
endpoint.
@ -1179,32 +1214,35 @@ class Flask(_PackageBoundObject):
"""
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options['endpoint'] = endpoint
methods = options.pop('methods', None)
options["endpoint"] = endpoint
methods = options.pop("methods", None)
# if the methods are not given and the view_func object knows its
# methods we can use that instead. If neither exists, we go with
# a tuple of only ``GET`` as default.
if methods is None:
methods = getattr(view_func, 'methods', None) or ('GET',)
methods = getattr(view_func, "methods", None) or ("GET",)
if isinstance(methods, string_types):
raise TypeError('Allowed methods have to be iterables of strings, '
'for example: @app.route(..., methods=["POST"])')
raise TypeError(
"Allowed methods have to be iterables of strings, "
'for example: @app.route(..., methods=["POST"])'
)
methods = set(item.upper() for item in methods)
# Methods that should always be added
required_methods = set(getattr(view_func, 'required_methods', ()))
required_methods = set(getattr(view_func, "required_methods", ()))
# starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.
if provide_automatic_options is None:
provide_automatic_options = getattr(view_func,
'provide_automatic_options', None)
provide_automatic_options = getattr(
view_func, "provide_automatic_options", None
)
if provide_automatic_options is None:
if 'OPTIONS' not in methods:
if "OPTIONS" not in methods:
provide_automatic_options = True
required_methods.add('OPTIONS')
required_methods.add("OPTIONS")
else:
provide_automatic_options = False
@ -1218,8 +1256,10 @@ class Flask(_PackageBoundObject):
if view_func is not None:
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
raise AssertionError('View function mapping is overwriting an '
'existing endpoint function: %s' % endpoint)
raise AssertionError(
"View function mapping is overwriting an "
"existing endpoint function: %s" % endpoint
)
self.view_functions[endpoint] = view_func
def route(self, rule, **options):
@ -1246,10 +1286,12 @@ class Flask(_PackageBoundObject):
Starting with Flask 0.6, ``OPTIONS`` is implicitly
added and handled by the standard request handling.
"""
def decorator(f):
endpoint = options.pop('endpoint', None)
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
@setupmethod
@ -1263,9 +1305,11 @@ class Flask(_PackageBoundObject):
:param endpoint: the name of the endpoint
"""
def decorator(f):
self.view_functions[endpoint] = f
return f
return decorator
@staticmethod
@ -1313,9 +1357,11 @@ class Flask(_PackageBoundObject):
:param code_or_exception: the code as integer for the handler, or
an arbitrary exception
"""
def decorator(f):
self._register_error_handler(None, code_or_exception, f)
return f
return decorator
@setupmethod
@ -1337,9 +1383,9 @@ class Flask(_PackageBoundObject):
"""
if isinstance(code_or_exception, HTTPException): # old broken behavior
raise ValueError(
'Tried to register a handler for an exception instance {0!r}.'
' Handlers can only be registered for exception classes or'
' HTTP error codes.'.format(code_or_exception)
"Tried to register a handler for an exception instance {0!r}."
" Handlers can only be registered for exception classes or"
" HTTP error codes.".format(code_or_exception)
)
try:
@ -1366,9 +1412,11 @@ class Flask(_PackageBoundObject):
:param name: the optional name of the filter, otherwise the
function name will be used.
"""
def decorator(f):
self.add_template_filter(f, name=name)
return f
return decorator
@setupmethod
@ -1401,9 +1449,11 @@ class Flask(_PackageBoundObject):
:param name: the optional name of the test, otherwise the
function name will be used.
"""
def decorator(f):
self.add_template_test(f, name=name)
return f
return decorator
@setupmethod
@ -1433,9 +1483,11 @@ class Flask(_PackageBoundObject):
:param name: the optional name of the global function, otherwise the
function name will be used.
"""
def decorator(f):
self.add_template_global(f, name=name)
return f
return decorator
@setupmethod
@ -1613,8 +1665,10 @@ class Flask(_PackageBoundObject):
exc_class, code = self._get_exc_class_and_code(type(e))
for name, c in (
(request.blueprint, code), (None, code),
(request.blueprint, None), (None, None)
(request.blueprint, code),
(None, code),
(request.blueprint, None),
(None, None),
):
handler_map = self.error_handler_spec.setdefault(name, {}).get(c)
@ -1677,14 +1731,15 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.8
"""
if self.config['TRAP_HTTP_EXCEPTIONS']:
if self.config["TRAP_HTTP_EXCEPTIONS"]:
return True
trap_bad_request = self.config['TRAP_BAD_REQUEST_ERRORS']
trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"]
# if unset, trap key errors in debug mode
if (
trap_bad_request is None and self.debug
trap_bad_request is None
and self.debug
and isinstance(e, BadRequestKeyError)
):
return True
@ -1773,10 +1828,9 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.8
"""
self.logger.error('Exception on %s [%s]' % (
request.path,
request.method
), exc_info=exc_info)
self.logger.error(
"Exception on %s [%s]" % (request.path, request.method), exc_info=exc_info
)
def raise_routing_exception(self, request):
"""Exceptions that are recording during routing are reraised with
@ -1786,12 +1840,15 @@ class Flask(_PackageBoundObject):
:internal:
"""
if not self.debug \
or not isinstance(request.routing_exception, RequestRedirect) \
or request.method in ('GET', 'HEAD', 'OPTIONS'):
if (
not self.debug
or not isinstance(request.routing_exception, RequestRedirect)
or request.method in ("GET", "HEAD", "OPTIONS")
):
raise request.routing_exception
from .debughelpers import FormDataRoutingRedirect
raise FormDataRoutingRedirect(request)
def dispatch_request(self):
@ -1810,8 +1867,10 @@ class Flask(_PackageBoundObject):
rule = req.url_rule
# if we provide automatic options for this URL and the
# request came with the OPTIONS method, reply automatically
if getattr(rule, 'provide_automatic_options', False) \
and req.method == 'OPTIONS':
if (
getattr(rule, "provide_automatic_options", False)
and req.method == "OPTIONS"
):
return self.make_default_options_response()
# otherwise dispatch to the handler for that endpoint
return self.view_functions[rule.endpoint](**req.view_args)
@ -1853,8 +1912,9 @@ class Flask(_PackageBoundObject):
except Exception:
if not from_error_handler:
raise
self.logger.exception('Request finalizing failed with an '
'error while handling an error')
self.logger.exception(
"Request finalizing failed with an " "error while handling an error"
)
return response
def try_trigger_before_first_request_functions(self):
@ -1881,13 +1941,13 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.7
"""
adapter = _request_ctx_stack.top.url_adapter
if hasattr(adapter, 'allowed_methods'):
if hasattr(adapter, "allowed_methods"):
methods = adapter.allowed_methods()
else:
# fallback for Werkzeug < 0.7
methods = []
try:
adapter.match(method='--')
adapter.match(method="--")
except MethodNotAllowed as e:
methods = e.valid_methods
except HTTPException as e:
@ -1964,17 +2024,17 @@ class Flask(_PackageBoundObject):
# other sized tuples are not allowed
else:
raise TypeError(
'The view function did not return a valid response tuple.'
' The tuple must have the form (body, status, headers),'
' (body, status), or (body, headers).'
"The view function did not return a valid response tuple."
" The tuple must have the form (body, status, headers),"
" (body, status), or (body, headers)."
)
# the body must not be None
if rv is None:
raise TypeError(
'The view function did not return a valid response. The'
' function either returned None or ended without a return'
' statement.'
"The view function did not return a valid response. The"
" function either returned None or ended without a return"
" statement."
)
# make sure the body is an instance of the response class
@ -1992,10 +2052,10 @@ class Flask(_PackageBoundObject):
rv = self.response_class.force_type(rv, request.environ)
except TypeError as e:
new_error = TypeError(
'{e}\nThe view function did not return a valid'
' response. The return type must be a string, tuple,'
' Response instance, or WSGI callable, but it was a'
' {rv.__class__.__name__}.'.format(e=e, rv=rv)
"{e}\nThe view function did not return a valid"
" response. The return type must be a string, tuple,"
" Response instance, or WSGI callable, but it was a"
" {rv.__class__.__name__}.".format(e=e, rv=rv)
)
reraise(TypeError, new_error, sys.exc_info()[2])
@ -2031,19 +2091,24 @@ class Flask(_PackageBoundObject):
# If subdomain matching is disabled (the default), use the
# default subdomain in all cases. This should be the default
# in Werkzeug but it currently does not have that feature.
subdomain = ((self.url_map.default_subdomain or None)
if not self.subdomain_matching else None)
subdomain = (
(self.url_map.default_subdomain or None)
if not self.subdomain_matching
else None
)
return self.url_map.bind_to_environ(
request.environ,
server_name=self.config['SERVER_NAME'],
subdomain=subdomain)
server_name=self.config["SERVER_NAME"],
subdomain=subdomain,
)
# We need at the very least the server name to be set for this
# to work.
if self.config['SERVER_NAME'] is not None:
if self.config["SERVER_NAME"] is not None:
return self.url_map.bind(
self.config['SERVER_NAME'],
script_name=self.config['APPLICATION_ROOT'],
url_scheme=self.config['PREFERRED_URL_SCHEME'])
self.config["SERVER_NAME"],
script_name=self.config["APPLICATION_ROOT"],
url_scheme=self.config["PREFERRED_URL_SCHEME"],
)
def inject_url_defaults(self, endpoint, values):
"""Injects the URL defaults for the given endpoint directly into
@ -2053,8 +2118,8 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.7
"""
funcs = self.url_default_functions.get(None, ())
if '.' in endpoint:
bp = endpoint.rsplit('.', 1)[0]
if "." in endpoint:
bp = endpoint.rsplit(".", 1)[0]
funcs = chain(funcs, self.url_default_functions.get(bp, ()))
for func in funcs:
func(endpoint, values)
@ -2327,7 +2392,4 @@ class Flask(_PackageBoundObject):
return self.wsgi_app(environ, start_response)
def __repr__(self):
return '<%s %r>' % (
self.__class__.__name__,
self.name,
)
return "<%s %r>" % (self.__class__.__name__, self.name)

View file

@ -39,7 +39,7 @@ class BlueprintSetupState(object):
#: out if the blueprint was registered in the past already.
self.first_registration = first_registration
subdomain = self.options.get('subdomain')
subdomain = self.options.get("subdomain")
if subdomain is None:
subdomain = self.blueprint.subdomain
@ -47,7 +47,7 @@ class BlueprintSetupState(object):
#: otherwise.
self.subdomain = subdomain
url_prefix = self.options.get('url_prefix')
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
@ -57,7 +57,7 @@ class BlueprintSetupState(object):
#: 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', ()))
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)
@ -66,18 +66,22 @@ class BlueprintSetupState(object):
"""
if self.url_prefix is not None:
if rule:
rule = '/'.join((
self.url_prefix.rstrip('/'), rule.lstrip('/')))
rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/")))
else:
rule = self.url_prefix
options.setdefault('subdomain', self.subdomain)
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)
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):
@ -115,12 +119,21 @@ class Blueprint(_PackageBoundObject):
#: resources contained in the package.
root_path = None
def __init__(self, name, import_name, static_folder=None,
static_url_path=None, template_folder=None,
url_prefix=None, subdomain=None, url_defaults=None,
root_path=None):
_PackageBoundObject.__init__(self, import_name, template_folder,
root_path=root_path)
def __init__(
self,
name,
import_name,
static_folder=None,
static_url_path=None,
template_folder=None,
url_prefix=None,
subdomain=None,
url_defaults=None,
root_path=None,
):
_PackageBoundObject.__init__(
self, import_name, template_folder, root_path=root_path
)
self.name = name
self.url_prefix = url_prefix
self.subdomain = subdomain
@ -139,9 +152,14 @@ class Blueprint(_PackageBoundObject):
"""
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.'))
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):
@ -150,9 +168,11 @@ class Blueprint(_PackageBoundObject):
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):
@ -179,8 +199,9 @@ class Blueprint(_PackageBoundObject):
if self.has_static_folder:
state.add_url_rule(
self.static_url_path + '/<path:filename>',
view_func=self.send_static_file, endpoint='static'
self.static_url_path + "/<path:filename>",
view_func=self.send_static_file,
endpoint="static",
)
for deferred in self.deferred_functions:
@ -190,10 +211,12 @@ class Blueprint(_PackageBoundObject):
"""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):
@ -201,11 +224,12 @@ class Blueprint(_PackageBoundObject):
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))
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
@ -214,11 +238,14 @@ class Blueprint(_PackageBoundObject):
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):
@ -228,9 +255,11 @@ class Blueprint(_PackageBoundObject):
: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):
@ -241,8 +270,10 @@ class Blueprint(_PackageBoundObject):
: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):
@ -254,9 +285,11 @@ class Blueprint(_PackageBoundObject):
: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):
@ -269,8 +302,10 @@ class Blueprint(_PackageBoundObject):
: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):
@ -282,9 +317,11 @@ class Blueprint(_PackageBoundObject):
: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):
@ -297,8 +334,10 @@ class Blueprint(_PackageBoundObject):
: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):
@ -306,16 +345,18 @@ class Blueprint(_PackageBoundObject):
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))
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))
self.record_once(
lambda s: s.app.before_request_funcs.setdefault(None, []).append(f)
)
return f
def before_app_first_request(self, f):
@ -330,16 +371,18 @@ class Blueprint(_PackageBoundObject):
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))
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))
self.record_once(
lambda s: s.app.after_request_funcs.setdefault(None, []).append(f)
)
return f
def teardown_request(self, f):
@ -349,8 +392,9 @@ class Blueprint(_PackageBoundObject):
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))
self.record_once(
lambda s: s.app.teardown_request_funcs.setdefault(self.name, []).append(f)
)
return f
def teardown_app_request(self, f):
@ -358,33 +402,40 @@ class Blueprint(_PackageBoundObject):
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))
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))
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))
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):
@ -392,8 +443,9 @@ class Blueprint(_PackageBoundObject):
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))
self.record_once(
lambda s: s.app.url_value_preprocessors.setdefault(self.name, []).append(f)
)
return f
def url_defaults(self, f):
@ -401,22 +453,25 @@ class Blueprint(_PackageBoundObject):
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))
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))
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))
self.record_once(
lambda s: s.app.url_default_functions.setdefault(None, []).append(f)
)
return f
def errorhandler(self, code_or_exception):
@ -430,10 +485,13 @@ class Blueprint(_PackageBoundObject):
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))
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):
@ -444,5 +502,6 @@ class Blueprint(_PackageBoundObject):
.. versionadded:: 0.11
"""
self.record_once(lambda s: s.app._register_error_handler(
self.name, code_or_exception, f))
self.record_once(
lambda s: s.app._register_error_handler(self.name, code_or_exception, f)
)

View file

@ -48,16 +48,14 @@ def find_best_app(script_info, module):
from . import Flask
# Search for the most common names first.
for attr_name in ('app', 'application'):
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)
]
matches = [v for v in itervalues(module.__dict__) if isinstance(v, Flask)]
if len(matches) == 1:
return matches[0]
@ -65,11 +63,11 @@ def find_best_app(script_info, module):
raise NoAppException(
'Detected multiple Flask applications in module "{module}". Use '
'"FLASK_APP={module}:name" to specify the correct '
'one.'.format(module=module.__name__)
"one.".format(module=module.__name__)
)
# Search for app factory functions.
for attr_name in ('create_app', 'make_app'):
for attr_name in ("create_app", "make_app"):
app_factory = getattr(module, attr_name, None)
if inspect.isfunction(app_factory):
@ -83,18 +81,14 @@ def find_best_app(script_info, module):
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__
)
"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__
)
'Use "FLASK_APP={module}:name to specify one.'.format(module=module.__name__)
)
@ -107,7 +101,7 @@ def call_factory(script_info, app_factory, arguments=()):
arg_names = args_spec.args
arg_defaults = args_spec.defaults
if 'script_info' in arg_names:
if "script_info" in arg_names:
return app_factory(*arguments, script_info=script_info)
elif arguments:
return app_factory(*arguments)
@ -148,12 +142,13 @@ def find_app_by_string(script_info, module, app_name):
arguments.
"""
from flask import Flask
match = re.match(r'^ *([^ ()]+) *(?:\((.*?) *,? *\))? *$', app_name)
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)
"expression.".format(name=app_name)
)
name, args = match.groups()
@ -166,10 +161,10 @@ def find_app_by_string(script_info, module, app_name):
if inspect.isfunction(attr):
if args:
try:
args = ast.literal_eval('({args},)'.format(args=args))
except (ValueError, SyntaxError)as e:
args = ast.literal_eval("({args},)".format(args=args))
except (ValueError, SyntaxError) as e:
raise NoAppException(
'Could not parse the arguments in '
"Could not parse the arguments in "
'"{app_name}".'.format(e=e, app_name=app_name)
)
else:
@ -183,7 +178,7 @@ def find_app_by_string(script_info, module, app_name):
raise NoAppException(
'{e}\nThe factory "{app_name}" in module "{module}" could not '
'be called with the specified arguments.'.format(
"be called with the specified arguments.".format(
e=e, app_name=app_name, module=module.__name__
)
)
@ -194,10 +189,8 @@ def find_app_by_string(script_info, module, app_name):
return app
raise NoAppException(
'A valid Flask application was not obtained from '
'"{module}:{app_name}".'.format(
module=module.__name__, app_name=app_name
)
"A valid Flask application was not obtained from "
'"{module}:{app_name}".'.format(module=module.__name__, app_name=app_name)
)
@ -208,10 +201,10 @@ def prepare_import(path):
path = os.path.realpath(path)
fname, ext = os.path.splitext(path)
if ext == '.py':
if ext == ".py":
path = fname
if os.path.basename(path) == '__init__':
if os.path.basename(path) == "__init__":
path = os.path.dirname(path)
module_name = []
@ -221,13 +214,13 @@ def prepare_import(path):
path, name = os.path.split(path)
module_name.append(name)
if not os.path.exists(os.path.join(path, '__init__.py')):
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])
return ".".join(module_name[::-1])
def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
@ -241,12 +234,10 @@ def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
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())
"\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)
)
raise NoAppException('Could not import "{name}".'.format(name=module_name))
else:
return
@ -262,26 +253,27 @@ def get_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
import werkzeug
message = (
'Python %(python)s\n'
'Flask %(flask)s\n'
'Werkzeug %(werkzeug)s'
message = "Python %(python)s\n" "Flask %(flask)s\n" "Werkzeug %(werkzeug)s"
click.echo(
message
% {
"python": platform.python_version(),
"flask": __version__,
"werkzeug": werkzeug.__version__,
},
color=ctx.color,
)
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',
["--version"],
help="Show the flask version",
expose_value=False,
callback=get_version,
is_flag=True,
is_eager=True
is_eager=True,
)
@ -310,6 +302,7 @@ class DispatchingApp(object):
self._load_unlocked()
except Exception:
self._bg_loading_exc_info = sys.exc_info()
t = Thread(target=_load_app, args=())
t.start()
@ -348,10 +341,9 @@ class ScriptInfo(object):
onwards as click object.
"""
def __init__(self, app_import_path=None, create_app=None,
set_debug_flag=True):
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')
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
@ -377,21 +369,22 @@ class ScriptInfo(object):
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]
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'):
for path in ("wsgi.py", "app.py"):
import_name = prepare_import(path)
app = locate_app(self, import_name, None,
raise_if_not_found=False)
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 '
"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.'
)
@ -414,10 +407,12 @@ def with_appcontext(f):
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)
@ -434,11 +429,13 @@ class AppGroup(click.Group):
: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)
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):
@ -446,7 +443,7 @@ class AppGroup(click.Group):
:class:`click.Group` but it defaults the group class to
:class:`AppGroup`.
"""
kwargs.setdefault('cls', AppGroup)
kwargs.setdefault("cls", AppGroup)
return click.Group.group(self, *args, **kwargs)
@ -475,10 +472,16 @@ class FlaskGroup(AppGroup):
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 ())
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)
@ -504,7 +507,7 @@ class FlaskGroup(AppGroup):
self._loaded_plugin_commands = True
return
for ep in pkg_resources.iter_entry_points('flask.commands'):
for ep in pkg_resources.iter_entry_points("flask.commands"):
self.add_command(ep.load(), ep.name)
self._loaded_plugin_commands = True
@ -554,19 +557,20 @@ class FlaskGroup(AppGroup):
# 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'
os.environ["FLASK_RUN_FROM_CLI"] = "true"
if get_load_dotenv(self.load_dotenv):
load_dotenv()
obj = kwargs.get('obj')
obj = kwargs.get("obj")
if obj is None:
obj = ScriptInfo(create_app=self.create_app,
set_debug_flag=self.set_debug_flag)
obj = ScriptInfo(
create_app=self.create_app, set_debug_flag=self.set_debug_flag
)
kwargs['obj'] = obj
kwargs.setdefault('auto_envvar_prefix', 'FLASK')
kwargs["obj"] = obj
kwargs.setdefault("auto_envvar_prefix", "FLASK")
return super(FlaskGroup, self).main(*args, **kwargs)
@ -574,7 +578,7 @@ 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
return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other
def load_dotenv(path=None):
@ -597,11 +601,12 @@ def load_dotenv(path=None):
.. versionadded:: 1.0
"""
if dotenv is None:
if path or os.path.isfile('.env') or os.path.isfile('.flaskenv'):
if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"):
click.secho(
' * Tip: There are .env or .flaskenv files present.'
" * Tip: There are .env or .flaskenv files present."
' Do "pip install python-dotenv" to use them.',
fg='yellow')
fg="yellow",
)
return
if path is not None:
@ -609,7 +614,7 @@ def load_dotenv(path=None):
new_dir = None
for name in ('.env', '.flaskenv'):
for name in (".env", ".flaskenv"):
path = dotenv.find_dotenv(name, usecwd=True)
if not path:
@ -630,27 +635,29 @@ 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':
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)'
message += " (lazy loading)"
click.echo(message)
click.echo(' * Environment: {0}'.format(env))
click.echo(" * Environment: {0}".format(env))
if env == 'production':
if env == "production":
click.secho(
' WARNING: Do not use the development server in a production'
' environment.', fg='red')
click.secho(' Use a production WSGI server instead.', dim=True)
" WARNING: Do not use the development server in a production"
" environment.",
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'))
click.echo(" * Debug mode: {0}".format("on" if debug else "off"))
class CertParamType(click.ParamType):
@ -659,11 +666,10 @@ class CertParamType(click.ParamType):
:class:`~ssl.SSLContext` object.
"""
name = 'path'
name = "path"
def __init__(self):
self.path_type = click.Path(
exists=True, dir_okay=False, resolve_path=True)
self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True)
def convert(self, value, param, ctx):
try:
@ -671,13 +677,13 @@ class CertParamType(click.ParamType):
except click.BadParameter:
value = click.STRING(value, param, ctx).lower()
if value == 'adhoc':
if value == "adhoc":
try:
import OpenSSL
except ImportError:
raise click.BadParameter(
'Using ad-hoc certificates requires pyOpenSSL.',
ctx, param)
"Using ad-hoc certificates requires pyOpenSSL.", ctx, param
)
return value
@ -697,8 +703,8 @@ 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'
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))
@ -708,55 +714,64 @@ def _validate_key(ctx, param, value):
if value is not None:
if is_adhoc:
raise click.BadParameter(
'When "--cert" is "adhoc", "--key" is not used.',
ctx, param)
'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)
'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)
raise click.BadParameter('"--cert" must also be specified.', ctx, param)
ctx.params['cert'] = cert, value
ctx.params["cert"] = cert, value
else:
if cert and not (is_adhoc or is_context):
raise click.BadParameter(
'Required when using "--cert".',
ctx, param)
raise click.BadParameter('Required when using "--cert".', ctx, param)
return value
@click.command('run', short_help='Run a development server.')
@click.option('--host', '-h', default='127.0.0.1',
help='The interface to bind to.')
@click.option('--port', '-p', default=5000,
help='The port to bind to.')
@click.option('--cert', type=CertParamType(),
help='Specify a certificate file to use HTTPS.')
@click.option('--key',
type=click.Path(exists=True, dir_okay=False, resolve_path=True),
callback=_validate_key, expose_value=False,
help='The key file to use when specifying a certificate.')
@click.option('--reload/--no-reload', default=None,
help='Enable or disable the reloader. By default the reloader '
'is active if debug is enabled.')
@click.option('--debugger/--no-debugger', default=None,
help='Enable or disable the debugger. By default the debugger '
'is active if debug is enabled.')
@click.option('--eager-loading/--lazy-loader', default=None,
help='Enable or disable eager loading. By default eager '
'loading is enabled if the reloader is disabled.')
@click.option('--with-threads/--without-threads', default=True,
help='Enable or disable multithreading.')
@click.command("run", short_help="Run a development server.")
@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.")
@click.option("--port", "-p", default=5000, help="The port to bind to.")
@click.option(
"--cert", type=CertParamType(), help="Specify a certificate file to use HTTPS."
)
@click.option(
"--key",
type=click.Path(exists=True, dir_okay=False, resolve_path=True),
callback=_validate_key,
expose_value=False,
help="The key file to use when specifying a certificate.",
)
@click.option(
"--reload/--no-reload",
default=None,
help="Enable or disable the reloader. By default the reloader "
"is active if debug is enabled.",
)
@click.option(
"--debugger/--no-debugger",
default=None,
help="Enable or disable the debugger. By default the debugger "
"is active if debug is enabled.",
)
@click.option(
"--eager-loading/--lazy-loader",
default=None,
help="Enable or disable eager loading. By default eager "
"loading is enabled if the reloader is disabled.",
)
@click.option(
"--with-threads/--without-threads",
default=True,
help="Enable or disable multithreading.",
)
@pass_script_info
def run_command(info, host, port, reload, debugger, eager_loading,
with_threads, cert):
def run_command(info, host, port, reload, debugger, eager_loading, with_threads, cert):
"""Run a local development server.
This server is for development purposes only. It does not provide
@ -780,11 +795,19 @@ def run_command(info, host, port, reload, debugger, 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)
run_simple(
host,
port,
app,
use_reloader=reload,
use_debugger=debugger,
threaded=with_threads,
ssl_context=cert,
)
@click.command('shell', short_help='Run a shell in the app context.')
@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
@ -796,8 +819,9 @@ def shell_command():
"""
import code
from flask.globals import _app_ctx_stack
app = _app_ctx_stack.top.app
banner = 'Python %s on %s\nApp: %s [%s]\nInstance: %s' % (
banner = "Python %s on %s\nApp: %s [%s]\nInstance: %s" % (
sys.version,
sys.platform,
app.import_name,
@ -808,68 +832,64 @@ def shell_command():
# Support the regular Python interpreter startup script if someone
# is using it.
startup = os.environ.get('PYTHONSTARTUP')
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)
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.command("routes", short_help="Show the routes for the app.")
@click.option(
'--sort', '-s',
type=click.Choice(('endpoint', 'methods', 'rule', 'match')),
default='endpoint',
"--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."
"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.')
click.echo("No routes were registered.")
return
ignored_methods = set(() if all_methods else ('HEAD', 'OPTIONS'))
ignored_methods = set(() if all_methods else ("HEAD", "OPTIONS"))
if sort in ('endpoint', 'rule'):
if sort in ("endpoint", "rule"):
rules = sorted(rules, key=attrgetter(sort))
elif sort == 'methods':
elif sort == "methods":
rules = sorted(rules, key=lambda rule: sorted(rule.methods))
rule_methods = [
', '.join(sorted(rule.methods - ignored_methods)) for rule in rules
]
rule_methods = [", ".join(sorted(rule.methods - ignored_methods)) for rule in rules]
headers = ('Endpoint', 'Methods', 'Rule')
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)
row = "{{0:<{0}}} {{1:<{1}}} {{2:<{2}}}".format(*widths)
click.echo(row.format(*headers).strip())
click.echo(row.format(*('-' * width for width in widths)))
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="""\
cli = FlaskGroup(
help="""\
A general utility script for Flask applications.
Provides commands from Flask, extensions, and the application. Loads the
@ -882,30 +902,31 @@ debug mode.
{prefix}{cmd} FLASK_ENV=development
{prefix}flask run
""".format(
cmd='export' if os.name == 'posix' else 'set',
prefix='$ ' if os.name == 'posix' else '> '
))
cmd="export" if os.name == "posix" else "set",
prefix="$ " if os.name == "posix" else "> ",
)
)
def main(as_module=False):
args = sys.argv[1:]
if as_module:
this_module = 'flask'
this_module = "flask"
if sys.version_info < (2, 7):
this_module += '.cli'
this_module += ".cli"
name = 'python -m ' + this_module
name = "python -m " + this_module
# Python rewrites "python -m flask" to the path to the file in argv.
# Restore the original command so that the reloader works.
sys.argv = ['-m', this_module] + args
sys.argv = ["-m", this_module] + args
else:
name = None
cli.main(args=args, prog_name=name)
if __name__ == '__main__':
if __name__ == "__main__":
main(as_module=True)

View file

@ -101,11 +101,12 @@ class Config(dict):
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)
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):
@ -123,17 +124,15 @@ class Config(dict):
`silent` parameter.
"""
filename = os.path.join(self.root_path, filename)
d = types.ModuleType('config')
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__)
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
):
if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR):
return False
e.strerror = 'Unable to load configuration file (%s)' % e.strerror
e.strerror = "Unable to load configuration file (%s)" % e.strerror
raise
self.from_object(d)
return True
@ -197,7 +196,7 @@ class Config(dict):
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
e.strerror = "Unable to load configuration file (%s)" % e.strerror
raise
return self.from_mapping(obj)
@ -209,13 +208,13 @@ class Config(dict):
"""
mappings = []
if len(mapping) == 1:
if hasattr(mapping[0], 'items'):
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)
"expected at most 1 positional argument, got %d" % len(mapping)
)
mappings.append(kwargs.items())
for mapping in mappings:
@ -257,7 +256,7 @@ class Config(dict):
if not k.startswith(namespace):
continue
if trim_namespace:
key = k[len(namespace):]
key = k[len(namespace) :]
else:
key = k
if lowercase:
@ -266,4 +265,4 @@ class Config(dict):
return rv
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self))
return "<%s %s>" % (self.__class__.__name__, dict.__repr__(self))

View file

@ -89,7 +89,7 @@ class _AppCtxGlobals(object):
def __repr__(self):
top = _app_ctx_stack.top
if top is not None:
return '<flask.g of %r>' % top.app.name
return "<flask.g of %r>" % top.app.name
return object.__repr__(self)
@ -144,13 +144,17 @@ def copy_current_request_context(f):
"""
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.')
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)
@ -217,7 +221,7 @@ class AppContext(object):
def push(self):
"""Binds the app context to the current context."""
self._refcnt += 1
if hasattr(sys, 'exc_clear'):
if hasattr(sys, "exc_clear"):
sys.exc_clear()
_app_ctx_stack.push(self)
appcontext_pushed.send(self.app)
@ -232,8 +236,7 @@ class AppContext(object):
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)
assert rv is self, "Popped wrong app context. (%r instead of %r)" % (rv, self)
appcontext_popped.send(self.app)
def __enter__(self):
@ -314,8 +317,10 @@ class RequestContext(object):
def _get_g(self):
return _app_ctx_stack.top.g
def _set_g(self, value):
_app_ctx_stack.top.g = value
g = property(_get_g, _set_g)
del _get_g, _set_g
@ -332,10 +337,11 @@ class RequestContext(object):
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,
return self.__class__(
self.app,
environ=self.request.environ,
request=self.request,
session=self.session
session=self.session,
)
def match_request(self):
@ -343,8 +349,7 @@ class RequestContext(object):
of the request.
"""
try:
url_rule, self.request.view_args = \
self.url_adapter.match(return_rule=True)
url_rule, self.request.view_args = self.url_adapter.match(return_rule=True)
self.request.url_rule = url_rule
except HTTPException as e:
self.request.routing_exception = e
@ -373,7 +378,7 @@ class RequestContext(object):
else:
self._implicit_app_ctx_stack.append(None)
if hasattr(sys, 'exc_clear'):
if hasattr(sys, "exc_clear"):
sys.exc_clear()
_request_ctx_stack.push(self)
@ -384,9 +389,7 @@ class RequestContext(object):
# 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
)
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
@ -414,10 +417,10 @@ class RequestContext(object):
# 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'):
if hasattr(sys, "exc_clear"):
sys.exc_clear()
request_close = getattr(self.request, 'close', None)
request_close = getattr(self.request, "close", None)
if request_close is not None:
request_close()
clear_request = True
@ -427,18 +430,20 @@ class RequestContext(object):
# 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
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)
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):
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:
@ -460,7 +465,7 @@ class RequestContext(object):
reraise(exc_type, exc_value, tb)
def __repr__(self):
return '<%s \'%s\' [%s] of %s>' % (
return "<%s '%s' [%s] of %s>" % (
self.__class__.__name__,
self.request.url,
self.request.method,

View file

@ -32,17 +32,20 @@ class DebugFilesKeyError(KeyError, AssertionError):
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)]
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)
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
@ -56,23 +59,28 @@ class FormDataRoutingRedirect(AssertionError):
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)]
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.')
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'))
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):
@ -81,6 +89,7 @@ def attach_enctype_error_multidict(request):
object is accessed.
"""
oldcls = request.files.__class__
class newcls(oldcls):
def __getitem__(self, key):
try:
@ -89,26 +98,27 @@ def attach_enctype_error_multidict(request):
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__)
yield "class: %s.%s" % (type(loader).__module__, type(loader).__name__)
for key, value in sorted(loader.__dict__.items()):
if key.startswith('_'):
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
yield "%s:" % key
for item in value:
yield ' - %s' % item
yield " - %s" % item
continue
elif not isinstance(value, (str, text_type, int, float, bool)):
continue
yield '%s: %r' % (key, value)
yield "%s: %r" % (key, value)
def explain_template_loading_attempts(app, template, attempts):
@ -124,45 +134,50 @@ def explain_template_loading_attempts(app, template, 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)
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))
info.append("% 5d: trying loader of %s" % (idx + 1, src_info))
for line in _dump_loader_info(loader):
info.append(' %s' % line)
info.append(" %s" % line)
if triple is None:
detail = 'no match'
detail = "no match"
else:
detail = 'found (%r)' % (triple[1] or '<string>')
detail = "found (%r)" % (triple[1] or "<string>")
total_found += 1
info.append(' -> %s' % detail)
info.append(" -> %s" % detail)
seems_fishy = False
if total_found == 0:
info.append('Error: the template could not be found.')
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.')
info.append("Warning: multiple loaders returned a match for the template.")
seems_fishy = True
if blueprint is not None and seems_fishy:
info.append(' The template was looked up from an endpoint that '
'belongs to the blueprint "%s".' % blueprint)
info.append(' Maybe you did not place a template in the right folder?')
info.append(' See http://flask.pocoo.org/docs/blueprints/#templates')
info.append(
" The template was looked up from an endpoint that "
'belongs to the blueprint "%s".' % blueprint
)
info.append(" Maybe you did not place a template in the right folder?")
info.append(" See http://flask.pocoo.org/docs/blueprints/#templates")
app.logger.info('\n'.join(info))
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)
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,
)

View file

@ -14,21 +14,21 @@ from functools import partial
from werkzeug.local import LocalStack, LocalProxy
_request_ctx_err_msg = '''\
_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 = '''\
"""
_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):
@ -56,6 +56,6 @@ def _find_app():
_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'))
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))

View file

@ -24,15 +24,13 @@ from functools import update_wrapper
from werkzeug.urls import url_quote
from werkzeug.datastructures import Headers, Range
from werkzeug.exceptions import BadRequest, NotFound, \
RequestedRangeNotSatisfiable
from werkzeug.exceptions import BadRequest, NotFound, RequestedRangeNotSatisfiable
from werkzeug.wsgi import wrap_file
from jinja2 import FileSystemLoader
from .signals import message_flashed
from .globals import session, _request_ctx_stack, _app_ctx_stack, \
current_app, request
from .globals import session, _request_ctx_stack, _app_ctx_stack, current_app, request
from ._compat import string_types, text_type, PY2, fspath
# sentinel
@ -42,8 +40,9 @@ _missing = object()
# what separators does this operating system provide that are not a slash?
# this is used by the send_from_directory function to ensure that nobody is
# able to access files from outside the filesystem.
_os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep]
if sep not in (None, '/'))
_os_alt_seps = list(
sep for sep in [os.path.sep, os.path.altsep] if sep not in (None, "/")
)
def get_env():
@ -51,7 +50,7 @@ def get_env():
:envvar:`FLASK_ENV` environment variable. The default is
``'production'``.
"""
return os.environ.get('FLASK_ENV') or 'production'
return os.environ.get("FLASK_ENV") or "production"
def get_debug_flag():
@ -60,12 +59,12 @@ def get_debug_flag():
``True`` if :func:`.get_env` returns ``'development'``, or ``False``
otherwise.
"""
val = os.environ.get('FLASK_DEBUG')
val = os.environ.get("FLASK_DEBUG")
if not val:
return get_env() == 'development'
return get_env() == "development"
return val.lower() not in ('0', 'false', 'no')
return val.lower() not in ("0", "false", "no")
def get_load_dotenv(default=True):
@ -75,20 +74,19 @@ def get_load_dotenv(default=True):
:param default: What to return if the env var isn't set.
"""
val = os.environ.get('FLASK_SKIP_DOTENV')
val = os.environ.get("FLASK_SKIP_DOTENV")
if not val:
return default
return val.lower() in ('0', 'false', 'no')
return val.lower() in ("0", "false", "no")
def _endpoint_from_view_func(view_func):
"""Internal helper that returns the default endpoint for a given
function. This always is the function name.
"""
assert view_func is not None, 'expected view func if endpoint ' \
'is not provided.'
assert view_func is not None, "expected view func if endpoint " "is not provided."
return view_func.__name__
@ -129,16 +127,20 @@ def stream_with_context(generator_or_function):
try:
gen = iter(generator_or_function)
except TypeError:
def decorator(*args, **kwargs):
gen = generator_or_function(*args, **kwargs)
return stream_with_context(gen)
return update_wrapper(decorator, generator_or_function)
def generator():
ctx = _request_ctx_stack.top
if ctx is None:
raise RuntimeError('Attempted to stream with context but '
'there was no context in the first place to keep around.')
raise RuntimeError(
"Attempted to stream with context but "
"there was no context in the first place to keep around."
)
with ctx:
# Dummy sentinel. Has to be inside the context block or we're
# not actually keeping the context around.
@ -152,7 +154,7 @@ def stream_with_context(generator_or_function):
for item in gen:
yield item
finally:
if hasattr(gen, 'close'):
if hasattr(gen, "close"):
gen.close()
# The trick is to start the generator. Then the code execution runs until
@ -291,9 +293,9 @@ def url_for(endpoint, **values):
if appctx is None:
raise RuntimeError(
'Attempted to generate a URL without the application context being'
' pushed. This has to be executed when application context is'
' available.'
"Attempted to generate a URL without the application context being"
" pushed. This has to be executed when application context is"
" available."
)
# If request specific information is available we have some extra
@ -302,13 +304,13 @@ def url_for(endpoint, **values):
url_adapter = reqctx.url_adapter
blueprint_name = request.blueprint
if endpoint[:1] == '.':
if endpoint[:1] == ".":
if blueprint_name is not None:
endpoint = blueprint_name + endpoint
else:
endpoint = endpoint[1:]
external = values.pop('_external', False)
external = values.pop("_external", False)
# Otherwise go with the url adapter from the appctx and make
# the URLs external by default.
@ -317,16 +319,16 @@ def url_for(endpoint, **values):
if url_adapter is None:
raise RuntimeError(
'Application was not able to create a URL adapter for request'
' independent URL generation. You might be able to fix this by'
' setting the SERVER_NAME config variable.'
"Application was not able to create a URL adapter for request"
" independent URL generation. You might be able to fix this by"
" setting the SERVER_NAME config variable."
)
external = values.pop('_external', True)
external = values.pop("_external", True)
anchor = values.pop('_anchor', None)
method = values.pop('_method', None)
scheme = values.pop('_scheme', None)
anchor = values.pop("_anchor", None)
method = values.pop("_method", None)
scheme = values.pop("_scheme", None)
appctx.app.inject_url_defaults(endpoint, values)
# This is not the best way to deal with this but currently the
@ -335,28 +337,29 @@ def url_for(endpoint, **values):
old_scheme = None
if scheme is not None:
if not external:
raise ValueError('When specifying _scheme, _external must be True')
raise ValueError("When specifying _scheme, _external must be True")
old_scheme = url_adapter.url_scheme
url_adapter.url_scheme = scheme
try:
try:
rv = url_adapter.build(endpoint, values, method=method,
force_external=external)
rv = url_adapter.build(
endpoint, values, method=method, force_external=external
)
finally:
if old_scheme is not None:
url_adapter.url_scheme = old_scheme
except BuildError as error:
# We need to inject the values again so that the app callback can
# deal with that sort of stuff.
values['_external'] = external
values['_anchor'] = anchor
values['_method'] = method
values['_scheme'] = scheme
values["_external"] = external
values["_anchor"] = anchor
values["_method"] = method
values["_scheme"] = scheme
return appctx.app.handle_url_build_error(error, endpoint, values)
if anchor is not None:
rv += '#' + url_quote(anchor)
rv += "#" + url_quote(anchor)
return rv
@ -379,11 +382,10 @@ def get_template_attribute(template_name, attribute):
:param template_name: the name of the template
:param attribute: the name of the variable of macro to access
"""
return getattr(current_app.jinja_env.get_template(template_name).module,
attribute)
return getattr(current_app.jinja_env.get_template(template_name).module, attribute)
def flash(message, category='message'):
def flash(message, category="message"):
"""Flashes a message to the next request. In order to remove the
flashed message from the session and to display it to the user,
the template has to call :func:`get_flashed_messages`.
@ -405,11 +407,12 @@ def flash(message, category='message'):
# This assumed that changes made to mutable structures in the session are
# always in sync with the session object, which is not true for session
# implementations that use external storage for keeping their keys/values.
flashes = session.get('_flashes', [])
flashes = session.get("_flashes", [])
flashes.append((category, message))
session['_flashes'] = flashes
message_flashed.send(current_app._get_current_object(),
message=message, category=category)
session["_flashes"] = flashes
message_flashed.send(
current_app._get_current_object(), message=message, category=category
)
def get_flashed_messages(with_categories=False, category_filter=[]):
@ -442,8 +445,9 @@ def get_flashed_messages(with_categories=False, category_filter=[]):
"""
flashes = _request_ctx_stack.top.flashes
if flashes is None:
_request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \
if '_flashes' in session else []
_request_ctx_stack.top.flashes = flashes = (
session.pop("_flashes") if "_flashes" in session else []
)
if category_filter:
flashes = list(filter(lambda f: f[0] in category_filter, flashes))
if not with_categories:
@ -451,9 +455,16 @@ def get_flashed_messages(with_categories=False, category_filter=[]):
return flashes
def send_file(filename_or_fp, mimetype=None, as_attachment=False,
attachment_filename=None, add_etags=True,
cache_timeout=None, conditional=False, last_modified=None):
def send_file(
filename_or_fp,
mimetype=None,
as_attachment=False,
attachment_filename=None,
add_etags=True,
cache_timeout=None,
conditional=False,
last_modified=None,
):
"""Sends the contents of a file to the client. This will use the
most efficient method available and configured. By default it will
try to use the WSGI server's file_wrapper support. Alternatively
@ -545,7 +556,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
mtime = None
fsize = None
if hasattr(filename_or_fp, '__fspath__'):
if hasattr(filename_or_fp, "__fspath__"):
filename_or_fp = fspath(filename_or_fp)
if isinstance(filename_or_fp, string_types):
@ -561,62 +572,67 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
if mimetype is None:
if attachment_filename is not None:
mimetype = mimetypes.guess_type(attachment_filename)[0] \
or 'application/octet-stream'
mimetype = (
mimetypes.guess_type(attachment_filename)[0]
or "application/octet-stream"
)
if mimetype is None:
raise ValueError(
'Unable to infer MIME-type because no filename is available. '
'Please set either `attachment_filename`, pass a filepath to '
'`filename_or_fp` or set your own MIME-type via `mimetype`.'
"Unable to infer MIME-type because no filename is available. "
"Please set either `attachment_filename`, pass a filepath to "
"`filename_or_fp` or set your own MIME-type via `mimetype`."
)
headers = Headers()
if as_attachment:
if attachment_filename is None:
raise TypeError('filename unavailable, required for '
'sending as attachment')
raise TypeError(
"filename unavailable, required for " "sending as attachment"
)
if not isinstance(attachment_filename, text_type):
attachment_filename = attachment_filename.decode('utf-8')
attachment_filename = attachment_filename.decode("utf-8")
try:
attachment_filename = attachment_filename.encode('ascii')
attachment_filename = attachment_filename.encode("ascii")
except UnicodeEncodeError:
filenames = {
'filename': unicodedata.normalize(
'NFKD', attachment_filename).encode('ascii', 'ignore'),
'filename*': "UTF-8''%s" % url_quote(attachment_filename),
"filename": unicodedata.normalize("NFKD", attachment_filename).encode(
"ascii", "ignore"
),
"filename*": "UTF-8''%s" % url_quote(attachment_filename),
}
else:
filenames = {'filename': attachment_filename}
filenames = {"filename": attachment_filename}
headers.add('Content-Disposition', 'attachment', **filenames)
headers.add("Content-Disposition", "attachment", **filenames)
if current_app.use_x_sendfile and filename:
if file is not None:
file.close()
headers['X-Sendfile'] = filename
headers["X-Sendfile"] = filename
fsize = os.path.getsize(filename)
headers['Content-Length'] = fsize
headers["Content-Length"] = fsize
data = None
else:
if file is None:
file = open(filename, 'rb')
file = open(filename, "rb")
mtime = os.path.getmtime(filename)
fsize = os.path.getsize(filename)
headers['Content-Length'] = fsize
headers["Content-Length"] = fsize
elif isinstance(file, io.BytesIO):
try:
fsize = file.getbuffer().nbytes
except AttributeError:
# Python 2 doesn't have getbuffer
fsize = len(file.getvalue())
headers['Content-Length'] = fsize
headers["Content-Length"] = fsize
data = wrap_file(request.environ, file)
rv = current_app.response_class(data, mimetype=mimetype, headers=headers,
direct_passthrough=True)
rv = current_app.response_class(
data, mimetype=mimetype, headers=headers, direct_passthrough=True
)
if last_modified is not None:
rv.last_modified = last_modified
@ -634,22 +650,29 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
from warnings import warn
try:
rv.set_etag('%s-%s-%s' % (
os.path.getmtime(filename),
os.path.getsize(filename),
adler32(
filename.encode('utf-8') if isinstance(filename, text_type)
else filename
) & 0xffffffff
))
rv.set_etag(
"%s-%s-%s"
% (
os.path.getmtime(filename),
os.path.getsize(filename),
adler32(
filename.encode("utf-8")
if isinstance(filename, text_type)
else filename
)
& 0xFFFFFFFF,
)
)
except OSError:
warn('Access %s failed, maybe it does not exist, so ignore etags in '
'headers' % filename, stacklevel=2)
warn(
"Access %s failed, maybe it does not exist, so ignore etags in "
"headers" % filename,
stacklevel=2,
)
if conditional:
try:
rv = rv.make_conditional(request, accept_ranges=True,
complete_length=fsize)
rv = rv.make_conditional(request, accept_ranges=True, complete_length=fsize)
except RequestedRangeNotSatisfiable:
if file is not None:
file.close()
@ -657,7 +680,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
# make sure we don't send x-sendfile for servers that
# ignore the 304 status code for x-sendfile.
if rv.status_code == 304:
rv.headers.pop('x-sendfile', None)
rv.headers.pop("x-sendfile", None)
return rv
@ -682,14 +705,14 @@ def safe_join(directory, *pathnames):
parts = [directory]
for filename in pathnames:
if filename != '':
if filename != "":
filename = posixpath.normpath(filename)
if (
any(sep in filename for sep in _os_alt_seps)
or os.path.isabs(filename)
or filename == '..'
or filename.startswith('../')
or filename == ".."
or filename.startswith("../")
):
raise NotFound()
@ -735,7 +758,7 @@ def send_from_directory(directory, filename, **options):
raise NotFound()
except (TypeError, ValueError):
raise BadRequest()
options.setdefault('conditional', True)
options.setdefault("conditional", True)
return send_file(filename, **options)
@ -747,7 +770,7 @@ def get_root_path(import_name):
"""
# Module already imported and has a file attribute. Use that first.
mod = sys.modules.get(import_name)
if mod is not None and hasattr(mod, '__file__'):
if mod is not None and hasattr(mod, "__file__"):
return os.path.dirname(os.path.abspath(mod.__file__))
# Next attempt: check the loader.
@ -756,30 +779,32 @@ def get_root_path(import_name):
# Loader does not exist or we're referring to an unloaded main module
# or a main module without path (interactive sessions), go with the
# current working directory.
if loader is None or import_name == '__main__':
if loader is None or import_name == "__main__":
return os.getcwd()
# For .egg, zipimporter does not have get_filename until Python 2.7.
# Some other loaders might exhibit the same behavior.
if hasattr(loader, 'get_filename'):
if hasattr(loader, "get_filename"):
filepath = loader.get_filename(import_name)
else:
# Fall back to imports.
__import__(import_name)
mod = sys.modules[import_name]
filepath = getattr(mod, '__file__', None)
filepath = getattr(mod, "__file__", None)
# If we don't have a filepath it might be because we are a
# namespace package. In this case we pick the root path from the
# first module that is contained in our package.
if filepath is None:
raise RuntimeError('No root path can be found for the provided '
'module "%s". This can happen because the '
'module came from an import hook that does '
'not provide file name information or because '
'it\'s a namespace package. In this case '
'the root path needs to be explicitly '
'provided.' % import_name)
raise RuntimeError(
"No root path can be found for the provided "
'module "%s". This can happen because the '
"module came from an import hook that does "
"not provide file name information or because "
"it's a namespace package. In this case "
"the root path needs to be explicitly "
"provided." % import_name
)
# filepath is import_name.py for a module, or __init__.py for a package.
return os.path.dirname(os.path.abspath(filepath))
@ -791,21 +816,26 @@ def _matching_loader_thinks_module_is_package(loader, mod_name):
"""
# If the loader can tell us if something is a package, we can
# directly ask the loader.
if hasattr(loader, 'is_package'):
if hasattr(loader, "is_package"):
return loader.is_package(mod_name)
# importlib's namespace loaders do not have this functionality but
# all the modules it loads are packages, so we can take advantage of
# this information.
elif (loader.__class__.__module__ == '_frozen_importlib' and
loader.__class__.__name__ == 'NamespaceLoader'):
elif (
loader.__class__.__module__ == "_frozen_importlib"
and loader.__class__.__name__ == "NamespaceLoader"
):
return True
# Otherwise we need to fail with an error that explains what went
# wrong.
raise AttributeError(
('%s.is_package() method is missing but is required by Flask of '
'PEP 302 import hooks. If you do not use import hooks and '
'you encounter this error please file a bug against Flask.') %
loader.__class__.__name__)
(
"%s.is_package() method is missing but is required by Flask of "
"PEP 302 import hooks. If you do not use import hooks and "
"you encounter this error please file a bug against Flask."
)
% loader.__class__.__name__
)
def find_package(import_name):
@ -816,16 +846,16 @@ def find_package(import_name):
import the module. The prefix is the path below which a UNIX like
folder structure exists (lib, share etc.).
"""
root_mod_name = import_name.split('.')[0]
root_mod_name = import_name.split(".")[0]
loader = pkgutil.get_loader(root_mod_name)
if loader is None or import_name == '__main__':
if loader is None or import_name == "__main__":
# import name is not found, or interactive/main module
package_path = os.getcwd()
else:
# For .egg, zipimporter does not have get_filename until Python 2.7.
if hasattr(loader, 'get_filename'):
if hasattr(loader, "get_filename"):
filename = loader.get_filename(root_mod_name)
elif hasattr(loader, 'archive'):
elif hasattr(loader, "archive"):
# zipimporter's loader.archive points to the .egg or .zip
# archive filename is dropped in call to dirname below.
filename = loader.archive
@ -841,21 +871,20 @@ def find_package(import_name):
# In case the root module is a package we need to chop of the
# rightmost part. This needs to go through a helper function
# because of python 3.3 namespace packages.
if _matching_loader_thinks_module_is_package(
loader, root_mod_name):
if _matching_loader_thinks_module_is_package(loader, root_mod_name):
package_path = os.path.dirname(package_path)
site_parent, site_folder = os.path.split(package_path)
py_prefix = os.path.abspath(sys.prefix)
if package_path.startswith(py_prefix):
return py_prefix, package_path
elif site_folder.lower() == 'site-packages':
elif site_folder.lower() == "site-packages":
parent, folder = os.path.split(site_parent)
# Windows like installations
if folder.lower() == 'lib':
if folder.lower() == "lib":
base_dir = parent
# UNIX like installations
elif os.path.basename(parent).lower() == 'lib':
elif os.path.basename(parent).lower() == "lib":
base_dir = os.path.dirname(parent)
else:
base_dir = site_parent
@ -921,8 +950,9 @@ class _PackageBoundObject(object):
self._static_folder = value
static_folder = property(
_get_static_folder, _set_static_folder,
doc='The absolute path to the configured static folder.'
_get_static_folder,
_set_static_folder,
doc="The absolute path to the configured static folder.",
)
del _get_static_folder, _set_static_folder
@ -931,14 +961,15 @@ class _PackageBoundObject(object):
return self._static_url_path
if self.static_folder is not None:
return '/' + os.path.basename(self.static_folder)
return "/" + os.path.basename(self.static_folder)
def _set_static_url_path(self, value):
self._static_url_path = value
static_url_path = property(
_get_static_url_path, _set_static_url_path,
doc='The URL prefix that the static route will be registered for.'
_get_static_url_path,
_set_static_url_path,
doc="The URL prefix that the static route will be registered for.",
)
del _get_static_url_path, _set_static_url_path
@ -958,8 +989,7 @@ class _PackageBoundObject(object):
.. versionadded:: 0.5
"""
if self.template_folder is not None:
return FileSystemLoader(os.path.join(self.root_path,
self.template_folder))
return FileSystemLoader(os.path.join(self.root_path, self.template_folder))
def get_send_file_max_age(self, filename):
"""Provides default cache_timeout for the :func:`send_file` functions.
@ -994,14 +1024,15 @@ class _PackageBoundObject(object):
.. versionadded:: 0.5
"""
if not self.has_static_folder:
raise RuntimeError('No static folder for this object')
raise RuntimeError("No static folder for this object")
# Ensure get_send_file_max_age is called in all cases.
# Here, we ensure get_send_file_max_age is called for Blueprints.
cache_timeout = self.get_send_file_max_age(filename)
return send_from_directory(self.static_folder, filename,
cache_timeout=cache_timeout)
return send_from_directory(
self.static_folder, filename, cache_timeout=cache_timeout
)
def open_resource(self, resource, mode='rb'):
def open_resource(self, resource, mode="rb"):
"""Opens a resource from the application's resource folder. To see
how this works, consider the following folder structure::
@ -1024,8 +1055,8 @@ class _PackageBoundObject(object):
subfolders use forward slashes as separator.
:param mode: resource file opening mode, default is 'rb'.
"""
if mode not in ('r', 'rb'):
raise ValueError('Resources can only be opened for reading')
if mode not in ("r", "rb"):
raise ValueError("Resources can only be opened for reading")
return open(os.path.join(self.root_path, resource), mode)
@ -1052,7 +1083,7 @@ def is_ip(value):
:return: True if string is an IP address
:rtype: bool
"""
if PY2 and os.name == 'nt':
if PY2 and os.name == "nt":
try:
socket.inet_aton(value)
return True

View file

@ -23,12 +23,20 @@ from itsdangerous import json as _json
# Figure out if simplejson escapes slashes. This behavior was changed
# from one version to another without reason.
_slash_escape = '\\/' not in _json.dumps('/')
_slash_escape = "\\/" not in _json.dumps("/")
__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump',
'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder',
'jsonify']
__all__ = [
"dump",
"dumps",
"load",
"loads",
"htmlsafe_dump",
"htmlsafe_dumps",
"JSONDecoder",
"JSONEncoder",
"jsonify",
]
def _wrap_reader_for_text(fp, encoding):
@ -39,7 +47,7 @@ def _wrap_reader_for_text(fp, encoding):
def _wrap_writer_for_text(fp, encoding):
try:
fp.write('')
fp.write("")
except TypeError:
fp = io.TextIOWrapper(fp, encoding)
return fp
@ -76,7 +84,7 @@ class JSONEncoder(_json.JSONEncoder):
return http_date(o.timetuple())
if isinstance(o, uuid.UUID):
return str(o)
if hasattr(o, '__html__'):
if hasattr(o, "__html__"):
return text_type(o.__html__())
return _json.JSONEncoder.default(self, o)
@ -94,18 +102,17 @@ def _dump_arg_defaults(kwargs):
if current_app:
bp = current_app.blueprints.get(request.blueprint) if request else None
kwargs.setdefault(
'cls',
bp.json_encoder if bp and bp.json_encoder
else current_app.json_encoder
"cls",
bp.json_encoder if bp and bp.json_encoder else current_app.json_encoder,
)
if not current_app.config['JSON_AS_ASCII']:
kwargs.setdefault('ensure_ascii', False)
if not current_app.config["JSON_AS_ASCII"]:
kwargs.setdefault("ensure_ascii", False)
kwargs.setdefault('sort_keys', current_app.config['JSON_SORT_KEYS'])
kwargs.setdefault("sort_keys", current_app.config["JSON_SORT_KEYS"])
else:
kwargs.setdefault('sort_keys', True)
kwargs.setdefault('cls', JSONEncoder)
kwargs.setdefault("sort_keys", True)
kwargs.setdefault("cls", JSONEncoder)
def _load_arg_defaults(kwargs):
@ -113,12 +120,11 @@ def _load_arg_defaults(kwargs):
if current_app:
bp = current_app.blueprints.get(request.blueprint) if request else None
kwargs.setdefault(
'cls',
bp.json_decoder if bp and bp.json_decoder
else current_app.json_decoder
"cls",
bp.json_decoder if bp and bp.json_decoder else current_app.json_decoder,
)
else:
kwargs.setdefault('cls', JSONDecoder)
kwargs.setdefault("cls", JSONDecoder)
def detect_encoding(data):
@ -134,34 +140,34 @@ def detect_encoding(data):
head = data[:4]
if head[:3] == codecs.BOM_UTF8:
return 'utf-8-sig'
return "utf-8-sig"
if b'\x00' not in head:
return 'utf-8'
if b"\x00" not in head:
return "utf-8"
if head in (codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE):
return 'utf-32'
return "utf-32"
if head[:2] in (codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE):
return 'utf-16'
return "utf-16"
if len(head) == 4:
if head[:3] == b'\x00\x00\x00':
return 'utf-32-be'
if head[:3] == b"\x00\x00\x00":
return "utf-32-be"
if head[::2] == b'\x00\x00':
return 'utf-16-be'
if head[::2] == b"\x00\x00":
return "utf-16-be"
if head[1:] == b'\x00\x00\x00':
return 'utf-32-le'
if head[1:] == b"\x00\x00\x00":
return "utf-32-le"
if head[1::2] == b'\x00\x00':
return 'utf-16-le'
if head[1::2] == b"\x00\x00":
return "utf-16-le"
if len(head) == 2:
return 'utf-16-be' if head.startswith(b'\x00') else 'utf-16-le'
return "utf-16-be" if head.startswith(b"\x00") else "utf-16-le"
return 'utf-8'
return "utf-8"
def dumps(obj, **kwargs):
@ -175,7 +181,7 @@ def dumps(obj, **kwargs):
and can be overridden by the simplejson ``ensure_ascii`` parameter.
"""
_dump_arg_defaults(kwargs)
encoding = kwargs.pop('encoding', None)
encoding = kwargs.pop("encoding", None)
rv = _json.dumps(obj, **kwargs)
if encoding is not None and isinstance(rv, text_type):
rv = rv.encode(encoding)
@ -185,7 +191,7 @@ def dumps(obj, **kwargs):
def dump(obj, fp, **kwargs):
"""Like :func:`dumps` but writes into a file object."""
_dump_arg_defaults(kwargs)
encoding = kwargs.pop('encoding', None)
encoding = kwargs.pop("encoding", None)
if encoding is not None:
fp = _wrap_writer_for_text(fp, encoding)
_json.dump(obj, fp, **kwargs)
@ -198,7 +204,7 @@ def loads(s, **kwargs):
"""
_load_arg_defaults(kwargs)
if isinstance(s, bytes):
encoding = kwargs.pop('encoding', None)
encoding = kwargs.pop("encoding", None)
if encoding is None:
encoding = detect_encoding(s)
s = s.decode(encoding)
@ -210,7 +216,7 @@ def load(fp, **kwargs):
"""
_load_arg_defaults(kwargs)
if not PY2:
fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8')
fp = _wrap_reader_for_text(fp, kwargs.pop("encoding", None) or "utf-8")
return _json.load(fp, **kwargs)
@ -239,13 +245,15 @@ def htmlsafe_dumps(obj, **kwargs):
quoted. Always single quote attributes if you use the ``|tojson``
filter. Alternatively use ``|tojson|forceescape``.
"""
rv = dumps(obj, **kwargs) \
.replace(u'<', u'\\u003c') \
.replace(u'>', u'\\u003e') \
.replace(u'&', u'\\u0026') \
.replace(u"'", u'\\u0027')
rv = (
dumps(obj, **kwargs)
.replace(u"<", u"\\u003c")
.replace(u">", u"\\u003e")
.replace(u"&", u"\\u0026")
.replace(u"'", u"\\u0027")
)
if not _slash_escape:
rv = rv.replace('\\/', '/')
rv = rv.replace("\\/", "/")
return rv
@ -304,22 +312,22 @@ def jsonify(*args, **kwargs):
"""
indent = None
separators = (',', ':')
separators = (",", ":")
if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] or current_app.debug:
if current_app.config["JSONIFY_PRETTYPRINT_REGULAR"] or current_app.debug:
indent = 2
separators = (', ', ': ')
separators = (", ", ": ")
if args and kwargs:
raise TypeError('jsonify() behavior undefined when passed both args and kwargs')
raise TypeError("jsonify() behavior undefined when passed both args and kwargs")
elif len(args) == 1: # single args are passed directly to dumps()
data = args[0]
else:
data = args or kwargs
return current_app.response_class(
dumps(data, indent=indent, separators=separators) + '\n',
mimetype=current_app.config['JSONIFY_MIMETYPE']
dumps(data, indent=indent, separators=separators) + "\n",
mimetype=current_app.config["JSONIFY_MIMETYPE"],
)

View file

@ -56,7 +56,7 @@ from flask.json import dumps, loads
class JSONTag(object):
"""Base class for defining type tags for :class:`TaggedJSONSerializer`."""
__slots__ = ('serializer',)
__slots__ = ("serializer",)
#: The tag to mark the serialized object with. If ``None``, this tag is
#: only used as an intermediate step during tagging.
@ -94,7 +94,7 @@ class TagDict(JSONTag):
"""
__slots__ = ()
key = ' di'
key = " di"
def check(self, value):
return (
@ -105,7 +105,7 @@ class TagDict(JSONTag):
def to_json(self, value):
key = next(iter(value))
return {key + '__': self.serializer.tag(value[key])}
return {key + "__": self.serializer.tag(value[key])}
def to_python(self, value):
key = next(iter(value))
@ -128,7 +128,7 @@ class PassDict(JSONTag):
class TagTuple(JSONTag):
__slots__ = ()
key = ' t'
key = " t"
def check(self, value):
return isinstance(value, tuple)
@ -154,13 +154,13 @@ class PassList(JSONTag):
class TagBytes(JSONTag):
__slots__ = ()
key = ' b'
key = " b"
def check(self, value):
return isinstance(value, bytes)
def to_json(self, value):
return b64encode(value).decode('ascii')
return b64encode(value).decode("ascii")
def to_python(self, value):
return b64decode(value)
@ -172,10 +172,10 @@ class TagMarkup(JSONTag):
deserializes to an instance of :class:`~flask.Markup`."""
__slots__ = ()
key = ' m'
key = " m"
def check(self, value):
return callable(getattr(value, '__html__', None))
return callable(getattr(value, "__html__", None))
def to_json(self, value):
return text_type(value.__html__())
@ -186,7 +186,7 @@ class TagMarkup(JSONTag):
class TagUUID(JSONTag):
__slots__ = ()
key = ' u'
key = " u"
def check(self, value):
return isinstance(value, UUID)
@ -200,7 +200,7 @@ class TagUUID(JSONTag):
class TagDateTime(JSONTag):
__slots__ = ()
key = ' d'
key = " d"
def check(self, value):
return isinstance(value, datetime)
@ -227,12 +227,18 @@ class TaggedJSONSerializer(object):
* :class:`~datetime.datetime`
"""
__slots__ = ('tags', 'order')
__slots__ = ("tags", "order")
#: Tag classes to bind when creating the serializer. Other tags can be
#: added later using :meth:`~register`.
default_tags = [
TagDict, PassDict, TagTuple, PassList, TagBytes, TagMarkup, TagUUID,
TagDict,
PassDict,
TagTuple,
PassList,
TagBytes,
TagMarkup,
TagUUID,
TagDateTime,
]
@ -293,7 +299,7 @@ class TaggedJSONSerializer(object):
def dumps(self, value):
"""Tag the value and dump it to a compact JSON string."""
return dumps(self.tag(value), separators=(',', ':'))
return dumps(self.tag(value), separators=(",", ":"))
def loads(self, value):
"""Load data from a JSON string and deserialized any tagged objects."""

View file

@ -27,7 +27,7 @@ def wsgi_errors_stream():
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
return request.environ["wsgi.errors"] if request else sys.stderr
def has_level_handler(logger):
@ -52,9 +52,9 @@ def has_level_handler(logger):
#: 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'
))
default_handler.setFormatter(
logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s")
)
def create_logger(app):
@ -67,7 +67,7 @@ def create_logger(app):
:class:`~logging.StreamHandler` for
:func:`~flask.logging.wsgi_errors_stream` with a basic format.
"""
logger = logging.getLogger('flask.app')
logger = logging.getLogger("flask.app")
if app.debug and logger.level == logging.NOTSET:
logger.setLevel(logging.DEBUG)

View file

@ -27,11 +27,11 @@ class SessionMixin(collections_abc.MutableMapping):
@property
def permanent(self):
"""This reflects the ``'_permanent'`` key in the dict."""
return self.get('_permanent', False)
return self.get("_permanent", False)
@permanent.setter
def permanent(self, value):
self['_permanent'] = bool(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
@ -98,11 +98,13 @@ class NullSession(SecureCookieSession):
"""
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
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
@ -180,52 +182,52 @@ class SessionInterface(object):
updated to avoid re-running the logic.
"""
rv = app.config['SESSION_COOKIE_DOMAIN']
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']
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
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('.')
rv = rv.rsplit(":", 1)[0].lstrip(".")
if '.' not in rv:
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'
" Add an entry to your hosts file, for example"
' "{rv}.localdomain", and use that instead.'.format(rv=rv)
)
app.config['SESSION_COOKIE_DOMAIN'] = False
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'
"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.'
" 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
if self.get_cookie_path(app) == "/" and not ip:
rv = "." + rv
app.config['SESSION_COOKIE_DOMAIN'] = rv
app.config["SESSION_COOKIE_DOMAIN"] = rv
return rv
def get_cookie_path(self, app):
@ -234,28 +236,27 @@ class SessionInterface(object):
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']
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']
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']
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']
return app.config["SESSION_COOKIE_SAMESITE"]
def get_expiration_time(self, app, session):
"""A helper method that returns an expiration date for the session
@ -279,7 +280,7 @@ class SessionInterface(object):
"""
return session.modified or (
session.permanent and app.config['SESSION_REFRESH_EACH_REQUEST']
session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"]
)
def open_session(self, app, request):
@ -306,14 +307,15 @@ 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'
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'
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.
@ -324,12 +326,14 @@ class SecureCookieSessionInterface(SessionInterface):
if not app.secret_key:
return None
signer_kwargs = dict(
key_derivation=self.key_derivation,
digest_method=self.digest_method
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,
)
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)
@ -354,16 +358,14 @@ class SecureCookieSessionInterface(SessionInterface):
if not session:
if session.modified:
response.delete_cookie(
app.session_cookie_name,
domain=domain,
path=path
app.session_cookie_name, domain=domain, path=path
)
return
# Add a "Vary: Cookie" header if the session was accessed at all.
if session.accessed:
response.vary.add('Cookie')
response.vary.add("Cookie")
if not self.should_set_cookie(app, session):
return
@ -381,5 +383,5 @@ class SecureCookieSessionInterface(SessionInterface):
domain=domain,
path=path,
secure=secure,
samesite=samesite
samesite=samesite,
)

View file

@ -13,8 +13,10 @@
signals_available = False
try:
from blinker import Namespace
signals_available = True
except ImportError:
class Namespace(object):
def signal(self, name, doc=None):
return _FakeSignal(name, doc)
@ -29,15 +31,23 @@ except ImportError:
def __init__(self, name, doc=None):
self.name = name
self.__doc__ = doc
def _fail(self, *args, **kwargs):
raise RuntimeError('signalling support is unavailable '
'because the blinker library is '
'not installed.')
raise RuntimeError(
"signalling support is unavailable "
"because the blinker library is "
"not installed."
)
send = lambda *a, **kw: None
connect = disconnect = has_receivers_for = receivers_for = \
temporarily_connected_to = connected_to = _fail
connect = (
disconnect
) = (
has_receivers_for
) = receivers_for = temporarily_connected_to = connected_to = _fail
del _fail
# The namespace for code signals. If you are not Flask code, do
# not put signals in here. Create your own namespace instead.
_signals = Namespace()
@ -45,13 +55,13 @@ _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')
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")

View file

@ -9,8 +9,7 @@
:license: BSD, see LICENSE for more details.
"""
from jinja2 import BaseLoader, Environment as BaseEnvironment, \
TemplateNotFound
from jinja2 import BaseLoader, Environment as BaseEnvironment, TemplateNotFound
from .globals import _request_ctx_stack, _app_ctx_stack
from .signals import template_rendered, before_render_template
@ -24,10 +23,10 @@ def _default_template_ctx_processor():
appctx = _app_ctx_stack.top
rv = {}
if appctx is not None:
rv['g'] = appctx.g
rv["g"] = appctx.g
if reqctx is not None:
rv['request'] = reqctx.request
rv['session'] = reqctx.session
rv["request"] = reqctx.request
rv["session"] = reqctx.session
return rv
@ -38,8 +37,8 @@ class Environment(BaseEnvironment):
"""
def __init__(self, app, **options):
if 'loader' not in options:
options['loader'] = app.create_global_jinja_loader()
if "loader" not in options:
options["loader"] = app.create_global_jinja_loader()
BaseEnvironment.__init__(self, **options)
self.app = app
@ -53,7 +52,7 @@ class DispatchingJinjaLoader(BaseLoader):
self.app = app
def get_source(self, environment, template):
if self.app.config['EXPLAIN_TEMPLATE_LOADING']:
if self.app.config["EXPLAIN_TEMPLATE_LOADING"]:
return self._get_source_explained(environment, template)
return self._get_source_fast(environment, template)
@ -71,6 +70,7 @@ class DispatchingJinjaLoader(BaseLoader):
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:
@ -131,8 +131,11 @@ def render_template(template_name_or_list, **context):
"""
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)
return _render(
ctx.app.jinja_env.get_or_select_template(template_name_or_list),
context,
ctx.app,
)
def render_template_string(source, **context):
@ -146,5 +149,4 @@ def render_template_string(source, **context):
"""
ctx = _app_ctx_stack.top
ctx.app.update_template_context(context)
return _render(ctx.app.jinja_env.from_string(source),
context, ctx.app)
return _render(ctx.app.jinja_env.from_string(source), context, ctx.app)

View file

@ -22,8 +22,7 @@ from werkzeug.urls import url_parse
def make_test_environ_builder(
app, path='/', base_url=None, subdomain=None, url_scheme=None,
*args, **kwargs
app, path="/", base_url=None, subdomain=None, url_scheme=None, *args, **kwargs
):
"""Create a :class:`~werkzeug.test.EnvironBuilder`, taking some
defaults from the application.
@ -46,44 +45,41 @@ def make_test_environ_builder(
:class:`~werkzeug.test.EnvironBuilder`.
"""
assert (
not (base_url or subdomain or url_scheme)
or (base_url is not None) != bool(subdomain or url_scheme)
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']
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)
http_host = "{0}.{1}".format(subdomain, http_host)
if url_scheme is None:
url_scheme = app.config['PREFERRED_URL_SCHEME']
url_scheme = app.config["PREFERRED_URL_SCHEME"]
url = url_parse(path)
base_url = '{scheme}://{netloc}/{path}'.format(
base_url = "{scheme}://{netloc}/{path}".format(
scheme=url.scheme or url_scheme,
netloc=url.netloc or http_host,
path=app_root.lstrip('/')
path=app_root.lstrip("/"),
)
path = url.path
if url.query:
sep = b'?' if isinstance(url.query, bytes) else '?'
sep = b"?" if isinstance(url.query, bytes) else "?"
path += sep + url.query
if 'json' in kwargs:
assert 'data' not in kwargs, (
"Client cannot provide both 'json' and 'data'."
)
if "json" in kwargs:
assert "data" not in kwargs, "Client cannot provide both 'json' and 'data'."
# push a context so flask.json can use app's json attributes
with app.app_context():
kwargs['data'] = json_dumps(kwargs.pop('json'))
kwargs["data"] = json_dumps(kwargs.pop("json"))
if 'content_type' not in kwargs:
kwargs['content_type'] = 'application/json'
if "content_type" not in kwargs:
kwargs["content_type"] = "application/json"
return EnvironBuilder(path, base_url, *args, **kwargs)
@ -109,7 +105,7 @@ class FlaskClient(Client):
super(FlaskClient, self).__init__(*args, **kwargs)
self.environ_base = {
"REMOTE_ADDR": "127.0.0.1",
"HTTP_USER_AGENT": "werkzeug/" + werkzeug.__version__
"HTTP_USER_AGENT": "werkzeug/" + werkzeug.__version__,
}
@contextmanager
@ -131,18 +127,20 @@ class FlaskClient(Client):
passed through.
"""
if self.cookie_jar is None:
raise RuntimeError('Session transactions only make sense '
'with cookies enabled.')
raise RuntimeError(
"Session transactions only make sense " "with cookies enabled."
)
app = self.application
environ_overrides = kwargs.setdefault('environ_overrides', {})
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')
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
@ -164,12 +162,13 @@ class FlaskClient(Client):
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)
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
not kwargs
and len(args) == 1
and isinstance(args[0], (EnvironBuilder, dict))
):
environ = self.environ_base.copy()
@ -179,14 +178,13 @@ class FlaskClient(Client):
else:
environ.update(args[0])
environ['flask._preserve_context'] = self.preserve_context
environ["flask._preserve_context"] = self.preserve_context
else:
kwargs.setdefault('environ_overrides', {}) \
['flask._preserve_context'] = self.preserve_context
kwargs.setdefault('environ_base', self.environ_base)
builder = make_test_environ_builder(
self.application, *args, **kwargs
)
kwargs.setdefault("environ_overrides", {})[
"flask._preserve_context"
] = self.preserve_context
kwargs.setdefault("environ_base", self.environ_base)
builder = make_test_environ_builder(self.application, *args, **kwargs)
try:
environ = builder.get_environ()
@ -194,15 +192,16 @@ class FlaskClient(Client):
builder.close()
return Client.open(
self, environ,
self,
environ,
as_tuple=as_tuple,
buffered=buffered,
follow_redirects=follow_redirects
follow_redirects=follow_redirects,
)
def __enter__(self):
if self.preserve_context:
raise RuntimeError('Cannot nest client invocations')
raise RuntimeError("Cannot nest client invocations")
self.preserve_context = True
return self
@ -222,6 +221,7 @@ class FlaskCliRunner(CliRunner):
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)
@ -244,7 +244,7 @@ class FlaskCliRunner(CliRunner):
if cli is None:
cli = self.app.cli
if 'obj' not in kwargs:
kwargs['obj'] = ScriptInfo(create_app=lambda: self.app)
if "obj" not in kwargs:
kwargs["obj"] = ScriptInfo(create_app=lambda: self.app)
return super(FlaskCliRunner, self).invoke(cli, args, **kwargs)

View file

@ -13,8 +13,9 @@ from .globals import request
from ._compat import with_metaclass
http_method_funcs = frozenset(['get', 'post', 'head', 'options',
'delete', 'put', 'trace', 'patch'])
http_method_funcs = frozenset(
["get", "post", "head", "options", "delete", "put", "trace", "patch"]
)
class View(object):
@ -83,6 +84,7 @@ class View(object):
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)
@ -115,7 +117,7 @@ class MethodViewType(type):
def __init__(cls, name, bases, d):
super(MethodViewType, cls).__init__(name, bases, d)
if 'methods' not in d:
if "methods" not in d:
methods = set()
for key in http_method_funcs:
@ -151,8 +153,8 @@ class MethodView(with_metaclass(MethodViewType, View)):
# 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)
if meth is None and request.method == "HEAD":
meth = getattr(self, "get", None)
assert meth is not None, 'Unimplemented method %r' % request.method
assert meth is not None, "Unimplemented method %r" % request.method
return meth(*args, **kwargs)

View file

@ -34,8 +34,9 @@ class JSONMixin(object):
"""
mt = self.mimetype
return (
mt == 'application/json'
or (mt.startswith('application/')) and mt.endswith('+json')
mt == "application/json"
or (mt.startswith("application/"))
and mt.endswith("+json")
)
@property
@ -103,7 +104,7 @@ class JSONMixin(object):
.. versionadded:: 0.8
"""
if current_app is not None and current_app.debug:
raise BadRequest('Failed to decode JSON object: {0}'.format(e))
raise BadRequest("Failed to decode JSON object: {0}".format(e))
raise BadRequest()
@ -146,7 +147,7 @@ class Request(RequestBase, JSONMixin):
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']
return current_app.config["MAX_CONTENT_LENGTH"]
@property
def endpoint(self):
@ -161,8 +162,8 @@ class Request(RequestBase, JSONMixin):
@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]
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)
@ -172,10 +173,11 @@ class Request(RequestBase, JSONMixin):
if (
current_app
and current_app.debug
and self.mimetype != 'multipart/form-data'
and self.mimetype != "multipart/form-data"
and not self.files
):
from .debughelpers import attach_enctype_error_multidict
attach_enctype_error_multidict(self)
@ -197,7 +199,7 @@ class Response(ResponseBase, JSONMixin):
Added :attr:`max_cookie_size`.
"""
default_mimetype = 'text/html'
default_mimetype = "text/html"
def _get_data_for_json(self, cache):
return self.get_data()
@ -210,7 +212,7 @@ class Response(ResponseBase, JSONMixin):
Werkzeug's docs.
"""
if current_app:
return current_app.config['MAX_COOKIE_SIZE']
return current_app.config["MAX_COOKIE_SIZE"]
# return Werkzeug's default when not in an app context
return super(Response, self).max_cookie_size