mirror of
https://github.com/janeczku/calibre-web
synced 2025-11-05 01:33:02 +00:00
Translation of UI (german and english)
Bugfix for feeds
- removed categories related and up
- load new books now working
- category random now working
login page is free of non accessible elements
boolean custom column is vivible in UI
books with only with certain languages can be shown
book shelfs can be deleted from UI
Anonymous user view is more resticted
Added browse of series in sidebar
Dependencys in vendor folder are updated to newer versions (licencs files are now present)
Bugfix editing Authors names
Made upload on windows working
This commit is contained in:
36
vendor/flask/AUTHORS
vendored
Normal file
36
vendor/flask/AUTHORS
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
Flask is written and maintained by Armin Ronacher and
|
||||
various contributors:
|
||||
|
||||
Development Lead
|
||||
````````````````
|
||||
|
||||
- Armin Ronacher <armin.ronacher@active-4.com>
|
||||
|
||||
Patches and Suggestions
|
||||
```````````````````````
|
||||
|
||||
- Adam Zapletal
|
||||
- Ali Afshar
|
||||
- Chris Edgemon
|
||||
- Chris Grindstaff
|
||||
- Christopher Grebs
|
||||
- Daniel Neuhäuser
|
||||
- David Lord @davidism
|
||||
- Edmond Burnett
|
||||
- Florent Xicluna
|
||||
- Georg Brandl
|
||||
- Jeff Widman @jeffwidman
|
||||
- Justin Quick
|
||||
- Kenneth Reitz
|
||||
- Keyan Pishdadian
|
||||
- Marian Sigler
|
||||
- Martijn Pieters
|
||||
- Matt Campell
|
||||
- Matthew Frazier
|
||||
- Michael van Tellingen
|
||||
- Ron DuPlain
|
||||
- Sebastien Estienne
|
||||
- Simon Sapin
|
||||
- Stephane Wirtel
|
||||
- Thomas Schranz
|
||||
- Zhao Xiaohong
|
||||
33
vendor/flask/LICENSE
vendored
Normal file
33
vendor/flask/LICENSE
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
Copyright (c) 2015 by Armin Ronacher and contributors. See AUTHORS
|
||||
for more details.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms of the software as well
|
||||
as documentation, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The names of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
|
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
11
vendor/flask/__init__.py
vendored
11
vendor/flask/__init__.py
vendored
@@ -6,11 +6,11 @@
|
||||
A microframework based on Werkzeug. It's extensively documented
|
||||
and follows best practice patterns.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
__version__ = '0.10'
|
||||
__version__ = '0.11'
|
||||
|
||||
# utilities we import from Werkzeug and Jinja2 that are unused
|
||||
# in the module but are exported as public interface.
|
||||
@@ -21,13 +21,12 @@ 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
|
||||
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 .module import Module
|
||||
from .blueprints import Blueprint
|
||||
from .templating import render_template, render_template_string
|
||||
|
||||
@@ -35,7 +34,7 @@ from .templating import render_template, render_template_string
|
||||
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
|
||||
appcontext_popped, message_flashed, before_render_template
|
||||
|
||||
# We're not exposing the actual json module but a convenient wrapper around
|
||||
# it.
|
||||
|
||||
45
vendor/flask/_compat.py
vendored
45
vendor/flask/_compat.py
vendored
@@ -7,7 +7,7 @@
|
||||
version of six so we don't have to depend on a specific version
|
||||
of it.
|
||||
|
||||
:copyright: (c) 2013 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import sys
|
||||
@@ -19,7 +19,7 @@ _identity = lambda x: x
|
||||
if not PY2:
|
||||
text_type = str
|
||||
string_types = (str,)
|
||||
integer_types = (int, )
|
||||
integer_types = (int,)
|
||||
|
||||
iterkeys = lambda d: iter(d.keys())
|
||||
itervalues = lambda d: iter(d.values())
|
||||
@@ -54,20 +54,35 @@ else:
|
||||
|
||||
|
||||
def with_metaclass(meta, *bases):
|
||||
"""Create a base class with a metaclass."""
|
||||
# This requires a bit of explanation: the basic idea is to make a
|
||||
# dummy metaclass for one level of class instantiation that replaces
|
||||
# itself with the actual metaclass. Because of internal type checks
|
||||
# we also need to make sure that we downgrade the custom metaclass
|
||||
# for one level to something closer to type (that's why __call__ and
|
||||
# __init__ comes back from type etc.).
|
||||
#
|
||||
# This has the advantage over six.with_metaclass in that it does not
|
||||
# introduce dummy classes into the final MRO.
|
||||
class metaclass(meta):
|
||||
__call__ = type.__call__
|
||||
__init__ = type.__init__
|
||||
# itself with the actual metaclass.
|
||||
class metaclass(type):
|
||||
def __new__(cls, name, this_bases, d):
|
||||
if this_bases is None:
|
||||
return type.__new__(cls, name, (), d)
|
||||
return meta(name, bases, d)
|
||||
return metaclass('temporary_class', None, {})
|
||||
return type.__new__(metaclass, 'temporary_class', (), {})
|
||||
|
||||
|
||||
# Certain versions of pypy have a bug where clearing the exception stack
|
||||
# breaks the __exit__ function in a very peculiar way. This is currently
|
||||
# true for pypy 2.2.1 for instance. The second level of exception blocks
|
||||
# is necessary because pypy seems to forget to check if an exception
|
||||
# happened until the next bytecode instruction?
|
||||
BROKEN_PYPY_CTXMGR_EXIT = False
|
||||
if hasattr(sys, 'pypy_version_info'):
|
||||
class _Mgr(object):
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, *args):
|
||||
sys.exc_clear()
|
||||
try:
|
||||
try:
|
||||
with _Mgr():
|
||||
raise AssertionError()
|
||||
except:
|
||||
raise
|
||||
except TypeError:
|
||||
BROKEN_PYPY_CTXMGR_EXIT = True
|
||||
except AssertionError:
|
||||
pass
|
||||
|
||||
544
vendor/flask/app.py
vendored
544
vendor/flask/app.py
vendored
File diff suppressed because it is too large
Load Diff
26
vendor/flask/blueprints.py
vendored
26
vendor/flask/blueprints.py
vendored
@@ -6,7 +6,7 @@
|
||||
Blueprints are the recommended way to implement larger or more
|
||||
pluggable applications in Flask 0.7 and later.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from functools import update_wrapper
|
||||
@@ -42,7 +42,7 @@ class BlueprintSetupState(object):
|
||||
if subdomain is None:
|
||||
subdomain = self.blueprint.subdomain
|
||||
|
||||
#: The subdomain that the blueprint should be active for, `None`
|
||||
#: The subdomain that the blueprint should be active for, ``None``
|
||||
#: otherwise.
|
||||
self.subdomain = subdomain
|
||||
|
||||
@@ -79,7 +79,7 @@ class BlueprintSetupState(object):
|
||||
class Blueprint(_PackageBoundObject):
|
||||
"""Represents a blueprint. A blueprint is an object that records
|
||||
functions that will be called with the
|
||||
:class:`~flask.blueprint.BlueprintSetupState` later to register functions
|
||||
:class:`~flask.blueprints.BlueprintSetupState` later to register functions
|
||||
or other things on the main application. See :ref:`blueprints` for more
|
||||
information.
|
||||
|
||||
@@ -91,15 +91,16 @@ class Blueprint(_PackageBoundObject):
|
||||
|
||||
def __init__(self, name, import_name, static_folder=None,
|
||||
static_url_path=None, template_folder=None,
|
||||
url_prefix=None, subdomain=None, url_defaults=None):
|
||||
_PackageBoundObject.__init__(self, import_name, template_folder)
|
||||
url_prefix=None, subdomain=None, url_defaults=None,
|
||||
root_path=None):
|
||||
_PackageBoundObject.__init__(self, import_name, template_folder,
|
||||
root_path=root_path)
|
||||
self.name = name
|
||||
self.url_prefix = url_prefix
|
||||
self.subdomain = subdomain
|
||||
self.static_folder = static_folder
|
||||
self.static_url_path = static_url_path
|
||||
self.deferred_functions = []
|
||||
self.view_functions = {}
|
||||
if url_defaults is None:
|
||||
url_defaults = {}
|
||||
self.url_values_defaults = url_defaults
|
||||
@@ -167,7 +168,7 @@ class Blueprint(_PackageBoundObject):
|
||||
the :func:`url_for` function is prefixed with the name of the blueprint.
|
||||
"""
|
||||
if endpoint:
|
||||
assert '.' not in endpoint, "Blueprint endpoint's should not contain dot's"
|
||||
assert '.' not in endpoint, "Blueprint endpoints should not contain dots"
|
||||
self.record(lambda s:
|
||||
s.add_url_rule(rule, endpoint, view_func, **options))
|
||||
|
||||
@@ -399,3 +400,14 @@ class Blueprint(_PackageBoundObject):
|
||||
self.name, code_or_exception, f))
|
||||
return f
|
||||
return decorator
|
||||
|
||||
def register_error_handler(self, code_or_exception, f):
|
||||
"""Non-decorator version of the :meth:`errorhandler` error attach
|
||||
function, akin to the :meth:`~flask.Flask.register_error_handler`
|
||||
application-wide function of the :class:`~flask.Flask` object but
|
||||
for error handlers limited to this blueprint.
|
||||
|
||||
.. versionadded:: 0.11
|
||||
"""
|
||||
self.record_once(lambda s: s.app._register_error_handler(
|
||||
self.name, code_or_exception, f))
|
||||
|
||||
482
vendor/flask/cli.py
vendored
Normal file
482
vendor/flask/cli.py
vendored
Normal file
@@ -0,0 +1,482 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.cli
|
||||
~~~~~~~~~
|
||||
|
||||
A simple command line application to run flask apps.
|
||||
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from threading import Lock, Thread
|
||||
from functools import update_wrapper
|
||||
|
||||
import click
|
||||
|
||||
from ._compat import iteritems, reraise
|
||||
from .helpers import get_debug_flag
|
||||
|
||||
|
||||
class NoAppException(click.UsageError):
|
||||
"""Raised if an application cannot be found or loaded."""
|
||||
|
||||
|
||||
def find_best_app(module):
|
||||
"""Given a module instance this tries to find the best possible
|
||||
application in the module or raises an exception.
|
||||
"""
|
||||
from . import Flask
|
||||
|
||||
# Search for the most common names first.
|
||||
for attr_name in 'app', 'application':
|
||||
app = getattr(module, attr_name, None)
|
||||
if app is not None and isinstance(app, Flask):
|
||||
return app
|
||||
|
||||
# Otherwise find the only object that is a Flask instance.
|
||||
matches = [v for k, v in iteritems(module.__dict__)
|
||||
if isinstance(v, Flask)]
|
||||
|
||||
if len(matches) == 1:
|
||||
return matches[0]
|
||||
raise NoAppException('Failed to find application in module "%s". Are '
|
||||
'you sure it contains a Flask application? Maybe '
|
||||
'you wrapped it in a WSGI middleware or you are '
|
||||
'using a factory function.' % module.__name__)
|
||||
|
||||
|
||||
def prepare_exec_for_file(filename):
|
||||
"""Given a filename this will try to calculate the python path, add it
|
||||
to the search path and return the actual module name that is expected.
|
||||
"""
|
||||
module = []
|
||||
|
||||
# Chop off file extensions or package markers
|
||||
if filename.endswith('.py'):
|
||||
filename = filename[:-3]
|
||||
elif os.path.split(filename)[1] == '__init__.py':
|
||||
filename = os.path.dirname(filename)
|
||||
else:
|
||||
raise NoAppException('The file provided (%s) does exist but is not a '
|
||||
'valid Python file. This means that it cannot '
|
||||
'be used as application. Please change the '
|
||||
'extension to .py' % filename)
|
||||
filename = os.path.realpath(filename)
|
||||
|
||||
dirpath = filename
|
||||
while 1:
|
||||
dirpath, extra = os.path.split(dirpath)
|
||||
module.append(extra)
|
||||
if not os.path.isfile(os.path.join(dirpath, '__init__.py')):
|
||||
break
|
||||
|
||||
sys.path.insert(0, dirpath)
|
||||
return '.'.join(module[::-1])
|
||||
|
||||
|
||||
def locate_app(app_id):
|
||||
"""Attempts to locate the application."""
|
||||
__traceback_hide__ = True
|
||||
if ':' in app_id:
|
||||
module, app_obj = app_id.split(':', 1)
|
||||
else:
|
||||
module = app_id
|
||||
app_obj = None
|
||||
|
||||
__import__(module)
|
||||
mod = sys.modules[module]
|
||||
if app_obj is None:
|
||||
app = find_best_app(mod)
|
||||
else:
|
||||
app = getattr(mod, app_obj, None)
|
||||
if app is None:
|
||||
raise RuntimeError('Failed to find application in module "%s"'
|
||||
% module)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def find_default_import_path():
|
||||
app = os.environ.get('FLASK_APP')
|
||||
if app is None:
|
||||
return
|
||||
if os.path.isfile(app):
|
||||
return prepare_exec_for_file(app)
|
||||
return app
|
||||
|
||||
|
||||
class DispatchingApp(object):
|
||||
"""Special application that dispatches to a flask application which
|
||||
is imported by name in a background thread. If an error happens
|
||||
it is is recorded and shows as part of the WSGI handling which in case
|
||||
of the Werkzeug debugger means that it shows up in the browser.
|
||||
"""
|
||||
|
||||
def __init__(self, loader, use_eager_loading=False):
|
||||
self.loader = loader
|
||||
self._app = None
|
||||
self._lock = Lock()
|
||||
self._bg_loading_exc_info = None
|
||||
if use_eager_loading:
|
||||
self._load_unlocked()
|
||||
else:
|
||||
self._load_in_background()
|
||||
|
||||
def _load_in_background(self):
|
||||
def _load_app():
|
||||
__traceback_hide__ = True
|
||||
with self._lock:
|
||||
try:
|
||||
self._load_unlocked()
|
||||
except Exception:
|
||||
self._bg_loading_exc_info = sys.exc_info()
|
||||
t = Thread(target=_load_app, args=())
|
||||
t.start()
|
||||
|
||||
def _flush_bg_loading_exception(self):
|
||||
__traceback_hide__ = True
|
||||
exc_info = self._bg_loading_exc_info
|
||||
if exc_info is not None:
|
||||
self._bg_loading_exc_info = None
|
||||
reraise(*exc_info)
|
||||
|
||||
def _load_unlocked(self):
|
||||
__traceback_hide__ = True
|
||||
self._app = rv = self.loader()
|
||||
self._bg_loading_exc_info = None
|
||||
return rv
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
__traceback_hide__ = True
|
||||
if self._app is not None:
|
||||
return self._app(environ, start_response)
|
||||
self._flush_bg_loading_exception()
|
||||
with self._lock:
|
||||
if self._app is not None:
|
||||
rv = self._app
|
||||
else:
|
||||
rv = self._load_unlocked()
|
||||
return rv(environ, start_response)
|
||||
|
||||
|
||||
class ScriptInfo(object):
|
||||
"""Help object to deal with Flask applications. This is usually not
|
||||
necessary to interface with as it's used internally in the dispatching
|
||||
to click. In future versions of Flask this object will most likely play
|
||||
a bigger role. Typically it's created automatically by the
|
||||
:class:`FlaskGroup` but you can also manually create it and pass it
|
||||
onwards as click object.
|
||||
"""
|
||||
|
||||
def __init__(self, app_import_path=None, create_app=None):
|
||||
if create_app is None:
|
||||
if app_import_path is None:
|
||||
app_import_path = find_default_import_path()
|
||||
self.app_import_path = app_import_path
|
||||
else:
|
||||
app_import_path = None
|
||||
|
||||
#: Optionally the import path for the Flask application.
|
||||
self.app_import_path = app_import_path
|
||||
#: Optionally a function that is passed the script info to create
|
||||
#: the instance of the application.
|
||||
self.create_app = create_app
|
||||
#: A dictionary with arbitrary data that can be associated with
|
||||
#: this script info.
|
||||
self.data = {}
|
||||
self._loaded_app = None
|
||||
|
||||
def load_app(self):
|
||||
"""Loads the Flask app (if not yet loaded) and returns it. Calling
|
||||
this multiple times will just result in the already loaded app to
|
||||
be returned.
|
||||
"""
|
||||
__traceback_hide__ = True
|
||||
if self._loaded_app is not None:
|
||||
return self._loaded_app
|
||||
if self.create_app is not None:
|
||||
rv = self.create_app(self)
|
||||
else:
|
||||
if not self.app_import_path:
|
||||
raise NoAppException(
|
||||
'Could not locate Flask application. You did not provide '
|
||||
'the FLASK_APP environment variable.\n\nFor more '
|
||||
'information see '
|
||||
'http://flask.pocoo.org/docs/latest/quickstart/')
|
||||
rv = locate_app(self.app_import_path)
|
||||
debug = get_debug_flag()
|
||||
if debug is not None:
|
||||
rv.debug = debug
|
||||
self._loaded_app = rv
|
||||
return rv
|
||||
|
||||
|
||||
pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True)
|
||||
|
||||
|
||||
def with_appcontext(f):
|
||||
"""Wraps a callback so that it's guaranteed to be executed with the
|
||||
script's application context. If callbacks are registered directly
|
||||
to the ``app.cli`` object then they are wrapped with this function
|
||||
by default unless it's disabled.
|
||||
"""
|
||||
@click.pass_context
|
||||
def decorator(__ctx, *args, **kwargs):
|
||||
with __ctx.ensure_object(ScriptInfo).load_app().app_context():
|
||||
return __ctx.invoke(f, *args, **kwargs)
|
||||
return update_wrapper(decorator, f)
|
||||
|
||||
|
||||
class AppGroup(click.Group):
|
||||
"""This works similar to a regular click :class:`~click.Group` but it
|
||||
changes the behavior of the :meth:`command` decorator so that it
|
||||
automatically wraps the functions in :func:`with_appcontext`.
|
||||
|
||||
Not to be confused with :class:`FlaskGroup`.
|
||||
"""
|
||||
|
||||
def command(self, *args, **kwargs):
|
||||
"""This works exactly like the method of the same name on a regular
|
||||
:class:`click.Group` but it wraps callbacks in :func:`with_appcontext`
|
||||
unless it's disabled by passing ``with_appcontext=False``.
|
||||
"""
|
||||
wrap_for_ctx = kwargs.pop('with_appcontext', True)
|
||||
def decorator(f):
|
||||
if wrap_for_ctx:
|
||||
f = with_appcontext(f)
|
||||
return click.Group.command(self, *args, **kwargs)(f)
|
||||
return decorator
|
||||
|
||||
def group(self, *args, **kwargs):
|
||||
"""This works exactly like the method of the same name on a regular
|
||||
:class:`click.Group` but it defaults the group class to
|
||||
:class:`AppGroup`.
|
||||
"""
|
||||
kwargs.setdefault('cls', AppGroup)
|
||||
return click.Group.group(self, *args, **kwargs)
|
||||
|
||||
|
||||
class FlaskGroup(AppGroup):
|
||||
"""Special subclass of the :class:`AppGroup` group that supports
|
||||
loading more commands from the configured Flask app. Normally a
|
||||
developer does not have to interface with this class but there are
|
||||
some very advanced use cases for which it makes sense to create an
|
||||
instance of this.
|
||||
|
||||
For information as of why this is useful see :ref:`custom-scripts`.
|
||||
|
||||
:param add_default_commands: if this is True then the default run and
|
||||
shell commands wil be added.
|
||||
:param create_app: an optional callback that is passed the script info
|
||||
and returns the loaded app.
|
||||
"""
|
||||
|
||||
def __init__(self, add_default_commands=True, create_app=None, **extra):
|
||||
AppGroup.__init__(self, **extra)
|
||||
self.create_app = create_app
|
||||
|
||||
if add_default_commands:
|
||||
self.add_command(run_command)
|
||||
self.add_command(shell_command)
|
||||
|
||||
self._loaded_plugin_commands = False
|
||||
|
||||
def _load_plugin_commands(self):
|
||||
if self._loaded_plugin_commands:
|
||||
return
|
||||
try:
|
||||
import pkg_resources
|
||||
except ImportError:
|
||||
self._loaded_plugin_commands = True
|
||||
return
|
||||
|
||||
for ep in pkg_resources.iter_entry_points('flask.commands'):
|
||||
self.add_command(ep.load(), ep.name)
|
||||
self._loaded_plugin_commands = True
|
||||
|
||||
def get_command(self, ctx, name):
|
||||
self._load_plugin_commands()
|
||||
|
||||
# We load built-in commands first as these should always be the
|
||||
# same no matter what the app does. If the app does want to
|
||||
# override this it needs to make a custom instance of this group
|
||||
# and not attach the default commands.
|
||||
#
|
||||
# This also means that the script stays functional in case the
|
||||
# application completely fails.
|
||||
rv = AppGroup.get_command(self, ctx, name)
|
||||
if rv is not None:
|
||||
return rv
|
||||
|
||||
info = ctx.ensure_object(ScriptInfo)
|
||||
try:
|
||||
rv = info.load_app().cli.get_command(ctx, name)
|
||||
if rv is not None:
|
||||
return rv
|
||||
except NoAppException:
|
||||
pass
|
||||
|
||||
def list_commands(self, ctx):
|
||||
self._load_plugin_commands()
|
||||
|
||||
# The commands available is the list of both the application (if
|
||||
# available) plus the builtin commands.
|
||||
rv = set(click.Group.list_commands(self, ctx))
|
||||
info = ctx.ensure_object(ScriptInfo)
|
||||
try:
|
||||
rv.update(info.load_app().cli.list_commands(ctx))
|
||||
except Exception:
|
||||
# Here we intentionally swallow all exceptions as we don't
|
||||
# want the help page to break if the app does not exist.
|
||||
# If someone attempts to use the command we try to create
|
||||
# the app again and this will give us the error.
|
||||
pass
|
||||
return sorted(rv)
|
||||
|
||||
def main(self, *args, **kwargs):
|
||||
obj = kwargs.get('obj')
|
||||
if obj is None:
|
||||
obj = ScriptInfo(create_app=self.create_app)
|
||||
kwargs['obj'] = obj
|
||||
kwargs.setdefault('auto_envvar_prefix', 'FLASK')
|
||||
return AppGroup.main(self, *args, **kwargs)
|
||||
|
||||
|
||||
@click.command('run', short_help='Runs 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('--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=False,
|
||||
help='Enable or disable multithreading.')
|
||||
@pass_script_info
|
||||
def run_command(info, host, port, reload, debugger, eager_loading,
|
||||
with_threads):
|
||||
"""Runs a local development server for the Flask application.
|
||||
|
||||
This local server is recommended for development purposes only but it
|
||||
can also be used for simple intranet deployments. By default it will
|
||||
not support any sort of concurrency at all to simplify debugging. This
|
||||
can be changed with the --with-threads option which will enable basic
|
||||
multithreading.
|
||||
|
||||
The reloader and debugger are by default enabled if the debug flag of
|
||||
Flask is enabled and disabled otherwise.
|
||||
"""
|
||||
from werkzeug.serving import run_simple
|
||||
|
||||
debug = get_debug_flag()
|
||||
if reload is None:
|
||||
reload = bool(debug)
|
||||
if debugger is None:
|
||||
debugger = bool(debug)
|
||||
if eager_loading is None:
|
||||
eager_loading = not reload
|
||||
|
||||
app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
|
||||
|
||||
# Extra startup messages. This depends a but on Werkzeug internals to
|
||||
# not double execute when the reloader kicks in.
|
||||
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
|
||||
# If we have an import path we can print it out now which can help
|
||||
# people understand what's being served. If we do not have an
|
||||
# import path because the app was loaded through a callback then
|
||||
# we won't print anything.
|
||||
if info.app_import_path is not None:
|
||||
print(' * Serving Flask app "%s"' % info.app_import_path)
|
||||
if debug is not None:
|
||||
print(' * Forcing debug mode %s' % (debug and 'on' or 'off'))
|
||||
|
||||
run_simple(host, port, app, use_reloader=reload,
|
||||
use_debugger=debugger, threaded=with_threads)
|
||||
|
||||
|
||||
@click.command('shell', short_help='Runs a shell in the app context.')
|
||||
@with_appcontext
|
||||
def shell_command():
|
||||
"""Runs an interactive Python shell in the context of a given
|
||||
Flask application. The application will populate the default
|
||||
namespace of this shell according to it's configuration.
|
||||
|
||||
This is useful for executing small snippets of management code
|
||||
without having to manually configuring the application.
|
||||
"""
|
||||
import code
|
||||
from flask.globals import _app_ctx_stack
|
||||
app = _app_ctx_stack.top.app
|
||||
banner = 'Python %s on %s\nApp: %s%s\nInstance: %s' % (
|
||||
sys.version,
|
||||
sys.platform,
|
||||
app.import_name,
|
||||
app.debug and ' [debug]' or '',
|
||||
app.instance_path,
|
||||
)
|
||||
ctx = {}
|
||||
|
||||
# Support the regular Python interpreter startup script if someone
|
||||
# is using it.
|
||||
startup = os.environ.get('PYTHONSTARTUP')
|
||||
if startup and os.path.isfile(startup):
|
||||
with open(startup, 'r') as f:
|
||||
eval(compile(f.read(), startup, 'exec'), ctx)
|
||||
|
||||
ctx.update(app.make_shell_context())
|
||||
|
||||
code.interact(banner=banner, local=ctx)
|
||||
|
||||
|
||||
cli = FlaskGroup(help="""\
|
||||
This shell command acts as general utility script for Flask applications.
|
||||
|
||||
It loads the application configured (either through the FLASK_APP environment
|
||||
variable) and then provides commands either provided by the application or
|
||||
Flask itself.
|
||||
|
||||
The most useful commands are the "run" and "shell" command.
|
||||
|
||||
Example usage:
|
||||
|
||||
\b
|
||||
%(prefix)s%(cmd)s FLASK_APP=hello
|
||||
%(prefix)s%(cmd)s FLASK_DEBUG=1
|
||||
%(prefix)sflask run
|
||||
""" % {
|
||||
'cmd': os.name == 'posix' and 'export' or 'set',
|
||||
'prefix': os.name == 'posix' and '$ ' or '',
|
||||
})
|
||||
|
||||
|
||||
def main(as_module=False):
|
||||
this_module = __package__ + '.cli'
|
||||
args = sys.argv[1:]
|
||||
|
||||
if as_module:
|
||||
if sys.version_info >= (2, 7):
|
||||
name = 'python -m ' + this_module.rsplit('.', 1)[0]
|
||||
else:
|
||||
name = 'python -m ' + this_module
|
||||
|
||||
# This module is always executed as "python -m flask.run" and as such
|
||||
# we need to ensure that we restore the actual command line so that
|
||||
# the reloader can properly operate.
|
||||
sys.argv = ['-m', this_module] + sys.argv[1:]
|
||||
else:
|
||||
name = None
|
||||
|
||||
cli.main(args=args, prog_name=name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(as_module=True)
|
||||
104
vendor/flask/config.py
vendored
104
vendor/flask/config.py
vendored
@@ -5,16 +5,17 @@
|
||||
|
||||
Implements the configuration related objects.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import imp
|
||||
import os
|
||||
import types
|
||||
import errno
|
||||
|
||||
from werkzeug.utils import import_string
|
||||
from ._compat import string_types
|
||||
from ._compat import string_types, iteritems
|
||||
from . import json
|
||||
|
||||
|
||||
class ConfigAttribute(object):
|
||||
@@ -92,9 +93,9 @@ class Config(dict):
|
||||
app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
|
||||
|
||||
:param variable_name: name of the environment variable
|
||||
:param silent: set to `True` if you want silent failure for missing
|
||||
:param silent: set to ``True`` if you want silent failure for missing
|
||||
files.
|
||||
:return: bool. `True` if able to load config, `False` otherwise.
|
||||
:return: bool. ``True`` if able to load config, ``False`` otherwise.
|
||||
"""
|
||||
rv = os.environ.get(variable_name)
|
||||
if not rv:
|
||||
@@ -115,14 +116,14 @@ class Config(dict):
|
||||
:param filename: the filename of the config. This can either be an
|
||||
absolute filename or a filename relative to the
|
||||
root path.
|
||||
:param silent: set to `True` if you want silent failure for missing
|
||||
:param silent: set to ``True`` if you want silent failure for missing
|
||||
files.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
`silent` parameter.
|
||||
"""
|
||||
filename = os.path.join(self.root_path, filename)
|
||||
d = imp.new_module('config')
|
||||
d = types.ModuleType('config')
|
||||
d.__file__ = filename
|
||||
try:
|
||||
with open(filename) as config_file:
|
||||
@@ -164,5 +165,94 @@ class Config(dict):
|
||||
if key.isupper():
|
||||
self[key] = getattr(obj, key)
|
||||
|
||||
def from_json(self, filename, silent=False):
|
||||
"""Updates the values in the config from a JSON file. This function
|
||||
behaves as if the JSON object was a dictionary and passed to the
|
||||
:meth:`from_mapping` function.
|
||||
|
||||
:param filename: the filename of the JSON file. This can either be an
|
||||
absolute filename or a filename relative to the
|
||||
root path.
|
||||
:param silent: set to ``True`` if you want silent failure for missing
|
||||
files.
|
||||
|
||||
.. versionadded:: 0.11
|
||||
"""
|
||||
filename = os.path.join(self.root_path, filename)
|
||||
|
||||
try:
|
||||
with open(filename) as json_file:
|
||||
obj = json.loads(json_file.read())
|
||||
except IOError as e:
|
||||
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
|
||||
return False
|
||||
e.strerror = 'Unable to load configuration file (%s)' % e.strerror
|
||||
raise
|
||||
return self.from_mapping(obj)
|
||||
|
||||
def from_mapping(self, *mapping, **kwargs):
|
||||
"""Updates the config like :meth:`update` ignoring items with non-upper
|
||||
keys.
|
||||
|
||||
.. versionadded:: 0.11
|
||||
"""
|
||||
mappings = []
|
||||
if len(mapping) == 1:
|
||||
if hasattr(mapping[0], 'items'):
|
||||
mappings.append(mapping[0].items())
|
||||
else:
|
||||
mappings.append(mapping[0])
|
||||
elif len(mapping) > 1:
|
||||
raise TypeError(
|
||||
'expected at most 1 positional argument, got %d' % len(mapping)
|
||||
)
|
||||
mappings.append(kwargs.items())
|
||||
for mapping in mappings:
|
||||
for (key, value) in mapping:
|
||||
if key.isupper():
|
||||
self[key] = value
|
||||
return True
|
||||
|
||||
def get_namespace(self, namespace, lowercase=True, trim_namespace=True):
|
||||
"""Returns a dictionary containing a subset of configuration options
|
||||
that match the specified namespace/prefix. Example usage::
|
||||
|
||||
app.config['IMAGE_STORE_TYPE'] = 'fs'
|
||||
app.config['IMAGE_STORE_PATH'] = '/var/app/images'
|
||||
app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com'
|
||||
image_store_config = app.config.get_namespace('IMAGE_STORE_')
|
||||
|
||||
The resulting dictionary `image_store_config` would look like::
|
||||
|
||||
{
|
||||
'type': 'fs',
|
||||
'path': '/var/app/images',
|
||||
'base_url': 'http://img.website.com'
|
||||
}
|
||||
|
||||
This is often useful when configuration options map directly to
|
||||
keyword arguments in functions or class constructors.
|
||||
|
||||
:param namespace: a configuration namespace
|
||||
:param lowercase: a flag indicating if the keys of the resulting
|
||||
dictionary should be lowercase
|
||||
:param trim_namespace: a flag indicating if the keys of the resulting
|
||||
dictionary should not include the namespace
|
||||
|
||||
.. versionadded:: 0.11
|
||||
"""
|
||||
rv = {}
|
||||
for k, v in iteritems(self):
|
||||
if not k.startswith(namespace):
|
||||
continue
|
||||
if trim_namespace:
|
||||
key = k[len(namespace):]
|
||||
else:
|
||||
key = k
|
||||
if lowercase:
|
||||
key = key.lower()
|
||||
rv[key] = v
|
||||
return rv
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self))
|
||||
|
||||
120
vendor/flask/ctx.py
vendored
120
vendor/flask/ctx.py
vendored
@@ -5,20 +5,22 @@
|
||||
|
||||
Implements the objects required to keep the context.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import sys
|
||||
from functools import update_wrapper
|
||||
|
||||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
from .globals import _request_ctx_stack, _app_ctx_stack
|
||||
from .module import blueprint_is_module
|
||||
from .signals import appcontext_pushed, appcontext_popped
|
||||
from ._compat import BROKEN_PYPY_CTXMGR_EXIT, reraise
|
||||
|
||||
|
||||
# a singleton sentinel value for parameter defaults
|
||||
_sentinel = object()
|
||||
|
||||
|
||||
class _AppCtxGlobals(object):
|
||||
@@ -27,6 +29,15 @@ class _AppCtxGlobals(object):
|
||||
def get(self, name, default=None):
|
||||
return self.__dict__.get(name, default)
|
||||
|
||||
def pop(self, name, default=_sentinel):
|
||||
if default is _sentinel:
|
||||
return self.__dict__.pop(name)
|
||||
else:
|
||||
return self.__dict__.pop(name, default)
|
||||
|
||||
def setdefault(self, name, default=None):
|
||||
return self.__dict__.setdefault(name, default)
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self.__dict__
|
||||
|
||||
@@ -163,17 +174,21 @@ class AppContext(object):
|
||||
def push(self):
|
||||
"""Binds the app context to the current context."""
|
||||
self._refcnt += 1
|
||||
if hasattr(sys, 'exc_clear'):
|
||||
sys.exc_clear()
|
||||
_app_ctx_stack.push(self)
|
||||
appcontext_pushed.send(self.app)
|
||||
|
||||
def pop(self, exc=None):
|
||||
def pop(self, exc=_sentinel):
|
||||
"""Pops the app context."""
|
||||
self._refcnt -= 1
|
||||
if self._refcnt <= 0:
|
||||
if exc is None:
|
||||
exc = sys.exc_info()[1]
|
||||
self.app.do_teardown_appcontext(exc)
|
||||
rv = _app_ctx_stack.pop()
|
||||
try:
|
||||
self._refcnt -= 1
|
||||
if self._refcnt <= 0:
|
||||
if exc is _sentinel:
|
||||
exc = sys.exc_info()[1]
|
||||
self.app.do_teardown_appcontext(exc)
|
||||
finally:
|
||||
rv = _app_ctx_stack.pop()
|
||||
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
|
||||
% (rv, self)
|
||||
appcontext_popped.send(self.app)
|
||||
@@ -185,6 +200,9 @@ class AppContext(object):
|
||||
def __exit__(self, exc_type, exc_value, tb):
|
||||
self.pop(exc_value)
|
||||
|
||||
if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
|
||||
reraise(exc_type, exc_value, tb)
|
||||
|
||||
|
||||
class RequestContext(object):
|
||||
"""The request context contains all request relevant information. It is
|
||||
@@ -204,8 +222,8 @@ class RequestContext(object):
|
||||
for you. In debug mode the request context is kept around if
|
||||
exceptions happen so that interactive debuggers have a chance to
|
||||
introspect the data. With 0.4 this can also be forced for requests
|
||||
that did not fail and outside of `DEBUG` mode. By setting
|
||||
``'flask._preserve_context'`` to `True` on the WSGI environment the
|
||||
that did not fail and outside of ``DEBUG`` mode. By setting
|
||||
``'flask._preserve_context'`` to ``True`` on the WSGI environment the
|
||||
context will not pop itself at the end of the request. This is used by
|
||||
the :meth:`~flask.Flask.test_client` for example to implement the
|
||||
deferred cleanup functionality.
|
||||
@@ -246,16 +264,6 @@ class RequestContext(object):
|
||||
|
||||
self.match_request()
|
||||
|
||||
# XXX: Support for deprecated functionality. This is going away with
|
||||
# Flask 1.0
|
||||
blueprint = self.request.blueprint
|
||||
if blueprint is not None:
|
||||
# better safe than sorry, we don't want to break code that
|
||||
# already worked
|
||||
bp = app.blueprints.get(blueprint)
|
||||
if bp is not None and blueprint_is_module(bp):
|
||||
self.request._is_old_module = True
|
||||
|
||||
def _get_g(self):
|
||||
return _app_ctx_stack.top.g
|
||||
def _set_g(self, value):
|
||||
@@ -296,7 +304,7 @@ class RequestContext(object):
|
||||
# information under debug situations. However if someone forgets to
|
||||
# pop that context again we want to make sure that on the next push
|
||||
# it's invalidated, otherwise we run at risk that something leaks
|
||||
# memory. This is usually only a problem in testsuite since this
|
||||
# memory. This is usually only a problem in test suite since this
|
||||
# functionality is not active in production environments.
|
||||
top = _request_ctx_stack.top
|
||||
if top is not None and top.preserved:
|
||||
@@ -312,6 +320,9 @@ class RequestContext(object):
|
||||
else:
|
||||
self._implicit_app_ctx_stack.append(None)
|
||||
|
||||
if hasattr(sys, 'exc_clear'):
|
||||
sys.exc_clear()
|
||||
|
||||
_request_ctx_stack.push(self)
|
||||
|
||||
# Open the session at the moment that the request context is
|
||||
@@ -322,7 +333,7 @@ class RequestContext(object):
|
||||
if self.session is None:
|
||||
self.session = self.app.make_null_session()
|
||||
|
||||
def pop(self, exc=None):
|
||||
def pop(self, exc=_sentinel):
|
||||
"""Pops the request context and unbinds it by doing that. This will
|
||||
also trigger the execution of functions registered by the
|
||||
:meth:`~flask.Flask.teardown_request` decorator.
|
||||
@@ -332,38 +343,40 @@ class RequestContext(object):
|
||||
"""
|
||||
app_ctx = self._implicit_app_ctx_stack.pop()
|
||||
|
||||
clear_request = False
|
||||
if not self._implicit_app_ctx_stack:
|
||||
self.preserved = False
|
||||
self._preserved_exc = None
|
||||
if exc is None:
|
||||
exc = sys.exc_info()[1]
|
||||
self.app.do_teardown_request(exc)
|
||||
try:
|
||||
clear_request = False
|
||||
if not self._implicit_app_ctx_stack:
|
||||
self.preserved = False
|
||||
self._preserved_exc = None
|
||||
if exc is _sentinel:
|
||||
exc = sys.exc_info()[1]
|
||||
self.app.do_teardown_request(exc)
|
||||
|
||||
# If this interpreter supports clearing the exception information
|
||||
# we do that now. This will only go into effect on Python 2.x,
|
||||
# on 3.x it disappears automatically at the end of the exception
|
||||
# stack.
|
||||
if hasattr(sys, 'exc_clear'):
|
||||
sys.exc_clear()
|
||||
# If this interpreter supports clearing the exception information
|
||||
# we do that now. This will only go into effect on Python 2.x,
|
||||
# on 3.x it disappears automatically at the end of the exception
|
||||
# stack.
|
||||
if hasattr(sys, 'exc_clear'):
|
||||
sys.exc_clear()
|
||||
|
||||
request_close = getattr(self.request, 'close', None)
|
||||
if request_close is not None:
|
||||
request_close()
|
||||
clear_request = True
|
||||
request_close = getattr(self.request, 'close', None)
|
||||
if request_close is not None:
|
||||
request_close()
|
||||
clear_request = True
|
||||
finally:
|
||||
rv = _request_ctx_stack.pop()
|
||||
|
||||
rv = _request_ctx_stack.pop()
|
||||
assert rv is self, 'Popped wrong request context. (%r instead of %r)' \
|
||||
% (rv, self)
|
||||
# get rid of circular dependencies at the end of the request
|
||||
# so that we don't require the GC to be active.
|
||||
if clear_request:
|
||||
rv.request.environ['werkzeug.request'] = None
|
||||
|
||||
# get rid of circular dependencies at the end of the request
|
||||
# so that we don't require the GC to be active.
|
||||
if clear_request:
|
||||
rv.request.environ['werkzeug.request'] = None
|
||||
# Get rid of the app as well if necessary.
|
||||
if app_ctx is not None:
|
||||
app_ctx.pop(exc)
|
||||
|
||||
# Get rid of the app as well if necessary.
|
||||
if app_ctx is not None:
|
||||
app_ctx.pop(exc)
|
||||
assert rv is self, 'Popped wrong request context. ' \
|
||||
'(%r instead of %r)' % (rv, self)
|
||||
|
||||
def auto_pop(self, exc):
|
||||
if self.request.environ.get('flask._preserve_context') or \
|
||||
@@ -385,6 +398,9 @@ class RequestContext(object):
|
||||
# See flask.testing for how this works.
|
||||
self.auto_pop(exc_value)
|
||||
|
||||
if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
|
||||
reraise(exc_type, exc_value, tb)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s \'%s\' [%s] of %s>' % (
|
||||
self.__class__.__name__,
|
||||
|
||||
74
vendor/flask/debughelpers.py
vendored
74
vendor/flask/debughelpers.py
vendored
@@ -5,10 +5,13 @@
|
||||
|
||||
Various helpers to make the development experience better.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from ._compat import implements_to_string
|
||||
from ._compat import implements_to_string, text_type
|
||||
from .app import Flask
|
||||
from .blueprints import Blueprint
|
||||
from .globals import _request_ctx_stack
|
||||
|
||||
|
||||
class UnexpectedUnicodeError(AssertionError, UnicodeError):
|
||||
@@ -78,10 +81,75 @@ def attach_enctype_error_multidict(request):
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return oldcls.__getitem__(self, key)
|
||||
except KeyError as e:
|
||||
except KeyError:
|
||||
if key not in request.form:
|
||||
raise
|
||||
raise DebugFilesKeyError(request, key)
|
||||
newcls.__name__ = oldcls.__name__
|
||||
newcls.__module__ = oldcls.__module__
|
||||
request.files.__class__ = newcls
|
||||
|
||||
|
||||
def _dump_loader_info(loader):
|
||||
yield 'class: %s.%s' % (type(loader).__module__, type(loader).__name__)
|
||||
for key, value in sorted(loader.__dict__.items()):
|
||||
if key.startswith('_'):
|
||||
continue
|
||||
if isinstance(value, (tuple, list)):
|
||||
if not all(isinstance(x, (str, text_type)) for x in value):
|
||||
continue
|
||||
yield '%s:' % key
|
||||
for item in value:
|
||||
yield ' - %s' % item
|
||||
continue
|
||||
elif not isinstance(value, (str, text_type, int, float, bool)):
|
||||
continue
|
||||
yield '%s: %r' % (key, value)
|
||||
|
||||
|
||||
def explain_template_loading_attempts(app, template, attempts):
|
||||
"""This should help developers understand what failed"""
|
||||
info = ['Locating template "%s":' % template]
|
||||
total_found = 0
|
||||
blueprint = None
|
||||
reqctx = _request_ctx_stack.top
|
||||
if reqctx is not None and reqctx.request.blueprint is not None:
|
||||
blueprint = reqctx.request.blueprint
|
||||
|
||||
for idx, (loader, srcobj, triple) in enumerate(attempts):
|
||||
if isinstance(srcobj, Flask):
|
||||
src_info = 'application "%s"' % srcobj.import_name
|
||||
elif isinstance(srcobj, Blueprint):
|
||||
src_info = 'blueprint "%s" (%s)' % (srcobj.name,
|
||||
srcobj.import_name)
|
||||
else:
|
||||
src_info = repr(srcobj)
|
||||
|
||||
info.append('% 5d: trying loader of %s' % (
|
||||
idx + 1, src_info))
|
||||
|
||||
for line in _dump_loader_info(loader):
|
||||
info.append(' %s' % line)
|
||||
|
||||
if triple is None:
|
||||
detail = 'no match'
|
||||
else:
|
||||
detail = 'found (%r)' % (triple[1] or '<string>')
|
||||
total_found += 1
|
||||
info.append(' -> %s' % detail)
|
||||
|
||||
seems_fishy = False
|
||||
if total_found == 0:
|
||||
info.append('Error: the template could not be found.')
|
||||
seems_fishy = True
|
||||
elif total_found > 1:
|
||||
info.append('Warning: multiple loaders returned a match for the template.')
|
||||
seems_fishy = True
|
||||
|
||||
if blueprint is not None and seems_fishy:
|
||||
info.append(' The template was looked up from an endpoint that '
|
||||
'belongs to the blueprint "%s".' % blueprint)
|
||||
info.append(' Maybe you did not place a template in the right folder?')
|
||||
info.append(' See http://flask.pocoo.org/docs/blueprints/#templates')
|
||||
|
||||
app.logger.info('\n'.join(info))
|
||||
|
||||
2
vendor/flask/ext/__init__.py
vendored
2
vendor/flask/ext/__init__.py
vendored
@@ -14,7 +14,7 @@
|
||||
We're switching from namespace packages because it was just too painful for
|
||||
everybody involved.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
|
||||
29
vendor/flask/exthook.py
vendored
29
vendor/flask/exthook.py
vendored
@@ -16,14 +16,21 @@
|
||||
|
||||
This is used by `flask.ext`.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import warnings
|
||||
from ._compat import reraise
|
||||
|
||||
|
||||
class ExtDeprecationWarning(DeprecationWarning):
|
||||
pass
|
||||
|
||||
warnings.simplefilter('always', ExtDeprecationWarning)
|
||||
|
||||
|
||||
class ExtensionImporter(object):
|
||||
"""This importer redirects imports from this submodule to other locations.
|
||||
This makes it possible to transition from the old flaskext.name to the
|
||||
@@ -49,13 +56,21 @@ class ExtensionImporter(object):
|
||||
sys.meta_path[:] = [x for x in sys.meta_path if self != x] + [self]
|
||||
|
||||
def find_module(self, fullname, path=None):
|
||||
if fullname.startswith(self.prefix):
|
||||
if fullname.startswith(self.prefix) and \
|
||||
fullname != 'flask.ext.ExtDeprecationWarning':
|
||||
return self
|
||||
|
||||
def load_module(self, fullname):
|
||||
if fullname in sys.modules:
|
||||
return sys.modules[fullname]
|
||||
|
||||
modname = fullname.split('.', self.prefix_cutoff)[self.prefix_cutoff]
|
||||
|
||||
warnings.warn(
|
||||
"Importing flask.ext.{x} is deprecated, use flask_{x} instead."
|
||||
.format(x=modname), ExtDeprecationWarning
|
||||
)
|
||||
|
||||
for path in self.module_choices:
|
||||
realname = path % modname
|
||||
try:
|
||||
@@ -83,6 +98,14 @@ class ExtensionImporter(object):
|
||||
module = sys.modules[fullname] = sys.modules[realname]
|
||||
if '.' not in modname:
|
||||
setattr(sys.modules[self.wrapper_module], modname, module)
|
||||
|
||||
if realname.startswith('flaskext.'):
|
||||
warnings.warn(
|
||||
"Detected extension named flaskext.{x}, please rename it "
|
||||
"to flask_{x}. The old form is deprecated."
|
||||
.format(x=modname), ExtDeprecationWarning
|
||||
)
|
||||
|
||||
return module
|
||||
raise ImportError('No module named %s' % fullname)
|
||||
|
||||
@@ -111,7 +134,7 @@ class ExtensionImporter(object):
|
||||
if module_name == important_module:
|
||||
return True
|
||||
|
||||
# Some python versions will will clean up modules so early that the
|
||||
# Some python versions will clean up modules so early that the
|
||||
# module name at that point is no longer set. Try guessing from
|
||||
# the filename then.
|
||||
filename = os.path.abspath(tb.tb_frame.f_code.co_filename)
|
||||
|
||||
25
vendor/flask/globals.py
vendored
25
vendor/flask/globals.py
vendored
@@ -6,7 +6,7 @@
|
||||
Defines all the global objects that are proxies to the current
|
||||
active context.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
@@ -14,24 +14,41 @@ from functools import partial
|
||||
from werkzeug.local import LocalStack, LocalProxy
|
||||
|
||||
|
||||
_request_ctx_err_msg = '''\
|
||||
Working outside of request context.
|
||||
|
||||
This typically means that you attempted to use functionality that needed
|
||||
an active HTTP request. Consult the documentation on testing for
|
||||
information about how to avoid this problem.\
|
||||
'''
|
||||
_app_ctx_err_msg = '''\
|
||||
Working outside of application context.
|
||||
|
||||
This typically means that you attempted to use functionality that needed
|
||||
to interface with the current application object in a way. To solve
|
||||
this set up an application context with app.app_context(). See the
|
||||
documentation for more information.\
|
||||
'''
|
||||
|
||||
|
||||
def _lookup_req_object(name):
|
||||
top = _request_ctx_stack.top
|
||||
if top is None:
|
||||
raise RuntimeError('working outside of request context')
|
||||
raise RuntimeError(_request_ctx_err_msg)
|
||||
return getattr(top, name)
|
||||
|
||||
|
||||
def _lookup_app_object(name):
|
||||
top = _app_ctx_stack.top
|
||||
if top is None:
|
||||
raise RuntimeError('working outside of application context')
|
||||
raise RuntimeError(_app_ctx_err_msg)
|
||||
return getattr(top, name)
|
||||
|
||||
|
||||
def _find_app():
|
||||
top = _app_ctx_stack.top
|
||||
if top is None:
|
||||
raise RuntimeError('working outside of application context')
|
||||
raise RuntimeError(_app_ctx_err_msg)
|
||||
return top.app
|
||||
|
||||
|
||||
|
||||
227
vendor/flask/helpers.py
vendored
227
vendor/flask/helpers.py
vendored
@@ -5,7 +5,7 @@
|
||||
|
||||
Implements various helpers.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
@@ -26,7 +26,7 @@ except ImportError:
|
||||
from urlparse import quote as url_quote
|
||||
|
||||
from werkzeug.datastructures import Headers
|
||||
from werkzeug.exceptions import NotFound
|
||||
from werkzeug.exceptions import BadRequest, NotFound
|
||||
|
||||
# this was moved in 0.7
|
||||
try:
|
||||
@@ -53,6 +53,13 @@ _os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep]
|
||||
if sep not in (None, '/'))
|
||||
|
||||
|
||||
def get_debug_flag(default=None):
|
||||
val = os.environ.get('FLASK_DEBUG')
|
||||
if not val:
|
||||
return default
|
||||
return val not 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.
|
||||
@@ -100,7 +107,7 @@ def stream_with_context(generator_or_function):
|
||||
gen = iter(generator_or_function)
|
||||
except TypeError:
|
||||
def decorator(*args, **kwargs):
|
||||
gen = generator_or_function()
|
||||
gen = generator_or_function(*args, **kwargs)
|
||||
return stream_with_context(gen)
|
||||
return update_wrapper(decorator, generator_or_function)
|
||||
|
||||
@@ -188,7 +195,7 @@ def url_for(endpoint, **values):
|
||||
|
||||
Variable arguments that are unknown to the target endpoint are appended
|
||||
to the generated URL as query arguments. If the value of a query argument
|
||||
is `None`, the whole pair is skipped. In case blueprints are active
|
||||
is ``None``, the whole pair is skipped. In case blueprints are active
|
||||
you can shortcut references to the same blueprint by prefixing the
|
||||
local endpoint with a dot (``.``).
|
||||
|
||||
@@ -199,16 +206,16 @@ def url_for(endpoint, **values):
|
||||
For more information, head over to the :ref:`Quickstart <url-building>`.
|
||||
|
||||
To integrate applications, :class:`Flask` has a hook to intercept URL build
|
||||
errors through :attr:`Flask.build_error_handler`. The `url_for` function
|
||||
results in a :exc:`~werkzeug.routing.BuildError` when the current app does
|
||||
not have a URL for the given endpoint and values. When it does, the
|
||||
:data:`~flask.current_app` calls its :attr:`~Flask.build_error_handler` if
|
||||
it is not `None`, which can return a string to use as the result of
|
||||
errors through :attr:`Flask.url_build_error_handlers`. The `url_for`
|
||||
function results in a :exc:`~werkzeug.routing.BuildError` when the current
|
||||
app does not have a URL for the given endpoint and values. When it does, the
|
||||
:data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if
|
||||
it is not ``None``, which can return a string to use as the result of
|
||||
`url_for` (instead of `url_for`'s default to raise the
|
||||
:exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception.
|
||||
An example::
|
||||
|
||||
def external_url_handler(error, endpoint, **values):
|
||||
def external_url_handler(error, endpoint, values):
|
||||
"Looks up an external URL when `url_for` cannot build a URL."
|
||||
# This is an example of hooking the build_error_handler.
|
||||
# Here, lookup_url is some utility function you've built
|
||||
@@ -225,10 +232,10 @@ def url_for(endpoint, **values):
|
||||
# url_for will use this result, instead of raising BuildError.
|
||||
return url
|
||||
|
||||
app.build_error_handler = external_url_handler
|
||||
app.url_build_error_handlers.append(external_url_handler)
|
||||
|
||||
Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and
|
||||
`endpoint` and `**values` are the arguments passed into `url_for`. Note
|
||||
`endpoint` and `values` are the arguments passed into `url_for`. Note
|
||||
that this is for building URLs outside the current application, and not for
|
||||
handling 404 NotFound errors.
|
||||
|
||||
@@ -244,11 +251,15 @@ def url_for(endpoint, **values):
|
||||
|
||||
:param endpoint: the endpoint of the URL (name of the function)
|
||||
:param values: the variable arguments of the URL rule
|
||||
:param _external: if set to `True`, an absolute URL is generated. Server
|
||||
address can be changed via `SERVER_NAME` configuration variable which
|
||||
:param _external: if set to ``True``, an absolute URL is generated. Server
|
||||
address can be changed via ``SERVER_NAME`` configuration variable which
|
||||
defaults to `localhost`.
|
||||
:param _scheme: a string specifying the desired URL scheme. The `_external`
|
||||
parameter must be set to `True` or a `ValueError` is raised.
|
||||
parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default
|
||||
behavior uses the same scheme as the current request, or
|
||||
``PREFERRED_URL_SCHEME`` from the :ref:`app configuration <config>` if no
|
||||
request context is available. As of Werkzeug 0.10, this also can be set
|
||||
to an empty string to build protocol-relative URLs.
|
||||
:param _anchor: if provided this is added as anchor to the URL.
|
||||
:param _method: if provided this explicitly specifies an HTTP method.
|
||||
"""
|
||||
@@ -260,7 +271,7 @@ def url_for(endpoint, **values):
|
||||
'executed when application context is available.')
|
||||
|
||||
# If request specific information is available we have some extra
|
||||
# features that support "relative" urls.
|
||||
# features that support "relative" URLs.
|
||||
if reqctx is not None:
|
||||
url_adapter = reqctx.url_adapter
|
||||
blueprint_name = request.blueprint
|
||||
@@ -280,7 +291,7 @@ def url_for(endpoint, **values):
|
||||
external = values.pop('_external', False)
|
||||
|
||||
# Otherwise go with the url adapter from the appctx and make
|
||||
# the urls external by default.
|
||||
# the URLs external by default.
|
||||
else:
|
||||
url_adapter = appctx.url_adapter
|
||||
if url_adapter is None:
|
||||
@@ -295,14 +306,23 @@ def url_for(endpoint, **values):
|
||||
scheme = values.pop('_scheme', None)
|
||||
appctx.app.inject_url_defaults(endpoint, values)
|
||||
|
||||
# This is not the best way to deal with this but currently the
|
||||
# underlying Werkzeug router does not support overriding the scheme on
|
||||
# a per build call basis.
|
||||
old_scheme = None
|
||||
if scheme is not None:
|
||||
if not external:
|
||||
raise ValueError('When specifying _scheme, _external must be True')
|
||||
old_scheme = url_adapter.url_scheme
|
||||
url_adapter.url_scheme = scheme
|
||||
|
||||
try:
|
||||
rv = url_adapter.build(endpoint, values, method=method,
|
||||
force_external=external)
|
||||
try:
|
||||
rv = url_adapter.build(endpoint, values, method=method,
|
||||
force_external=external)
|
||||
finally:
|
||||
if old_scheme is not None:
|
||||
url_adapter.url_scheme = old_scheme
|
||||
except BuildError as error:
|
||||
# We need to inject the values again so that the app callback can
|
||||
# deal with that sort of stuff.
|
||||
@@ -319,7 +339,7 @@ def url_for(endpoint, **values):
|
||||
def get_template_attribute(template_name, attribute):
|
||||
"""Loads a macro (or variable) a template exports. This can be used to
|
||||
invoke a macro from within Python code. If you for example have a
|
||||
template named `_cider.html` with the following contents:
|
||||
template named :file:`_cider.html` with the following contents:
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
@@ -359,7 +379,7 @@ def flash(message, category='message'):
|
||||
# session.setdefault('_flashes', []).append((category, message))
|
||||
#
|
||||
# This assumed that changes made to mutable structures in the session are
|
||||
# are always in sync with the sess on object, which is not true for session
|
||||
# are always in sync with the session object, which is not true for session
|
||||
# implementations that use external storage for keeping their keys/values.
|
||||
flashes = session.get('_flashes', [])
|
||||
flashes.append((category, message))
|
||||
@@ -372,7 +392,7 @@ def get_flashed_messages(with_categories=False, category_filter=[]):
|
||||
"""Pulls all flashed messages from the session and returns them.
|
||||
Further calls in the same request to the function will return
|
||||
the same messages. By default just the messages are returned,
|
||||
but when `with_categories` is set to `True`, the return value will
|
||||
but when `with_categories` is set to ``True``, the return value will
|
||||
be a list of tuples in the form ``(category, message)`` instead.
|
||||
|
||||
Filter the flashed messages to one or more categories by providing those
|
||||
@@ -381,7 +401,7 @@ def get_flashed_messages(with_categories=False, category_filter=[]):
|
||||
arguments are distinct:
|
||||
|
||||
* `with_categories` controls whether categories are returned with message
|
||||
text (`True` gives a tuple, where `False` gives just the message text).
|
||||
text (``True`` gives a tuple, where ``False`` gives just the message text).
|
||||
* `category_filter` filters the messages down to only those matching the
|
||||
provided categories.
|
||||
|
||||
@@ -393,7 +413,7 @@ def get_flashed_messages(with_categories=False, category_filter=[]):
|
||||
.. versionchanged:: 0.9
|
||||
`category_filter` parameter added.
|
||||
|
||||
:param with_categories: set to `True` to also receive categories.
|
||||
:param with_categories: set to ``True`` to also receive categories.
|
||||
:param category_filter: whitelist of categories to limit return values
|
||||
"""
|
||||
flashes = _request_ctx_stack.top.flashes
|
||||
@@ -414,8 +434,8 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||
most efficient method available and configured. By default it will
|
||||
try to use the WSGI server's file_wrapper support. Alternatively
|
||||
you can set the application's :attr:`~Flask.use_x_sendfile` attribute
|
||||
to ``True`` to directly emit an `X-Sendfile` header. This however
|
||||
requires support of the underlying webserver for `X-Sendfile`.
|
||||
to ``True`` to directly emit an ``X-Sendfile`` header. This however
|
||||
requires support of the underlying webserver for ``X-Sendfile``.
|
||||
|
||||
By default it will try to guess the mimetype for you, but you can
|
||||
also explicitly provide one. For extra security you probably want
|
||||
@@ -423,12 +443,8 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||
guessing requires a `filename` or an `attachment_filename` to be
|
||||
provided.
|
||||
|
||||
Please never pass filenames to this function from user sources without
|
||||
checking them first. Something like this is usually sufficient to
|
||||
avoid security problems::
|
||||
|
||||
if '..' in filename or filename.startswith('/'):
|
||||
abort(404)
|
||||
Please never pass filenames to this function from user sources;
|
||||
you should use :func:`send_from_directory` instead.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
|
||||
@@ -445,24 +461,24 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||
.. versionchanged:: 0.9
|
||||
cache_timeout pulls its default from application config, when None.
|
||||
|
||||
:param filename_or_fp: the filename of the file to send. This is
|
||||
relative to the :attr:`~Flask.root_path` if a
|
||||
relative path is specified.
|
||||
Alternatively a file object might be provided
|
||||
in which case `X-Sendfile` might not work and
|
||||
fall back to the traditional method. Make sure
|
||||
that the file pointer is positioned at the start
|
||||
of data to send before calling :func:`send_file`.
|
||||
:param filename_or_fp: the filename of the file to send in `latin-1`.
|
||||
This is relative to the :attr:`~Flask.root_path`
|
||||
if a relative path is specified.
|
||||
Alternatively a file object might be provided in
|
||||
which case ``X-Sendfile`` might not work and fall
|
||||
back to the traditional method. Make sure that the
|
||||
file pointer is positioned at the start of data to
|
||||
send before calling :func:`send_file`.
|
||||
:param mimetype: the mimetype of the file if provided, otherwise
|
||||
auto detection happens.
|
||||
:param as_attachment: set to `True` if you want to send this file with
|
||||
:param as_attachment: set to ``True`` if you want to send this file with
|
||||
a ``Content-Disposition: attachment`` header.
|
||||
:param attachment_filename: the filename for the attachment if it
|
||||
differs from the file's filename.
|
||||
:param add_etags: set to `False` to disable attaching of etags.
|
||||
:param conditional: set to `True` to enable conditional responses.
|
||||
:param add_etags: set to ``False`` to disable attaching of etags.
|
||||
:param conditional: set to ``True`` to enable conditional responses.
|
||||
|
||||
:param cache_timeout: the timeout in seconds for the headers. When `None`
|
||||
:param cache_timeout: the timeout in seconds for the headers. When ``None``
|
||||
(default), this value is set by
|
||||
:meth:`~Flask.get_send_file_max_age` of
|
||||
:data:`~flask.current_app`.
|
||||
@@ -525,7 +541,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||
rv = current_app.response_class(data, mimetype=mimetype, headers=headers,
|
||||
direct_passthrough=True)
|
||||
|
||||
# if we know the file modification date, we can store it as the
|
||||
# if we know the file modification date, we can store it as
|
||||
# the time of the last modification.
|
||||
if mtime is not None:
|
||||
rv.last_modified = int(mtime)
|
||||
@@ -538,14 +554,19 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||
rv.expires = int(time() + cache_timeout)
|
||||
|
||||
if add_etags and filename is not None:
|
||||
rv.set_etag('flask-%s-%s-%s' % (
|
||||
os.path.getmtime(filename),
|
||||
os.path.getsize(filename),
|
||||
adler32(
|
||||
filename.encode('utf-8') if isinstance(filename, text_type)
|
||||
else filename
|
||||
) & 0xffffffff
|
||||
))
|
||||
try:
|
||||
rv.set_etag('%s-%s-%s' % (
|
||||
os.path.getmtime(filename),
|
||||
os.path.getsize(filename),
|
||||
adler32(
|
||||
filename.encode('utf-8') if isinstance(filename, text_type)
|
||||
else filename
|
||||
) & 0xffffffff
|
||||
))
|
||||
except OSError:
|
||||
warn('Access %s failed, maybe it does not exist, so ignore etags in '
|
||||
'headers' % filename, stacklevel=2)
|
||||
|
||||
if conditional:
|
||||
rv = rv.make_conditional(request)
|
||||
# make sure we don't send x-sendfile for servers that
|
||||
@@ -564,7 +585,7 @@ def safe_join(directory, filename):
|
||||
def wiki_page(filename):
|
||||
filename = safe_join(app.config['WIKI_FOLDER'], filename)
|
||||
with open(filename, 'rb') as fd:
|
||||
content = fd.read() # Read and process the file content...
|
||||
content = fd.read() # Read and process the file content...
|
||||
|
||||
:param directory: the base directory.
|
||||
:param filename: the untrusted filename relative to that directory.
|
||||
@@ -596,7 +617,7 @@ def send_from_directory(directory, filename, **options):
|
||||
|
||||
.. admonition:: Sending files and Performance
|
||||
|
||||
It is strongly recommended to activate either `X-Sendfile` support in
|
||||
It is strongly recommended to activate either ``X-Sendfile`` support in
|
||||
your webserver or (if no authentication happens) to tell the webserver
|
||||
to serve files for the given path on its own without calling into the
|
||||
web application for improved performance.
|
||||
@@ -610,8 +631,13 @@ def send_from_directory(directory, filename, **options):
|
||||
forwarded to :func:`send_file`.
|
||||
"""
|
||||
filename = safe_join(directory, filename)
|
||||
if not os.path.isfile(filename):
|
||||
raise NotFound()
|
||||
if not os.path.isabs(filename):
|
||||
filename = os.path.join(current_app.root_path, filename)
|
||||
try:
|
||||
if not os.path.isfile(filename):
|
||||
raise NotFound()
|
||||
except (TypeError, ValueError):
|
||||
raise BadRequest()
|
||||
options.setdefault('conditional', True)
|
||||
return send_file(filename, **options)
|
||||
|
||||
@@ -643,12 +669,48 @@ def get_root_path(import_name):
|
||||
else:
|
||||
# Fall back to imports.
|
||||
__import__(import_name)
|
||||
filepath = sys.modules[import_name].__file__
|
||||
mod = sys.modules[import_name]
|
||||
filepath = getattr(mod, '__file__', None)
|
||||
|
||||
# If we don't have a filepath it might be because we are a
|
||||
# namespace package. In this case we pick the root path from the
|
||||
# first module that is contained in our package.
|
||||
if filepath is None:
|
||||
raise RuntimeError('No root path can be found for the provided '
|
||||
'module "%s". This can happen because the '
|
||||
'module came from an import hook that does '
|
||||
'not provide file name information or because '
|
||||
'it\'s a namespace package. In this case '
|
||||
'the root path needs to be explicitly '
|
||||
'provided.' % import_name)
|
||||
|
||||
# filepath is import_name.py for a module, or __init__.py for a package.
|
||||
return os.path.dirname(os.path.abspath(filepath))
|
||||
|
||||
|
||||
def _matching_loader_thinks_module_is_package(loader, mod_name):
|
||||
"""Given the loader that loaded a module and the module this function
|
||||
attempts to figure out if the given module is actually a package.
|
||||
"""
|
||||
# If the loader can tell us if something is a package, we can
|
||||
# directly ask the loader.
|
||||
if hasattr(loader, 'is_package'):
|
||||
return loader.is_package(mod_name)
|
||||
# importlib's namespace loaders do not have this functionality but
|
||||
# all the modules it loads are packages, so we can take advantage of
|
||||
# this information.
|
||||
elif (loader.__class__.__module__ == '_frozen_importlib' and
|
||||
loader.__class__.__name__ == 'NamespaceLoader'):
|
||||
return True
|
||||
# Otherwise we need to fail with an error that explains what went
|
||||
# wrong.
|
||||
raise AttributeError(
|
||||
('%s.is_package() method is missing but is required by Flask of '
|
||||
'PEP 302 import hooks. If you do not use import hooks and '
|
||||
'you encounter this error please file a bug against Flask.') %
|
||||
loader.__class__.__name__)
|
||||
|
||||
|
||||
def find_package(import_name):
|
||||
"""Finds a package and returns the prefix (or None if the package is
|
||||
not installed) as well as the folder that contains the package or
|
||||
@@ -678,8 +740,12 @@ def find_package(import_name):
|
||||
__import__(import_name)
|
||||
filename = sys.modules[import_name].__file__
|
||||
package_path = os.path.abspath(os.path.dirname(filename))
|
||||
# package_path ends with __init__.py for a package
|
||||
if loader.is_package(root_mod_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):
|
||||
package_path = os.path.dirname(package_path)
|
||||
|
||||
site_parent, site_folder = os.path.split(package_path)
|
||||
@@ -728,17 +794,20 @@ class locked_cached_property(object):
|
||||
|
||||
class _PackageBoundObject(object):
|
||||
|
||||
def __init__(self, import_name, template_folder=None):
|
||||
def __init__(self, import_name, template_folder=None, root_path=None):
|
||||
#: The name of the package or module. Do not change this once
|
||||
#: it was set by the constructor.
|
||||
self.import_name = import_name
|
||||
|
||||
#: location of the templates. `None` if templates should not be
|
||||
#: location of the templates. ``None`` if templates should not be
|
||||
#: exposed.
|
||||
self.template_folder = template_folder
|
||||
|
||||
if root_path is None:
|
||||
root_path = get_root_path(self.import_name)
|
||||
|
||||
#: Where is the app root located?
|
||||
self.root_path = get_root_path(self.import_name)
|
||||
self.root_path = root_path
|
||||
|
||||
self._static_folder = None
|
||||
self._static_url_path = None
|
||||
@@ -748,15 +817,16 @@ class _PackageBoundObject(object):
|
||||
return os.path.join(self.root_path, self._static_folder)
|
||||
def _set_static_folder(self, value):
|
||||
self._static_folder = value
|
||||
static_folder = property(_get_static_folder, _set_static_folder)
|
||||
static_folder = property(_get_static_folder, _set_static_folder, doc='''
|
||||
The absolute path to the configured static folder.
|
||||
''')
|
||||
del _get_static_folder, _set_static_folder
|
||||
|
||||
def _get_static_url_path(self):
|
||||
if self._static_url_path is None:
|
||||
if self.static_folder is None:
|
||||
return None
|
||||
if self._static_url_path is not None:
|
||||
return self._static_url_path
|
||||
if self.static_folder is not None:
|
||||
return '/' + os.path.basename(self.static_folder)
|
||||
return self._static_url_path
|
||||
def _set_static_url_path(self, value):
|
||||
self._static_url_path = value
|
||||
static_url_path = property(_get_static_url_path, _set_static_url_path)
|
||||
@@ -764,8 +834,8 @@ class _PackageBoundObject(object):
|
||||
|
||||
@property
|
||||
def has_static_folder(self):
|
||||
"""This is `True` if the package bound object's container has a
|
||||
folder named ``'static'``.
|
||||
"""This is ``True`` if the package bound object's container has a
|
||||
folder for static files.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
"""
|
||||
@@ -789,7 +859,7 @@ class _PackageBoundObject(object):
|
||||
|
||||
Static file functions such as :func:`send_from_directory` use this
|
||||
function, and :func:`send_file` calls this function on
|
||||
:data:`~flask.current_app` when the given cache_timeout is `None`. If a
|
||||
:data:`~flask.current_app` when the given cache_timeout is ``None``. If a
|
||||
cache_timeout is given in :func:`send_file`, that timeout is used;
|
||||
otherwise, this method is called.
|
||||
|
||||
@@ -805,7 +875,7 @@ class _PackageBoundObject(object):
|
||||
|
||||
.. versionadded:: 0.9
|
||||
"""
|
||||
return current_app.config['SEND_FILE_MAX_AGE_DEFAULT']
|
||||
return total_seconds(current_app.send_file_max_age_default)
|
||||
|
||||
def send_static_file(self, filename):
|
||||
"""Function used internally to send static files from the static
|
||||
@@ -833,7 +903,7 @@ class _PackageBoundObject(object):
|
||||
/layout.html
|
||||
/index.html
|
||||
|
||||
If you want to open the `schema.sql` file you would do the
|
||||
If you want to open the :file:`schema.sql` file you would do the
|
||||
following::
|
||||
|
||||
with app.open_resource('schema.sql') as f:
|
||||
@@ -847,3 +917,14 @@ class _PackageBoundObject(object):
|
||||
if mode not in ('r', 'rb'):
|
||||
raise ValueError('Resources can only be opened for reading')
|
||||
return open(os.path.join(self.root_path, resource), mode)
|
||||
|
||||
|
||||
def total_seconds(td):
|
||||
"""Returns the total seconds from a timedelta object.
|
||||
|
||||
:param timedelta td: the timedelta to be converted in seconds
|
||||
|
||||
:returns: number of seconds
|
||||
:rtype: int
|
||||
"""
|
||||
return td.days * 60 * 60 * 24 + td.seconds
|
||||
|
||||
86
vendor/flask/json.py
vendored
86
vendor/flask/json.py
vendored
@@ -5,12 +5,12 @@
|
||||
|
||||
Implementation helpers for the JSON support in Flask.
|
||||
|
||||
:copyright: (c) 2012 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import io
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
from .globals import current_app, request
|
||||
from ._compat import text_type, PY2
|
||||
|
||||
@@ -25,7 +25,7 @@ except ImportError:
|
||||
from itsdangerous import json as _json
|
||||
|
||||
|
||||
# figure out if simplejson escapes slashes. This behavior was changed
|
||||
# Figure out if simplejson escapes slashes. This behavior was changed
|
||||
# from one version to another without reason.
|
||||
_slash_escape = '\\/' not in _json.dumps('/')
|
||||
|
||||
@@ -60,7 +60,7 @@ class JSONEncoder(_json.JSONEncoder):
|
||||
def default(self, o):
|
||||
"""Implement this method in a subclass such that it returns a
|
||||
serializable object for ``o``, or calls the base implementation (to
|
||||
raise a ``TypeError``).
|
||||
raise a :exc:`TypeError`).
|
||||
|
||||
For example, to support arbitrary iterators, you could implement
|
||||
default like this::
|
||||
@@ -74,8 +74,8 @@ class JSONEncoder(_json.JSONEncoder):
|
||||
return list(iterable)
|
||||
return JSONEncoder.default(self, o)
|
||||
"""
|
||||
if isinstance(o, datetime):
|
||||
return http_date(o)
|
||||
if isinstance(o, date):
|
||||
return http_date(o.timetuple())
|
||||
if isinstance(o, uuid.UUID):
|
||||
return str(o)
|
||||
if hasattr(o, '__html__'):
|
||||
@@ -85,7 +85,7 @@ class JSONEncoder(_json.JSONEncoder):
|
||||
|
||||
class JSONDecoder(_json.JSONDecoder):
|
||||
"""The default JSON decoder. This one does not change the behavior from
|
||||
the default simplejson encoder. Consult the :mod:`json` documentation
|
||||
the default simplejson decoder. Consult the :mod:`json` documentation
|
||||
for more information. This decoder is not only used for the load
|
||||
functions of this module but also :attr:`~flask.Request`.
|
||||
"""
|
||||
@@ -119,7 +119,7 @@ def dumps(obj, **kwargs):
|
||||
This function can return ``unicode`` strings or ascii-only bytestrings by
|
||||
default which coerce into unicode strings automatically. That behavior by
|
||||
default is controlled by the ``JSON_AS_ASCII`` configuration variable
|
||||
and can be overriden by the simplejson ``ensure_ascii`` parameter.
|
||||
and can be overridden by the simplejson ``ensure_ascii`` parameter.
|
||||
"""
|
||||
_dump_arg_defaults(kwargs)
|
||||
encoding = kwargs.pop('encoding', None)
|
||||
@@ -165,14 +165,29 @@ def htmlsafe_dumps(obj, **kwargs):
|
||||
also mark the result as safe. Due to how this function escapes certain
|
||||
characters this is safe even if used outside of ``<script>`` tags.
|
||||
|
||||
The following characters are escaped in strings:
|
||||
|
||||
- ``<``
|
||||
- ``>``
|
||||
- ``&``
|
||||
- ``'``
|
||||
|
||||
This makes it safe to embed such strings in any place in HTML with the
|
||||
notable exception of double quoted attributes. In that case single
|
||||
quote your attributes or HTML escape it in addition.
|
||||
|
||||
.. versionchanged:: 0.10
|
||||
This function's return value is now always safe for HTML usage, even
|
||||
if outside of script tags or if used in XHTML.
|
||||
if outside of script tags or if used in XHTML. This rule does not
|
||||
hold true when using this function in HTML attributes that are double
|
||||
quoted. Always single quote attributes if you use the ``|tojson``
|
||||
filter. Alternatively use ``|tojson|forceescape``.
|
||||
"""
|
||||
rv = dumps(obj, **kwargs) \
|
||||
.replace(u'<', u'\\u003c') \
|
||||
.replace(u'>', u'\\u003e') \
|
||||
.replace(u'&', u'\\u0026')
|
||||
.replace(u'&', u'\\u0026') \
|
||||
.replace(u"'", u'\\u0027')
|
||||
if not _slash_escape:
|
||||
rv = rv.replace('\\/', '/')
|
||||
return rv
|
||||
@@ -180,13 +195,26 @@ def htmlsafe_dumps(obj, **kwargs):
|
||||
|
||||
def htmlsafe_dump(obj, fp, **kwargs):
|
||||
"""Like :func:`htmlsafe_dumps` but writes into a file object."""
|
||||
fp.write(unicode(htmlsafe_dumps(obj, **kwargs)))
|
||||
fp.write(text_type(htmlsafe_dumps(obj, **kwargs)))
|
||||
|
||||
|
||||
def jsonify(*args, **kwargs):
|
||||
"""Creates a :class:`~flask.Response` with the JSON representation of
|
||||
the given arguments with an `application/json` mimetype. The arguments
|
||||
to this function are the same as to the :class:`dict` constructor.
|
||||
"""This function wraps :func:`dumps` to add a few enhancements that make
|
||||
life easier. It turns the JSON output into a :class:`~flask.Response`
|
||||
object with the :mimetype:`application/json` mimetype. For convenience, it
|
||||
also converts multiple arguments into an array or multiple keyword arguments
|
||||
into a dict. This means that both ``jsonify(1,2,3)`` and
|
||||
``jsonify([1,2,3])`` serialize to ``[1,2,3]``.
|
||||
|
||||
For clarity, the JSON serialization behavior has the following differences
|
||||
from :func:`dumps`:
|
||||
|
||||
1. Single argument: Passed straight through to :func:`dumps`.
|
||||
2. Multiple arguments: Converted to an array before being passed to
|
||||
:func:`dumps`.
|
||||
3. Multiple keyword arguments: Converted to a dict before being passed to
|
||||
:func:`dumps`.
|
||||
4. Both args and kwargs: Behavior undefined and will throw an exception.
|
||||
|
||||
Example usage::
|
||||
|
||||
@@ -206,22 +234,38 @@ def jsonify(*args, **kwargs):
|
||||
"id": 42
|
||||
}
|
||||
|
||||
For security reasons only objects are supported toplevel. For more
|
||||
information about this, have a look at :ref:`json-security`.
|
||||
|
||||
.. versionchanged:: 0.11
|
||||
Added support for serializing top-level arrays. This introduces a
|
||||
security risk in ancient browsers. See :ref:`json-security` for details.
|
||||
|
||||
This function's response will be pretty printed if it was not requested
|
||||
with ``X-Requested-With: XMLHttpRequest`` to simplify debugging unless
|
||||
the ``JSONIFY_PRETTYPRINT_REGULAR`` config parameter is set to false.
|
||||
Compressed (not pretty) formatting currently means no indents and no
|
||||
spaces after separators.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
"""
|
||||
|
||||
indent = None
|
||||
if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] \
|
||||
and not request.is_xhr:
|
||||
separators = (',', ':')
|
||||
|
||||
if current_app.config['JSONIFY_PRETTYPRINT_REGULAR'] and not request.is_xhr:
|
||||
indent = 2
|
||||
return current_app.response_class(dumps(dict(*args, **kwargs),
|
||||
indent=indent),
|
||||
mimetype='application/json')
|
||||
separators = (', ', ': ')
|
||||
|
||||
if args and kwargs:
|
||||
raise TypeError('jsonify() behavior undefined when passed both args and kwargs')
|
||||
elif len(args) == 1: # single args are passed directly to dumps()
|
||||
data = args[0]
|
||||
else:
|
||||
data = args or kwargs
|
||||
|
||||
return current_app.response_class(
|
||||
(dumps(data, indent=indent, separators=separators), '\n'),
|
||||
mimetype=current_app.config['JSONIFY_MIMETYPE']
|
||||
)
|
||||
|
||||
|
||||
def tojson_filter(obj, **kwargs):
|
||||
|
||||
67
vendor/flask/logging.py
vendored
67
vendor/flask/logging.py
vendored
@@ -5,13 +5,46 @@
|
||||
|
||||
Implements the logging support for Flask.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from logging import getLogger, StreamHandler, Formatter, getLoggerClass, DEBUG
|
||||
import sys
|
||||
|
||||
from werkzeug.local import LocalProxy
|
||||
from logging import getLogger, StreamHandler, Formatter, getLoggerClass, \
|
||||
DEBUG, ERROR
|
||||
from .globals import _request_ctx_stack
|
||||
|
||||
|
||||
PROD_LOG_FORMAT = '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
|
||||
DEBUG_LOG_FORMAT = (
|
||||
'-' * 80 + '\n' +
|
||||
'%(levelname)s in %(module)s [%(pathname)s:%(lineno)d]:\n' +
|
||||
'%(message)s\n' +
|
||||
'-' * 80
|
||||
)
|
||||
|
||||
|
||||
@LocalProxy
|
||||
def _proxy_stream():
|
||||
"""Finds the most appropriate error stream for the application. If a
|
||||
WSGI request is in flight we log to wsgi.errors, otherwise this resolves
|
||||
to sys.stderr.
|
||||
"""
|
||||
ctx = _request_ctx_stack.top
|
||||
if ctx is not None:
|
||||
return ctx.request.environ['wsgi.errors']
|
||||
return sys.stderr
|
||||
|
||||
|
||||
def _should_log_for(app, mode):
|
||||
policy = app.config['LOGGER_HANDLER_POLICY']
|
||||
if policy == mode or policy == 'always':
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def create_logger(app):
|
||||
@@ -24,22 +57,34 @@ def create_logger(app):
|
||||
Logger = getLoggerClass()
|
||||
|
||||
class DebugLogger(Logger):
|
||||
def getEffectiveLevel(x):
|
||||
if x.level == 0 and app.debug:
|
||||
def getEffectiveLevel(self):
|
||||
if self.level == 0 and app.debug:
|
||||
return DEBUG
|
||||
return Logger.getEffectiveLevel(x)
|
||||
return Logger.getEffectiveLevel(self)
|
||||
|
||||
class DebugHandler(StreamHandler):
|
||||
def emit(x, record):
|
||||
StreamHandler.emit(x, record) if app.debug else None
|
||||
def emit(self, record):
|
||||
if app.debug and _should_log_for(app, 'debug'):
|
||||
StreamHandler.emit(self, record)
|
||||
|
||||
class ProductionHandler(StreamHandler):
|
||||
def emit(self, record):
|
||||
if not app.debug and _should_log_for(app, 'production'):
|
||||
StreamHandler.emit(self, record)
|
||||
|
||||
debug_handler = DebugHandler()
|
||||
debug_handler.setLevel(DEBUG)
|
||||
debug_handler.setFormatter(Formatter(DEBUG_LOG_FORMAT))
|
||||
|
||||
prod_handler = ProductionHandler(_proxy_stream)
|
||||
prod_handler.setLevel(ERROR)
|
||||
prod_handler.setFormatter(Formatter(PROD_LOG_FORMAT))
|
||||
|
||||
handler = DebugHandler()
|
||||
handler.setLevel(DEBUG)
|
||||
handler.setFormatter(Formatter(app.debug_log_format))
|
||||
logger = getLogger(app.logger_name)
|
||||
# just in case that was not a new logger, get rid of all the handlers
|
||||
# already attached to it.
|
||||
del logger.handlers[:]
|
||||
logger.__class__ = DebugLogger
|
||||
logger.addHandler(handler)
|
||||
logger.addHandler(debug_handler)
|
||||
logger.addHandler(prod_handler)
|
||||
return logger
|
||||
|
||||
42
vendor/flask/module.py
vendored
42
vendor/flask/module.py
vendored
@@ -1,42 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.module
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Implements a class that represents module blueprints.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from .blueprints import Blueprint
|
||||
|
||||
|
||||
def blueprint_is_module(bp):
|
||||
"""Used to figure out if something is actually a module"""
|
||||
return isinstance(bp, Module)
|
||||
|
||||
|
||||
class Module(Blueprint):
|
||||
"""Deprecated module support. Until Flask 0.6 modules were a different
|
||||
name of the concept now available as blueprints in Flask. They are
|
||||
essentially doing the same but have some bad semantics for templates and
|
||||
static files that were fixed with blueprints.
|
||||
|
||||
.. versionchanged:: 0.7
|
||||
Modules were deprecated in favor for blueprints.
|
||||
"""
|
||||
|
||||
def __init__(self, import_name, name=None, url_prefix=None,
|
||||
static_path=None, subdomain=None):
|
||||
if name is None:
|
||||
assert '.' in import_name, 'name required if package name ' \
|
||||
'does not point to a submodule'
|
||||
name = import_name.rsplit('.', 1)[1]
|
||||
Blueprint.__init__(self, name, import_name, url_prefix=url_prefix,
|
||||
subdomain=subdomain, template_folder='templates')
|
||||
|
||||
if os.path.isdir(os.path.join(self.root_path, 'static')):
|
||||
self._static_folder = 'static'
|
||||
117
vendor/flask/sessions.py
vendored
117
vendor/flask/sessions.py
vendored
@@ -5,25 +5,23 @@
|
||||
|
||||
Implements cookie based sessions based on itsdangerous.
|
||||
|
||||
:copyright: (c) 2012 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
import hashlib
|
||||
from base64 import b64encode, b64decode
|
||||
from datetime import datetime
|
||||
from werkzeug.http import http_date, parse_date
|
||||
from werkzeug.datastructures import CallbackDict
|
||||
from . import Markup, json
|
||||
from ._compat import iteritems, text_type
|
||||
from .helpers import total_seconds
|
||||
|
||||
from itsdangerous import URLSafeTimedSerializer, BadSignature
|
||||
|
||||
|
||||
def total_seconds(td):
|
||||
return td.days * 60 * 60 * 24 + td.seconds
|
||||
|
||||
|
||||
class SessionMixin(object):
|
||||
"""Expands a basic dictionary with an accessors that are expected
|
||||
by Flask extensions and users for the session.
|
||||
@@ -41,44 +39,49 @@ class SessionMixin(object):
|
||||
|
||||
#: some session backends can tell you if a session is new, but that is
|
||||
#: not necessarily guaranteed. Use with caution. The default mixin
|
||||
#: implementation just hardcodes `False` in.
|
||||
#: implementation just hardcodes ``False`` in.
|
||||
new = False
|
||||
|
||||
#: for some backends this will always be `True`, but some backends will
|
||||
#: for some backends this will always be ``True``, but some backends will
|
||||
#: default this to false and detect changes in the dictionary for as
|
||||
#: long as changes do not happen on mutable structures in the session.
|
||||
#: The default mixin implementation just hardcodes `True` in.
|
||||
#: The default mixin implementation just hardcodes ``True`` in.
|
||||
modified = True
|
||||
|
||||
|
||||
def _tag(value):
|
||||
if isinstance(value, tuple):
|
||||
return {' t': [_tag(x) for x in value]}
|
||||
elif isinstance(value, uuid.UUID):
|
||||
return {' u': value.hex}
|
||||
elif isinstance(value, bytes):
|
||||
return {' b': b64encode(value).decode('ascii')}
|
||||
elif callable(getattr(value, '__html__', None)):
|
||||
return {' m': text_type(value.__html__())}
|
||||
elif isinstance(value, list):
|
||||
return [_tag(x) for x in value]
|
||||
elif isinstance(value, datetime):
|
||||
return {' d': http_date(value)}
|
||||
elif isinstance(value, dict):
|
||||
return dict((k, _tag(v)) for k, v in iteritems(value))
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
return text_type(value)
|
||||
except UnicodeError:
|
||||
from flask.debughelpers import UnexpectedUnicodeError
|
||||
raise UnexpectedUnicodeError(u'A byte string with '
|
||||
u'non-ASCII data was passed to the session system '
|
||||
u'which can only store unicode strings. Consider '
|
||||
u'base64 encoding your string (String was %r)' % value)
|
||||
return value
|
||||
|
||||
|
||||
class TaggedJSONSerializer(object):
|
||||
"""A customized JSON serializer that supports a few extra types that
|
||||
we take for granted when serializing (tuples, markup objects, datetime).
|
||||
"""
|
||||
|
||||
def dumps(self, value):
|
||||
def _tag(value):
|
||||
if isinstance(value, tuple):
|
||||
return {' t': [_tag(x) for x in value]}
|
||||
elif isinstance(value, uuid.UUID):
|
||||
return {' u': value.hex}
|
||||
elif callable(getattr(value, '__html__', None)):
|
||||
return {' m': text_type(value.__html__())}
|
||||
elif isinstance(value, list):
|
||||
return [_tag(x) for x in value]
|
||||
elif isinstance(value, datetime):
|
||||
return {' d': http_date(value)}
|
||||
elif isinstance(value, dict):
|
||||
return dict((k, _tag(v)) for k, v in iteritems(value))
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
return text_type(value)
|
||||
except UnicodeError:
|
||||
raise UnexpectedUnicodeError(u'A byte string with '
|
||||
u'non-ASCII data was passed to the session system '
|
||||
u'which can only store unicode strings. Consider '
|
||||
u'base64 encoding your string (String was %r)' % value)
|
||||
return value
|
||||
return json.dumps(_tag(value), separators=(',', ':'))
|
||||
|
||||
def loads(self, value):
|
||||
@@ -90,6 +93,8 @@ class TaggedJSONSerializer(object):
|
||||
return tuple(the_value)
|
||||
elif the_key == ' u':
|
||||
return uuid.UUID(the_value)
|
||||
elif the_key == ' b':
|
||||
return b64decode(the_value)
|
||||
elif the_key == ' m':
|
||||
return Markup(the_value)
|
||||
elif the_key == ' d':
|
||||
@@ -102,7 +107,7 @@ session_json_serializer = TaggedJSONSerializer()
|
||||
|
||||
|
||||
class SecureCookieSession(CallbackDict, SessionMixin):
|
||||
"""Baseclass for sessions based on signed cookies."""
|
||||
"""Base class for sessions based on signed cookies."""
|
||||
|
||||
def __init__(self, initial=None):
|
||||
def on_update(self):
|
||||
@@ -118,7 +123,7 @@ class NullSession(SecureCookieSession):
|
||||
"""
|
||||
|
||||
def _fail(self, *args, **kwargs):
|
||||
raise RuntimeError('the session is unavailable because no secret '
|
||||
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 = \
|
||||
@@ -141,7 +146,7 @@ class SessionInterface(object):
|
||||
class Session(dict, SessionMixin):
|
||||
pass
|
||||
|
||||
If :meth:`open_session` returns `None` Flask will call into
|
||||
If :meth:`open_session` returns ``None`` Flask will call into
|
||||
:meth:`make_null_session` to create a session that acts as replacement
|
||||
if the session support cannot work because some requirement is not
|
||||
fulfilled. The default :class:`NullSession` class that is created
|
||||
@@ -197,7 +202,7 @@ class SessionInterface(object):
|
||||
if app.config['SESSION_COOKIE_DOMAIN'] is not None:
|
||||
return app.config['SESSION_COOKIE_DOMAIN']
|
||||
if app.config['SERVER_NAME'] is not None:
|
||||
# chop of the port which is usually not supported by browsers
|
||||
# chop off the port which is usually not supported by browsers
|
||||
rv = '.' + app.config['SERVER_NAME'].rsplit(':', 1)[0]
|
||||
|
||||
# Google chrome does not like cookies set to .localhost, so
|
||||
@@ -218,9 +223,9 @@ class SessionInterface(object):
|
||||
|
||||
def get_cookie_path(self, app):
|
||||
"""Returns the path for which the cookie should be valid. The
|
||||
default implementation uses the value from the SESSION_COOKIE_PATH``
|
||||
default implementation uses the value from the ``SESSION_COOKIE_PATH``
|
||||
config var if it's set, and falls back to ``APPLICATION_ROOT`` or
|
||||
uses ``/`` if it's `None`.
|
||||
uses ``/`` if it's ``None``.
|
||||
"""
|
||||
return app.config['SESSION_COOKIE_PATH'] or \
|
||||
app.config['APPLICATION_ROOT'] or '/'
|
||||
@@ -240,15 +245,33 @@ class SessionInterface(object):
|
||||
|
||||
def get_expiration_time(self, app, session):
|
||||
"""A helper method that returns an expiration date for the session
|
||||
or `None` if the session is linked to the browser session. The
|
||||
or ``None`` if the session is linked to the browser session. The
|
||||
default implementation returns now + the permanent session
|
||||
lifetime configured on the application.
|
||||
"""
|
||||
if session.permanent:
|
||||
return datetime.utcnow() + app.permanent_session_lifetime
|
||||
|
||||
def should_set_cookie(self, app, session):
|
||||
"""Indicates whether a cookie should be set now or not. This is
|
||||
used by session backends to figure out if they should emit a
|
||||
set-cookie header or not. The default behavior is controlled by
|
||||
the ``SESSION_REFRESH_EACH_REQUEST`` config variable. If
|
||||
it's set to ``False`` then a cookie is only set if the session is
|
||||
modified, if set to ``True`` it's always set if the session is
|
||||
permanent.
|
||||
|
||||
This check is usually skipped if sessions get deleted.
|
||||
|
||||
.. versionadded:: 0.11
|
||||
"""
|
||||
if session.modified:
|
||||
return True
|
||||
save_each = app.config['SESSION_REFRESH_EACH_REQUEST']
|
||||
return save_each and session.permanent
|
||||
|
||||
def open_session(self, app, request):
|
||||
"""This method has to be implemented and must either return `None`
|
||||
"""This method has to be implemented and must either return ``None``
|
||||
in case the loading failed because of a configuration error or an
|
||||
instance of a session object which implements a dictionary like
|
||||
interface + the methods and attributes on :class:`SessionMixin`.
|
||||
@@ -310,11 +333,26 @@ class SecureCookieSessionInterface(SessionInterface):
|
||||
def save_session(self, app, session, response):
|
||||
domain = self.get_cookie_domain(app)
|
||||
path = self.get_cookie_path(app)
|
||||
|
||||
# Delete case. If there is no session we bail early.
|
||||
# If the session was modified to be empty we remove the
|
||||
# whole cookie.
|
||||
if not session:
|
||||
if session.modified:
|
||||
response.delete_cookie(app.session_cookie_name,
|
||||
domain=domain, path=path)
|
||||
return
|
||||
|
||||
# Modification case. There are upsides and downsides to
|
||||
# emitting a set-cookie header each request. The behavior
|
||||
# is controlled by the :meth:`should_set_cookie` method
|
||||
# which performs a quick check to figure out if the cookie
|
||||
# should be set or not. This is controlled by the
|
||||
# SESSION_REFRESH_EACH_REQUEST config flag as well as
|
||||
# the permanent flag on the session itself.
|
||||
if not self.should_set_cookie(app, session):
|
||||
return
|
||||
|
||||
httponly = self.get_cookie_httponly(app)
|
||||
secure = self.get_cookie_secure(app)
|
||||
expires = self.get_expiration_time(app, session)
|
||||
@@ -322,6 +360,3 @@ class SecureCookieSessionInterface(SessionInterface):
|
||||
response.set_cookie(app.session_cookie_name, val,
|
||||
expires=expires, httponly=httponly,
|
||||
domain=domain, path=path, secure=secure)
|
||||
|
||||
|
||||
from flask.debughelpers import UnexpectedUnicodeError
|
||||
|
||||
9
vendor/flask/signals.py
vendored
9
vendor/flask/signals.py
vendored
@@ -4,9 +4,9 @@
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Implements signals based on blinker if available, otherwise
|
||||
falls silently back to a noop
|
||||
falls silently back to a noop.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
signals_available = False
|
||||
@@ -37,14 +37,15 @@ except ImportError:
|
||||
temporarily_connected_to = connected_to = _fail
|
||||
del _fail
|
||||
|
||||
# the namespace for code signals. If you are not flask code, do
|
||||
# The namespace for code signals. If you are not flask code, do
|
||||
# not put signals in here. Create your own namespace instead.
|
||||
_signals = Namespace()
|
||||
|
||||
|
||||
# core signals. For usage examples grep the sourcecode or consult
|
||||
# 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')
|
||||
|
||||
74
vendor/flask/templating.py
vendored
74
vendor/flask/templating.py
vendored
@@ -5,17 +5,14 @@
|
||||
|
||||
Implements the bridge to Jinja2.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import posixpath
|
||||
from jinja2 import BaseLoader, Environment as BaseEnvironment, \
|
||||
TemplateNotFound
|
||||
|
||||
from .globals import _request_ctx_stack, _app_ctx_stack
|
||||
from .signals import template_rendered
|
||||
from .module import blueprint_is_module
|
||||
from ._compat import itervalues, iteritems
|
||||
from .signals import template_rendered, before_render_template
|
||||
|
||||
|
||||
def _default_template_ctx_processor():
|
||||
@@ -55,37 +52,47 @@ class DispatchingJinjaLoader(BaseLoader):
|
||||
self.app = app
|
||||
|
||||
def get_source(self, environment, template):
|
||||
for loader, local_name in self._iter_loaders(template):
|
||||
try:
|
||||
return loader.get_source(environment, local_name)
|
||||
except TemplateNotFound:
|
||||
pass
|
||||
if self.app.config['EXPLAIN_TEMPLATE_LOADING']:
|
||||
return self._get_source_explained(environment, template)
|
||||
return self._get_source_fast(environment, template)
|
||||
|
||||
def _get_source_explained(self, environment, template):
|
||||
attempts = []
|
||||
trv = None
|
||||
|
||||
for srcobj, loader in self._iter_loaders(template):
|
||||
try:
|
||||
rv = loader.get_source(environment, template)
|
||||
if trv is None:
|
||||
trv = rv
|
||||
except TemplateNotFound:
|
||||
rv = None
|
||||
attempts.append((loader, srcobj, rv))
|
||||
|
||||
from .debughelpers import explain_template_loading_attempts
|
||||
explain_template_loading_attempts(self.app, template, attempts)
|
||||
|
||||
if trv is not None:
|
||||
return trv
|
||||
raise TemplateNotFound(template)
|
||||
|
||||
def _get_source_fast(self, environment, template):
|
||||
for srcobj, loader in self._iter_loaders(template):
|
||||
try:
|
||||
return loader.get_source(environment, template)
|
||||
except TemplateNotFound:
|
||||
continue
|
||||
raise TemplateNotFound(template)
|
||||
|
||||
def _iter_loaders(self, template):
|
||||
loader = self.app.jinja_loader
|
||||
if loader is not None:
|
||||
yield loader, template
|
||||
yield self.app, loader
|
||||
|
||||
# old style module based loaders in case we are dealing with a
|
||||
# blueprint that is an old style module
|
||||
try:
|
||||
module, local_name = posixpath.normpath(template).split('/', 1)
|
||||
blueprint = self.app.blueprints[module]
|
||||
if blueprint_is_module(blueprint):
|
||||
loader = blueprint.jinja_loader
|
||||
if loader is not None:
|
||||
yield loader, local_name
|
||||
except (ValueError, KeyError):
|
||||
pass
|
||||
|
||||
for blueprint in itervalues(self.app.blueprints):
|
||||
if blueprint_is_module(blueprint):
|
||||
continue
|
||||
for blueprint in self.app.iter_blueprints():
|
||||
loader = blueprint.jinja_loader
|
||||
if loader is not None:
|
||||
yield loader, template
|
||||
yield blueprint, loader
|
||||
|
||||
def list_templates(self):
|
||||
result = set()
|
||||
@@ -93,20 +100,19 @@ class DispatchingJinjaLoader(BaseLoader):
|
||||
if loader is not None:
|
||||
result.update(loader.list_templates())
|
||||
|
||||
for name, blueprint in iteritems(self.app.blueprints):
|
||||
for blueprint in self.app.iter_blueprints():
|
||||
loader = blueprint.jinja_loader
|
||||
if loader is not None:
|
||||
for template in loader.list_templates():
|
||||
prefix = ''
|
||||
if blueprint_is_module(blueprint):
|
||||
prefix = name + '/'
|
||||
result.add(prefix + template)
|
||||
result.add(template)
|
||||
|
||||
return list(result)
|
||||
|
||||
|
||||
def _render(template, context, app):
|
||||
"""Renders the template and fires the signal"""
|
||||
|
||||
before_render_template.send(app, template=template, context=context)
|
||||
rv = template.render(context)
|
||||
template_rendered.send(app, template=template, context=context)
|
||||
return rv
|
||||
@@ -130,9 +136,9 @@ def render_template(template_name_or_list, **context):
|
||||
|
||||
def render_template_string(source, **context):
|
||||
"""Renders a template from the given template source string
|
||||
with the given context.
|
||||
with the given context. Template variables will be autoescaped.
|
||||
|
||||
:param source: the sourcecode of the template to be
|
||||
:param source: the source code of the template to be
|
||||
rendered
|
||||
:param context: the variables that should be available in the
|
||||
context of the template.
|
||||
|
||||
15
vendor/flask/testing.py
vendored
15
vendor/flask/testing.py
vendored
@@ -6,7 +6,7 @@
|
||||
Implements test support helpers. This module is lazily imported
|
||||
and usually not used in production environments.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
@@ -31,14 +31,17 @@ def make_test_environ_builder(app, path='/', base_url=None, *args, **kwargs):
|
||||
base_url += app_root.lstrip('/')
|
||||
if url.netloc:
|
||||
path = url.path
|
||||
if url.query:
|
||||
path += '?' + url.query
|
||||
return EnvironBuilder(path, base_url, *args, **kwargs)
|
||||
|
||||
|
||||
class FlaskClient(Client):
|
||||
"""Works like a regular Werkzeug test client but has some knowledge about
|
||||
how Flask works to defer the cleanup of the request context stack to the
|
||||
end of a with body when used in a with statement. For general information
|
||||
about how to use this class refer to :class:`werkzeug.test.Client`.
|
||||
end of a ``with`` body when used in a ``with`` statement. For general
|
||||
information about how to use this class refer to
|
||||
:class:`werkzeug.test.Client`.
|
||||
|
||||
Basic usage is outlined in the :ref:`testing` chapter.
|
||||
"""
|
||||
@@ -47,11 +50,13 @@ class FlaskClient(Client):
|
||||
|
||||
@contextmanager
|
||||
def session_transaction(self, *args, **kwargs):
|
||||
"""When used in combination with a with statement this opens a
|
||||
"""When used in combination with a ``with`` statement this opens a
|
||||
session transaction. This can be used to modify the session that
|
||||
the test client uses. Once the with block is left the session is
|
||||
the test client uses. Once the ``with`` block is left the session is
|
||||
stored back.
|
||||
|
||||
::
|
||||
|
||||
with client.session_transaction() as session:
|
||||
session['value'] = 42
|
||||
|
||||
|
||||
246
vendor/flask/testsuite/__init__.py
vendored
246
vendor/flask/testsuite/__init__.py
vendored
@@ -1,246 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Tests Flask itself. The majority of Flask is already tested
|
||||
as part of Werkzeug.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import flask
|
||||
import warnings
|
||||
import unittest
|
||||
from functools import update_wrapper
|
||||
from contextlib import contextmanager
|
||||
from werkzeug.utils import import_string, find_modules
|
||||
from flask._compat import reraise, StringIO
|
||||
|
||||
|
||||
def add_to_path(path):
|
||||
"""Adds an entry to sys.path if it's not already there. This does
|
||||
not append it but moves it to the front so that we can be sure it
|
||||
is loaded.
|
||||
"""
|
||||
if not os.path.isdir(path):
|
||||
raise RuntimeError('Tried to add nonexisting path')
|
||||
|
||||
def _samefile(x, y):
|
||||
if x == y:
|
||||
return True
|
||||
try:
|
||||
return os.path.samefile(x, y)
|
||||
except (IOError, OSError, AttributeError):
|
||||
# Windows has no samefile
|
||||
return False
|
||||
sys.path[:] = [x for x in sys.path if not _samefile(path, x)]
|
||||
sys.path.insert(0, path)
|
||||
|
||||
|
||||
def iter_suites():
|
||||
"""Yields all testsuites."""
|
||||
for module in find_modules(__name__):
|
||||
mod = import_string(module)
|
||||
if hasattr(mod, 'suite'):
|
||||
yield mod.suite()
|
||||
|
||||
|
||||
def find_all_tests(suite):
|
||||
"""Yields all the tests and their names from a given suite."""
|
||||
suites = [suite]
|
||||
while suites:
|
||||
s = suites.pop()
|
||||
try:
|
||||
suites.extend(s)
|
||||
except TypeError:
|
||||
yield s, '%s.%s.%s' % (
|
||||
s.__class__.__module__,
|
||||
s.__class__.__name__,
|
||||
s._testMethodName
|
||||
)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def catch_warnings():
|
||||
"""Catch warnings in a with block in a list"""
|
||||
# make sure deprecation warnings are active in tests
|
||||
warnings.simplefilter('default', category=DeprecationWarning)
|
||||
|
||||
filters = warnings.filters
|
||||
warnings.filters = filters[:]
|
||||
old_showwarning = warnings.showwarning
|
||||
log = []
|
||||
def showwarning(message, category, filename, lineno, file=None, line=None):
|
||||
log.append(locals())
|
||||
try:
|
||||
warnings.showwarning = showwarning
|
||||
yield log
|
||||
finally:
|
||||
warnings.filters = filters
|
||||
warnings.showwarning = old_showwarning
|
||||
|
||||
|
||||
@contextmanager
|
||||
def catch_stderr():
|
||||
"""Catch stderr in a StringIO"""
|
||||
old_stderr = sys.stderr
|
||||
sys.stderr = rv = StringIO()
|
||||
try:
|
||||
yield rv
|
||||
finally:
|
||||
sys.stderr = old_stderr
|
||||
|
||||
|
||||
def emits_module_deprecation_warning(f):
|
||||
def new_f(self, *args, **kwargs):
|
||||
with catch_warnings() as log:
|
||||
f(self, *args, **kwargs)
|
||||
self.assert_true(log, 'expected deprecation warning')
|
||||
for entry in log:
|
||||
self.assert_in('Modules are deprecated', str(entry['message']))
|
||||
return update_wrapper(new_f, f)
|
||||
|
||||
|
||||
class FlaskTestCase(unittest.TestCase):
|
||||
"""Baseclass for all the tests that Flask uses. Use these methods
|
||||
for testing instead of the camelcased ones in the baseclass for
|
||||
consistency.
|
||||
"""
|
||||
|
||||
def ensure_clean_request_context(self):
|
||||
# make sure we're not leaking a request context since we are
|
||||
# testing flask internally in debug mode in a few cases
|
||||
leaks = []
|
||||
while flask._request_ctx_stack.top is not None:
|
||||
leaks.append(flask._request_ctx_stack.pop())
|
||||
self.assert_equal(leaks, [])
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def teardown(self):
|
||||
pass
|
||||
|
||||
def setUp(self):
|
||||
self.setup()
|
||||
|
||||
def tearDown(self):
|
||||
unittest.TestCase.tearDown(self)
|
||||
self.ensure_clean_request_context()
|
||||
self.teardown()
|
||||
|
||||
def assert_equal(self, x, y):
|
||||
return self.assertEqual(x, y)
|
||||
|
||||
def assert_raises(self, exc_type, callable=None, *args, **kwargs):
|
||||
catcher = _ExceptionCatcher(self, exc_type)
|
||||
if callable is None:
|
||||
return catcher
|
||||
with catcher:
|
||||
callable(*args, **kwargs)
|
||||
|
||||
def assert_true(self, x, msg=None):
|
||||
self.assertTrue(x, msg)
|
||||
|
||||
def assert_false(self, x, msg=None):
|
||||
self.assertFalse(x, msg)
|
||||
|
||||
def assert_in(self, x, y):
|
||||
self.assertIn(x, y)
|
||||
|
||||
def assert_not_in(self, x, y):
|
||||
self.assertNotIn(x, y)
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
def assertIn(self, x, y):
|
||||
assert x in y, "%r unexpectedly not in %r" % (x, y)
|
||||
|
||||
def assertNotIn(self, x, y):
|
||||
assert x not in y, "%r unexpectedly in %r" % (x, y)
|
||||
|
||||
|
||||
class _ExceptionCatcher(object):
|
||||
|
||||
def __init__(self, test_case, exc_type):
|
||||
self.test_case = test_case
|
||||
self.exc_type = exc_type
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, tb):
|
||||
exception_name = self.exc_type.__name__
|
||||
if exc_type is None:
|
||||
self.test_case.fail('Expected exception of type %r' %
|
||||
exception_name)
|
||||
elif not issubclass(exc_type, self.exc_type):
|
||||
reraise(exc_type, exc_value, tb)
|
||||
return True
|
||||
|
||||
|
||||
class BetterLoader(unittest.TestLoader):
|
||||
"""A nicer loader that solves two problems. First of all we are setting
|
||||
up tests from different sources and we're doing this programmatically
|
||||
which breaks the default loading logic so this is required anyways.
|
||||
Secondly this loader has a nicer interpolation for test names than the
|
||||
default one so you can just do ``run-tests.py ViewTestCase`` and it
|
||||
will work.
|
||||
"""
|
||||
|
||||
def getRootSuite(self):
|
||||
return suite()
|
||||
|
||||
def loadTestsFromName(self, name, module=None):
|
||||
root = self.getRootSuite()
|
||||
if name == 'suite':
|
||||
return root
|
||||
|
||||
all_tests = []
|
||||
for testcase, testname in find_all_tests(root):
|
||||
if testname == name or \
|
||||
testname.endswith('.' + name) or \
|
||||
('.' + name + '.') in testname or \
|
||||
testname.startswith(name + '.'):
|
||||
all_tests.append(testcase)
|
||||
|
||||
if not all_tests:
|
||||
raise LookupError('could not find test case for "%s"' % name)
|
||||
|
||||
if len(all_tests) == 1:
|
||||
return all_tests[0]
|
||||
rv = unittest.TestSuite()
|
||||
for test in all_tests:
|
||||
rv.addTest(test)
|
||||
return rv
|
||||
|
||||
|
||||
def setup_path():
|
||||
add_to_path(os.path.abspath(os.path.join(
|
||||
os.path.dirname(__file__), 'test_apps')))
|
||||
|
||||
|
||||
def suite():
|
||||
"""A testsuite that has all the Flask tests. You can use this
|
||||
function to integrate the Flask tests into your own testsuite
|
||||
in case you want to test that monkeypatches to Flask do not
|
||||
break it.
|
||||
"""
|
||||
setup_path()
|
||||
suite = unittest.TestSuite()
|
||||
for other_suite in iter_suites():
|
||||
suite.addTest(other_suite)
|
||||
return suite
|
||||
|
||||
|
||||
def main():
|
||||
"""Runs the testsuite as command line application."""
|
||||
try:
|
||||
unittest.main(testLoader=BetterLoader(), defaultTest='suite')
|
||||
except Exception as e:
|
||||
print('Error: %s' % e)
|
||||
101
vendor/flask/testsuite/appctx.py
vendored
101
vendor/flask/testsuite/appctx.py
vendored
@@ -1,101 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.appctx
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the application context.
|
||||
|
||||
:copyright: (c) 2012 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import unittest
|
||||
from flask.testsuite import FlaskTestCase
|
||||
|
||||
|
||||
class AppContextTestCase(FlaskTestCase):
|
||||
|
||||
def test_basic_url_generation(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.config['SERVER_NAME'] = 'localhost'
|
||||
app.config['PREFERRED_URL_SCHEME'] = 'https'
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
pass
|
||||
|
||||
with app.app_context():
|
||||
rv = flask.url_for('index')
|
||||
self.assert_equal(rv, 'https://localhost/')
|
||||
|
||||
def test_url_generation_requires_server_name(self):
|
||||
app = flask.Flask(__name__)
|
||||
with app.app_context():
|
||||
with self.assert_raises(RuntimeError):
|
||||
flask.url_for('index')
|
||||
|
||||
def test_url_generation_without_context_fails(self):
|
||||
with self.assert_raises(RuntimeError):
|
||||
flask.url_for('index')
|
||||
|
||||
def test_request_context_means_app_context(self):
|
||||
app = flask.Flask(__name__)
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.current_app._get_current_object(), app)
|
||||
self.assert_equal(flask._app_ctx_stack.top, None)
|
||||
|
||||
def test_app_context_provides_current_app(self):
|
||||
app = flask.Flask(__name__)
|
||||
with app.app_context():
|
||||
self.assert_equal(flask.current_app._get_current_object(), app)
|
||||
self.assert_equal(flask._app_ctx_stack.top, None)
|
||||
|
||||
def test_app_tearing_down(self):
|
||||
cleanup_stuff = []
|
||||
app = flask.Flask(__name__)
|
||||
@app.teardown_appcontext
|
||||
def cleanup(exception):
|
||||
cleanup_stuff.append(exception)
|
||||
|
||||
with app.app_context():
|
||||
pass
|
||||
|
||||
self.assert_equal(cleanup_stuff, [None])
|
||||
|
||||
def test_custom_app_ctx_globals_class(self):
|
||||
class CustomRequestGlobals(object):
|
||||
def __init__(self):
|
||||
self.spam = 'eggs'
|
||||
app = flask.Flask(__name__)
|
||||
app.app_ctx_globals_class = CustomRequestGlobals
|
||||
with app.app_context():
|
||||
self.assert_equal(
|
||||
flask.render_template_string('{{ g.spam }}'), 'eggs')
|
||||
|
||||
def test_context_refcounts(self):
|
||||
called = []
|
||||
app = flask.Flask(__name__)
|
||||
@app.teardown_request
|
||||
def teardown_req(error=None):
|
||||
called.append('request')
|
||||
@app.teardown_appcontext
|
||||
def teardown_app(error=None):
|
||||
called.append('app')
|
||||
@app.route('/')
|
||||
def index():
|
||||
with flask._app_ctx_stack.top:
|
||||
with flask._request_ctx_stack.top:
|
||||
pass
|
||||
self.assert_true(flask._request_ctx_stack.top.request.environ
|
||||
['werkzeug.request'] is not None)
|
||||
return u''
|
||||
c = app.test_client()
|
||||
c.get('/')
|
||||
self.assertEqual(called, ['request', 'app'])
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(AppContextTestCase))
|
||||
return suite
|
||||
1222
vendor/flask/testsuite/basic.py
vendored
1222
vendor/flask/testsuite/basic.py
vendored
File diff suppressed because it is too large
Load Diff
790
vendor/flask/testsuite/blueprints.py
vendored
790
vendor/flask/testsuite/blueprints.py
vendored
@@ -1,790 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.blueprints
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Blueprints (and currently modules)
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import unittest
|
||||
import warnings
|
||||
from flask.testsuite import FlaskTestCase, emits_module_deprecation_warning
|
||||
from flask._compat import text_type
|
||||
from werkzeug.exceptions import NotFound
|
||||
from werkzeug.http import parse_cache_control_header
|
||||
from jinja2 import TemplateNotFound
|
||||
|
||||
|
||||
# import moduleapp here because it uses deprecated features and we don't
|
||||
# want to see the warnings
|
||||
warnings.simplefilter('ignore', DeprecationWarning)
|
||||
from moduleapp import app as moduleapp
|
||||
warnings.simplefilter('default', DeprecationWarning)
|
||||
|
||||
|
||||
class ModuleTestCase(FlaskTestCase):
|
||||
|
||||
@emits_module_deprecation_warning
|
||||
def test_basic_module(self):
|
||||
app = flask.Flask(__name__)
|
||||
admin = flask.Module(__name__, 'admin', url_prefix='/admin')
|
||||
@admin.route('/')
|
||||
def admin_index():
|
||||
return 'admin index'
|
||||
@admin.route('/login')
|
||||
def admin_login():
|
||||
return 'admin login'
|
||||
@admin.route('/logout')
|
||||
def admin_logout():
|
||||
return 'admin logout'
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'the index'
|
||||
app.register_module(admin)
|
||||
c = app.test_client()
|
||||
self.assert_equal(c.get('/').data, b'the index')
|
||||
self.assert_equal(c.get('/admin/').data, b'admin index')
|
||||
self.assert_equal(c.get('/admin/login').data, b'admin login')
|
||||
self.assert_equal(c.get('/admin/logout').data, b'admin logout')
|
||||
|
||||
@emits_module_deprecation_warning
|
||||
def test_default_endpoint_name(self):
|
||||
app = flask.Flask(__name__)
|
||||
mod = flask.Module(__name__, 'frontend')
|
||||
def index():
|
||||
return 'Awesome'
|
||||
mod.add_url_rule('/', view_func=index)
|
||||
app.register_module(mod)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'Awesome')
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.url_for('frontend.index'), '/')
|
||||
|
||||
@emits_module_deprecation_warning
|
||||
def test_request_processing(self):
|
||||
catched = []
|
||||
app = flask.Flask(__name__)
|
||||
admin = flask.Module(__name__, 'admin', url_prefix='/admin')
|
||||
@admin.before_request
|
||||
def before_admin_request():
|
||||
catched.append('before-admin')
|
||||
@admin.after_request
|
||||
def after_admin_request(response):
|
||||
catched.append('after-admin')
|
||||
return response
|
||||
@admin.route('/')
|
||||
def admin_index():
|
||||
return 'the admin'
|
||||
@app.before_request
|
||||
def before_request():
|
||||
catched.append('before-app')
|
||||
@app.after_request
|
||||
def after_request(response):
|
||||
catched.append('after-app')
|
||||
return response
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'the index'
|
||||
app.register_module(admin)
|
||||
c = app.test_client()
|
||||
|
||||
self.assert_equal(c.get('/').data, b'the index')
|
||||
self.assert_equal(catched, ['before-app', 'after-app'])
|
||||
del catched[:]
|
||||
|
||||
self.assert_equal(c.get('/admin/').data, b'the admin')
|
||||
self.assert_equal(catched, ['before-app', 'before-admin',
|
||||
'after-admin', 'after-app'])
|
||||
|
||||
@emits_module_deprecation_warning
|
||||
def test_context_processors(self):
|
||||
app = flask.Flask(__name__)
|
||||
admin = flask.Module(__name__, 'admin', url_prefix='/admin')
|
||||
@app.context_processor
|
||||
def inject_all_regular():
|
||||
return {'a': 1}
|
||||
@admin.context_processor
|
||||
def inject_admin():
|
||||
return {'b': 2}
|
||||
@admin.app_context_processor
|
||||
def inject_all_module():
|
||||
return {'c': 3}
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template_string('{{ a }}{{ b }}{{ c }}')
|
||||
@admin.route('/')
|
||||
def admin_index():
|
||||
return flask.render_template_string('{{ a }}{{ b }}{{ c }}')
|
||||
app.register_module(admin)
|
||||
c = app.test_client()
|
||||
self.assert_equal(c.get('/').data, b'13')
|
||||
self.assert_equal(c.get('/admin/').data, b'123')
|
||||
|
||||
@emits_module_deprecation_warning
|
||||
def test_late_binding(self):
|
||||
app = flask.Flask(__name__)
|
||||
admin = flask.Module(__name__, 'admin')
|
||||
@admin.route('/')
|
||||
def index():
|
||||
return '42'
|
||||
app.register_module(admin, url_prefix='/admin')
|
||||
self.assert_equal(app.test_client().get('/admin/').data, b'42')
|
||||
|
||||
@emits_module_deprecation_warning
|
||||
def test_error_handling(self):
|
||||
app = flask.Flask(__name__)
|
||||
admin = flask.Module(__name__, 'admin')
|
||||
@admin.app_errorhandler(404)
|
||||
def not_found(e):
|
||||
return 'not found', 404
|
||||
@admin.app_errorhandler(500)
|
||||
def internal_server_error(e):
|
||||
return 'internal server error', 500
|
||||
@admin.route('/')
|
||||
def index():
|
||||
flask.abort(404)
|
||||
@admin.route('/error')
|
||||
def error():
|
||||
1 // 0
|
||||
app.register_module(admin)
|
||||
c = app.test_client()
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.status_code, 404)
|
||||
self.assert_equal(rv.data, b'not found')
|
||||
rv = c.get('/error')
|
||||
self.assert_equal(rv.status_code, 500)
|
||||
self.assert_equal(b'internal server error', rv.data)
|
||||
|
||||
def test_templates_and_static(self):
|
||||
app = moduleapp
|
||||
app.testing = True
|
||||
c = app.test_client()
|
||||
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'Hello from the Frontend')
|
||||
rv = c.get('/admin/')
|
||||
self.assert_equal(rv.data, b'Hello from the Admin')
|
||||
rv = c.get('/admin/index2')
|
||||
self.assert_equal(rv.data, b'Hello from the Admin')
|
||||
rv = c.get('/admin/static/test.txt')
|
||||
self.assert_equal(rv.data.strip(), b'Admin File')
|
||||
rv.close()
|
||||
rv = c.get('/admin/static/css/test.css')
|
||||
self.assert_equal(rv.data.strip(), b'/* nested file */')
|
||||
rv.close()
|
||||
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.url_for('admin.static', filename='test.txt'),
|
||||
'/admin/static/test.txt')
|
||||
|
||||
with app.test_request_context():
|
||||
try:
|
||||
flask.render_template('missing.html')
|
||||
except TemplateNotFound as e:
|
||||
self.assert_equal(e.name, 'missing.html')
|
||||
else:
|
||||
self.assert_true(0, 'expected exception')
|
||||
|
||||
with flask.Flask(__name__).test_request_context():
|
||||
self.assert_equal(flask.render_template('nested/nested.txt'), 'I\'m nested')
|
||||
|
||||
def test_safe_access(self):
|
||||
app = moduleapp
|
||||
|
||||
with app.test_request_context():
|
||||
f = app.view_functions['admin.static']
|
||||
|
||||
try:
|
||||
f('/etc/passwd')
|
||||
except NotFound:
|
||||
pass
|
||||
else:
|
||||
self.assert_true(0, 'expected exception')
|
||||
try:
|
||||
f('../__init__.py')
|
||||
except NotFound:
|
||||
pass
|
||||
else:
|
||||
self.assert_true(0, 'expected exception')
|
||||
|
||||
# testcase for a security issue that may exist on windows systems
|
||||
import os
|
||||
import ntpath
|
||||
old_path = os.path
|
||||
os.path = ntpath
|
||||
try:
|
||||
try:
|
||||
f('..\\__init__.py')
|
||||
except NotFound:
|
||||
pass
|
||||
else:
|
||||
self.assert_true(0, 'expected exception')
|
||||
finally:
|
||||
os.path = old_path
|
||||
|
||||
@emits_module_deprecation_warning
|
||||
def test_endpoint_decorator(self):
|
||||
from werkzeug.routing import Submount, Rule
|
||||
from flask import Module
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
app.url_map.add(Submount('/foo', [
|
||||
Rule('/bar', endpoint='bar'),
|
||||
Rule('/', endpoint='index')
|
||||
]))
|
||||
module = Module(__name__, __name__)
|
||||
|
||||
@module.endpoint('bar')
|
||||
def bar():
|
||||
return 'bar'
|
||||
|
||||
@module.endpoint('index')
|
||||
def index():
|
||||
return 'index'
|
||||
|
||||
app.register_module(module)
|
||||
|
||||
c = app.test_client()
|
||||
self.assert_equal(c.get('/foo/').data, b'index')
|
||||
self.assert_equal(c.get('/foo/bar').data, b'bar')
|
||||
|
||||
|
||||
class BlueprintTestCase(FlaskTestCase):
|
||||
|
||||
def test_blueprint_specific_error_handling(self):
|
||||
frontend = flask.Blueprint('frontend', __name__)
|
||||
backend = flask.Blueprint('backend', __name__)
|
||||
sideend = flask.Blueprint('sideend', __name__)
|
||||
|
||||
@frontend.errorhandler(403)
|
||||
def frontend_forbidden(e):
|
||||
return 'frontend says no', 403
|
||||
|
||||
@frontend.route('/frontend-no')
|
||||
def frontend_no():
|
||||
flask.abort(403)
|
||||
|
||||
@backend.errorhandler(403)
|
||||
def backend_forbidden(e):
|
||||
return 'backend says no', 403
|
||||
|
||||
@backend.route('/backend-no')
|
||||
def backend_no():
|
||||
flask.abort(403)
|
||||
|
||||
@sideend.route('/what-is-a-sideend')
|
||||
def sideend_no():
|
||||
flask.abort(403)
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(frontend)
|
||||
app.register_blueprint(backend)
|
||||
app.register_blueprint(sideend)
|
||||
|
||||
@app.errorhandler(403)
|
||||
def app_forbidden(e):
|
||||
return 'application itself says no', 403
|
||||
|
||||
c = app.test_client()
|
||||
|
||||
self.assert_equal(c.get('/frontend-no').data, b'frontend says no')
|
||||
self.assert_equal(c.get('/backend-no').data, b'backend says no')
|
||||
self.assert_equal(c.get('/what-is-a-sideend').data, b'application itself says no')
|
||||
|
||||
def test_blueprint_url_definitions(self):
|
||||
bp = flask.Blueprint('test', __name__)
|
||||
|
||||
@bp.route('/foo', defaults={'baz': 42})
|
||||
def foo(bar, baz):
|
||||
return '%s/%d' % (bar, baz)
|
||||
|
||||
@bp.route('/bar')
|
||||
def bar(bar):
|
||||
return text_type(bar)
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/1', url_defaults={'bar': 23})
|
||||
app.register_blueprint(bp, url_prefix='/2', url_defaults={'bar': 19})
|
||||
|
||||
c = app.test_client()
|
||||
self.assert_equal(c.get('/1/foo').data, b'23/42')
|
||||
self.assert_equal(c.get('/2/foo').data, b'19/42')
|
||||
self.assert_equal(c.get('/1/bar').data, b'23')
|
||||
self.assert_equal(c.get('/2/bar').data, b'19')
|
||||
|
||||
def test_blueprint_url_processors(self):
|
||||
bp = flask.Blueprint('frontend', __name__, url_prefix='/<lang_code>')
|
||||
|
||||
@bp.url_defaults
|
||||
def add_language_code(endpoint, values):
|
||||
values.setdefault('lang_code', flask.g.lang_code)
|
||||
|
||||
@bp.url_value_preprocessor
|
||||
def pull_lang_code(endpoint, values):
|
||||
flask.g.lang_code = values.pop('lang_code')
|
||||
|
||||
@bp.route('/')
|
||||
def index():
|
||||
return flask.url_for('.about')
|
||||
|
||||
@bp.route('/about')
|
||||
def about():
|
||||
return flask.url_for('.index')
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp)
|
||||
|
||||
c = app.test_client()
|
||||
|
||||
self.assert_equal(c.get('/de/').data, b'/de/about')
|
||||
self.assert_equal(c.get('/de/about').data, b'/de/')
|
||||
|
||||
def test_templates_and_static(self):
|
||||
from blueprintapp import app
|
||||
c = app.test_client()
|
||||
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'Hello from the Frontend')
|
||||
rv = c.get('/admin/')
|
||||
self.assert_equal(rv.data, b'Hello from the Admin')
|
||||
rv = c.get('/admin/index2')
|
||||
self.assert_equal(rv.data, b'Hello from the Admin')
|
||||
rv = c.get('/admin/static/test.txt')
|
||||
self.assert_equal(rv.data.strip(), b'Admin File')
|
||||
rv.close()
|
||||
rv = c.get('/admin/static/css/test.css')
|
||||
self.assert_equal(rv.data.strip(), b'/* nested file */')
|
||||
rv.close()
|
||||
|
||||
# try/finally, in case other tests use this app for Blueprint tests.
|
||||
max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT']
|
||||
try:
|
||||
expected_max_age = 3600
|
||||
if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age:
|
||||
expected_max_age = 7200
|
||||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age
|
||||
rv = c.get('/admin/static/css/test.css')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, expected_max_age)
|
||||
rv.close()
|
||||
finally:
|
||||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
|
||||
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.url_for('admin.static', filename='test.txt'),
|
||||
'/admin/static/test.txt')
|
||||
|
||||
with app.test_request_context():
|
||||
try:
|
||||
flask.render_template('missing.html')
|
||||
except TemplateNotFound as e:
|
||||
self.assert_equal(e.name, 'missing.html')
|
||||
else:
|
||||
self.assert_true(0, 'expected exception')
|
||||
|
||||
with flask.Flask(__name__).test_request_context():
|
||||
self.assert_equal(flask.render_template('nested/nested.txt'), 'I\'m nested')
|
||||
|
||||
def test_default_static_cache_timeout(self):
|
||||
app = flask.Flask(__name__)
|
||||
class MyBlueprint(flask.Blueprint):
|
||||
def get_send_file_max_age(self, filename):
|
||||
return 100
|
||||
|
||||
blueprint = MyBlueprint('blueprint', __name__, static_folder='static')
|
||||
app.register_blueprint(blueprint)
|
||||
|
||||
# try/finally, in case other tests use this app for Blueprint tests.
|
||||
max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT']
|
||||
try:
|
||||
with app.test_request_context():
|
||||
unexpected_max_age = 3600
|
||||
if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == unexpected_max_age:
|
||||
unexpected_max_age = 7200
|
||||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = unexpected_max_age
|
||||
rv = blueprint.send_static_file('index.html')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, 100)
|
||||
rv.close()
|
||||
finally:
|
||||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
|
||||
|
||||
def test_templates_list(self):
|
||||
from blueprintapp import app
|
||||
templates = sorted(app.jinja_env.list_templates())
|
||||
self.assert_equal(templates, ['admin/index.html',
|
||||
'frontend/index.html'])
|
||||
|
||||
def test_dotted_names(self):
|
||||
frontend = flask.Blueprint('myapp.frontend', __name__)
|
||||
backend = flask.Blueprint('myapp.backend', __name__)
|
||||
|
||||
@frontend.route('/fe')
|
||||
def frontend_index():
|
||||
return flask.url_for('myapp.backend.backend_index')
|
||||
|
||||
@frontend.route('/fe2')
|
||||
def frontend_page2():
|
||||
return flask.url_for('.frontend_index')
|
||||
|
||||
@backend.route('/be')
|
||||
def backend_index():
|
||||
return flask.url_for('myapp.frontend.frontend_index')
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(frontend)
|
||||
app.register_blueprint(backend)
|
||||
|
||||
c = app.test_client()
|
||||
self.assert_equal(c.get('/fe').data.strip(), b'/be')
|
||||
self.assert_equal(c.get('/fe2').data.strip(), b'/fe')
|
||||
self.assert_equal(c.get('/be').data.strip(), b'/fe')
|
||||
|
||||
def test_dotted_names_from_app(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
test = flask.Blueprint('test', __name__)
|
||||
|
||||
@app.route('/')
|
||||
def app_index():
|
||||
return flask.url_for('test.index')
|
||||
|
||||
@test.route('/test/')
|
||||
def index():
|
||||
return flask.url_for('app_index')
|
||||
|
||||
app.register_blueprint(test)
|
||||
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'/test/')
|
||||
|
||||
def test_empty_url_defaults(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
|
||||
@bp.route('/', defaults={'page': 1})
|
||||
@bp.route('/page/<int:page>')
|
||||
def something(page):
|
||||
return str(page)
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp)
|
||||
|
||||
c = app.test_client()
|
||||
self.assert_equal(c.get('/').data, b'1')
|
||||
self.assert_equal(c.get('/page/2').data, b'2')
|
||||
|
||||
def test_route_decorator_custom_endpoint(self):
|
||||
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
|
||||
@bp.route('/foo')
|
||||
def foo():
|
||||
return flask.request.endpoint
|
||||
|
||||
@bp.route('/bar', endpoint='bar')
|
||||
def foo_bar():
|
||||
return flask.request.endpoint
|
||||
|
||||
@bp.route('/bar/123', endpoint='123')
|
||||
def foo_bar_foo():
|
||||
return flask.request.endpoint
|
||||
|
||||
@bp.route('/bar/foo')
|
||||
def bar_foo():
|
||||
return flask.request.endpoint
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.request.endpoint
|
||||
|
||||
c = app.test_client()
|
||||
self.assertEqual(c.get('/').data, b'index')
|
||||
self.assertEqual(c.get('/py/foo').data, b'bp.foo')
|
||||
self.assertEqual(c.get('/py/bar').data, b'bp.bar')
|
||||
self.assertEqual(c.get('/py/bar/123').data, b'bp.123')
|
||||
self.assertEqual(c.get('/py/bar/foo').data, b'bp.bar_foo')
|
||||
|
||||
def test_route_decorator_custom_endpoint_with_dots(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
|
||||
@bp.route('/foo')
|
||||
def foo():
|
||||
return flask.request.endpoint
|
||||
|
||||
try:
|
||||
@bp.route('/bar', endpoint='bar.bar')
|
||||
def foo_bar():
|
||||
return flask.request.endpoint
|
||||
except AssertionError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError('expected AssertionError not raised')
|
||||
|
||||
try:
|
||||
@bp.route('/bar/123', endpoint='bar.123')
|
||||
def foo_bar_foo():
|
||||
return flask.request.endpoint
|
||||
except AssertionError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError('expected AssertionError not raised')
|
||||
|
||||
def foo_foo_foo():
|
||||
pass
|
||||
|
||||
self.assertRaises(
|
||||
AssertionError,
|
||||
lambda: bp.add_url_rule(
|
||||
'/bar/123', endpoint='bar.123', view_func=foo_foo_foo
|
||||
)
|
||||
)
|
||||
|
||||
self.assertRaises(
|
||||
AssertionError,
|
||||
bp.route('/bar/123', endpoint='bar.123'),
|
||||
lambda: None
|
||||
)
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
|
||||
c = app.test_client()
|
||||
self.assertEqual(c.get('/py/foo').data, b'bp.foo')
|
||||
# The rule's didn't actually made it through
|
||||
rv = c.get('/py/bar')
|
||||
assert rv.status_code == 404
|
||||
rv = c.get('/py/bar/123')
|
||||
assert rv.status_code == 404
|
||||
|
||||
def test_template_filter(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_filter()
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('my_reverse', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
|
||||
|
||||
def test_add_template_filter(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
bp.add_app_template_filter(my_reverse)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('my_reverse', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
|
||||
|
||||
def test_template_filter_with_name(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_filter('strrev')
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('strrev', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
|
||||
|
||||
def test_add_template_filter_with_name(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
bp.add_app_template_filter(my_reverse, 'strrev')
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('strrev', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
|
||||
|
||||
def test_template_filter_with_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_filter()
|
||||
def super_reverse(s):
|
||||
return s[::-1]
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_template_filter_after_route_with_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_filter()
|
||||
def super_reverse(s):
|
||||
return s[::-1]
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_add_template_filter_with_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def super_reverse(s):
|
||||
return s[::-1]
|
||||
bp.add_app_template_filter(super_reverse)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_template_filter_with_name_and_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_filter('super_reverse')
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_add_template_filter_with_name_and_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
bp.add_app_template_filter(my_reverse, 'super_reverse')
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_template_test(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_test()
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('is_boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean)
|
||||
self.assert_true(app.jinja_env.tests['is_boolean'](False))
|
||||
|
||||
def test_add_template_test(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
bp.add_app_template_test(is_boolean)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('is_boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean)
|
||||
self.assert_true(app.jinja_env.tests['is_boolean'](False))
|
||||
|
||||
def test_template_test_with_name(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_test('boolean')
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
|
||||
self.assert_true(app.jinja_env.tests['boolean'](False))
|
||||
|
||||
def test_add_template_test_with_name(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
bp.add_app_template_test(is_boolean, 'boolean')
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
self.assert_in('boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
|
||||
self.assert_true(app.jinja_env.tests['boolean'](False))
|
||||
|
||||
def test_template_test_with_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_test()
|
||||
def boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_template_test_after_route_with_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_test()
|
||||
def boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_add_template_test_with_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def boolean(value):
|
||||
return isinstance(value, bool)
|
||||
bp.add_app_template_test(boolean)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_template_test_with_name_and_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
@bp.app_template_test('boolean')
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_add_template_test_with_name_and_template(self):
|
||||
bp = flask.Blueprint('bp', __name__)
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
bp.add_app_template_test(is_boolean, 'boolean')
|
||||
app = flask.Flask(__name__)
|
||||
app.register_blueprint(bp, url_prefix='/py')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(BlueprintTestCase))
|
||||
suite.addTest(unittest.makeSuite(ModuleTestCase))
|
||||
return suite
|
||||
299
vendor/flask/testsuite/config.py
vendored
299
vendor/flask/testsuite/config.py
vendored
@@ -1,299 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.config
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Configuration and instances.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import flask
|
||||
import pkgutil
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
from flask.testsuite import FlaskTestCase
|
||||
|
||||
|
||||
# config keys used for the ConfigTestCase
|
||||
TEST_KEY = 'foo'
|
||||
SECRET_KEY = 'devkey'
|
||||
|
||||
|
||||
class ConfigTestCase(FlaskTestCase):
|
||||
|
||||
def common_object_test(self, app):
|
||||
self.assert_equal(app.secret_key, 'devkey')
|
||||
self.assert_equal(app.config['TEST_KEY'], 'foo')
|
||||
self.assert_not_in('ConfigTestCase', app.config)
|
||||
|
||||
def test_config_from_file(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.config.from_pyfile(__file__.rsplit('.', 1)[0] + '.py')
|
||||
self.common_object_test(app)
|
||||
|
||||
def test_config_from_object(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.config.from_object(__name__)
|
||||
self.common_object_test(app)
|
||||
|
||||
def test_config_from_class(self):
|
||||
class Base(object):
|
||||
TEST_KEY = 'foo'
|
||||
class Test(Base):
|
||||
SECRET_KEY = 'devkey'
|
||||
app = flask.Flask(__name__)
|
||||
app.config.from_object(Test)
|
||||
self.common_object_test(app)
|
||||
|
||||
def test_config_from_envvar(self):
|
||||
env = os.environ
|
||||
try:
|
||||
os.environ = {}
|
||||
app = flask.Flask(__name__)
|
||||
try:
|
||||
app.config.from_envvar('FOO_SETTINGS')
|
||||
except RuntimeError as e:
|
||||
self.assert_true("'FOO_SETTINGS' is not set" in str(e))
|
||||
else:
|
||||
self.assert_true(0, 'expected exception')
|
||||
self.assert_false(app.config.from_envvar('FOO_SETTINGS', silent=True))
|
||||
|
||||
os.environ = {'FOO_SETTINGS': __file__.rsplit('.', 1)[0] + '.py'}
|
||||
self.assert_true(app.config.from_envvar('FOO_SETTINGS'))
|
||||
self.common_object_test(app)
|
||||
finally:
|
||||
os.environ = env
|
||||
|
||||
def test_config_from_envvar_missing(self):
|
||||
env = os.environ
|
||||
try:
|
||||
os.environ = {'FOO_SETTINGS': 'missing.cfg'}
|
||||
try:
|
||||
app = flask.Flask(__name__)
|
||||
app.config.from_envvar('FOO_SETTINGS')
|
||||
except IOError as e:
|
||||
msg = str(e)
|
||||
self.assert_true(msg.startswith('[Errno 2] Unable to load configuration '
|
||||
'file (No such file or directory):'))
|
||||
self.assert_true(msg.endswith("missing.cfg'"))
|
||||
else:
|
||||
self.fail('expected IOError')
|
||||
self.assertFalse(app.config.from_envvar('FOO_SETTINGS', silent=True))
|
||||
finally:
|
||||
os.environ = env
|
||||
|
||||
def test_config_missing(self):
|
||||
app = flask.Flask(__name__)
|
||||
try:
|
||||
app.config.from_pyfile('missing.cfg')
|
||||
except IOError as e:
|
||||
msg = str(e)
|
||||
self.assert_true(msg.startswith('[Errno 2] Unable to load configuration '
|
||||
'file (No such file or directory):'))
|
||||
self.assert_true(msg.endswith("missing.cfg'"))
|
||||
else:
|
||||
self.assert_true(0, 'expected config')
|
||||
self.assert_false(app.config.from_pyfile('missing.cfg', silent=True))
|
||||
|
||||
def test_session_lifetime(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.config['PERMANENT_SESSION_LIFETIME'] = 42
|
||||
self.assert_equal(app.permanent_session_lifetime.seconds, 42)
|
||||
|
||||
|
||||
class LimitedLoaderMockWrapper(object):
|
||||
def __init__(self, loader):
|
||||
self.loader = loader
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name in ('archive', 'get_filename'):
|
||||
msg = 'Mocking a loader which does not have `%s.`' % name
|
||||
raise AttributeError(msg)
|
||||
return getattr(self.loader, name)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def patch_pkgutil_get_loader(wrapper_class=LimitedLoaderMockWrapper):
|
||||
"""Patch pkgutil.get_loader to give loader without get_filename or archive.
|
||||
|
||||
This provides for tests where a system has custom loaders, e.g. Google App
|
||||
Engine's HardenedModulesHook, which have neither the `get_filename` method
|
||||
nor the `archive` attribute.
|
||||
"""
|
||||
old_get_loader = pkgutil.get_loader
|
||||
def get_loader(*args, **kwargs):
|
||||
return wrapper_class(old_get_loader(*args, **kwargs))
|
||||
try:
|
||||
pkgutil.get_loader = get_loader
|
||||
yield
|
||||
finally:
|
||||
pkgutil.get_loader = old_get_loader
|
||||
|
||||
|
||||
class InstanceTestCase(FlaskTestCase):
|
||||
|
||||
def test_explicit_instance_paths(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
try:
|
||||
flask.Flask(__name__, instance_path='instance')
|
||||
except ValueError as e:
|
||||
self.assert_in('must be absolute', str(e))
|
||||
else:
|
||||
self.fail('Expected value error')
|
||||
|
||||
app = flask.Flask(__name__, instance_path=here)
|
||||
self.assert_equal(app.instance_path, here)
|
||||
|
||||
def test_main_module_paths(self):
|
||||
# Test an app with '__main__' as the import name, uses cwd.
|
||||
from main_app import app
|
||||
here = os.path.abspath(os.getcwd())
|
||||
self.assert_equal(app.instance_path, os.path.join(here, 'instance'))
|
||||
if 'main_app' in sys.modules:
|
||||
del sys.modules['main_app']
|
||||
|
||||
def test_uninstalled_module_paths(self):
|
||||
from config_module_app import app
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
self.assert_equal(app.instance_path, os.path.join(here, 'test_apps', 'instance'))
|
||||
|
||||
def test_uninstalled_package_paths(self):
|
||||
from config_package_app import app
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
self.assert_equal(app.instance_path, os.path.join(here, 'test_apps', 'instance'))
|
||||
|
||||
def test_installed_module_paths(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
expected_prefix = os.path.join(here, 'test_apps')
|
||||
real_prefix, sys.prefix = sys.prefix, expected_prefix
|
||||
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
|
||||
sys.path.append(site_packages)
|
||||
try:
|
||||
import site_app
|
||||
self.assert_equal(site_app.app.instance_path,
|
||||
os.path.join(expected_prefix, 'var',
|
||||
'site_app-instance'))
|
||||
finally:
|
||||
sys.prefix = real_prefix
|
||||
sys.path.remove(site_packages)
|
||||
if 'site_app' in sys.modules:
|
||||
del sys.modules['site_app']
|
||||
|
||||
def test_installed_module_paths_with_limited_loader(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
expected_prefix = os.path.join(here, 'test_apps')
|
||||
real_prefix, sys.prefix = sys.prefix, expected_prefix
|
||||
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
|
||||
sys.path.append(site_packages)
|
||||
with patch_pkgutil_get_loader():
|
||||
try:
|
||||
import site_app
|
||||
self.assert_equal(site_app.app.instance_path,
|
||||
os.path.join(expected_prefix, 'var',
|
||||
'site_app-instance'))
|
||||
finally:
|
||||
sys.prefix = real_prefix
|
||||
sys.path.remove(site_packages)
|
||||
if 'site_app' in sys.modules:
|
||||
del sys.modules['site_app']
|
||||
|
||||
def test_installed_package_paths(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
expected_prefix = os.path.join(here, 'test_apps')
|
||||
real_prefix, sys.prefix = sys.prefix, expected_prefix
|
||||
installed_path = os.path.join(expected_prefix, 'path')
|
||||
sys.path.append(installed_path)
|
||||
try:
|
||||
import installed_package
|
||||
self.assert_equal(installed_package.app.instance_path,
|
||||
os.path.join(expected_prefix, 'var',
|
||||
'installed_package-instance'))
|
||||
finally:
|
||||
sys.prefix = real_prefix
|
||||
sys.path.remove(installed_path)
|
||||
if 'installed_package' in sys.modules:
|
||||
del sys.modules['installed_package']
|
||||
|
||||
def test_installed_package_paths_with_limited_loader(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
expected_prefix = os.path.join(here, 'test_apps')
|
||||
real_prefix, sys.prefix = sys.prefix, expected_prefix
|
||||
installed_path = os.path.join(expected_prefix, 'path')
|
||||
sys.path.append(installed_path)
|
||||
with patch_pkgutil_get_loader():
|
||||
try:
|
||||
import installed_package
|
||||
self.assert_equal(installed_package.app.instance_path,
|
||||
os.path.join(expected_prefix, 'var',
|
||||
'installed_package-instance'))
|
||||
finally:
|
||||
sys.prefix = real_prefix
|
||||
sys.path.remove(installed_path)
|
||||
if 'installed_package' in sys.modules:
|
||||
del sys.modules['installed_package']
|
||||
|
||||
def test_prefix_package_paths(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
expected_prefix = os.path.join(here, 'test_apps')
|
||||
real_prefix, sys.prefix = sys.prefix, expected_prefix
|
||||
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
|
||||
sys.path.append(site_packages)
|
||||
try:
|
||||
import site_package
|
||||
self.assert_equal(site_package.app.instance_path,
|
||||
os.path.join(expected_prefix, 'var',
|
||||
'site_package-instance'))
|
||||
finally:
|
||||
sys.prefix = real_prefix
|
||||
sys.path.remove(site_packages)
|
||||
if 'site_package' in sys.modules:
|
||||
del sys.modules['site_package']
|
||||
|
||||
def test_prefix_package_paths_with_limited_loader(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
expected_prefix = os.path.join(here, 'test_apps')
|
||||
real_prefix, sys.prefix = sys.prefix, expected_prefix
|
||||
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
|
||||
sys.path.append(site_packages)
|
||||
with patch_pkgutil_get_loader():
|
||||
try:
|
||||
import site_package
|
||||
self.assert_equal(site_package.app.instance_path,
|
||||
os.path.join(expected_prefix, 'var',
|
||||
'site_package-instance'))
|
||||
finally:
|
||||
sys.prefix = real_prefix
|
||||
sys.path.remove(site_packages)
|
||||
if 'site_package' in sys.modules:
|
||||
del sys.modules['site_package']
|
||||
|
||||
def test_egg_installed_paths(self):
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
expected_prefix = os.path.join(here, 'test_apps')
|
||||
real_prefix, sys.prefix = sys.prefix, expected_prefix
|
||||
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
|
||||
egg_path = os.path.join(site_packages, 'SiteEgg.egg')
|
||||
sys.path.append(site_packages)
|
||||
sys.path.append(egg_path)
|
||||
try:
|
||||
import site_egg # in SiteEgg.egg
|
||||
self.assert_equal(site_egg.app.instance_path,
|
||||
os.path.join(expected_prefix, 'var',
|
||||
'site_egg-instance'))
|
||||
finally:
|
||||
sys.prefix = real_prefix
|
||||
sys.path.remove(site_packages)
|
||||
sys.path.remove(egg_path)
|
||||
if 'site_egg' in sys.modules:
|
||||
del sys.modules['site_egg']
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(ConfigTestCase))
|
||||
suite.addTest(unittest.makeSuite(InstanceTestCase))
|
||||
return suite
|
||||
24
vendor/flask/testsuite/deprecations.py
vendored
24
vendor/flask/testsuite/deprecations.py
vendored
@@ -1,24 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.deprecations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests deprecation support.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import unittest
|
||||
from flask.testsuite import FlaskTestCase, catch_warnings
|
||||
|
||||
|
||||
class DeprecationsTestCase(FlaskTestCase):
|
||||
"""not used currently"""
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(DeprecationsTestCase))
|
||||
return suite
|
||||
38
vendor/flask/testsuite/examples.py
vendored
38
vendor/flask/testsuite/examples.py
vendored
@@ -1,38 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.examples
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the examples.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import os
|
||||
import unittest
|
||||
from flask.testsuite import add_to_path
|
||||
|
||||
|
||||
def setup_path():
|
||||
example_path = os.path.join(os.path.dirname(__file__),
|
||||
os.pardir, os.pardir, 'examples')
|
||||
add_to_path(os.path.join(example_path, 'flaskr'))
|
||||
add_to_path(os.path.join(example_path, 'minitwit'))
|
||||
|
||||
|
||||
def suite():
|
||||
setup_path()
|
||||
suite = unittest.TestSuite()
|
||||
try:
|
||||
from minitwit_tests import MiniTwitTestCase
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
suite.addTest(unittest.makeSuite(MiniTwitTestCase))
|
||||
try:
|
||||
from flaskr_tests import FlaskrTestCase
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
suite.addTest(unittest.makeSuite(FlaskrTestCase))
|
||||
return suite
|
||||
134
vendor/flask/testsuite/ext.py
vendored
134
vendor/flask/testsuite/ext.py
vendored
@@ -1,134 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.ext
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the extension import thing.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
try:
|
||||
from imp import reload as reload_module
|
||||
except ImportError:
|
||||
reload_module = reload
|
||||
from flask.testsuite import FlaskTestCase
|
||||
from flask._compat import PY2
|
||||
|
||||
class ExtImportHookTestCase(FlaskTestCase):
|
||||
|
||||
def setup(self):
|
||||
# we clear this out for various reasons. The most important one is
|
||||
# that a real flaskext could be in there which would disable our
|
||||
# fake package. Secondly we want to make sure that the flaskext
|
||||
# import hook does not break on reloading.
|
||||
for entry, value in list(sys.modules.items()):
|
||||
if (entry.startswith('flask.ext.') or
|
||||
entry.startswith('flask_') or
|
||||
entry.startswith('flaskext.') or
|
||||
entry == 'flaskext') and value is not None:
|
||||
sys.modules.pop(entry, None)
|
||||
from flask import ext
|
||||
reload_module(ext)
|
||||
|
||||
# reloading must not add more hooks
|
||||
import_hooks = 0
|
||||
for item in sys.meta_path:
|
||||
cls = type(item)
|
||||
if cls.__module__ == 'flask.exthook' and \
|
||||
cls.__name__ == 'ExtensionImporter':
|
||||
import_hooks += 1
|
||||
self.assert_equal(import_hooks, 1)
|
||||
|
||||
def teardown(self):
|
||||
from flask import ext
|
||||
for key in ext.__dict__:
|
||||
self.assert_not_in('.', key)
|
||||
|
||||
def test_flaskext_new_simple_import_normal(self):
|
||||
from flask.ext.newext_simple import ext_id
|
||||
self.assert_equal(ext_id, 'newext_simple')
|
||||
|
||||
def test_flaskext_new_simple_import_module(self):
|
||||
from flask.ext import newext_simple
|
||||
self.assert_equal(newext_simple.ext_id, 'newext_simple')
|
||||
self.assert_equal(newext_simple.__name__, 'flask_newext_simple')
|
||||
|
||||
def test_flaskext_new_package_import_normal(self):
|
||||
from flask.ext.newext_package import ext_id
|
||||
self.assert_equal(ext_id, 'newext_package')
|
||||
|
||||
def test_flaskext_new_package_import_module(self):
|
||||
from flask.ext import newext_package
|
||||
self.assert_equal(newext_package.ext_id, 'newext_package')
|
||||
self.assert_equal(newext_package.__name__, 'flask_newext_package')
|
||||
|
||||
def test_flaskext_new_package_import_submodule_function(self):
|
||||
from flask.ext.newext_package.submodule import test_function
|
||||
self.assert_equal(test_function(), 42)
|
||||
|
||||
def test_flaskext_new_package_import_submodule(self):
|
||||
from flask.ext.newext_package import submodule
|
||||
self.assert_equal(submodule.__name__, 'flask_newext_package.submodule')
|
||||
self.assert_equal(submodule.test_function(), 42)
|
||||
|
||||
def test_flaskext_old_simple_import_normal(self):
|
||||
from flask.ext.oldext_simple import ext_id
|
||||
self.assert_equal(ext_id, 'oldext_simple')
|
||||
|
||||
def test_flaskext_old_simple_import_module(self):
|
||||
from flask.ext import oldext_simple
|
||||
self.assert_equal(oldext_simple.ext_id, 'oldext_simple')
|
||||
self.assert_equal(oldext_simple.__name__, 'flaskext.oldext_simple')
|
||||
|
||||
def test_flaskext_old_package_import_normal(self):
|
||||
from flask.ext.oldext_package import ext_id
|
||||
self.assert_equal(ext_id, 'oldext_package')
|
||||
|
||||
def test_flaskext_old_package_import_module(self):
|
||||
from flask.ext import oldext_package
|
||||
self.assert_equal(oldext_package.ext_id, 'oldext_package')
|
||||
self.assert_equal(oldext_package.__name__, 'flaskext.oldext_package')
|
||||
|
||||
def test_flaskext_old_package_import_submodule(self):
|
||||
from flask.ext.oldext_package import submodule
|
||||
self.assert_equal(submodule.__name__, 'flaskext.oldext_package.submodule')
|
||||
self.assert_equal(submodule.test_function(), 42)
|
||||
|
||||
def test_flaskext_old_package_import_submodule_function(self):
|
||||
from flask.ext.oldext_package.submodule import test_function
|
||||
self.assert_equal(test_function(), 42)
|
||||
|
||||
def test_flaskext_broken_package_no_module_caching(self):
|
||||
for x in range(2):
|
||||
with self.assert_raises(ImportError):
|
||||
import flask.ext.broken
|
||||
|
||||
def test_no_error_swallowing(self):
|
||||
try:
|
||||
import flask.ext.broken
|
||||
except ImportError:
|
||||
exc_type, exc_value, tb = sys.exc_info()
|
||||
self.assert_true(exc_type is ImportError)
|
||||
if PY2:
|
||||
message = 'No module named missing_module'
|
||||
else:
|
||||
message = 'No module named \'missing_module\''
|
||||
self.assert_equal(str(exc_value), message)
|
||||
self.assert_true(tb.tb_frame.f_globals is globals())
|
||||
|
||||
# reraise() adds a second frame so we need to skip that one too.
|
||||
# On PY3 we even have another one :(
|
||||
next = tb.tb_next.tb_next
|
||||
if not PY2:
|
||||
next = next.tb_next
|
||||
self.assert_in('flask_broken/__init__.py', next.tb_frame.f_code.co_filename)
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(ExtImportHookTestCase))
|
||||
return suite
|
||||
587
vendor/flask/testsuite/helpers.py
vendored
587
vendor/flask/testsuite/helpers.py
vendored
@@ -1,587 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.helpers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Various helpers.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import flask
|
||||
import unittest
|
||||
from logging import StreamHandler
|
||||
from flask.testsuite import FlaskTestCase, catch_warnings, catch_stderr
|
||||
from werkzeug.http import parse_cache_control_header, parse_options_header
|
||||
from flask._compat import StringIO, text_type
|
||||
|
||||
|
||||
def has_encoding(name):
|
||||
try:
|
||||
import codecs
|
||||
codecs.lookup(name)
|
||||
return True
|
||||
except LookupError:
|
||||
return False
|
||||
|
||||
|
||||
class JSONTestCase(FlaskTestCase):
|
||||
|
||||
def test_json_bad_requests(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/json', methods=['POST'])
|
||||
def return_json():
|
||||
return flask.jsonify(foo=text_type(flask.request.get_json()))
|
||||
c = app.test_client()
|
||||
rv = c.post('/json', data='malformed', content_type='application/json')
|
||||
self.assert_equal(rv.status_code, 400)
|
||||
|
||||
def test_json_body_encoding(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.request.get_json()
|
||||
|
||||
c = app.test_client()
|
||||
resp = c.get('/', data=u'"Hällo Wörld"'.encode('iso-8859-15'),
|
||||
content_type='application/json; charset=iso-8859-15')
|
||||
self.assert_equal(resp.data, u'Hällo Wörld'.encode('utf-8'))
|
||||
|
||||
def test_jsonify(self):
|
||||
d = dict(a=23, b=42, c=[1, 2, 3])
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/kw')
|
||||
def return_kwargs():
|
||||
return flask.jsonify(**d)
|
||||
@app.route('/dict')
|
||||
def return_dict():
|
||||
return flask.jsonify(d)
|
||||
c = app.test_client()
|
||||
for url in '/kw', '/dict':
|
||||
rv = c.get(url)
|
||||
self.assert_equal(rv.mimetype, 'application/json')
|
||||
self.assert_equal(flask.json.loads(rv.data), d)
|
||||
|
||||
def test_json_as_unicode(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
app.config['JSON_AS_ASCII'] = True
|
||||
with app.app_context():
|
||||
rv = flask.json.dumps(u'\N{SNOWMAN}')
|
||||
self.assert_equal(rv, '"\\u2603"')
|
||||
|
||||
app.config['JSON_AS_ASCII'] = False
|
||||
with app.app_context():
|
||||
rv = flask.json.dumps(u'\N{SNOWMAN}')
|
||||
self.assert_equal(rv, u'"\u2603"')
|
||||
|
||||
def test_json_attr(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/add', methods=['POST'])
|
||||
def add():
|
||||
json = flask.request.get_json()
|
||||
return text_type(json['a'] + json['b'])
|
||||
c = app.test_client()
|
||||
rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}),
|
||||
content_type='application/json')
|
||||
self.assert_equal(rv.data, b'3')
|
||||
|
||||
def test_template_escaping(self):
|
||||
app = flask.Flask(__name__)
|
||||
render = flask.render_template_string
|
||||
with app.test_request_context():
|
||||
rv = flask.json.htmlsafe_dumps('</script>')
|
||||
self.assert_equal(rv, u'"\\u003c/script\\u003e"')
|
||||
self.assert_equal(type(rv), text_type)
|
||||
rv = render('{{ "</script>"|tojson }}')
|
||||
self.assert_equal(rv, '"\\u003c/script\\u003e"')
|
||||
rv = render('{{ "<\0/script>"|tojson }}')
|
||||
self.assert_equal(rv, '"\\u003c\\u0000/script\\u003e"')
|
||||
rv = render('{{ "<!--<script>"|tojson }}')
|
||||
self.assert_equal(rv, '"\\u003c!--\\u003cscript\\u003e"')
|
||||
rv = render('{{ "&"|tojson }}')
|
||||
self.assert_equal(rv, '"\\u0026"')
|
||||
|
||||
def test_json_customization(self):
|
||||
class X(object):
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
class MyEncoder(flask.json.JSONEncoder):
|
||||
def default(self, o):
|
||||
if isinstance(o, X):
|
||||
return '<%d>' % o.val
|
||||
return flask.json.JSONEncoder.default(self, o)
|
||||
class MyDecoder(flask.json.JSONDecoder):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('object_hook', self.object_hook)
|
||||
flask.json.JSONDecoder.__init__(self, *args, **kwargs)
|
||||
def object_hook(self, obj):
|
||||
if len(obj) == 1 and '_foo' in obj:
|
||||
return X(obj['_foo'])
|
||||
return obj
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
app.json_encoder = MyEncoder
|
||||
app.json_decoder = MyDecoder
|
||||
@app.route('/', methods=['POST'])
|
||||
def index():
|
||||
return flask.json.dumps(flask.request.get_json()['x'])
|
||||
c = app.test_client()
|
||||
rv = c.post('/', data=flask.json.dumps({
|
||||
'x': {'_foo': 42}
|
||||
}), content_type='application/json')
|
||||
self.assertEqual(rv.data, b'"<42>"')
|
||||
|
||||
def test_modified_url_encoding(self):
|
||||
class ModifiedRequest(flask.Request):
|
||||
url_charset = 'euc-kr'
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
app.request_class = ModifiedRequest
|
||||
app.url_map.charset = 'euc-kr'
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.request.args['foo']
|
||||
|
||||
rv = app.test_client().get(u'/?foo=정상처리'.encode('euc-kr'))
|
||||
self.assert_equal(rv.status_code, 200)
|
||||
self.assert_equal(rv.data, u'정상처리'.encode('utf-8'))
|
||||
|
||||
if not has_encoding('euc-kr'):
|
||||
test_modified_url_encoding = None
|
||||
|
||||
def test_json_key_sorting(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
self.assert_equal(app.config['JSON_SORT_KEYS'], True)
|
||||
d = dict.fromkeys(range(20), 'foo')
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.jsonify(values=d)
|
||||
|
||||
c = app.test_client()
|
||||
rv = c.get('/')
|
||||
lines = [x.strip() for x in rv.data.strip().decode('utf-8').splitlines()]
|
||||
self.assert_equal(lines, [
|
||||
'{',
|
||||
'"values": {',
|
||||
'"0": "foo",',
|
||||
'"1": "foo",',
|
||||
'"2": "foo",',
|
||||
'"3": "foo",',
|
||||
'"4": "foo",',
|
||||
'"5": "foo",',
|
||||
'"6": "foo",',
|
||||
'"7": "foo",',
|
||||
'"8": "foo",',
|
||||
'"9": "foo",',
|
||||
'"10": "foo",',
|
||||
'"11": "foo",',
|
||||
'"12": "foo",',
|
||||
'"13": "foo",',
|
||||
'"14": "foo",',
|
||||
'"15": "foo",',
|
||||
'"16": "foo",',
|
||||
'"17": "foo",',
|
||||
'"18": "foo",',
|
||||
'"19": "foo"',
|
||||
'}',
|
||||
'}'
|
||||
])
|
||||
|
||||
|
||||
class SendfileTestCase(FlaskTestCase):
|
||||
|
||||
def test_send_file_regular(self):
|
||||
app = flask.Flask(__name__)
|
||||
with app.test_request_context():
|
||||
rv = flask.send_file('static/index.html')
|
||||
self.assert_true(rv.direct_passthrough)
|
||||
self.assert_equal(rv.mimetype, 'text/html')
|
||||
with app.open_resource('static/index.html') as f:
|
||||
rv.direct_passthrough = False
|
||||
self.assert_equal(rv.data, f.read())
|
||||
rv.close()
|
||||
|
||||
def test_send_file_xsendfile(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.use_x_sendfile = True
|
||||
with app.test_request_context():
|
||||
rv = flask.send_file('static/index.html')
|
||||
self.assert_true(rv.direct_passthrough)
|
||||
self.assert_in('x-sendfile', rv.headers)
|
||||
self.assert_equal(rv.headers['x-sendfile'],
|
||||
os.path.join(app.root_path, 'static/index.html'))
|
||||
self.assert_equal(rv.mimetype, 'text/html')
|
||||
rv.close()
|
||||
|
||||
def test_send_file_object(self):
|
||||
app = flask.Flask(__name__)
|
||||
with catch_warnings() as captured:
|
||||
with app.test_request_context():
|
||||
f = open(os.path.join(app.root_path, 'static/index.html'))
|
||||
rv = flask.send_file(f)
|
||||
rv.direct_passthrough = False
|
||||
with app.open_resource('static/index.html') as f:
|
||||
self.assert_equal(rv.data, f.read())
|
||||
self.assert_equal(rv.mimetype, 'text/html')
|
||||
rv.close()
|
||||
# mimetypes + etag
|
||||
self.assert_equal(len(captured), 2)
|
||||
|
||||
app.use_x_sendfile = True
|
||||
with catch_warnings() as captured:
|
||||
with app.test_request_context():
|
||||
f = open(os.path.join(app.root_path, 'static/index.html'))
|
||||
rv = flask.send_file(f)
|
||||
self.assert_equal(rv.mimetype, 'text/html')
|
||||
self.assert_in('x-sendfile', rv.headers)
|
||||
self.assert_equal(rv.headers['x-sendfile'],
|
||||
os.path.join(app.root_path, 'static/index.html'))
|
||||
rv.close()
|
||||
# mimetypes + etag
|
||||
self.assert_equal(len(captured), 2)
|
||||
|
||||
app.use_x_sendfile = False
|
||||
with app.test_request_context():
|
||||
with catch_warnings() as captured:
|
||||
f = StringIO('Test')
|
||||
rv = flask.send_file(f)
|
||||
rv.direct_passthrough = False
|
||||
self.assert_equal(rv.data, b'Test')
|
||||
self.assert_equal(rv.mimetype, 'application/octet-stream')
|
||||
rv.close()
|
||||
# etags
|
||||
self.assert_equal(len(captured), 1)
|
||||
with catch_warnings() as captured:
|
||||
f = StringIO('Test')
|
||||
rv = flask.send_file(f, mimetype='text/plain')
|
||||
rv.direct_passthrough = False
|
||||
self.assert_equal(rv.data, b'Test')
|
||||
self.assert_equal(rv.mimetype, 'text/plain')
|
||||
rv.close()
|
||||
# etags
|
||||
self.assert_equal(len(captured), 1)
|
||||
|
||||
app.use_x_sendfile = True
|
||||
with catch_warnings() as captured:
|
||||
with app.test_request_context():
|
||||
f = StringIO('Test')
|
||||
rv = flask.send_file(f)
|
||||
self.assert_not_in('x-sendfile', rv.headers)
|
||||
rv.close()
|
||||
# etags
|
||||
self.assert_equal(len(captured), 1)
|
||||
|
||||
def test_attachment(self):
|
||||
app = flask.Flask(__name__)
|
||||
with catch_warnings() as captured:
|
||||
with app.test_request_context():
|
||||
f = open(os.path.join(app.root_path, 'static/index.html'))
|
||||
rv = flask.send_file(f, as_attachment=True)
|
||||
value, options = parse_options_header(rv.headers['Content-Disposition'])
|
||||
self.assert_equal(value, 'attachment')
|
||||
rv.close()
|
||||
# mimetypes + etag
|
||||
self.assert_equal(len(captured), 2)
|
||||
|
||||
with app.test_request_context():
|
||||
self.assert_equal(options['filename'], 'index.html')
|
||||
rv = flask.send_file('static/index.html', as_attachment=True)
|
||||
value, options = parse_options_header(rv.headers['Content-Disposition'])
|
||||
self.assert_equal(value, 'attachment')
|
||||
self.assert_equal(options['filename'], 'index.html')
|
||||
rv.close()
|
||||
|
||||
with app.test_request_context():
|
||||
rv = flask.send_file(StringIO('Test'), as_attachment=True,
|
||||
attachment_filename='index.txt',
|
||||
add_etags=False)
|
||||
self.assert_equal(rv.mimetype, 'text/plain')
|
||||
value, options = parse_options_header(rv.headers['Content-Disposition'])
|
||||
self.assert_equal(value, 'attachment')
|
||||
self.assert_equal(options['filename'], 'index.txt')
|
||||
rv.close()
|
||||
|
||||
def test_static_file(self):
|
||||
app = flask.Flask(__name__)
|
||||
# default cache timeout is 12 hours
|
||||
with app.test_request_context():
|
||||
# Test with static file handler.
|
||||
rv = app.send_static_file('index.html')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, 12 * 60 * 60)
|
||||
rv.close()
|
||||
# Test again with direct use of send_file utility.
|
||||
rv = flask.send_file('static/index.html')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, 12 * 60 * 60)
|
||||
rv.close()
|
||||
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600
|
||||
with app.test_request_context():
|
||||
# Test with static file handler.
|
||||
rv = app.send_static_file('index.html')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, 3600)
|
||||
rv.close()
|
||||
# Test again with direct use of send_file utility.
|
||||
rv = flask.send_file('static/index.html')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, 3600)
|
||||
rv.close()
|
||||
class StaticFileApp(flask.Flask):
|
||||
def get_send_file_max_age(self, filename):
|
||||
return 10
|
||||
app = StaticFileApp(__name__)
|
||||
with app.test_request_context():
|
||||
# Test with static file handler.
|
||||
rv = app.send_static_file('index.html')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, 10)
|
||||
rv.close()
|
||||
# Test again with direct use of send_file utility.
|
||||
rv = flask.send_file('static/index.html')
|
||||
cc = parse_cache_control_header(rv.headers['Cache-Control'])
|
||||
self.assert_equal(cc.max_age, 10)
|
||||
rv.close()
|
||||
|
||||
|
||||
class LoggingTestCase(FlaskTestCase):
|
||||
|
||||
def test_logger_cache(self):
|
||||
app = flask.Flask(__name__)
|
||||
logger1 = app.logger
|
||||
self.assert_true(app.logger is logger1)
|
||||
self.assert_equal(logger1.name, __name__)
|
||||
app.logger_name = __name__ + '/test_logger_cache'
|
||||
self.assert_true(app.logger is not logger1)
|
||||
|
||||
def test_debug_log(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
app.logger.warning('the standard library is dead')
|
||||
app.logger.debug('this is a debug statement')
|
||||
return ''
|
||||
|
||||
@app.route('/exc')
|
||||
def exc():
|
||||
1 // 0
|
||||
|
||||
with app.test_client() as c:
|
||||
with catch_stderr() as err:
|
||||
c.get('/')
|
||||
out = err.getvalue()
|
||||
self.assert_in('WARNING in helpers [', out)
|
||||
self.assert_in(os.path.basename(__file__.rsplit('.', 1)[0] + '.py'), out)
|
||||
self.assert_in('the standard library is dead', out)
|
||||
self.assert_in('this is a debug statement', out)
|
||||
|
||||
with catch_stderr() as err:
|
||||
try:
|
||||
c.get('/exc')
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
self.assert_true(False, 'debug log ate the exception')
|
||||
|
||||
def test_debug_log_override(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.debug = True
|
||||
app.logger_name = 'flask_tests/test_debug_log_override'
|
||||
app.logger.level = 10
|
||||
self.assert_equal(app.logger.level, 10)
|
||||
|
||||
def test_exception_logging(self):
|
||||
out = StringIO()
|
||||
app = flask.Flask(__name__)
|
||||
app.logger_name = 'flask_tests/test_exception_logging'
|
||||
app.logger.addHandler(StreamHandler(out))
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
1 // 0
|
||||
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.status_code, 500)
|
||||
self.assert_in(b'Internal Server Error', rv.data)
|
||||
|
||||
err = out.getvalue()
|
||||
self.assert_in('Exception on / [GET]', err)
|
||||
self.assert_in('Traceback (most recent call last):', err)
|
||||
self.assert_in('1 // 0', err)
|
||||
self.assert_in('ZeroDivisionError:', err)
|
||||
|
||||
def test_processor_exceptions(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.before_request
|
||||
def before_request():
|
||||
if trigger == 'before':
|
||||
1 // 0
|
||||
@app.after_request
|
||||
def after_request(response):
|
||||
if trigger == 'after':
|
||||
1 // 0
|
||||
return response
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Foo'
|
||||
@app.errorhandler(500)
|
||||
def internal_server_error(e):
|
||||
return 'Hello Server Error', 500
|
||||
for trigger in 'before', 'after':
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.status_code, 500)
|
||||
self.assert_equal(rv.data, b'Hello Server Error')
|
||||
|
||||
def test_url_for_with_anchor(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return '42'
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.url_for('index', _anchor='x y'),
|
||||
'/#x%20y')
|
||||
|
||||
def test_url_for_with_scheme(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return '42'
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.url_for('index',
|
||||
_external=True,
|
||||
_scheme='https'),
|
||||
'https://localhost/')
|
||||
|
||||
def test_url_for_with_scheme_not_external(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return '42'
|
||||
with app.test_request_context():
|
||||
self.assert_raises(ValueError,
|
||||
flask.url_for,
|
||||
'index',
|
||||
_scheme='https')
|
||||
|
||||
def test_url_with_method(self):
|
||||
from flask.views import MethodView
|
||||
app = flask.Flask(__name__)
|
||||
class MyView(MethodView):
|
||||
def get(self, id=None):
|
||||
if id is None:
|
||||
return 'List'
|
||||
return 'Get %d' % id
|
||||
def post(self):
|
||||
return 'Create'
|
||||
myview = MyView.as_view('myview')
|
||||
app.add_url_rule('/myview/', methods=['GET'],
|
||||
view_func=myview)
|
||||
app.add_url_rule('/myview/<int:id>', methods=['GET'],
|
||||
view_func=myview)
|
||||
app.add_url_rule('/myview/create', methods=['POST'],
|
||||
view_func=myview)
|
||||
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.url_for('myview', _method='GET'),
|
||||
'/myview/')
|
||||
self.assert_equal(flask.url_for('myview', id=42, _method='GET'),
|
||||
'/myview/42')
|
||||
self.assert_equal(flask.url_for('myview', _method='POST'),
|
||||
'/myview/create')
|
||||
|
||||
|
||||
class NoImportsTestCase(FlaskTestCase):
|
||||
"""Test Flasks are created without import.
|
||||
|
||||
Avoiding ``__import__`` helps create Flask instances where there are errors
|
||||
at import time. Those runtime errors will be apparent to the user soon
|
||||
enough, but tools which build Flask instances meta-programmatically benefit
|
||||
from a Flask which does not ``__import__``. Instead of importing to
|
||||
retrieve file paths or metadata on a module or package, use the pkgutil and
|
||||
imp modules in the Python standard library.
|
||||
"""
|
||||
|
||||
def test_name_with_import_error(self):
|
||||
try:
|
||||
flask.Flask('importerror')
|
||||
except NotImplementedError:
|
||||
self.fail('Flask(import_name) is importing import_name.')
|
||||
|
||||
|
||||
class StreamingTestCase(FlaskTestCase):
|
||||
|
||||
def test_streaming_with_context(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
@app.route('/')
|
||||
def index():
|
||||
def generate():
|
||||
yield 'Hello '
|
||||
yield flask.request.args['name']
|
||||
yield '!'
|
||||
return flask.Response(flask.stream_with_context(generate()))
|
||||
c = app.test_client()
|
||||
rv = c.get('/?name=World')
|
||||
self.assertEqual(rv.data, b'Hello World!')
|
||||
|
||||
def test_streaming_with_context_as_decorator(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
@app.route('/')
|
||||
def index():
|
||||
@flask.stream_with_context
|
||||
def generate():
|
||||
yield 'Hello '
|
||||
yield flask.request.args['name']
|
||||
yield '!'
|
||||
return flask.Response(generate())
|
||||
c = app.test_client()
|
||||
rv = c.get('/?name=World')
|
||||
self.assertEqual(rv.data, b'Hello World!')
|
||||
|
||||
def test_streaming_with_context_and_custom_close(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
called = []
|
||||
class Wrapper(object):
|
||||
def __init__(self, gen):
|
||||
self._gen = gen
|
||||
def __iter__(self):
|
||||
return self
|
||||
def close(self):
|
||||
called.append(42)
|
||||
def __next__(self):
|
||||
return next(self._gen)
|
||||
next = __next__
|
||||
@app.route('/')
|
||||
def index():
|
||||
def generate():
|
||||
yield 'Hello '
|
||||
yield flask.request.args['name']
|
||||
yield '!'
|
||||
return flask.Response(flask.stream_with_context(
|
||||
Wrapper(generate())))
|
||||
c = app.test_client()
|
||||
rv = c.get('/?name=World')
|
||||
self.assertEqual(rv.data, b'Hello World!')
|
||||
self.assertEqual(called, [42])
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
if flask.json_available:
|
||||
suite.addTest(unittest.makeSuite(JSONTestCase))
|
||||
suite.addTest(unittest.makeSuite(SendfileTestCase))
|
||||
suite.addTest(unittest.makeSuite(LoggingTestCase))
|
||||
suite.addTest(unittest.makeSuite(NoImportsTestCase))
|
||||
suite.addTest(unittest.makeSuite(StreamingTestCase))
|
||||
return suite
|
||||
116
vendor/flask/testsuite/regression.py
vendored
116
vendor/flask/testsuite/regression.py
vendored
@@ -1,116 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.regression
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests regressions.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import gc
|
||||
import sys
|
||||
import flask
|
||||
import threading
|
||||
import unittest
|
||||
from werkzeug.exceptions import NotFound
|
||||
from flask.testsuite import FlaskTestCase
|
||||
|
||||
|
||||
_gc_lock = threading.Lock()
|
||||
|
||||
|
||||
class _NoLeakAsserter(object):
|
||||
|
||||
def __init__(self, testcase):
|
||||
self.testcase = testcase
|
||||
|
||||
def __enter__(self):
|
||||
gc.disable()
|
||||
_gc_lock.acquire()
|
||||
loc = flask._request_ctx_stack._local
|
||||
|
||||
# Force Python to track this dictionary at all times.
|
||||
# This is necessary since Python only starts tracking
|
||||
# dicts if they contain mutable objects. It's a horrible,
|
||||
# horrible hack but makes this kinda testable.
|
||||
loc.__storage__['FOOO'] = [1, 2, 3]
|
||||
|
||||
gc.collect()
|
||||
self.old_objects = len(gc.get_objects())
|
||||
|
||||
def __exit__(self, exc_type, exc_value, tb):
|
||||
if not hasattr(sys, 'getrefcount'):
|
||||
gc.collect()
|
||||
new_objects = len(gc.get_objects())
|
||||
if new_objects > self.old_objects:
|
||||
self.testcase.fail('Example code leaked')
|
||||
_gc_lock.release()
|
||||
gc.enable()
|
||||
|
||||
|
||||
class MemoryTestCase(FlaskTestCase):
|
||||
|
||||
def assert_no_leak(self):
|
||||
return _NoLeakAsserter(self)
|
||||
|
||||
def test_memory_consumption(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('simple_template.html', whiskey=42)
|
||||
|
||||
def fire():
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.status_code, 200)
|
||||
self.assert_equal(rv.data, b'<h1>42</h1>')
|
||||
|
||||
# Trigger caches
|
||||
fire()
|
||||
|
||||
# This test only works on CPython 2.7.
|
||||
if sys.version_info >= (2, 7) and \
|
||||
not hasattr(sys, 'pypy_translation_info'):
|
||||
with self.assert_no_leak():
|
||||
for x in range(10):
|
||||
fire()
|
||||
|
||||
def test_safe_join_toplevel_pardir(self):
|
||||
from flask.helpers import safe_join
|
||||
with self.assert_raises(NotFound):
|
||||
safe_join('/foo', '..')
|
||||
|
||||
|
||||
class ExceptionTestCase(FlaskTestCase):
|
||||
|
||||
def test_aborting(self):
|
||||
class Foo(Exception):
|
||||
whatever = 42
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
@app.errorhandler(Foo)
|
||||
def handle_foo(e):
|
||||
return str(e.whatever)
|
||||
@app.route('/')
|
||||
def index():
|
||||
raise flask.abort(flask.redirect(flask.url_for('test')))
|
||||
@app.route('/test')
|
||||
def test():
|
||||
raise Foo()
|
||||
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/')
|
||||
self.assertEqual(rv.headers['Location'], 'http://localhost/test')
|
||||
rv = c.get('/test')
|
||||
self.assertEqual(rv.data, b'42')
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
if os.environ.get('RUN_FLASK_MEMORY_TESTS') == '1':
|
||||
suite.addTest(unittest.makeSuite(MemoryTestCase))
|
||||
suite.addTest(unittest.makeSuite(ExceptionTestCase))
|
||||
return suite
|
||||
185
vendor/flask/testsuite/reqctx.py
vendored
185
vendor/flask/testsuite/reqctx.py
vendored
@@ -1,185 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.reqctx
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the request context.
|
||||
|
||||
:copyright: (c) 2012 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import unittest
|
||||
try:
|
||||
from greenlet import greenlet
|
||||
except ImportError:
|
||||
greenlet = None
|
||||
from flask.testsuite import FlaskTestCase
|
||||
|
||||
|
||||
class RequestContextTestCase(FlaskTestCase):
|
||||
|
||||
def test_teardown_on_pop(self):
|
||||
buffer = []
|
||||
app = flask.Flask(__name__)
|
||||
@app.teardown_request
|
||||
def end_of_request(exception):
|
||||
buffer.append(exception)
|
||||
|
||||
ctx = app.test_request_context()
|
||||
ctx.push()
|
||||
self.assert_equal(buffer, [])
|
||||
ctx.pop()
|
||||
self.assert_equal(buffer, [None])
|
||||
|
||||
def test_proper_test_request_context(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.config.update(
|
||||
SERVER_NAME='localhost.localdomain:5000'
|
||||
)
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return None
|
||||
|
||||
@app.route('/', subdomain='foo')
|
||||
def sub():
|
||||
return None
|
||||
|
||||
with app.test_request_context('/'):
|
||||
self.assert_equal(flask.url_for('index', _external=True), 'http://localhost.localdomain:5000/')
|
||||
|
||||
with app.test_request_context('/'):
|
||||
self.assert_equal(flask.url_for('sub', _external=True), 'http://foo.localhost.localdomain:5000/')
|
||||
|
||||
try:
|
||||
with app.test_request_context('/', environ_overrides={'HTTP_HOST': 'localhost'}):
|
||||
pass
|
||||
except Exception as e:
|
||||
self.assert_true(isinstance(e, ValueError))
|
||||
self.assert_equal(str(e), "the server name provided " +
|
||||
"('localhost.localdomain:5000') does not match the " + \
|
||||
"server name from the WSGI environment ('localhost')")
|
||||
|
||||
try:
|
||||
app.config.update(SERVER_NAME='localhost')
|
||||
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost'}):
|
||||
pass
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
"No ValueError exception should have been raised \"%s\"" % e
|
||||
)
|
||||
|
||||
try:
|
||||
app.config.update(SERVER_NAME='localhost:80')
|
||||
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost:80'}):
|
||||
pass
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
"No ValueError exception should have been raised \"%s\"" % e
|
||||
)
|
||||
|
||||
def test_context_binding(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Hello %s!' % flask.request.args['name']
|
||||
@app.route('/meh')
|
||||
def meh():
|
||||
return flask.request.url
|
||||
|
||||
with app.test_request_context('/?name=World'):
|
||||
self.assert_equal(index(), 'Hello World!')
|
||||
with app.test_request_context('/meh'):
|
||||
self.assert_equal(meh(), 'http://localhost/meh')
|
||||
self.assert_true(flask._request_ctx_stack.top is None)
|
||||
|
||||
def test_context_test(self):
|
||||
app = flask.Flask(__name__)
|
||||
self.assert_false(flask.request)
|
||||
self.assert_false(flask.has_request_context())
|
||||
ctx = app.test_request_context()
|
||||
ctx.push()
|
||||
try:
|
||||
self.assert_true(flask.request)
|
||||
self.assert_true(flask.has_request_context())
|
||||
finally:
|
||||
ctx.pop()
|
||||
|
||||
def test_manual_context_binding(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Hello %s!' % flask.request.args['name']
|
||||
|
||||
ctx = app.test_request_context('/?name=World')
|
||||
ctx.push()
|
||||
self.assert_equal(index(), 'Hello World!')
|
||||
ctx.pop()
|
||||
try:
|
||||
index()
|
||||
except RuntimeError:
|
||||
pass
|
||||
else:
|
||||
self.assert_true(0, 'expected runtime error')
|
||||
|
||||
def test_greenlet_context_copying(self):
|
||||
app = flask.Flask(__name__)
|
||||
greenlets = []
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
reqctx = flask._request_ctx_stack.top.copy()
|
||||
def g():
|
||||
self.assert_false(flask.request)
|
||||
self.assert_false(flask.current_app)
|
||||
with reqctx:
|
||||
self.assert_true(flask.request)
|
||||
self.assert_equal(flask.current_app, app)
|
||||
self.assert_equal(flask.request.path, '/')
|
||||
self.assert_equal(flask.request.args['foo'], 'bar')
|
||||
self.assert_false(flask.request)
|
||||
return 42
|
||||
greenlets.append(greenlet(g))
|
||||
return 'Hello World!'
|
||||
|
||||
rv = app.test_client().get('/?foo=bar')
|
||||
self.assert_equal(rv.data, b'Hello World!')
|
||||
|
||||
result = greenlets[0].run()
|
||||
self.assert_equal(result, 42)
|
||||
|
||||
def test_greenlet_context_copying_api(self):
|
||||
app = flask.Flask(__name__)
|
||||
greenlets = []
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
reqctx = flask._request_ctx_stack.top.copy()
|
||||
@flask.copy_current_request_context
|
||||
def g():
|
||||
self.assert_true(flask.request)
|
||||
self.assert_equal(flask.current_app, app)
|
||||
self.assert_equal(flask.request.path, '/')
|
||||
self.assert_equal(flask.request.args['foo'], 'bar')
|
||||
return 42
|
||||
greenlets.append(greenlet(g))
|
||||
return 'Hello World!'
|
||||
|
||||
rv = app.test_client().get('/?foo=bar')
|
||||
self.assert_equal(rv.data, b'Hello World!')
|
||||
|
||||
result = greenlets[0].run()
|
||||
self.assert_equal(result, 42)
|
||||
|
||||
# Disable test if we don't have greenlets available
|
||||
if greenlet is None:
|
||||
test_greenlet_context_copying = None
|
||||
test_greenlet_context_copying_api = None
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(RequestContextTestCase))
|
||||
return suite
|
||||
153
vendor/flask/testsuite/signals.py
vendored
153
vendor/flask/testsuite/signals.py
vendored
@@ -1,153 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.signals
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Signalling.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import unittest
|
||||
from flask.testsuite import FlaskTestCase
|
||||
|
||||
|
||||
class SignalsTestCase(FlaskTestCase):
|
||||
|
||||
def test_template_rendered(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('simple_template.html', whiskey=42)
|
||||
|
||||
recorded = []
|
||||
def record(sender, template, context):
|
||||
recorded.append((template, context))
|
||||
|
||||
flask.template_rendered.connect(record, app)
|
||||
try:
|
||||
app.test_client().get('/')
|
||||
self.assert_equal(len(recorded), 1)
|
||||
template, context = recorded[0]
|
||||
self.assert_equal(template.name, 'simple_template.html')
|
||||
self.assert_equal(context['whiskey'], 42)
|
||||
finally:
|
||||
flask.template_rendered.disconnect(record, app)
|
||||
|
||||
def test_request_signals(self):
|
||||
app = flask.Flask(__name__)
|
||||
calls = []
|
||||
|
||||
def before_request_signal(sender):
|
||||
calls.append('before-signal')
|
||||
|
||||
def after_request_signal(sender, response):
|
||||
self.assert_equal(response.data, b'stuff')
|
||||
calls.append('after-signal')
|
||||
|
||||
@app.before_request
|
||||
def before_request_handler():
|
||||
calls.append('before-handler')
|
||||
|
||||
@app.after_request
|
||||
def after_request_handler(response):
|
||||
calls.append('after-handler')
|
||||
response.data = 'stuff'
|
||||
return response
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
calls.append('handler')
|
||||
return 'ignored anyway'
|
||||
|
||||
flask.request_started.connect(before_request_signal, app)
|
||||
flask.request_finished.connect(after_request_signal, app)
|
||||
|
||||
try:
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'stuff')
|
||||
|
||||
self.assert_equal(calls, ['before-signal', 'before-handler',
|
||||
'handler', 'after-handler',
|
||||
'after-signal'])
|
||||
finally:
|
||||
flask.request_started.disconnect(before_request_signal, app)
|
||||
flask.request_finished.disconnect(after_request_signal, app)
|
||||
|
||||
def test_request_exception_signal(self):
|
||||
app = flask.Flask(__name__)
|
||||
recorded = []
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
1 // 0
|
||||
|
||||
def record(sender, exception):
|
||||
recorded.append(exception)
|
||||
|
||||
flask.got_request_exception.connect(record, app)
|
||||
try:
|
||||
self.assert_equal(app.test_client().get('/').status_code, 500)
|
||||
self.assert_equal(len(recorded), 1)
|
||||
self.assert_true(isinstance(recorded[0], ZeroDivisionError))
|
||||
finally:
|
||||
flask.got_request_exception.disconnect(record, app)
|
||||
|
||||
def test_appcontext_signals(self):
|
||||
app = flask.Flask(__name__)
|
||||
recorded = []
|
||||
def record_push(sender, **kwargs):
|
||||
recorded.append('push')
|
||||
def record_pop(sender, **kwargs):
|
||||
recorded.append('push')
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Hello'
|
||||
|
||||
flask.appcontext_pushed.connect(record_push, app)
|
||||
flask.appcontext_popped.connect(record_pop, app)
|
||||
try:
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'Hello')
|
||||
self.assert_equal(recorded, ['push'])
|
||||
self.assert_equal(recorded, ['push', 'pop'])
|
||||
finally:
|
||||
flask.appcontext_pushed.disconnect(record_push, app)
|
||||
flask.appcontext_popped.disconnect(record_pop, app)
|
||||
|
||||
def test_flash_signal(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.config['SECRET_KEY'] = 'secret'
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
flask.flash('This is a flash message', category='notice')
|
||||
return flask.redirect('/other')
|
||||
|
||||
recorded = []
|
||||
def record(sender, message, category):
|
||||
recorded.append((message, category))
|
||||
|
||||
flask.message_flashed.connect(record, app)
|
||||
try:
|
||||
client = app.test_client()
|
||||
with client.session_transaction():
|
||||
client.get('/')
|
||||
self.assert_equal(len(recorded), 1)
|
||||
message, category = recorded[0]
|
||||
self.assert_equal(message, 'This is a flash message')
|
||||
self.assert_equal(category, 'notice')
|
||||
finally:
|
||||
flask.message_flashed.disconnect(record, app)
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
if flask.signals_available:
|
||||
suite.addTest(unittest.makeSuite(SignalsTestCase))
|
||||
return suite
|
||||
1
vendor/flask/testsuite/static/index.html
vendored
1
vendor/flask/testsuite/static/index.html
vendored
@@ -1 +0,0 @@
|
||||
<h1>Hello World!</h1>
|
||||
46
vendor/flask/testsuite/subclassing.py
vendored
46
vendor/flask/testsuite/subclassing.py
vendored
@@ -1,46 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.subclassing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Test that certain behavior of flask can be customized by
|
||||
subclasses.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import flask
|
||||
import unittest
|
||||
from logging import StreamHandler
|
||||
from flask.testsuite import FlaskTestCase
|
||||
from flask._compat import StringIO
|
||||
|
||||
|
||||
class FlaskSubclassingTestCase(FlaskTestCase):
|
||||
|
||||
def test_suppressed_exception_logging(self):
|
||||
class SuppressedFlask(flask.Flask):
|
||||
def log_exception(self, exc_info):
|
||||
pass
|
||||
|
||||
out = StringIO()
|
||||
app = SuppressedFlask(__name__)
|
||||
app.logger_name = 'flask_tests/test_suppressed_exception_logging'
|
||||
app.logger.addHandler(StreamHandler(out))
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
1 // 0
|
||||
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.status_code, 500)
|
||||
self.assert_in(b'Internal Server Error', rv.data)
|
||||
|
||||
err = out.getvalue()
|
||||
self.assert_equal(err, '')
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(FlaskSubclassingTestCase))
|
||||
return suite
|
||||
1
vendor/flask/testsuite/templates/_macro.html
vendored
1
vendor/flask/testsuite/templates/_macro.html
vendored
@@ -1 +0,0 @@
|
||||
{% macro hello(name) %}Hello {{ name }}!{% endmacro %}
|
||||
@@ -1 +0,0 @@
|
||||
<p>{{ value }}|{{ injected_value }}
|
||||
@@ -1,6 +0,0 @@
|
||||
{{ text }}
|
||||
{{ html }}
|
||||
{% autoescape false %}{{ text }}
|
||||
{{ html }}{% endautoescape %}
|
||||
{% autoescape true %}{{ text }}
|
||||
{{ html }}{% endautoescape %}
|
||||
1
vendor/flask/testsuite/templates/mail.txt
vendored
1
vendor/flask/testsuite/templates/mail.txt
vendored
@@ -1 +0,0 @@
|
||||
{{ foo}} Mail
|
||||
@@ -1 +0,0 @@
|
||||
I'm nested
|
||||
@@ -1 +0,0 @@
|
||||
<h1>{{ whiskey }}</h1>
|
||||
@@ -1 +0,0 @@
|
||||
{{ value|super_reverse }}
|
||||
@@ -1,3 +0,0 @@
|
||||
{% if value is boolean %}
|
||||
Success!
|
||||
{% endif %}
|
||||
302
vendor/flask/testsuite/templating.py
vendored
302
vendor/flask/testsuite/templating.py
vendored
@@ -1,302 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.templating
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Template functionality
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import unittest
|
||||
from flask.testsuite import FlaskTestCase
|
||||
|
||||
|
||||
class TemplatingTestCase(FlaskTestCase):
|
||||
|
||||
def test_context_processing(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.context_processor
|
||||
def context_processor():
|
||||
return {'injected_value': 42}
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('context_template.html', value=23)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'<p>23|42')
|
||||
|
||||
def test_original_win(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template_string('{{ config }}', config=42)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'42')
|
||||
|
||||
def test_request_less_rendering(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.config['WORLD_NAME'] = 'Special World'
|
||||
@app.context_processor
|
||||
def context_processor():
|
||||
return dict(foo=42)
|
||||
|
||||
with app.app_context():
|
||||
rv = flask.render_template_string('Hello {{ config.WORLD_NAME }} '
|
||||
'{{ foo }}')
|
||||
self.assert_equal(rv, 'Hello Special World 42')
|
||||
|
||||
def test_standard_context(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.secret_key = 'development key'
|
||||
@app.route('/')
|
||||
def index():
|
||||
flask.g.foo = 23
|
||||
flask.session['test'] = 'aha'
|
||||
return flask.render_template_string('''
|
||||
{{ request.args.foo }}
|
||||
{{ g.foo }}
|
||||
{{ config.DEBUG }}
|
||||
{{ session.test }}
|
||||
''')
|
||||
rv = app.test_client().get('/?foo=42')
|
||||
self.assert_equal(rv.data.split(), [b'42', b'23', b'False', b'aha'])
|
||||
|
||||
def test_escaping(self):
|
||||
text = '<p>Hello World!'
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('escaping_template.html', text=text,
|
||||
html=flask.Markup(text))
|
||||
lines = app.test_client().get('/').data.splitlines()
|
||||
self.assert_equal(lines, [
|
||||
b'<p>Hello World!',
|
||||
b'<p>Hello World!',
|
||||
b'<p>Hello World!',
|
||||
b'<p>Hello World!',
|
||||
b'<p>Hello World!',
|
||||
b'<p>Hello World!'
|
||||
])
|
||||
|
||||
def test_no_escaping(self):
|
||||
app = flask.Flask(__name__)
|
||||
with app.test_request_context():
|
||||
self.assert_equal(flask.render_template_string('{{ foo }}',
|
||||
foo='<test>'), '<test>')
|
||||
self.assert_equal(flask.render_template('mail.txt', foo='<test>'),
|
||||
'<test> Mail')
|
||||
|
||||
def test_macros(self):
|
||||
app = flask.Flask(__name__)
|
||||
with app.test_request_context():
|
||||
macro = flask.get_template_attribute('_macro.html', 'hello')
|
||||
self.assert_equal(macro('World'), 'Hello World!')
|
||||
|
||||
def test_template_filter(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_filter()
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
self.assert_in('my_reverse', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
|
||||
|
||||
def test_add_template_filter(self):
|
||||
app = flask.Flask(__name__)
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
app.add_template_filter(my_reverse)
|
||||
self.assert_in('my_reverse', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
|
||||
|
||||
def test_template_filter_with_name(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_filter('strrev')
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
self.assert_in('strrev', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
|
||||
|
||||
def test_add_template_filter_with_name(self):
|
||||
app = flask.Flask(__name__)
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
app.add_template_filter(my_reverse, 'strrev')
|
||||
self.assert_in('strrev', app.jinja_env.filters.keys())
|
||||
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
|
||||
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
|
||||
|
||||
def test_template_filter_with_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_filter()
|
||||
def super_reverse(s):
|
||||
return s[::-1]
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_add_template_filter_with_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
def super_reverse(s):
|
||||
return s[::-1]
|
||||
app.add_template_filter(super_reverse)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_template_filter_with_name_and_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_filter('super_reverse')
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_add_template_filter_with_name_and_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
def my_reverse(s):
|
||||
return s[::-1]
|
||||
app.add_template_filter(my_reverse, 'super_reverse')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_filter.html', value='abcd')
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'dcba')
|
||||
|
||||
def test_template_test(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_test()
|
||||
def boolean(value):
|
||||
return isinstance(value, bool)
|
||||
self.assert_in('boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['boolean'], boolean)
|
||||
self.assert_true(app.jinja_env.tests['boolean'](False))
|
||||
|
||||
def test_add_template_test(self):
|
||||
app = flask.Flask(__name__)
|
||||
def boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app.add_template_test(boolean)
|
||||
self.assert_in('boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['boolean'], boolean)
|
||||
self.assert_true(app.jinja_env.tests['boolean'](False))
|
||||
|
||||
def test_template_test_with_name(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_test('boolean')
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
self.assert_in('boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
|
||||
self.assert_true(app.jinja_env.tests['boolean'](False))
|
||||
|
||||
def test_add_template_test_with_name(self):
|
||||
app = flask.Flask(__name__)
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app.add_template_test(is_boolean, 'boolean')
|
||||
self.assert_in('boolean', app.jinja_env.tests.keys())
|
||||
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
|
||||
self.assert_true(app.jinja_env.tests['boolean'](False))
|
||||
|
||||
def test_template_test_with_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_test()
|
||||
def boolean(value):
|
||||
return isinstance(value, bool)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_add_template_test_with_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
def boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app.add_template_test(boolean)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_template_test_with_name_and_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_test('boolean')
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_add_template_test_with_name_and_template(self):
|
||||
app = flask.Flask(__name__)
|
||||
def is_boolean(value):
|
||||
return isinstance(value, bool)
|
||||
app.add_template_test(is_boolean, 'boolean')
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('template_test.html', value=False)
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_in(b'Success!', rv.data)
|
||||
|
||||
def test_add_template_global(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.template_global()
|
||||
def get_stuff():
|
||||
return 42
|
||||
self.assert_in('get_stuff', app.jinja_env.globals.keys())
|
||||
self.assert_equal(app.jinja_env.globals['get_stuff'], get_stuff)
|
||||
self.assert_true(app.jinja_env.globals['get_stuff'](), 42)
|
||||
with app.app_context():
|
||||
rv = flask.render_template_string('{{ get_stuff() }}')
|
||||
self.assert_equal(rv, '42')
|
||||
|
||||
def test_custom_template_loader(self):
|
||||
class MyFlask(flask.Flask):
|
||||
def create_global_jinja_loader(self):
|
||||
from jinja2 import DictLoader
|
||||
return DictLoader({'index.html': 'Hello Custom World!'})
|
||||
app = MyFlask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template('index.html')
|
||||
c = app.test_client()
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'Hello Custom World!')
|
||||
|
||||
def test_iterable_loader(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.context_processor
|
||||
def context_processor():
|
||||
return {'whiskey': 'Jameson'}
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.render_template(
|
||||
['no_template.xml', # should skip this one
|
||||
'simple_template.html', # should render this
|
||||
'context_template.html'],
|
||||
value=23)
|
||||
|
||||
rv = app.test_client().get('/')
|
||||
self.assert_equal(rv.data, b'<h1>Jameson</h1>')
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(TemplatingTestCase))
|
||||
return suite
|
||||
@@ -1,7 +0,0 @@
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
from blueprintapp.apps.admin import admin
|
||||
from blueprintapp.apps.frontend import frontend
|
||||
app.register_blueprint(admin)
|
||||
app.register_blueprint(frontend)
|
||||
@@ -1,15 +0,0 @@
|
||||
from flask import Blueprint, render_template
|
||||
|
||||
admin = Blueprint('admin', __name__, url_prefix='/admin',
|
||||
template_folder='templates',
|
||||
static_folder='static')
|
||||
|
||||
|
||||
@admin.route('/')
|
||||
def index():
|
||||
return render_template('admin/index.html')
|
||||
|
||||
|
||||
@admin.route('/index2')
|
||||
def index2():
|
||||
return render_template('./admin/index.html')
|
||||
@@ -1 +0,0 @@
|
||||
/* nested file */
|
||||
@@ -1 +0,0 @@
|
||||
Admin File
|
||||
@@ -1 +0,0 @@
|
||||
Hello from the Admin
|
||||
@@ -1,8 +0,0 @@
|
||||
from flask import Blueprint, render_template
|
||||
|
||||
frontend = Blueprint('frontend', __name__, template_folder='templates')
|
||||
|
||||
|
||||
@frontend.route('/')
|
||||
def index():
|
||||
return render_template('frontend/index.html')
|
||||
@@ -1 +0,0 @@
|
||||
Hello from the Frontend
|
||||
@@ -1,4 +0,0 @@
|
||||
import os
|
||||
import flask
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
app = flask.Flask(__name__)
|
||||
@@ -1,4 +0,0 @@
|
||||
import os
|
||||
import flask
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
app = flask.Flask(__name__)
|
||||
@@ -1,2 +0,0 @@
|
||||
import flask.ext.broken.b
|
||||
import missing_module
|
||||
@@ -1 +0,0 @@
|
||||
ext_id = 'newext_package'
|
||||
@@ -1,2 +0,0 @@
|
||||
def test_function():
|
||||
return 42
|
||||
@@ -1 +0,0 @@
|
||||
ext_id = 'newext_simple'
|
||||
@@ -1 +0,0 @@
|
||||
ext_id = 'oldext_package'
|
||||
@@ -1,2 +0,0 @@
|
||||
def test_function():
|
||||
return 42
|
||||
@@ -1 +0,0 @@
|
||||
ext_id = 'oldext_simple'
|
||||
@@ -1,2 +0,0 @@
|
||||
# NoImportsTestCase
|
||||
raise NotImplementedError
|
||||
@@ -1,3 +0,0 @@
|
||||
import flask
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
@@ -1,3 +0,0 @@
|
||||
import flask
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
4
vendor/flask/testsuite/test_apps/main_app.py
vendored
4
vendor/flask/testsuite/test_apps/main_app.py
vendored
@@ -1,4 +0,0 @@
|
||||
import flask
|
||||
|
||||
# Test Flask initialization with main module.
|
||||
app = flask.Flask('__main__')
|
||||
@@ -1,7 +0,0 @@
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
from moduleapp.apps.admin import admin
|
||||
from moduleapp.apps.frontend import frontend
|
||||
app.register_module(admin)
|
||||
app.register_module(frontend)
|
||||
@@ -1,14 +0,0 @@
|
||||
from flask import Module, render_template
|
||||
|
||||
|
||||
admin = Module(__name__, url_prefix='/admin')
|
||||
|
||||
|
||||
@admin.route('/')
|
||||
def index():
|
||||
return render_template('admin/index.html')
|
||||
|
||||
|
||||
@admin.route('/index2')
|
||||
def index2():
|
||||
return render_template('./admin/index.html')
|
||||
@@ -1 +0,0 @@
|
||||
/* nested file */
|
||||
@@ -1 +0,0 @@
|
||||
Admin File
|
||||
@@ -1 +0,0 @@
|
||||
Hello from the Admin
|
||||
@@ -1,9 +0,0 @@
|
||||
from flask import Module, render_template
|
||||
|
||||
|
||||
frontend = Module(__name__)
|
||||
|
||||
|
||||
@frontend.route('/')
|
||||
def index():
|
||||
return render_template('frontend/index.html')
|
||||
@@ -1 +0,0 @@
|
||||
Hello from the Frontend
|
||||
@@ -1,3 +0,0 @@
|
||||
import flask
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
@@ -1,4 +0,0 @@
|
||||
from flask import Module
|
||||
|
||||
|
||||
mod = Module(__name__, 'foo', subdomain='foo')
|
||||
@@ -1 +0,0 @@
|
||||
Hello Subdomain
|
||||
242
vendor/flask/testsuite/testing.py
vendored
242
vendor/flask/testsuite/testing.py
vendored
@@ -1,242 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.testing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Test client and more.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import unittest
|
||||
from flask.testsuite import FlaskTestCase
|
||||
from flask._compat import text_type
|
||||
|
||||
|
||||
class TestToolsTestCase(FlaskTestCase):
|
||||
|
||||
def test_environ_defaults_from_config(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
app.config['SERVER_NAME'] = 'example.com:1234'
|
||||
app.config['APPLICATION_ROOT'] = '/foo'
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.request.url
|
||||
|
||||
ctx = app.test_request_context()
|
||||
self.assert_equal(ctx.request.url, 'http://example.com:1234/foo/')
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'http://example.com:1234/foo/')
|
||||
|
||||
def test_environ_defaults(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
@app.route('/')
|
||||
def index():
|
||||
return flask.request.url
|
||||
|
||||
ctx = app.test_request_context()
|
||||
self.assert_equal(ctx.request.url, 'http://localhost/')
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'http://localhost/')
|
||||
|
||||
def test_redirect_keep_session(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.secret_key = 'testing'
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
def index():
|
||||
if flask.request.method == 'POST':
|
||||
return flask.redirect('/getsession')
|
||||
flask.session['data'] = 'foo'
|
||||
return 'index'
|
||||
|
||||
@app.route('/getsession')
|
||||
def get_session():
|
||||
return flask.session.get('data', '<missing>')
|
||||
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/getsession')
|
||||
assert rv.data == b'<missing>'
|
||||
|
||||
rv = c.get('/')
|
||||
assert rv.data == b'index'
|
||||
assert flask.session.get('data') == 'foo'
|
||||
rv = c.post('/', data={}, follow_redirects=True)
|
||||
assert rv.data == b'foo'
|
||||
|
||||
# This support requires a new Werkzeug version
|
||||
if not hasattr(c, 'redirect_client'):
|
||||
assert flask.session.get('data') == 'foo'
|
||||
|
||||
rv = c.get('/getsession')
|
||||
assert rv.data == b'foo'
|
||||
|
||||
def test_session_transactions(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
app.secret_key = 'testing'
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return text_type(flask.session['foo'])
|
||||
|
||||
with app.test_client() as c:
|
||||
with c.session_transaction() as sess:
|
||||
self.assert_equal(len(sess), 0)
|
||||
sess['foo'] = [42]
|
||||
self.assert_equal(len(sess), 1)
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'[42]')
|
||||
with c.session_transaction() as sess:
|
||||
self.assert_equal(len(sess), 1)
|
||||
self.assert_equal(sess['foo'], [42])
|
||||
|
||||
def test_session_transactions_no_null_sessions(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
|
||||
with app.test_client() as c:
|
||||
try:
|
||||
with c.session_transaction() as sess:
|
||||
pass
|
||||
except RuntimeError as e:
|
||||
self.assert_in('Session backend did not open a session', str(e))
|
||||
else:
|
||||
self.fail('Expected runtime error')
|
||||
|
||||
def test_session_transactions_keep_context(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
app.secret_key = 'testing'
|
||||
|
||||
with app.test_client() as c:
|
||||
rv = c.get('/')
|
||||
req = flask.request._get_current_object()
|
||||
self.assert_true(req is not None)
|
||||
with c.session_transaction():
|
||||
self.assert_true(req is flask.request._get_current_object())
|
||||
|
||||
def test_session_transaction_needs_cookies(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.testing = True
|
||||
c = app.test_client(use_cookies=False)
|
||||
try:
|
||||
with c.session_transaction() as s:
|
||||
pass
|
||||
except RuntimeError as e:
|
||||
self.assert_in('cookies', str(e))
|
||||
else:
|
||||
self.fail('Expected runtime error')
|
||||
|
||||
def test_test_client_context_binding(self):
|
||||
app = flask.Flask(__name__)
|
||||
@app.route('/')
|
||||
def index():
|
||||
flask.g.value = 42
|
||||
return 'Hello World!'
|
||||
|
||||
@app.route('/other')
|
||||
def other():
|
||||
1 // 0
|
||||
|
||||
with app.test_client() as c:
|
||||
resp = c.get('/')
|
||||
self.assert_equal(flask.g.value, 42)
|
||||
self.assert_equal(resp.data, b'Hello World!')
|
||||
self.assert_equal(resp.status_code, 200)
|
||||
|
||||
resp = c.get('/other')
|
||||
self.assert_false(hasattr(flask.g, 'value'))
|
||||
self.assert_in(b'Internal Server Error', resp.data)
|
||||
self.assert_equal(resp.status_code, 500)
|
||||
flask.g.value = 23
|
||||
|
||||
try:
|
||||
flask.g.value
|
||||
except (AttributeError, RuntimeError):
|
||||
pass
|
||||
else:
|
||||
raise AssertionError('some kind of exception expected')
|
||||
|
||||
def test_reuse_client(self):
|
||||
app = flask.Flask(__name__)
|
||||
c = app.test_client()
|
||||
|
||||
with c:
|
||||
self.assert_equal(c.get('/').status_code, 404)
|
||||
|
||||
with c:
|
||||
self.assert_equal(c.get('/').status_code, 404)
|
||||
|
||||
def test_test_client_calls_teardown_handlers(self):
|
||||
app = flask.Flask(__name__)
|
||||
called = []
|
||||
@app.teardown_request
|
||||
def remember(error):
|
||||
called.append(error)
|
||||
|
||||
with app.test_client() as c:
|
||||
self.assert_equal(called, [])
|
||||
c.get('/')
|
||||
self.assert_equal(called, [])
|
||||
self.assert_equal(called, [None])
|
||||
|
||||
del called[:]
|
||||
with app.test_client() as c:
|
||||
self.assert_equal(called, [])
|
||||
c.get('/')
|
||||
self.assert_equal(called, [])
|
||||
c.get('/')
|
||||
self.assert_equal(called, [None])
|
||||
self.assert_equal(called, [None, None])
|
||||
|
||||
|
||||
class SubdomainTestCase(FlaskTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.app = flask.Flask(__name__)
|
||||
self.app.config['SERVER_NAME'] = 'example.com'
|
||||
self.client = self.app.test_client()
|
||||
|
||||
self._ctx = self.app.test_request_context()
|
||||
self._ctx.push()
|
||||
|
||||
def tearDown(self):
|
||||
if self._ctx is not None:
|
||||
self._ctx.pop()
|
||||
|
||||
def test_subdomain(self):
|
||||
@self.app.route('/', subdomain='<company_id>')
|
||||
def view(company_id):
|
||||
return company_id
|
||||
|
||||
url = flask.url_for('view', company_id='xxx')
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assert_equal(200, response.status_code)
|
||||
self.assert_equal(b'xxx', response.data)
|
||||
|
||||
|
||||
def test_nosubdomain(self):
|
||||
@self.app.route('/<company_id>')
|
||||
def view(company_id):
|
||||
return company_id
|
||||
|
||||
url = flask.url_for('view', company_id='xxx')
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assert_equal(200, response.status_code)
|
||||
self.assert_equal(b'xxx', response.data)
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(TestToolsTestCase))
|
||||
suite.addTest(unittest.makeSuite(SubdomainTestCase))
|
||||
return suite
|
||||
169
vendor/flask/testsuite/views.py
vendored
169
vendor/flask/testsuite/views.py
vendored
@@ -1,169 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask.testsuite.views
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Pluggable views.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
import flask
|
||||
import flask.views
|
||||
import unittest
|
||||
from flask.testsuite import FlaskTestCase
|
||||
from werkzeug.http import parse_set_header
|
||||
|
||||
class ViewTestCase(FlaskTestCase):
|
||||
|
||||
def common_test(self, app):
|
||||
c = app.test_client()
|
||||
|
||||
self.assert_equal(c.get('/').data, b'GET')
|
||||
self.assert_equal(c.post('/').data, b'POST')
|
||||
self.assert_equal(c.put('/').status_code, 405)
|
||||
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
|
||||
self.assert_equal(sorted(meths), ['GET', 'HEAD', 'OPTIONS', 'POST'])
|
||||
|
||||
def test_basic_view(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
class Index(flask.views.View):
|
||||
methods = ['GET', 'POST']
|
||||
def dispatch_request(self):
|
||||
return flask.request.method
|
||||
|
||||
app.add_url_rule('/', view_func=Index.as_view('index'))
|
||||
self.common_test(app)
|
||||
|
||||
def test_method_based_view(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
class Index(flask.views.MethodView):
|
||||
def get(self):
|
||||
return 'GET'
|
||||
def post(self):
|
||||
return 'POST'
|
||||
|
||||
app.add_url_rule('/', view_func=Index.as_view('index'))
|
||||
|
||||
self.common_test(app)
|
||||
|
||||
def test_view_patching(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
class Index(flask.views.MethodView):
|
||||
def get(self):
|
||||
1 // 0
|
||||
def post(self):
|
||||
1 // 0
|
||||
|
||||
class Other(Index):
|
||||
def get(self):
|
||||
return 'GET'
|
||||
def post(self):
|
||||
return 'POST'
|
||||
|
||||
view = Index.as_view('index')
|
||||
view.view_class = Other
|
||||
app.add_url_rule('/', view_func=view)
|
||||
self.common_test(app)
|
||||
|
||||
def test_view_inheritance(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
class Index(flask.views.MethodView):
|
||||
def get(self):
|
||||
return 'GET'
|
||||
def post(self):
|
||||
return 'POST'
|
||||
|
||||
class BetterIndex(Index):
|
||||
def delete(self):
|
||||
return 'DELETE'
|
||||
|
||||
app.add_url_rule('/', view_func=BetterIndex.as_view('index'))
|
||||
c = app.test_client()
|
||||
|
||||
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
|
||||
self.assert_equal(sorted(meths), ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST'])
|
||||
|
||||
def test_view_decorators(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
def add_x_parachute(f):
|
||||
def new_function(*args, **kwargs):
|
||||
resp = flask.make_response(f(*args, **kwargs))
|
||||
resp.headers['X-Parachute'] = 'awesome'
|
||||
return resp
|
||||
return new_function
|
||||
|
||||
class Index(flask.views.View):
|
||||
decorators = [add_x_parachute]
|
||||
def dispatch_request(self):
|
||||
return 'Awesome'
|
||||
|
||||
app.add_url_rule('/', view_func=Index.as_view('index'))
|
||||
c = app.test_client()
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.headers['X-Parachute'], 'awesome')
|
||||
self.assert_equal(rv.data, b'Awesome')
|
||||
|
||||
def test_implicit_head(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
class Index(flask.views.MethodView):
|
||||
def get(self):
|
||||
return flask.Response('Blub', headers={
|
||||
'X-Method': flask.request.method
|
||||
})
|
||||
|
||||
app.add_url_rule('/', view_func=Index.as_view('index'))
|
||||
c = app.test_client()
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'Blub')
|
||||
self.assert_equal(rv.headers['X-Method'], 'GET')
|
||||
rv = c.head('/')
|
||||
self.assert_equal(rv.data, b'')
|
||||
self.assert_equal(rv.headers['X-Method'], 'HEAD')
|
||||
|
||||
def test_explicit_head(self):
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
class Index(flask.views.MethodView):
|
||||
def get(self):
|
||||
return 'GET'
|
||||
def head(self):
|
||||
return flask.Response('', headers={'X-Method': 'HEAD'})
|
||||
|
||||
app.add_url_rule('/', view_func=Index.as_view('index'))
|
||||
c = app.test_client()
|
||||
rv = c.get('/')
|
||||
self.assert_equal(rv.data, b'GET')
|
||||
rv = c.head('/')
|
||||
self.assert_equal(rv.data, b'')
|
||||
self.assert_equal(rv.headers['X-Method'], 'HEAD')
|
||||
|
||||
def test_endpoint_override(self):
|
||||
app = flask.Flask(__name__)
|
||||
app.debug = True
|
||||
|
||||
class Index(flask.views.View):
|
||||
methods = ['GET', 'POST']
|
||||
def dispatch_request(self):
|
||||
return flask.request.method
|
||||
|
||||
app.add_url_rule('/', view_func=Index.as_view('index'))
|
||||
|
||||
with self.assert_raises(AssertionError):
|
||||
app.add_url_rule('/', view_func=Index.as_view('index'))
|
||||
|
||||
# But these tests should still pass. We just log a warning.
|
||||
self.common_test(app)
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(ViewTestCase))
|
||||
return suite
|
||||
16
vendor/flask/views.py
vendored
16
vendor/flask/views.py
vendored
@@ -5,7 +5,7 @@
|
||||
|
||||
This module provides class-based views inspired by the ones in Django.
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from .globals import request
|
||||
@@ -48,7 +48,7 @@ class View(object):
|
||||
generated view function!
|
||||
"""
|
||||
|
||||
#: A for which methods this pluggable view can handle.
|
||||
#: A list of methods this view can handle.
|
||||
methods = None
|
||||
|
||||
#: The canonical way to decorate class-based views is to decorate the
|
||||
@@ -60,7 +60,7 @@ class View(object):
|
||||
#: view function is created the result is automatically decorated.
|
||||
#:
|
||||
#: .. versionadded:: 0.8
|
||||
decorators = []
|
||||
decorators = ()
|
||||
|
||||
def dispatch_request(self):
|
||||
"""Subclasses have to override this method to implement the
|
||||
@@ -89,7 +89,7 @@ class View(object):
|
||||
for decorator in cls.decorators:
|
||||
view = decorator(view)
|
||||
|
||||
# we attach the view class to the view function for two reasons:
|
||||
# We attach the view class to the view function for two reasons:
|
||||
# first of all it allows us to easily figure out what class-based
|
||||
# view this thing came from, secondly it's also used for instantiating
|
||||
# the view class so you can actually replace it with something else
|
||||
@@ -111,9 +111,9 @@ class MethodViewType(type):
|
||||
for key in d:
|
||||
if key in http_method_funcs:
|
||||
methods.add(key.upper())
|
||||
# if we have no method at all in there we don't want to
|
||||
# If we have no method at all in there we don't want to
|
||||
# add a method list. (This is for instance the case for
|
||||
# the baseclass or another subclass of a base method view
|
||||
# the base class or another subclass of a base method view
|
||||
# that does not introduce new methods).
|
||||
if methods:
|
||||
rv.methods = sorted(methods)
|
||||
@@ -141,8 +141,8 @@ class MethodView(with_metaclass(MethodViewType, View)):
|
||||
"""
|
||||
def dispatch_request(self, *args, **kwargs):
|
||||
meth = getattr(self, request.method.lower(), None)
|
||||
# if the request method is HEAD and we don't have a handler for it
|
||||
# retry with GET
|
||||
# If the request method is HEAD and we don't have a handler for it
|
||||
# retry with GET.
|
||||
if meth is None and request.method == 'HEAD':
|
||||
meth = getattr(self, 'get', None)
|
||||
assert meth is not None, 'Unimplemented method %r' % request.method
|
||||
|
||||
72
vendor/flask/wrappers.py
vendored
72
vendor/flask/wrappers.py
vendored
@@ -5,18 +5,16 @@
|
||||
|
||||
Implements the WSGI wrappers (request and response).
|
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher.
|
||||
:copyright: (c) 2015 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase
|
||||
from werkzeug.exceptions import BadRequest
|
||||
|
||||
from .debughelpers import attach_enctype_error_multidict
|
||||
from . import json
|
||||
from .globals import _request_ctx_stack
|
||||
|
||||
|
||||
_missing = object()
|
||||
|
||||
|
||||
@@ -40,30 +38,30 @@ class Request(RequestBase):
|
||||
specific ones.
|
||||
"""
|
||||
|
||||
#: the internal URL rule that matched the request. This can be
|
||||
#: The internal URL rule that matched the request. This can be
|
||||
#: useful to inspect which methods are allowed for the URL from
|
||||
#: a before/after handler (``request.url_rule.methods``) etc.
|
||||
#:
|
||||
#: .. versionadded:: 0.6
|
||||
url_rule = None
|
||||
|
||||
#: a dict of view arguments that matched the request. If an exception
|
||||
#: happened when matching, this will be `None`.
|
||||
#: A dict of view arguments that matched the request. If an exception
|
||||
#: happened when matching, this will be ``None``.
|
||||
view_args = None
|
||||
|
||||
#: if matching the URL failed, this is the exception that will be
|
||||
#: If matching the URL failed, this is the exception that will be
|
||||
#: raised / was raised as part of the request handling. This is
|
||||
#: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
|
||||
#: something similar.
|
||||
routing_exception = None
|
||||
|
||||
# switched by the request context until 1.0 to opt in deprecated
|
||||
# module functionality
|
||||
# Switched by the request context until 1.0 to opt in deprecated
|
||||
# module functionality.
|
||||
_is_old_module = False
|
||||
|
||||
@property
|
||||
def max_content_length(self):
|
||||
"""Read-only view of the `MAX_CONTENT_LENGTH` config key."""
|
||||
"""Read-only view of the ``MAX_CONTENT_LENGTH`` config key."""
|
||||
ctx = _request_ctx_stack.top
|
||||
if ctx is not None:
|
||||
return ctx.app.config['MAX_CONTENT_LENGTH']
|
||||
@@ -73,7 +71,7 @@ class Request(RequestBase):
|
||||
"""The endpoint that matched the request. This in combination with
|
||||
:attr:`view_args` can be used to reconstruct the same or a
|
||||
modified URL. If an exception happened when matching, this will
|
||||
be `None`.
|
||||
be ``None``.
|
||||
"""
|
||||
if self.url_rule is not None:
|
||||
return self.url_rule.endpoint
|
||||
@@ -99,32 +97,50 @@ class Request(RequestBase):
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
"""If the mimetype is `application/json` this will contain the
|
||||
parsed JSON data. Otherwise this will be `None`.
|
||||
"""If the mimetype is :mimetype:`application/json` this will contain the
|
||||
parsed JSON data. Otherwise this will be ``None``.
|
||||
|
||||
The :meth:`get_json` method should be used instead.
|
||||
"""
|
||||
# XXX: deprecate property
|
||||
from warnings import warn
|
||||
warn(DeprecationWarning('json is deprecated. '
|
||||
'Use get_json() instead.'), stacklevel=2)
|
||||
return self.get_json()
|
||||
|
||||
def get_json(self, force=False, silent=False, cache=True):
|
||||
"""Parses the incoming JSON request data and returns it. If
|
||||
parsing fails the :meth:`on_json_loading_failed` method on the
|
||||
request object will be invoked. By default this function will
|
||||
only load the json data if the mimetype is ``application/json``
|
||||
but this can be overriden by the `force` parameter.
|
||||
@property
|
||||
def is_json(self):
|
||||
"""Indicates if this request is JSON or not. By default a request
|
||||
is considered to include JSON data if the mimetype is
|
||||
:mimetype:`application/json` or :mimetype:`application/*+json`.
|
||||
|
||||
:param force: if set to `True` the mimetype is ignored.
|
||||
:param silent: if set to `False` this method will fail silently
|
||||
and return `False`.
|
||||
:param cache: if set to `True` the parsed JSON data is remembered
|
||||
.. versionadded:: 0.11
|
||||
"""
|
||||
mt = self.mimetype
|
||||
if mt == 'application/json':
|
||||
return True
|
||||
if mt.startswith('application/') and mt.endswith('+json'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_json(self, force=False, silent=False, cache=True):
|
||||
"""Parses the incoming JSON request data and returns it. By default
|
||||
this function will return ``None`` if the mimetype is not
|
||||
:mimetype:`application/json` but this can be overridden by the
|
||||
``force`` parameter. If parsing fails the
|
||||
:meth:`on_json_loading_failed` method on the request object will be
|
||||
invoked.
|
||||
|
||||
:param force: if set to ``True`` the mimetype is ignored.
|
||||
:param silent: if set to ``True`` this method will fail silently
|
||||
and return ``None``.
|
||||
:param cache: if set to ``True`` the parsed JSON data is remembered
|
||||
on the request.
|
||||
"""
|
||||
rv = getattr(self, '_cached_json', _missing)
|
||||
if rv is not _missing:
|
||||
return rv
|
||||
|
||||
if self.mimetype != 'application/json' and not force:
|
||||
if not (force or self.is_json):
|
||||
return None
|
||||
|
||||
# We accept a request charset against the specification as
|
||||
@@ -159,16 +175,20 @@ class Request(RequestBase):
|
||||
|
||||
.. versionadded:: 0.8
|
||||
"""
|
||||
ctx = _request_ctx_stack.top
|
||||
if ctx is not None and ctx.app.config.get('DEBUG', False):
|
||||
raise BadRequest('Failed to decode JSON object: {0}'.format(e))
|
||||
raise BadRequest()
|
||||
|
||||
def _load_form_data(self):
|
||||
RequestBase._load_form_data(self)
|
||||
|
||||
# in debug mode we're replacing the files multidict with an ad-hoc
|
||||
# In debug mode we're replacing the files multidict with an ad-hoc
|
||||
# subclass that raises a different error for key errors.
|
||||
ctx = _request_ctx_stack.top
|
||||
if ctx is not None and ctx.app.debug and \
|
||||
self.mimetype != 'multipart/form-data' and not self.files:
|
||||
from .debughelpers import attach_enctype_error_multidict
|
||||
attach_enctype_error_multidict(self)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user