mirror of https://github.com/mitsuhiko/flask.git
602 changed files with 0 additions and 151282 deletions
@ -1,80 +0,0 @@
|
||||
# This file must be used with "source bin/activate" *from bash* |
||||
# you cannot run it directly |
||||
|
||||
deactivate () { |
||||
unset pydoc |
||||
|
||||
# reset old environment variables |
||||
if [ -n "$_OLD_VIRTUAL_PATH" ] ; then |
||||
PATH="$_OLD_VIRTUAL_PATH" |
||||
export PATH |
||||
unset _OLD_VIRTUAL_PATH |
||||
fi |
||||
if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then |
||||
PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" |
||||
export PYTHONHOME |
||||
unset _OLD_VIRTUAL_PYTHONHOME |
||||
fi |
||||
|
||||
# This should detect bash and zsh, which have a hash command that must |
||||
# be called to get it to forget past commands. Without forgetting |
||||
# past commands the $PATH changes we made may not be respected |
||||
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then |
||||
hash -r 2>/dev/null |
||||
fi |
||||
|
||||
if [ -n "$_OLD_VIRTUAL_PS1" ] ; then |
||||
PS1="$_OLD_VIRTUAL_PS1" |
||||
export PS1 |
||||
unset _OLD_VIRTUAL_PS1 |
||||
fi |
||||
|
||||
unset VIRTUAL_ENV |
||||
if [ ! "$1" = "nondestructive" ] ; then |
||||
# Self destruct! |
||||
unset -f deactivate |
||||
fi |
||||
} |
||||
|
||||
# unset irrelevant variables |
||||
deactivate nondestructive |
||||
|
||||
VIRTUAL_ENV="/home/melvin/development/shortenmyurl/venv" |
||||
export VIRTUAL_ENV |
||||
|
||||
_OLD_VIRTUAL_PATH="$PATH" |
||||
PATH="$VIRTUAL_ENV/bin:$PATH" |
||||
export PATH |
||||
|
||||
# unset PYTHONHOME if set |
||||
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) |
||||
# could use `if (set -u; : $PYTHONHOME) ;` in bash |
||||
if [ -n "$PYTHONHOME" ] ; then |
||||
_OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" |
||||
unset PYTHONHOME |
||||
fi |
||||
|
||||
if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then |
||||
_OLD_VIRTUAL_PS1="$PS1" |
||||
if [ "x" != x ] ; then |
||||
PS1="$PS1" |
||||
else |
||||
if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then |
||||
# special case for Aspen magic directories |
||||
# see http://www.zetadev.com/software/aspen/ |
||||
PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" |
||||
else |
||||
PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" |
||||
fi |
||||
fi |
||||
export PS1 |
||||
fi |
||||
|
||||
alias pydoc="python -m pydoc" |
||||
|
||||
# This should detect bash and zsh, which have a hash command that must |
||||
# be called to get it to forget past commands. Without forgetting |
||||
# past commands the $PATH changes we made may not be respected |
||||
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then |
||||
hash -r 2>/dev/null |
||||
fi |
@ -1,42 +0,0 @@
|
||||
# This file must be used with "source bin/activate.csh" *from csh*. |
||||
# You cannot run it directly. |
||||
# Created by Davide Di Blasi <davidedb@gmail.com>. |
||||
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' |
||||
|
||||
# Unset irrelevant variables. |
||||
deactivate nondestructive |
||||
|
||||
setenv VIRTUAL_ENV "/home/melvin/development/shortenmyurl/venv" |
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH" |
||||
setenv PATH "$VIRTUAL_ENV/bin:$PATH" |
||||
|
||||
|
||||
|
||||
if ("" != "") then |
||||
set env_name = "" |
||||
else |
||||
if (`basename "$VIRTUAL_ENV"` == "__") then |
||||
# special case for Aspen magic directories |
||||
# see http://www.zetadev.com/software/aspen/ |
||||
set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` |
||||
else |
||||
set env_name = `basename "$VIRTUAL_ENV"` |
||||
endif |
||||
endif |
||||
|
||||
# Could be in a non-interactive environment, |
||||
# in which case, $prompt is undefined and we wouldn't |
||||
# care about the prompt anyway. |
||||
if ( $?prompt ) then |
||||
set _OLD_VIRTUAL_PROMPT="$prompt" |
||||
set prompt = "[$env_name] $prompt" |
||||
endif |
||||
|
||||
unset env_name |
||||
|
||||
alias pydoc python -m pydoc |
||||
|
||||
rehash |
||||
|
@ -1,74 +0,0 @@
|
||||
# This file must be used with "source bin/activate.fish" *from fish* (http://fishshell.com) |
||||
# you cannot run it directly |
||||
|
||||
function deactivate -d "Exit virtualenv and return to normal shell environment" |
||||
# reset old environment variables |
||||
if test -n "$_OLD_VIRTUAL_PATH" |
||||
set -gx PATH $_OLD_VIRTUAL_PATH |
||||
set -e _OLD_VIRTUAL_PATH |
||||
end |
||||
if test -n "$_OLD_VIRTUAL_PYTHONHOME" |
||||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME |
||||
set -e _OLD_VIRTUAL_PYTHONHOME |
||||
end |
||||
|
||||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE" |
||||
# set an empty local fish_function_path, so fish_prompt doesn't automatically reload |
||||
set -l fish_function_path |
||||
# erase the virtualenv's fish_prompt function, and restore the original |
||||
functions -e fish_prompt |
||||
functions -c _old_fish_prompt fish_prompt |
||||
functions -e _old_fish_prompt |
||||
set -e _OLD_FISH_PROMPT_OVERRIDE |
||||
end |
||||
|
||||
set -e VIRTUAL_ENV |
||||
if test "$argv[1]" != "nondestructive" |
||||
# Self destruct! |
||||
functions -e deactivate |
||||
end |
||||
end |
||||
|
||||
# unset irrelevant variables |
||||
deactivate nondestructive |
||||
|
||||
set -gx VIRTUAL_ENV "/home/melvin/development/shortenmyurl/venv" |
||||
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH |
||||
set -gx PATH "$VIRTUAL_ENV/bin" $PATH |
||||
|
||||
# unset PYTHONHOME if set |
||||
if set -q PYTHONHOME |
||||
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME |
||||
set -e PYTHONHOME |
||||
end |
||||
|
||||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" |
||||
# fish uses a function instead of an env var to generate the prompt. |
||||
|
||||
# copy the current fish_prompt function as the function _old_fish_prompt |
||||
functions -c fish_prompt _old_fish_prompt |
||||
|
||||
# with the original prompt function copied, we can override with our own. |
||||
function fish_prompt |
||||
# Prompt override? |
||||
if test -n "" |
||||
printf "%s%s" "" (set_color normal) |
||||
_old_fish_prompt |
||||
return |
||||
end |
||||
# ...Otherwise, prepend env |
||||
set -l _checkbase (basename "$VIRTUAL_ENV") |
||||
if test $_checkbase = "__" |
||||
# special case for Aspen magic directories |
||||
# see http://www.zetadev.com/software/aspen/ |
||||
printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) |
||||
_old_fish_prompt |
||||
else |
||||
printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) |
||||
_old_fish_prompt |
||||
end |
||||
end |
||||
|
||||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" |
||||
end |
@ -1,34 +0,0 @@
|
||||
"""By using execfile(this_file, dict(__file__=this_file)) you will |
||||
activate this virtualenv environment. |
||||
|
||||
This can be used when you must use an existing Python interpreter, not |
||||
the virtualenv bin/python |
||||
""" |
||||
|
||||
try: |
||||
__file__ |
||||
except NameError: |
||||
raise AssertionError( |
||||
"You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))") |
||||
import sys |
||||
import os |
||||
|
||||
old_os_path = os.environ['PATH'] |
||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path |
||||
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
||||
if sys.platform == 'win32': |
||||
site_packages = os.path.join(base, 'Lib', 'site-packages') |
||||
else: |
||||
site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages') |
||||
prev_sys_path = list(sys.path) |
||||
import site |
||||
site.addsitedir(site_packages) |
||||
sys.real_prefix = sys.prefix |
||||
sys.prefix = base |
||||
# Move the added items to the front of the path: |
||||
new_sys_path = [] |
||||
for item in list(sys.path): |
||||
if item not in prev_sys_path: |
||||
new_sys_path.append(item) |
||||
sys.path.remove(item) |
||||
sys.path[:0] = new_sys_path |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from setuptools.command.easy_install import main |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(main()) |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from setuptools.command.easy_install import main |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(main()) |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from gunicorn.app.wsgiapp import run |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(run()) |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from gunicorn.app.djangoapp import run |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(run()) |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from gunicorn.app.pasterapp import run |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(run()) |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from pip import main |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(main()) |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from pip import main |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(main()) |
@ -1,11 +0,0 @@
|
||||
#!/home/melvin/development/shortenmyurl/venv/bin/python |
||||
|
||||
# -*- coding: utf-8 -*- |
||||
import re |
||||
import sys |
||||
|
||||
from pip import main |
||||
|
||||
if __name__ == '__main__': |
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
||||
sys.exit(main()) |
Binary file not shown.
@ -1 +0,0 @@
|
||||
/usr/include/python2.7 |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/UserDict.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/_abcoll.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/_weakrefset.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/abc.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/codecs.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/copy_reg.py |
@ -1,101 +0,0 @@
|
||||
import os |
||||
import sys |
||||
import warnings |
||||
import imp |
||||
import opcode # opcode is not a virtualenv module, so we can use it to find the stdlib |
||||
# Important! To work on pypy, this must be a module that resides in the |
||||
# lib-python/modified-x.y.z directory |
||||
|
||||
dirname = os.path.dirname |
||||
|
||||
distutils_path = os.path.join(os.path.dirname(opcode.__file__), 'distutils') |
||||
if os.path.normpath(distutils_path) == os.path.dirname(os.path.normpath(__file__)): |
||||
warnings.warn( |
||||
"The virtualenv distutils package at %s appears to be in the same location as the system distutils?") |
||||
else: |
||||
__path__.insert(0, distutils_path) |
||||
real_distutils = imp.load_module("_virtualenv_distutils", None, distutils_path, ('', '', imp.PKG_DIRECTORY)) |
||||
# Copy the relevant attributes |
||||
try: |
||||
__revision__ = real_distutils.__revision__ |
||||
except AttributeError: |
||||
pass |
||||
__version__ = real_distutils.__version__ |
||||
|
||||
from distutils import dist, sysconfig |
||||
|
||||
try: |
||||
basestring |
||||
except NameError: |
||||
basestring = str |
||||
|
||||
## patch build_ext (distutils doesn't know how to get the libs directory |
||||
## path on windows - it hardcodes the paths around the patched sys.prefix) |
||||
|
||||
if sys.platform == 'win32': |
||||
from distutils.command.build_ext import build_ext as old_build_ext |
||||
class build_ext(old_build_ext): |
||||
def finalize_options (self): |
||||
if self.library_dirs is None: |
||||
self.library_dirs = [] |
||||
elif isinstance(self.library_dirs, basestring): |
||||
self.library_dirs = self.library_dirs.split(os.pathsep) |
||||
|
||||
self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs")) |
||||
old_build_ext.finalize_options(self) |
||||
|
||||
from distutils.command import build_ext as build_ext_module |
||||
build_ext_module.build_ext = build_ext |
||||
|
||||
## distutils.dist patches: |
||||
|
||||
old_find_config_files = dist.Distribution.find_config_files |
||||
def find_config_files(self): |
||||
found = old_find_config_files(self) |
||||
system_distutils = os.path.join(distutils_path, 'distutils.cfg') |
||||
#if os.path.exists(system_distutils): |
||||
# found.insert(0, system_distutils) |
||||
# What to call the per-user config file |
||||
if os.name == 'posix': |
||||
user_filename = ".pydistutils.cfg" |
||||
else: |
||||
user_filename = "pydistutils.cfg" |
||||
user_filename = os.path.join(sys.prefix, user_filename) |
||||
if os.path.isfile(user_filename): |
||||
for item in list(found): |
||||
if item.endswith('pydistutils.cfg'): |
||||
found.remove(item) |
||||
found.append(user_filename) |
||||
return found |
||||
dist.Distribution.find_config_files = find_config_files |
||||
|
||||
## distutils.sysconfig patches: |
||||
|
||||
old_get_python_inc = sysconfig.get_python_inc |
||||
def sysconfig_get_python_inc(plat_specific=0, prefix=None): |
||||
if prefix is None: |
||||
prefix = sys.real_prefix |
||||
return old_get_python_inc(plat_specific, prefix) |
||||
sysconfig_get_python_inc.__doc__ = old_get_python_inc.__doc__ |
||||
sysconfig.get_python_inc = sysconfig_get_python_inc |
||||
|
||||
old_get_python_lib = sysconfig.get_python_lib |
||||
def sysconfig_get_python_lib(plat_specific=0, standard_lib=0, prefix=None): |
||||
if standard_lib and prefix is None: |
||||
prefix = sys.real_prefix |
||||
return old_get_python_lib(plat_specific, standard_lib, prefix) |
||||
sysconfig_get_python_lib.__doc__ = old_get_python_lib.__doc__ |
||||
sysconfig.get_python_lib = sysconfig_get_python_lib |
||||
|
||||
old_get_config_vars = sysconfig.get_config_vars |
||||
def sysconfig_get_config_vars(*args): |
||||
real_vars = old_get_config_vars(*args) |
||||
if sys.platform == 'win32': |
||||
lib_dir = os.path.join(sys.real_prefix, "libs") |
||||
if isinstance(real_vars, dict) and 'LIBDIR' not in real_vars: |
||||
real_vars['LIBDIR'] = lib_dir # asked for all |
||||
elif isinstance(real_vars, list) and 'LIBDIR' in args: |
||||
real_vars = real_vars + [lib_dir] # asked for list |
||||
return real_vars |
||||
sysconfig_get_config_vars.__doc__ = old_get_config_vars.__doc__ |
||||
sysconfig.get_config_vars = sysconfig_get_config_vars |
@ -1,6 +0,0 @@
|
||||
# This is a config file local to this virtualenv installation |
||||
# You may include options that will be used by all distutils commands, |
||||
# and by easy_install. For instance: |
||||
# |
||||
# [easy_install] |
||||
# find_links = http://mylocalsite |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/encodings |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/fnmatch.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/genericpath.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/lib-dynload |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/linecache.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/locale.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/ntpath.py |
@ -1 +0,0 @@
|
||||
/usr |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/os.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/posixpath.py |
@ -1 +0,0 @@
|
||||
/usr/lib/python2.7/re.py |
@ -1,16 +0,0 @@
|
||||
try: |
||||
import ast |
||||
from _markerlib.markers import default_environment, compile, interpret |
||||
except ImportError: |
||||
if 'ast' in globals(): |
||||
raise |
||||
def default_environment(): |
||||
return {} |
||||
def compile(marker): |
||||
def marker_fn(environment=None, override=None): |
||||
# 'empty markers are True' heuristic won't install extra deps. |
||||
return not marker.strip() |
||||
marker_fn.__doc__ = marker |
||||
return marker_fn |
||||
def interpret(marker, environment=None, override=None): |
||||
return compile(marker)() |
@ -1,119 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
"""Interpret PEP 345 environment markers. |
||||
|
||||
EXPR [in|==|!=|not in] EXPR [or|and] ... |
||||
|
||||
where EXPR belongs to any of those: |
||||
|
||||
python_version = '%s.%s' % (sys.version_info[0], sys.version_info[1]) |
||||
python_full_version = sys.version.split()[0] |
||||
os.name = os.name |
||||
sys.platform = sys.platform |
||||
platform.version = platform.version() |
||||
platform.machine = platform.machine() |
||||
platform.python_implementation = platform.python_implementation() |
||||
a free string, like '2.6', or 'win32' |
||||
""" |
||||
|
||||
__all__ = ['default_environment', 'compile', 'interpret'] |
||||
|
||||
import ast |
||||
import os |
||||
import platform |
||||
import sys |
||||
import weakref |
||||
|
||||
_builtin_compile = compile |
||||
|
||||
try: |
||||
from platform import python_implementation |
||||
except ImportError: |
||||
if os.name == "java": |
||||
# Jython 2.5 has ast module, but not platform.python_implementation() function. |
||||
def python_implementation(): |
||||
return "Jython" |
||||
else: |
||||
raise |
||||
|
||||
|
||||
# restricted set of variables |
||||
_VARS = {'sys.platform': sys.platform, |
||||
'python_version': '%s.%s' % sys.version_info[:2], |
||||
# FIXME parsing sys.platform is not reliable, but there is no other |
||||
# way to get e.g. 2.7.2+, and the PEP is defined with sys.version |
||||
'python_full_version': sys.version.split(' ', 1)[0], |
||||
'os.name': os.name, |
||||
'platform.version': platform.version(), |
||||
'platform.machine': platform.machine(), |
||||
'platform.python_implementation': python_implementation(), |
||||
'extra': None # wheel extension |
||||
} |
||||
|
||||
for var in list(_VARS.keys()): |
||||
if '.' in var: |
||||
_VARS[var.replace('.', '_')] = _VARS[var] |
||||
|
||||
def default_environment(): |
||||
"""Return copy of default PEP 385 globals dictionary.""" |
||||
return dict(_VARS) |
||||
|
||||
class ASTWhitelist(ast.NodeTransformer): |
||||
def __init__(self, statement): |
||||
self.statement = statement # for error messages |
||||
|
||||
ALLOWED = (ast.Compare, ast.BoolOp, ast.Attribute, ast.Name, ast.Load, ast.Str) |
||||
# Bool operations |
||||
ALLOWED += (ast.And, ast.Or) |
||||
# Comparison operations |
||||
ALLOWED += (ast.Eq, ast.Gt, ast.GtE, ast.In, ast.Is, ast.IsNot, ast.Lt, ast.LtE, ast.NotEq, ast.NotIn) |
||||
|
||||
def visit(self, node): |
||||
"""Ensure statement only contains allowed nodes.""" |
||||
if not isinstance(node, self.ALLOWED): |
||||
raise SyntaxError('Not allowed in environment markers.\n%s\n%s' % |
||||
(self.statement, |
||||
(' ' * node.col_offset) + '^')) |
||||
return ast.NodeTransformer.visit(self, node) |
||||
|
||||
def visit_Attribute(self, node): |
||||
"""Flatten one level of attribute access.""" |
||||
new_node = ast.Name("%s.%s" % (node.value.id, node.attr), node.ctx) |
||||
return ast.copy_location(new_node, node) |
||||
|
||||
def parse_marker(marker): |
||||
tree = ast.parse(marker, mode='eval') |
||||
new_tree = ASTWhitelist(marker).generic_visit(tree) |
||||
return new_tree |
||||
|
||||
def compile_marker(parsed_marker): |
||||
return _builtin_compile(parsed_marker, '<environment marker>', 'eval', |
||||
dont_inherit=True) |
||||
|
||||
_cache = weakref.WeakValueDictionary() |
||||
|
||||
def compile(marker): |
||||
"""Return compiled marker as a function accepting an environment dict.""" |
||||
try: |
||||
return _cache[marker] |
||||
except KeyError: |
||||
pass |
||||
if not marker.strip(): |
||||
def marker_fn(environment=None, override=None): |
||||
"""""" |
||||
return True |
||||
else: |
||||
compiled_marker = compile_marker(parse_marker(marker)) |
||||
def marker_fn(environment=None, override=None): |
||||
"""override updates environment""" |
||||
if override is None: |
||||
override = {} |
||||
if environment is None: |
||||
environment = default_environment() |
||||
environment.update(override) |
||||
return eval(compiled_marker, environment) |
||||
marker_fn.__doc__ = marker |
||||
_cache[marker] = marker_fn |
||||
return _cache[marker] |
||||
|
||||
def interpret(marker, environment=None): |
||||
return compile(marker)(environment) |
@ -1,5 +0,0 @@
|
||||
"""Run the EasyInstall command""" |
||||
|
||||
if __name__ == '__main__': |
||||
from setuptools.command.easy_install import main |
||||
main() |
@ -1,50 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask |
||||
~~~~~ |
||||
|
||||
A microframework based on Werkzeug. It's extensively documented |
||||
and follows best practice patterns. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
__version__ = '0.10.1' |
||||
|
||||
# utilities we import from Werkzeug and Jinja2 that are unused |
||||
# in the module but are exported as public interface. |
||||
from werkzeug.exceptions import abort |
||||
from werkzeug.utils import redirect |
||||
from jinja2 import Markup, escape |
||||
|
||||
from .app import Flask, Request, Response |
||||
from .config import Config |
||||
from .helpers import url_for, flash, send_file, send_from_directory, \ |
||||
get_flashed_messages, get_template_attribute, make_response, safe_join, \ |
||||
stream_with_context |
||||
from .globals import current_app, g, request, session, _request_ctx_stack, \ |
||||
_app_ctx_stack |
||||
from .ctx import has_request_context, has_app_context, \ |
||||
after_this_request, copy_current_request_context |
||||
from .module import Module |
||||
from .blueprints import Blueprint |
||||
from .templating import render_template, render_template_string |
||||
|
||||
# the signals |
||||
from .signals import signals_available, template_rendered, request_started, \ |
||||
request_finished, got_request_exception, request_tearing_down, \ |
||||
appcontext_tearing_down, appcontext_pushed, \ |
||||
appcontext_popped, message_flashed |
||||
|
||||
# We're not exposing the actual json module but a convenient wrapper around |
||||
# it. |
||||
from . import json |
||||
|
||||
# This was the only thing that flask used to export at one point and it had |
||||
# a more generic name. |
||||
jsonify = json.jsonify |
||||
|
||||
# backwards compat, goes away in 1.0 |
||||
from .sessions import SecureCookieSession as Session |
||||
json_available = True |
@ -1,73 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask._compat |
||||
~~~~~~~~~~~~~ |
||||
|
||||
Some py2/py3 compatibility support based on a stripped down |
||||
version of six so we don't have to depend on a specific version |
||||
of it. |
||||
|
||||
:copyright: (c) 2013 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
import sys |
||||
|
||||
PY2 = sys.version_info[0] == 2 |
||||
_identity = lambda x: x |
||||
|
||||
|
||||
if not PY2: |
||||
text_type = str |
||||
string_types = (str,) |
||||
integer_types = (int, ) |
||||
|
||||
iterkeys = lambda d: iter(d.keys()) |
||||
itervalues = lambda d: iter(d.values()) |
||||
iteritems = lambda d: iter(d.items()) |
||||
|
||||
from io import StringIO |
||||
|
||||
def reraise(tp, value, tb=None): |
||||
if value.__traceback__ is not tb: |
||||
raise value.with_traceback(tb) |
||||
raise value |
||||
|
||||
implements_to_string = _identity |
||||
|
||||
else: |
||||
text_type = unicode |
||||
string_types = (str, unicode) |
||||
integer_types = (int, long) |
||||
|
||||
iterkeys = lambda d: d.iterkeys() |
||||
itervalues = lambda d: d.itervalues() |
||||
iteritems = lambda d: d.iteritems() |
||||
|
||||
from cStringIO import StringIO |
||||
|
||||
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb') |
||||
|
||||
def implements_to_string(cls): |
||||
cls.__unicode__ = cls.__str__ |
||||
cls.__str__ = lambda x: x.__unicode__().encode('utf-8') |
||||
return cls |
||||
|
||||
|
||||
def with_metaclass(meta, *bases): |
||||
# 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__ |
||||
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, {}) |
File diff suppressed because it is too large
Load Diff
@ -1,401 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.blueprints |
||||
~~~~~~~~~~~~~~~~ |
||||
|
||||
Blueprints are the recommended way to implement larger or more |
||||
pluggable applications in Flask 0.7 and later. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
from functools import update_wrapper |
||||
|
||||
from .helpers import _PackageBoundObject, _endpoint_from_view_func |
||||
|
||||
|
||||
class BlueprintSetupState(object): |
||||
"""Temporary holder object for registering a blueprint with the |
||||
application. An instance of this class is created by the |
||||
:meth:`~flask.Blueprint.make_setup_state` method and later passed |
||||
to all register callback functions. |
||||
""" |
||||
|
||||
def __init__(self, blueprint, app, options, first_registration): |
||||
#: a reference to the current application |
||||
self.app = app |
||||
|
||||
#: a reference to the blueprint that created this setup state. |
||||
self.blueprint = blueprint |
||||
|
||||
#: a dictionary with all options that were passed to the |
||||
#: :meth:`~flask.Flask.register_blueprint` method. |
||||
self.options = options |
||||
|
||||
#: as blueprints can be registered multiple times with the |
||||
#: application and not everything wants to be registered |
||||
#: multiple times on it, this attribute can be used to figure |
||||
#: out if the blueprint was registered in the past already. |
||||
self.first_registration = first_registration |
||||
|
||||
subdomain = self.options.get('subdomain') |
||||
if subdomain is None: |
||||
subdomain = self.blueprint.subdomain |
||||
|
||||
#: The subdomain that the blueprint should be active for, `None` |
||||
#: otherwise. |
||||
self.subdomain = subdomain |
||||
|
||||
url_prefix = self.options.get('url_prefix') |
||||
if url_prefix is None: |
||||
url_prefix = self.blueprint.url_prefix |
||||
|
||||
#: The prefix that should be used for all URLs defined on the |
||||
#: blueprint. |
||||
self.url_prefix = url_prefix |
||||
|
||||
#: A dictionary with URL defaults that is added to each and every |
||||
#: URL that was defined with the blueprint. |
||||
self.url_defaults = dict(self.blueprint.url_values_defaults) |
||||
self.url_defaults.update(self.options.get('url_defaults', ())) |
||||
|
||||
def add_url_rule(self, rule, endpoint=None, view_func=None, **options): |
||||
"""A helper method to register a rule (and optionally a view function) |
||||
to the application. The endpoint is automatically prefixed with the |
||||
blueprint's name. |
||||
""" |
||||
if self.url_prefix: |
||||
rule = self.url_prefix + rule |
||||
options.setdefault('subdomain', self.subdomain) |
||||
if endpoint is None: |
||||
endpoint = _endpoint_from_view_func(view_func) |
||||
defaults = self.url_defaults |
||||
if 'defaults' in options: |
||||
defaults = dict(defaults, **options.pop('defaults')) |
||||
self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint), |
||||
view_func, defaults=defaults, **options) |
||||
|
||||
|
||||
class Blueprint(_PackageBoundObject): |
||||
"""Represents a blueprint. A blueprint is an object that records |
||||
functions that will be called with the |
||||
:class:`~flask.blueprint.BlueprintSetupState` later to register functions |
||||
or other things on the main application. See :ref:`blueprints` for more |
||||
information. |
||||
|
||||
.. versionadded:: 0.7 |
||||
""" |
||||
|
||||
warn_on_modifications = False |
||||
_got_registered_once = False |
||||
|
||||
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) |
||||
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 |
||||
|
||||
def record(self, func): |
||||
"""Registers a function that is called when the blueprint is |
||||
registered on the application. This function is called with the |
||||
state as argument as returned by the :meth:`make_setup_state` |
||||
method. |
||||
""" |
||||
if self._got_registered_once and self.warn_on_modifications: |
||||
from warnings import warn |
||||
warn(Warning('The blueprint was already registered once ' |
||||
'but is getting modified now. These changes ' |
||||
'will not show up.')) |
||||
self.deferred_functions.append(func) |
||||
|
||||
def record_once(self, func): |
||||
"""Works like :meth:`record` but wraps the function in another |
||||
function that will ensure the function is only called once. If the |
||||
blueprint is registered a second time on the application, the |
||||
function passed is not called. |
||||
""" |
||||
def wrapper(state): |
||||
if state.first_registration: |
||||
func(state) |
||||
return self.record(update_wrapper(wrapper, func)) |
||||
|
||||
def make_setup_state(self, app, options, first_registration=False): |
||||
"""Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` |
||||
object that is later passed to the register callback functions. |
||||
Subclasses can override this to return a subclass of the setup state. |
||||
""" |
||||
return BlueprintSetupState(self, app, options, first_registration) |
||||
|
||||
def register(self, app, options, first_registration=False): |
||||
"""Called by :meth:`Flask.register_blueprint` to register a blueprint |
||||
on the application. This can be overridden to customize the register |
||||
behavior. Keyword arguments from |
||||
:func:`~flask.Flask.register_blueprint` are directly forwarded to this |
||||
method in the `options` dictionary. |
||||
""" |
||||
self._got_registered_once = True |
||||
state = self.make_setup_state(app, options, first_registration) |
||||
if self.has_static_folder: |
||||
state.add_url_rule(self.static_url_path + '/<path:filename>', |
||||
view_func=self.send_static_file, |
||||
endpoint='static') |
||||
|
||||
for deferred in self.deferred_functions: |
||||
deferred(state) |
||||
|
||||
def route(self, rule, **options): |
||||
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the |
||||
:func:`url_for` function is prefixed with the name of the blueprint. |
||||
""" |
||||
def decorator(f): |
||||
endpoint = options.pop("endpoint", f.__name__) |
||||
self.add_url_rule(rule, endpoint, f, **options) |
||||
return f |
||||
return decorator |
||||
|
||||
def add_url_rule(self, rule, endpoint=None, view_func=None, **options): |
||||
"""Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for |
||||
the :func:`url_for` function is prefixed with the name of the blueprint. |
||||
""" |
||||
if endpoint: |
||||
assert '.' not in endpoint, "Blueprint endpoint's should not contain dot's" |
||||
self.record(lambda s: |
||||
s.add_url_rule(rule, endpoint, view_func, **options)) |
||||
|
||||
def endpoint(self, endpoint): |
||||
"""Like :meth:`Flask.endpoint` but for a blueprint. This does not |
||||
prefix the endpoint with the blueprint name, this has to be done |
||||
explicitly by the user of this method. If the endpoint is prefixed |
||||
with a `.` it will be registered to the current blueprint, otherwise |
||||
it's an application independent endpoint. |
||||
""" |
||||
def decorator(f): |
||||
def register_endpoint(state): |
||||
state.app.view_functions[endpoint] = f |
||||
self.record_once(register_endpoint) |
||||
return f |
||||
return decorator |
||||
|
||||
def app_template_filter(self, name=None): |
||||
"""Register a custom template filter, available application wide. Like |
||||
:meth:`Flask.template_filter` but for a blueprint. |
||||
|
||||
:param name: the optional name of the filter, otherwise the |
||||
function name will be used. |
||||
""" |
||||
def decorator(f): |
||||
self.add_app_template_filter(f, name=name) |
||||
return f |
||||
return decorator |
||||
|
||||
def add_app_template_filter(self, f, name=None): |
||||
"""Register a custom template filter, available application wide. Like |
||||
:meth:`Flask.add_template_filter` but for a blueprint. Works exactly |
||||
like the :meth:`app_template_filter` decorator. |
||||
|
||||
:param name: the optional name of the filter, otherwise the |
||||
function name will be used. |
||||
""" |
||||
def register_template(state): |
||||
state.app.jinja_env.filters[name or f.__name__] = f |
||||
self.record_once(register_template) |
||||
|
||||
def app_template_test(self, name=None): |
||||
"""Register a custom template test, available application wide. Like |
||||
:meth:`Flask.template_test` but for a blueprint. |
||||
|
||||
.. versionadded:: 0.10 |
||||
|
||||
:param name: the optional name of the test, otherwise the |
||||
function name will be used. |
||||
""" |
||||
def decorator(f): |
||||
self.add_app_template_test(f, name=name) |
||||
return f |
||||
return decorator |
||||
|
||||
def add_app_template_test(self, f, name=None): |
||||
"""Register a custom template test, available application wide. Like |
||||
:meth:`Flask.add_template_test` but for a blueprint. Works exactly |
||||
like the :meth:`app_template_test` decorator. |
||||
|
||||
.. versionadded:: 0.10 |
||||
|
||||
:param name: the optional name of the test, otherwise the |
||||
function name will be used. |
||||
""" |
||||
def register_template(state): |
||||
state.app.jinja_env.tests[name or f.__name__] = f |
||||
self.record_once(register_template) |
||||
|
||||
def app_template_global(self, name=None): |
||||
"""Register a custom template global, available application wide. Like |
||||
:meth:`Flask.template_global` but for a blueprint. |
||||
|
||||
.. versionadded:: 0.10 |
||||
|
||||
:param name: the optional name of the global, otherwise the |
||||
function name will be used. |
||||
""" |
||||
def decorator(f): |
||||
self.add_app_template_global(f, name=name) |
||||
return f |
||||
return decorator |
||||
|
||||
def add_app_template_global(self, f, name=None): |
||||
"""Register a custom template global, available application wide. Like |
||||
:meth:`Flask.add_template_global` but for a blueprint. Works exactly |
||||
like the :meth:`app_template_global` decorator. |
||||
|
||||
.. versionadded:: 0.10 |
||||
|
||||
:param name: the optional name of the global, otherwise the |
||||
function name will be used. |
||||
""" |
||||
def register_template(state): |
||||
state.app.jinja_env.globals[name or f.__name__] = f |
||||
self.record_once(register_template) |
||||
|
||||
def before_request(self, f): |
||||
"""Like :meth:`Flask.before_request` but for a blueprint. This function |
||||
is only executed before each request that is handled by a function of |
||||
that blueprint. |
||||
""" |
||||
self.record_once(lambda s: s.app.before_request_funcs |
||||
.setdefault(self.name, []).append(f)) |
||||
return f |
||||
|
||||
def before_app_request(self, f): |
||||
"""Like :meth:`Flask.before_request`. Such a function is executed |
||||
before each request, even if outside of a blueprint. |
||||
""" |
||||
self.record_once(lambda s: s.app.before_request_funcs |
||||
.setdefault(None, []).append(f)) |
||||
return f |
||||
|
||||
def before_app_first_request(self, f): |
||||
"""Like :meth:`Flask.before_first_request`. Such a function is |
||||
executed before the first request to the application. |
||||
""" |
||||
self.record_once(lambda s: s.app.before_first_request_funcs.append(f)) |
||||
return f |
||||
|
||||
def after_request(self, f): |
||||
"""Like :meth:`Flask.after_request` but for a blueprint. This function |
||||
is only executed after each request that is handled by a function of |
||||
that blueprint. |
||||
""" |
||||
self.record_once(lambda s: s.app.after_request_funcs |
||||
.setdefault(self.name, []).append(f)) |
||||
return f |
||||
|
||||
def after_app_request(self, f): |
||||
"""Like :meth:`Flask.after_request` but for a blueprint. Such a function |
||||
is executed after each request, even if outside of the blueprint. |
||||
""" |
||||
self.record_once(lambda s: s.app.after_request_funcs |
||||
.setdefault(None, []).append(f)) |
||||
return f |
||||
|
||||
def teardown_request(self, f): |
||||
"""Like :meth:`Flask.teardown_request` but for a blueprint. This |
||||
function is only executed when tearing down requests handled by a |
||||
function of that blueprint. Teardown request functions are executed |
||||
when the request context is popped, even when no actual request was |
||||
performed. |
||||
""" |
||||
self.record_once(lambda s: s.app.teardown_request_funcs |
||||
.setdefault(self.name, []).append(f)) |
||||
return f |
||||
|
||||
def teardown_app_request(self, f): |
||||
"""Like :meth:`Flask.teardown_request` but for a blueprint. Such a |
||||
function is executed when tearing down each request, even if outside of |
||||
the blueprint. |
||||
""" |
||||
self.record_once(lambda s: s.app.teardown_request_funcs |
||||
.setdefault(None, []).append(f)) |
||||
return f |
||||
|
||||
def context_processor(self, f): |
||||
"""Like :meth:`Flask.context_processor` but for a blueprint. This |
||||
function is only executed for requests handled by a blueprint. |
||||
""" |
||||
self.record_once(lambda s: s.app.template_context_processors |
||||
.setdefault(self.name, []).append(f)) |
||||
return f |
||||
|
||||
def app_context_processor(self, f): |
||||
"""Like :meth:`Flask.context_processor` but for a blueprint. Such a |
||||
function is executed each request, even if outside of the blueprint. |
||||
""" |
||||
self.record_once(lambda s: s.app.template_context_processors |
||||
.setdefault(None, []).append(f)) |
||||
return f |
||||
|
||||
def app_errorhandler(self, code): |
||||
"""Like :meth:`Flask.errorhandler` but for a blueprint. This |
||||
handler is used for all requests, even if outside of the blueprint. |
||||
""" |
||||
def decorator(f): |
||||
self.record_once(lambda s: s.app.errorhandler(code)(f)) |
||||
return f |
||||
return decorator |
||||
|
||||
def url_value_preprocessor(self, f): |
||||
"""Registers a function as URL value preprocessor for this |
||||
blueprint. It's called before the view functions are called and |
||||
can modify the url values provided. |
||||
""" |
||||
self.record_once(lambda s: s.app.url_value_preprocessors |
||||
.setdefault(self.name, []).append(f)) |
||||
return f |
||||
|
||||
def url_defaults(self, f): |
||||
"""Callback function for URL defaults for this blueprint. It's called |
||||
with the endpoint and values and should update the values passed |
||||
in place. |
||||
""" |
||||
self.record_once(lambda s: s.app.url_default_functions |
||||
.setdefault(self.name, []).append(f)) |
||||
return f |
||||
|
||||
def app_url_value_preprocessor(self, f): |
||||
"""Same as :meth:`url_value_preprocessor` but application wide. |
||||
""" |
||||
self.record_once(lambda s: s.app.url_value_preprocessors |
||||
.setdefault(None, []).append(f)) |
||||
return f |
||||
|
||||
def app_url_defaults(self, f): |
||||
"""Same as :meth:`url_defaults` but application wide. |
||||
""" |
||||
self.record_once(lambda s: s.app.url_default_functions |
||||
.setdefault(None, []).append(f)) |
||||
return f |
||||
|
||||
def errorhandler(self, code_or_exception): |
||||
"""Registers an error handler that becomes active for this blueprint |
||||
only. Please be aware that routing does not happen local to a |
||||
blueprint so an error handler for 404 usually is not handled by |
||||
a blueprint unless it is caused inside a view function. Another |
||||
special case is the 500 internal server error which is always looked |
||||
up from the application. |
||||
|
||||
Otherwise works as the :meth:`~flask.Flask.errorhandler` decorator |
||||
of the :class:`~flask.Flask` object. |
||||
""" |
||||
def decorator(f): |
||||
self.record_once(lambda s: s.app._register_error_handler( |
||||
self.name, code_or_exception, f)) |
||||
return f |
||||
return decorator |
@ -1,168 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.config |
||||
~~~~~~~~~~~~ |
||||
|
||||
Implements the configuration related objects. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
import imp |
||||
import os |
||||
import errno |
||||
|
||||
from werkzeug.utils import import_string |
||||
from ._compat import string_types |
||||
|
||||
|
||||
class ConfigAttribute(object): |
||||
"""Makes an attribute forward to the config""" |
||||
|
||||
def __init__(self, name, get_converter=None): |
||||
self.__name__ = name |
||||
self.get_converter = get_converter |
||||
|
||||
def __get__(self, obj, type=None): |
||||
if obj is None: |
||||
return self |
||||
rv = obj.config[self.__name__] |
||||
if self.get_converter is not None: |
||||
rv = self.get_converter(rv) |
||||
return rv |
||||
|
||||
def __set__(self, obj, value): |
||||
obj.config[self.__name__] = value |
||||
|
||||
|
||||
class Config(dict): |
||||
"""Works exactly like a dict but provides ways to fill it from files |
||||
or special dictionaries. There are two common patterns to populate the |
||||
config. |
||||
|
||||
Either you can fill the config from a config file:: |
||||
|
||||
app.config.from_pyfile('yourconfig.cfg') |
||||
|
||||
Or alternatively you can define the configuration options in the |
||||
module that calls :meth:`from_object` or provide an import path to |
||||
a module that should be loaded. It is also possible to tell it to |
||||
use the same module and with that provide the configuration values |
||||
just before the call:: |
||||
|
||||
DEBUG = True |
||||
SECRET_KEY = 'development key' |
||||
app.config.from_object(__name__) |
||||
|
||||
In both cases (loading from any Python file or loading from modules), |
||||
only uppercase keys are added to the config. This makes it possible to use |
||||
lowercase values in the config file for temporary values that are not added |
||||
to the config or to define the config keys in the same file that implements |
||||
the application. |
||||
|
||||
Probably the most interesting way to load configurations is from an |
||||
environment variable pointing to a file:: |
||||
|
||||
app.config.from_envvar('YOURAPPLICATION_SETTINGS') |
||||
|
||||
In this case before launching the application you have to set this |
||||
environment variable to the file you want to use. On Linux and OS X |
||||
use the export statement:: |
||||
|
||||
export YOURAPPLICATION_SETTINGS='/path/to/config/file' |
||||
|
||||
On windows use `set` instead. |
||||
|
||||
:param root_path: path to which files are read relative from. When the |
||||
config object is created by the application, this is |
||||
the application's :attr:`~flask.Flask.root_path`. |
||||
:param defaults: an optional dictionary of default values |
||||
""" |
||||
|
||||
def __init__(self, root_path, defaults=None): |
||||
dict.__init__(self, defaults or {}) |
||||
self.root_path = root_path |
||||
|
||||
def from_envvar(self, variable_name, silent=False): |
||||
"""Loads a configuration from an environment variable pointing to |
||||
a configuration file. This is basically just a shortcut with nicer |
||||
error messages for this line of code:: |
||||
|
||||
app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) |
||||
|
||||
:param variable_name: name of the environment variable |
||||
:param silent: set to `True` if you want silent failure for missing |
||||
files. |
||||
:return: bool. `True` if able to load config, `False` otherwise. |
||||
""" |
||||
rv = os.environ.get(variable_name) |
||||
if not rv: |
||||
if silent: |
||||
return False |
||||
raise RuntimeError('The environment variable %r is not set ' |
||||
'and as such configuration could not be ' |
||||
'loaded. Set this variable and make it ' |
||||
'point to a configuration file' % |
||||
variable_name) |
||||
return self.from_pyfile(rv, silent=silent) |
||||
|
||||
def from_pyfile(self, filename, silent=False): |
||||
"""Updates the values in the config from a Python file. This function |
||||
behaves as if the file was imported as module with the |
||||
:meth:`from_object` function. |
||||
|
||||
:param filename: the filename of the config. This can either be an |
||||
absolute filename or a filename relative to the |
||||
root path. |
||||
:param silent: set to `True` if you want silent failure for missing |
||||
files. |
||||
|
||||
.. versionadded:: 0.7 |
||||
`silent` parameter. |
||||
""" |
||||
filename = os.path.join(self.root_path, filename) |
||||
d = imp.new_module('config') |
||||
d.__file__ = filename |
||||
try: |
||||
with open(filename) as config_file: |
||||
exec(compile(config_file.read(), filename, 'exec'), d.__dict__) |
||||
except IOError as e: |
||||
if silent and e.errno in (errno.ENOENT, errno.EISDIR): |
||||
return False |
||||
e.strerror = 'Unable to load configuration file (%s)' % e.strerror |
||||
raise |
||||
self.from_object(d) |
||||
return True |
||||
|
||||
def from_object(self, obj): |
||||
"""Updates the values from the given object. An object can be of one |
||||
of the following two types: |
||||
|
||||
- a string: in this case the object with that name will be imported |
||||
- an actual object reference: that object is used directly |
||||
|
||||
Objects are usually either modules or classes. |
||||
|
||||
Just the uppercase variables in that object are stored in the config. |
||||
Example usage:: |
||||
|
||||
app.config.from_object('yourapplication.default_config') |
||||
from yourapplication import default_config |
||||
app.config.from_object(default_config) |
||||
|
||||
You should not use this function to load the actual configuration but |
||||
rather configuration defaults. The actual config should be loaded |
||||
with :meth:`from_pyfile` and ideally from a location not within the |
||||
package because the package might be installed system wide. |
||||
|
||||
:param obj: an import name or object |
||||
""" |
||||
if isinstance(obj, string_types): |
||||
obj = import_string(obj) |
||||
for key in dir(obj): |
||||
if key.isupper(): |
||||
self[key] = getattr(obj, key) |
||||
|
||||
def __repr__(self): |
||||
return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self)) |
@ -1,394 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.ctx |
||||
~~~~~~~~~ |
||||
|
||||
Implements the objects required to keep the context. |
||||
|
||||
:copyright: (c) 2011 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 |
||||
|
||||
|
||||
class _AppCtxGlobals(object): |
||||
"""A plain object.""" |
||||
|
||||
def get(self, name, default=None): |
||||
return self.__dict__.get(name, default) |
||||
|
||||
def __contains__(self, item): |
||||
return item in self.__dict__ |
||||
|
||||
def __iter__(self): |
||||
return iter(self.__dict__) |
||||
|
||||
def __repr__(self): |
||||
top = _app_ctx_stack.top |
||||
if top is not None: |
||||
return '<flask.g of %r>' % top.app.name |
||||
return object.__repr__(self) |
||||
|
||||
|
||||
def after_this_request(f): |
||||
"""Executes a function after this request. This is useful to modify |
||||
response objects. The function is passed the response object and has |
||||
to return the same or a new one. |
||||
|
||||
Example:: |
||||
|
||||
@app.route('/') |
||||
def index(): |
||||
@after_this_request |
||||
def add_header(response): |
||||
response.headers['X-Foo'] = 'Parachute' |
||||
return response |
||||
return 'Hello World!' |
||||
|
||||
This is more useful if a function other than the view function wants to |
||||
modify a response. For instance think of a decorator that wants to add |
||||
some headers without converting the return value into a response object. |
||||
|
||||
.. versionadded:: 0.9 |
||||
""" |
||||
_request_ctx_stack.top._after_request_functions.append(f) |
||||
return f |
||||
|
||||
|
||||
def copy_current_request_context(f): |
||||
"""A helper function that decorates a function to retain the current |
||||
request context. This is useful when working with greenlets. The moment |
||||
the function is decorated a copy of the request context is created and |
||||
then pushed when the function is called. |
||||
|
||||
Example:: |
||||
|
||||
import gevent |
||||
from flask import copy_current_request_context |
||||
|
||||
@app.route('/') |
||||
def index(): |
||||
@copy_current_request_context |
||||
def do_some_work(): |
||||
# do some work here, it can access flask.request like you |
||||
# would otherwise in the view function. |
||||
... |
||||
gevent.spawn(do_some_work) |
||||
return 'Regular response' |
||||
|
||||
.. versionadded:: 0.10 |
||||
""" |
||||
top = _request_ctx_stack.top |
||||
if top is None: |
||||
raise RuntimeError('This decorator can only be used at local scopes ' |
||||
'when a request context is on the stack. For instance within ' |
||||
'view functions.') |
||||
reqctx = top.copy() |
||||
def wrapper(*args, **kwargs): |
||||
with reqctx: |
||||
return f(*args, **kwargs) |
||||
return update_wrapper(wrapper, f) |
||||
|
||||
|
||||
def has_request_context(): |
||||
"""If you have code that wants to test if a request context is there or |
||||
not this function can be used. For instance, you may want to take advantage |
||||
of request information if the request object is available, but fail |
||||
silently if it is unavailable. |
||||
|
||||
:: |
||||
|
||||
class User(db.Model): |
||||
|
||||
def __init__(self, username, remote_addr=None): |
||||
self.username = username |
||||
if remote_addr is None and has_request_context(): |
||||
remote_addr = request.remote_addr |
||||
self.remote_addr = remote_addr |
||||
|
||||
Alternatively you can also just test any of the context bound objects |
||||
(such as :class:`request` or :class:`g` for truthness):: |
||||
|
||||
class User(db.Model): |
||||
|
||||
def __init__(self, username, remote_addr=None): |
||||
self.username = username |
||||
if remote_addr is None and request: |
||||
remote_addr = request.remote_addr |
||||
self.remote_addr = remote_addr |
||||
|
||||
.. versionadded:: 0.7 |
||||
""" |
||||
return _request_ctx_stack.top is not None |
||||
|
||||
|
||||
def has_app_context(): |
||||
"""Works like :func:`has_request_context` but for the application |
||||
context. You can also just do a boolean check on the |
||||
:data:`current_app` object instead. |
||||
|
||||
.. versionadded:: 0.9 |
||||
""" |
||||
return _app_ctx_stack.top is not None |
||||
|
||||
|
||||
class AppContext(object): |
||||
"""The application context binds an application object implicitly |
||||
to the current thread or greenlet, similar to how the |
||||
:class:`RequestContext` binds request information. The application |
||||
context is also implicitly created if a request context is created |
||||
but the application is not on top of the individual application |
||||
context. |
||||
""" |
||||
|
||||
def __init__(self, app): |
||||
self.app = app |
||||
self.url_adapter = app.create_url_adapter(None) |
||||
self.g = app.app_ctx_globals_class() |
||||
|
||||
# Like request context, app contexts can be pushed multiple times |
||||
# but there a basic "refcount" is enough to track them. |
||||
self._refcnt = 0 |
||||
|
||||
def push(self): |
||||
"""Binds the app context to the current context.""" |
||||
self._refcnt += 1 |
||||
_app_ctx_stack.push(self) |
||||
appcontext_pushed.send(self.app) |
||||
|
||||
def pop(self, exc=None): |
||||
"""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() |
||||
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \ |
||||
% (rv, self) |
||||
appcontext_popped.send(self.app) |
||||
|
||||
def __enter__(self): |
||||
self.push() |
||||
return self |
||||
|
||||
def __exit__(self, exc_type, exc_value, tb): |
||||
self.pop(exc_value) |
||||
|
||||
|
||||
class RequestContext(object): |
||||
"""The request context contains all request relevant information. It is |
||||
created at the beginning of the request and pushed to the |
||||
`_request_ctx_stack` and removed at the end of it. It will create the |
||||
URL adapter and request object for the WSGI environment provided. |
||||
|
||||
Do not attempt to use this class directly, instead use |
||||
:meth:`~flask.Flask.test_request_context` and |
||||
:meth:`~flask.Flask.request_context` to create this object. |
||||
|
||||
When the request context is popped, it will evaluate all the |
||||
functions registered on the application for teardown execution |
||||
(:meth:`~flask.Flask.teardown_request`). |
||||
|
||||
The request context is automatically popped at the end of the request |
||||
for you. In debug mode the request context is kept around if |
||||
exceptions happen so that interactive debuggers have a chance to |
||||
introspect the data. With 0.4 this can also be forced for requests |
||||
that did not fail and outside of `DEBUG` mode. By setting |
||||
``'flask._preserve_context'`` to `True` on the WSGI environment the |
||||
context will not pop itself at the end of the request. This is used by |
||||
the :meth:`~flask.Flask.test_client` for example to implement the |
||||
deferred cleanup functionality. |
||||
|
||||
You might find this helpful for unittests where you need the |
||||
information from the context local around for a little longer. Make |
||||
sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in |
||||
that situation, otherwise your unittests will leak memory. |
||||
""" |
||||
|
||||
def __init__(self, app, environ, request=None): |
||||
self.app = app |
||||
if request is None: |
||||
request = app.request_class(environ) |
||||
self.request = request |
||||
self.url_adapter = app.create_url_adapter(self.request) |
||||
self.flashes = None |
||||
self.session = None |
||||
|
||||
# Request contexts can be pushed multiple times and interleaved with |
||||
# other request contexts. Now only if the last level is popped we |
||||
# get rid of them. Additionally if an application context is missing |
||||
# one is created implicitly so for each level we add this information |
||||
self._implicit_app_ctx_stack = [] |
||||
|
||||
# indicator if the context was preserved. Next time another context |
||||
# is pushed the preserved context is popped. |
||||
self.preserved = False |
||||
|
||||
# remembers the exception for pop if there is one in case the context |
||||
# preservation kicks in. |
||||
self._preserved_exc = None |
||||
|
||||
# Functions that should be executed after the request on the response |
||||
# object. These will be called before the regular "after_request" |
||||
# functions. |
||||
self._after_request_functions = [] |
||||
|
||||
self.match_request() |
||||
|
||||
# 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): |
||||
_app_ctx_stack.top.g = value |
||||
g = property(_get_g, _set_g) |
||||
del _get_g, _set_g |
||||
|
||||
def copy(self): |
||||
"""Creates a copy of this request context with the same request object. |
||||
This can be used to move a request context to a different greenlet. |
||||
Because the actual request object is the same this cannot be used to |
||||
move a request context to a different thread unless access to the |
||||
request object is locked. |
||||
|
||||
.. versionadded:: 0.10 |
||||
""" |
||||
return self.__class__(self.app, |
||||
environ=self.request.environ, |
||||
request=self.request |
||||
) |
||||
|
||||
def match_request(self): |
||||
"""Can be overridden by a subclass to hook into the matching |
||||
of the request. |
||||
""" |
||||
try: |
||||
url_rule, self.request.view_args = \ |
||||
self.url_adapter.match(return_rule=True) |
||||
self.request.url_rule = url_rule |
||||
except HTTPException as e: |
||||
self.request.routing_exception = e |
||||
|
||||
def push(self): |
||||
"""Binds the request context to the current context.""" |
||||
# If an exception occurs in debug mode or if context preservation is |
||||
# activated under exception situations exactly one context stays |
||||
# on the stack. The rationale is that you want to access that |
||||
# information under debug situations. However if someone forgets to |
||||
# pop that context again we want to make sure that on the next push |
||||
# it's invalidated, otherwise we run at risk that something leaks |
||||
# memory. This is usually only a problem in testsuite since this |
||||
# functionality is not active in production environments. |
||||
top = _request_ctx_stack.top |
||||
if top is not None and top.preserved: |
||||
top.pop(top._preserved_exc) |
||||
|
||||
# Before we push the request context we have to ensure that there |
||||
# is an application context. |
||||
app_ctx = _app_ctx_stack.top |
||||
if app_ctx is None or app_ctx.app != self.app: |
||||
app_ctx = self.app.app_context() |
||||
app_ctx.push() |
||||
self._implicit_app_ctx_stack.append(app_ctx) |
||||
else: |
||||
self._implicit_app_ctx_stack.append(None) |
||||
|
||||
_request_ctx_stack.push(self) |
||||
|
||||
# Open the session at the moment that the request context is |
||||
# available. This allows a custom open_session method to use the |
||||
# request context (e.g. code that access database information |
||||
# stored on `g` instead of the appcontext). |
||||
self.session = self.app.open_session(self.request) |
||||
if self.session is None: |
||||
self.session = self.app.make_null_session() |
||||
|
||||
def pop(self, exc=None): |
||||
"""Pops the request context and unbinds it by doing that. This will |
||||
also trigger the execution of functions registered by the |
||||
:meth:`~flask.Flask.teardown_request` decorator. |
||||
|
||||
.. versionchanged:: 0.9 |
||||
Added the `exc` argument. |
||||
""" |
||||
app_ctx = self._implicit_app_ctx_stack.pop() |
||||
|
||||
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) |
||||
|
||||
# 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 |
||||
|
||||
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 the app as well if necessary. |
||||
if app_ctx is not None: |
||||
app_ctx.pop(exc) |
||||
|
||||
def auto_pop(self, exc): |
||||
if self.request.environ.get('flask._preserve_context') or \ |
||||
(exc is not None and self.app.preserve_context_on_exception): |
||||
self.preserved = True |
||||
self._preserved_exc = exc |
||||
else: |
||||
self.pop(exc) |
||||
|
||||
def __enter__(self): |
||||
self.push() |
||||
return self |
||||
|
||||
def __exit__(self, exc_type, exc_value, tb): |
||||
# do not pop the request stack if we are in debug mode and an |
||||
# exception happened. This will allow the debugger to still |
||||
# access the request object in the interactive shell. Furthermore |
||||
# the context can be force kept alive for the test client. |
||||
# See flask.testing for how this works. |
||||
self.auto_pop(exc_value) |
||||
|
||||
def __repr__(self): |
||||
return '<%s \'%s\' [%s] of %s>' % ( |
||||
self.__class__.__name__, |
||||
self.request.url, |
||||
self.request.method, |
||||
self.app.name, |
||||
) |
@ -1,87 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.debughelpers |
||||
~~~~~~~~~~~~~~~~~~ |
||||
|
||||
Various helpers to make the development experience better. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
from ._compat import implements_to_string |
||||
|
||||
|
||||
class UnexpectedUnicodeError(AssertionError, UnicodeError): |
||||
"""Raised in places where we want some better error reporting for |
||||
unexpected unicode or binary data. |
||||
""" |
||||
|
||||
|
||||
@implements_to_string |
||||
class DebugFilesKeyError(KeyError, AssertionError): |
||||
"""Raised from request.files during debugging. The idea is that it can |
||||
provide a better error message than just a generic KeyError/BadRequest. |
||||
""" |
||||
|
||||
def __init__(self, request, key): |
||||
form_matches = request.form.getlist(key) |
||||
buf = ['You tried to access the file "%s" in the request.files ' |
||||
'dictionary but it does not exist. The mimetype for the request ' |
||||
'is "%s" instead of "multipart/form-data" which means that no ' |
||||
'file contents were transmitted. To fix this error you should ' |
||||
'provide enctype="multipart/form-data" in your form.' % |
||||
(key, request.mimetype)] |
||||
if form_matches: |
||||
buf.append('\n\nThe browser instead transmitted some file names. ' |
||||
'This was submitted: %s' % ', '.join('"%s"' % x |
||||
for x in form_matches)) |
||||
self.msg = ''.join(buf) |
||||
|
||||
def __str__(self): |
||||
return self.msg |
||||
|
||||
|
||||
class FormDataRoutingRedirect(AssertionError): |
||||
"""This exception is raised by Flask in debug mode if it detects a |
||||
redirect caused by the routing system when the request method is not |
||||
GET, HEAD or OPTIONS. Reasoning: form data will be dropped. |
||||
""" |
||||
|
||||
def __init__(self, request): |
||||
exc = request.routing_exception |
||||
buf = ['A request was sent to this URL (%s) but a redirect was ' |
||||
'issued automatically by the routing system to "%s".' |
||||
% (request.url, exc.new_url)] |
||||
|
||||
# In case just a slash was appended we can be extra helpful |
||||
if request.base_url + '/' == exc.new_url.split('?')[0]: |
||||
buf.append(' The URL was defined with a trailing slash so ' |
||||
'Flask will automatically redirect to the URL ' |
||||
'with the trailing slash if it was accessed ' |
||||
'without one.') |
||||
|
||||
buf.append(' Make sure to directly send your %s-request to this URL ' |
||||
'since we can\'t make browsers or HTTP clients redirect ' |
||||
'with form data reliably or without user interaction.' % |
||||
request.method) |
||||
buf.append('\n\nNote: this exception is only raised in debug mode') |
||||
AssertionError.__init__(self, ''.join(buf).encode('utf-8')) |
||||
|
||||
|
||||
def attach_enctype_error_multidict(request): |
||||
"""Since Flask 0.8 we're monkeypatching the files object in case a |
||||
request is detected that does not use multipart form data but the files |
||||
object is accessed. |
||||
""" |
||||
oldcls = request.files.__class__ |
||||
class newcls(oldcls): |
||||
def __getitem__(self, key): |
||||
try: |
||||
return oldcls.__getitem__(self, key) |
||||
except KeyError as e: |
||||
if key not in request.form: |
||||
raise |
||||
raise DebugFilesKeyError(request, key) |
||||
newcls.__name__ = oldcls.__name__ |
||||
newcls.__module__ = oldcls.__module__ |
||||
request.files.__class__ = newcls |
@ -1,29 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.ext |
||||
~~~~~~~~~ |
||||
|
||||
Redirect imports for extensions. This module basically makes it possible |
||||
for us to transition from flaskext.foo to flask_foo without having to |
||||
force all extensions to upgrade at the same time. |
||||
|
||||
When a user does ``from flask.ext.foo import bar`` it will attempt to |
||||
import ``from flask_foo import bar`` first and when that fails it will |
||||
try to import ``from flaskext.foo import bar``. |
||||
|
||||
We're switching from namespace packages because it was just too painful for |
||||
everybody involved. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
|
||||
def setup(): |
||||
from ..exthook import ExtensionImporter |
||||
importer = ExtensionImporter(['flask_%s', 'flaskext.%s'], __name__) |
||||
importer.install() |
||||
|
||||
|
||||
setup() |
||||
del setup |
@ -1,120 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.exthook |
||||
~~~~~~~~~~~~~ |
||||
|
||||
Redirect imports for extensions. This module basically makes it possible |
||||
for us to transition from flaskext.foo to flask_foo without having to |
||||
force all extensions to upgrade at the same time. |
||||
|
||||
When a user does ``from flask.ext.foo import bar`` it will attempt to |
||||
import ``from flask_foo import bar`` first and when that fails it will |
||||
try to import ``from flaskext.foo import bar``. |
||||
|
||||
We're switching from namespace packages because it was just too painful for |
||||
everybody involved. |
||||
|
||||
This is used by `flask.ext`. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
import sys |
||||
import os |
||||
from ._compat import reraise |
||||
|
||||
|
||||
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 |
||||
newer flask_name without people having a hard time. |
||||
""" |
||||
|
||||
def __init__(self, module_choices, wrapper_module): |
||||
self.module_choices = module_choices |
||||
self.wrapper_module = wrapper_module |
||||
self.prefix = wrapper_module + '.' |
||||
self.prefix_cutoff = wrapper_module.count('.') + 1 |
||||
|
||||
def __eq__(self, other): |
||||
return self.__class__.__module__ == other.__class__.__module__ and \ |
||||
self.__class__.__name__ == other.__class__.__name__ and \ |
||||
self.wrapper_module == other.wrapper_module and \ |
||||
self.module_choices == other.module_choices |
||||
|
||||
def __ne__(self, other): |
||||
return not self.__eq__(other) |
||||
|
||||
def install(self): |
||||
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): |
||||
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] |
||||
for path in self.module_choices: |
||||
realname = path % modname |
||||
try: |
||||
__import__(realname) |
||||
except ImportError: |
||||
exc_type, exc_value, tb = sys.exc_info() |
||||
# since we only establish the entry in sys.modules at the |
||||
# very this seems to be redundant, but if recursive imports |
||||
# happen we will call into the move import a second time. |
||||
# On the second invocation we still don't have an entry for |
||||
# fullname in sys.modules, but we will end up with the same |
||||
# fake module name and that import will succeed since this |
||||
# one already has a temporary entry in the modules dict. |
||||
# Since this one "succeeded" temporarily that second |
||||
# invocation now will have created a fullname entry in |
||||
# sys.modules which we have to kill. |
||||
sys.modules.pop(fullname, None) |
||||
|
||||
# If it's an important traceback we reraise it, otherwise |
||||
# we swallow it and try the next choice. The skipped frame |
||||
# is the one from __import__ above which we don't care about |
||||
if self.is_important_traceback(realname, tb): |
||||
reraise(exc_type, exc_value, tb.tb_next) |
||||
continue |
||||
module = sys.modules[fullname] = sys.modules[realname] |
||||
if '.' not in modname: |
||||
setattr(sys.modules[self.wrapper_module], modname, module) |
||||
return module |
||||
raise ImportError('No module named %s' % fullname) |
||||
|
||||
def is_important_traceback(self, important_module, tb): |
||||
"""Walks a traceback's frames and checks if any of the frames |
||||
originated in the given important module. If that is the case then we |
||||
were able to import the module itself but apparently something went |
||||
wrong when the module was imported. (Eg: import of an import failed). |
||||
""" |
||||
while tb is not None: |
||||
if self.is_important_frame(important_module, tb): |
||||
return True |
||||
tb = tb.tb_next |
||||
return False |
||||
|
||||
def is_important_frame(self, important_module, tb): |
||||
"""Checks a single frame if it's important.""" |
||||
g = tb.tb_frame.f_globals |
||||
if '__name__' not in g: |
||||
return False |
||||
|
||||
module_name = g['__name__'] |
||||
|
||||
# Python 2.7 Behavior. Modules are cleaned up late so the |
||||
# name shows up properly here. Success! |
||||
if module_name == important_module: |
||||
return True |
||||
|
||||
# Some python versions will 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) |
||||
test_string = os.path.sep + important_module.replace('.', os.path.sep) |
||||
return test_string + '.py' in filename or \ |
||||
test_string + os.path.sep + '__init__.py' in filename |
@ -1,44 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.globals |
||||
~~~~~~~~~~~~~ |
||||
|
||||
Defines all the global objects that are proxies to the current |
||||
active context. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
from functools import partial |
||||
from werkzeug.local import LocalStack, LocalProxy |
||||
|
||||
|
||||
def _lookup_req_object(name): |
||||
top = _request_ctx_stack.top |
||||
if top is None: |
||||
raise RuntimeError('working outside of request context') |
||||
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') |
||||
return getattr(top, name) |
||||
|
||||
|
||||
def _find_app(): |
||||
top = _app_ctx_stack.top |
||||
if top is None: |
||||
raise RuntimeError('working outside of application context') |
||||
return top.app |
||||
|
||||
|
||||
# context locals |
||||
_request_ctx_stack = LocalStack() |
||||
_app_ctx_stack = LocalStack() |
||||
current_app = LocalProxy(_find_app) |
||||
request = LocalProxy(partial(_lookup_req_object, 'request')) |
||||
session = LocalProxy(partial(_lookup_req_object, 'session')) |
||||
g = LocalProxy(partial(_lookup_app_object, 'g')) |
@ -1,849 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.helpers |
||||
~~~~~~~~~~~~~ |
||||
|
||||
Implements various helpers. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
import os |
||||
import sys |
||||
import pkgutil |
||||
import posixpath |
||||
import mimetypes |
||||
from time import time |
||||
from zlib import adler32 |
||||
from threading import RLock |
||||
from werkzeug.routing import BuildError |
||||
from functools import update_wrapper |
||||
|
||||
try: |
||||
from werkzeug.urls import url_quote |
||||
except ImportError: |
||||
from urlparse import quote as url_quote |
||||
|
||||
from werkzeug.datastructures import Headers |
||||
from werkzeug.exceptions import NotFound |
||||
|
||||
# this was moved in 0.7 |
||||
try: |
||||
from werkzeug.wsgi import wrap_file |
||||
except ImportError: |
||||
from werkzeug.utils import wrap_file |
||||
|
||||
from jinja2 import FileSystemLoader |
||||
|
||||
from .signals import message_flashed |
||||
from .globals import session, _request_ctx_stack, _app_ctx_stack, \ |
||||
current_app, request |
||||
from ._compat import string_types, text_type |
||||
|
||||
|
||||
# sentinel |
||||
_missing = object() |
||||
|
||||
|
||||
# what separators does this operating system provide that are not a slash? |
||||
# this is used by the send_from_directory function to ensure that nobody is |
||||
# able to access files from outside the filesystem. |
||||
_os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep] |
||||
if sep not in (None, '/')) |
||||
|
||||
|
||||
def _endpoint_from_view_func(view_func): |
||||
"""Internal helper that returns the default endpoint for a given |
||||
function. This always is the function name. |
||||
""" |
||||
assert view_func is not None, 'expected view func if endpoint ' \ |
||||
'is not provided.' |
||||
return view_func.__name__ |
||||
|
||||
|
||||
def stream_with_context(generator_or_function): |
||||
"""Request contexts disappear when the response is started on the server. |
||||
This is done for efficiency reasons and to make it less likely to encounter |
||||
memory leaks with badly written WSGI middlewares. The downside is that if |
||||
you are using streamed responses, the generator cannot access request bound |
||||
information any more. |
||||
|
||||
This function however can help you keep the context around for longer:: |
||||
|
||||
from flask import stream_with_context, request, Response |
||||
|
||||
@app.route('/stream') |
||||
def streamed_response(): |
||||
@stream_with_context |
||||
def generate(): |
||||
yield 'Hello ' |
||||
yield request.args['name'] |
||||
yield '!' |
||||
return Response(generate()) |
||||
|
||||
Alternatively it can also be used around a specific generator:: |
||||
|
||||
from flask import stream_with_context, request, Response |
||||
|
||||
@app.route('/stream') |
||||
def streamed_response(): |
||||
def generate(): |
||||
yield 'Hello ' |
||||
yield request.args['name'] |
||||
yield '!' |
||||
return Response(stream_with_context(generate())) |
||||
|
||||
.. versionadded:: 0.9 |
||||
""" |
||||
try: |
||||
gen = iter(generator_or_function) |
||||
except TypeError: |
||||
def decorator(*args, **kwargs): |
||||
gen = generator_or_function() |
||||
return stream_with_context(gen) |
||||
return update_wrapper(decorator, generator_or_function) |
||||
|
||||
def generator(): |
||||
ctx = _request_ctx_stack.top |
||||
if ctx is None: |
||||
raise RuntimeError('Attempted to stream with context but ' |
||||
'there was no context in the first place to keep around.') |
||||
with ctx: |
||||
# Dummy sentinel. Has to be inside the context block or we're |
||||
# not actually keeping the context around. |
||||
yield None |
||||
|
||||
# The try/finally is here so that if someone passes a WSGI level |
||||
# iterator in we're still running the cleanup logic. Generators |
||||
# don't need that because they are closed on their destruction |
||||
# automatically. |
||||
try: |
||||
for item in gen: |
||||
yield item |
||||
finally: |
||||
if hasattr(gen, 'close'): |
||||
gen.close() |
||||
|
||||
# The trick is to start the generator. Then the code execution runs until |
||||
# the first dummy None is yielded at which point the context was already |
||||
# pushed. This item is discarded. Then when the iteration continues the |
||||
# real generator is executed. |
||||
wrapped_g = generator() |
||||
next(wrapped_g) |
||||
return wrapped_g |
||||
|
||||
|
||||
def make_response(*args): |
||||
"""Sometimes it is necessary to set additional headers in a view. Because |
||||
views do not have to return response objects but can return a value that |
||||
is converted into a response object by Flask itself, it becomes tricky to |
||||
add headers to it. This function can be called instead of using a return |
||||
and you will get a response object which you can use to attach headers. |
||||
|
||||
If view looked like this and you want to add a new header:: |
||||
|
||||
def index(): |
||||
return render_template('index.html', foo=42) |
||||
|
||||
You can now do something like this:: |
||||
|
||||
def index(): |
||||
response = make_response(render_template('index.html', foo=42)) |
||||
response.headers['X-Parachutes'] = 'parachutes are cool' |
||||
return response |
||||
|
||||
This function accepts the very same arguments you can return from a |
||||
view function. This for example creates a response with a 404 error |
||||
code:: |
||||
|
||||
response = make_response(render_template('not_found.html'), 404) |
||||
|
||||
The other use case of this function is to force the return value of a |
||||
view function into a response which is helpful with view |
||||
decorators:: |
||||
|
||||
response = make_response(view_function()) |
||||
response.headers['X-Parachutes'] = 'parachutes are cool' |
||||
|
||||
Internally this function does the following things: |
||||
|
||||
- if no arguments are passed, it creates a new response argument |
||||
- if one argument is passed, :meth:`flask.Flask.make_response` |
||||
is invoked with it. |
||||
- if more than one argument is passed, the arguments are passed |
||||
to the :meth:`flask.Flask.make_response` function as tuple. |
||||
|
||||
.. versionadded:: 0.6 |
||||
""" |
||||
if not args: |
||||
return current_app.response_class() |
||||
if len(args) == 1: |
||||
args = args[0] |
||||
return current_app.make_response(args) |
||||
|
||||
|
||||
def url_for(endpoint, **values): |
||||
"""Generates a URL to the given endpoint with the method provided. |
||||
|
||||
Variable arguments that are unknown to the target endpoint are appended |
||||
to the generated URL as query arguments. If the value of a query argument |
||||
is `None`, the whole pair is skipped. In case blueprints are active |
||||
you can shortcut references to the same blueprint by prefixing the |
||||
local endpoint with a dot (``.``). |
||||
|
||||
This will reference the index function local to the current blueprint:: |
||||
|
||||
url_for('.index') |
||||
|
||||
For more information, head over to the :ref:`Quickstart <url-building>`. |
||||
|
||||
To integrate applications, :class:`Flask` has a hook to intercept URL build |
||||
errors through :attr:`Flask.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 |
||||
`url_for` (instead of `url_for`'s default to raise the |
||||
:exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception. |
||||
An example:: |
||||
|
||||
def external_url_handler(error, endpoint, **values): |
||||
"Looks up an external URL when `url_for` cannot build a URL." |
||||
# This is an example of hooking the build_error_handler. |
||||
# Here, lookup_url is some utility function you've built |
||||
# which looks up the endpoint in some external URL registry. |
||||
url = lookup_url(endpoint, **values) |
||||
if url is None: |
||||
# External lookup did not have a URL. |
||||
# Re-raise the BuildError, in context of original traceback. |
||||
exc_type, exc_value, tb = sys.exc_info() |
||||
if exc_value is error: |
||||
raise exc_type, exc_value, tb |
||||
else: |
||||
raise error |
||||
# url_for will use this result, instead of raising BuildError. |
||||
return url |
||||
|
||||
app.build_error_handler = external_url_handler |
||||
|
||||
Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and |
||||
`endpoint` and `**values` are the arguments passed into `url_for`. Note |
||||
that this is for building URLs outside the current application, and not for |
||||
handling 404 NotFound errors. |
||||
|
||||
.. versionadded:: 0.10 |
||||
The `_scheme` parameter was added. |
||||
|
||||
.. versionadded:: 0.9 |
||||
The `_anchor` and `_method` parameters were added. |
||||
|
||||
.. versionadded:: 0.9 |
||||
Calls :meth:`Flask.handle_build_error` on |
||||
:exc:`~werkzeug.routing.BuildError`. |
||||
|
||||
:param endpoint: the endpoint of the URL (name of the function) |
||||
:param values: the variable arguments of the URL rule |
||||
:param _external: if set to `True`, an absolute URL is generated. Server |
||||
address can be changed via `SERVER_NAME` configuration variable which |
||||
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. |
||||
:param _anchor: if provided this is added as anchor to the URL. |
||||
:param _method: if provided this explicitly specifies an HTTP method. |
||||
""" |
||||
appctx = _app_ctx_stack.top |
||||
reqctx = _request_ctx_stack.top |
||||
if appctx is None: |
||||
raise RuntimeError('Attempted to generate a URL without the ' |
||||
'application context being pushed. This has to be ' |
||||
'executed when application context is available.') |
||||
|
||||
# If request specific information is available we have some extra |
||||
# features that support "relative" urls. |
||||
if reqctx is not None: |
||||
url_adapter = reqctx.url_adapter |
||||
blueprint_name = request.blueprint |
||||
if not reqctx.request._is_old_module: |
||||
if endpoint[:1] == '.': |
||||
if blueprint_name is not None: |
||||
endpoint = blueprint_name + endpoint |
||||
else: |
||||
endpoint = endpoint[1:] |
||||
else: |
||||
# TODO: get rid of this deprecated functionality in 1.0 |
||||
if '.' not in endpoint: |
||||
if blueprint_name is not None: |
||||
endpoint = blueprint_name + '.' + endpoint |
||||
elif endpoint.startswith('.'): |
||||
endpoint = endpoint[1:] |
||||
external = values.pop('_external', False) |
||||
|
||||
# Otherwise go with the url adapter from the appctx and make |
||||
# the urls external by default. |
||||
else: |
||||
url_adapter = appctx.url_adapter |
||||
if url_adapter is None: |
||||
raise RuntimeError('Application was not able to create a URL ' |
||||
'adapter for request independent URL generation. ' |
||||
'You might be able to fix this by setting ' |
||||
'the SERVER_NAME config variable.') |
||||
external = values.pop('_external', True) |
||||
|
||||
anchor = values.pop('_anchor', None) |
||||
method = values.pop('_method', None) |
||||
scheme = values.pop('_scheme', None) |
||||
appctx.app.inject_url_defaults(endpoint, values) |
||||
|
||||
if scheme is not None: |
||||
if not external: |
||||
raise ValueError('When specifying _scheme, _external must be True') |
||||
url_adapter.url_scheme = scheme |
||||
|
||||
try: |
||||
rv = url_adapter.build(endpoint, values, method=method, |
||||
force_external=external) |
||||
except BuildError as error: |
||||
# We need to inject the values again so that the app callback can |
||||
# deal with that sort of stuff. |
||||
values['_external'] = external |
||||
values['_anchor'] = anchor |
||||
values['_method'] = method |
||||
return appctx.app.handle_url_build_error(error, endpoint, values) |
||||
|
||||
if anchor is not None: |
||||
rv += '#' + url_quote(anchor) |
||||
return rv |
||||
|
||||
|
||||
def get_template_attribute(template_name, attribute): |
||||
"""Loads a macro (or variable) a template exports. This can be used to |
||||
invoke a macro from within Python code. If you for example have a |
||||
template named `_cider.html` with the following contents: |
||||
|
||||
.. sourcecode:: html+jinja |
||||
|
||||
{% macro hello(name) %}Hello {{ name }}!{% endmacro %} |
||||
|
||||
You can access this from Python code like this:: |
||||
|
||||
hello = get_template_attribute('_cider.html', 'hello') |
||||
return hello('World') |
||||
|
||||
.. versionadded:: 0.2 |
||||
|
||||
:param template_name: the name of the template |
||||
:param attribute: the name of the variable of macro to access |
||||
""" |
||||
return getattr(current_app.jinja_env.get_template(template_name).module, |
||||
attribute) |
||||
|
||||
|
||||
def flash(message, category='message'): |
||||
"""Flashes a message to the next request. In order to remove the |
||||
flashed message from the session and to display it to the user, |
||||
the template has to call :func:`get_flashed_messages`. |
||||
|
||||
.. versionchanged:: 0.3 |
||||
`category` parameter added. |
||||
|
||||
:param message: the message to be flashed. |
||||
:param category: the category for the message. The following values |
||||
are recommended: ``'message'`` for any kind of message, |
||||
``'error'`` for errors, ``'info'`` for information |
||||
messages and ``'warning'`` for warnings. However any |
||||
kind of string can be used as category. |
||||
""" |
||||
# Original implementation: |
||||
# |
||||
# session.setdefault('_flashes', []).append((category, message)) |
||||
# |
||||
# This assumed that changes made to mutable structures in the session are |
||||
# are always in sync with the sess on object, which is not true for session |
||||
# implementations that use external storage for keeping their keys/values. |
||||
flashes = session.get('_flashes', []) |
||||
flashes.append((category, message)) |
||||
session['_flashes'] = flashes |
||||
message_flashed.send(current_app._get_current_object(), |
||||
message=message, category=category) |
||||
|
||||
|
||||
def get_flashed_messages(with_categories=False, category_filter=[]): |
||||
"""Pulls all flashed messages from the session and returns them. |
||||
Further calls in the same request to the function will return |
||||
the same messages. By default just the messages are returned, |
||||
but when `with_categories` is set to `True`, the return value will |
||||
be a list of tuples in the form ``(category, message)`` instead. |
||||
|
||||
Filter the flashed messages to one or more categories by providing those |
||||
categories in `category_filter`. This allows rendering categories in |
||||
separate html blocks. The `with_categories` and `category_filter` |
||||
arguments are distinct: |
||||
|
||||
* `with_categories` controls whether categories are returned with message |
||||
text (`True` gives a tuple, where `False` gives just the message text). |
||||
* `category_filter` filters the messages down to only those matching the |
||||
provided categories. |
||||
|
||||
See :ref:`message-flashing-pattern` for examples. |
||||
|
||||
.. versionchanged:: 0.3 |
||||
`with_categories` parameter added. |
||||
|
||||
.. versionchanged:: 0.9 |
||||
`category_filter` parameter added. |
||||
|
||||
:param with_categories: set to `True` to also receive categories. |
||||
:param category_filter: whitelist of categories to limit return values |
||||
""" |
||||
flashes = _request_ctx_stack.top.flashes |
||||
if flashes is None: |
||||
_request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \ |
||||
if '_flashes' in session else [] |
||||
if category_filter: |
||||
flashes = list(filter(lambda f: f[0] in category_filter, flashes)) |
||||
if not with_categories: |
||||
return [x[1] for x in flashes] |
||||
return flashes |
||||
|
||||
|
||||
def send_file(filename_or_fp, mimetype=None, as_attachment=False, |
||||
attachment_filename=None, add_etags=True, |
||||
cache_timeout=None, conditional=False): |
||||
"""Sends the contents of a file to the client. This will use the |
||||
most efficient method available and configured. By default it will |
||||
try to use the WSGI server's file_wrapper support. Alternatively |
||||
you can set the application's :attr:`~Flask.use_x_sendfile` attribute |
||||
to ``True`` to directly emit an `X-Sendfile` header. This however |
||||
requires support of the underlying webserver for `X-Sendfile`. |
||||
|
||||
By default it will try to guess the mimetype for you, but you can |
||||
also explicitly provide one. For extra security you probably want |
||||
to send certain files as attachment (HTML for instance). The mimetype |
||||
guessing requires a `filename` or an `attachment_filename` to be |
||||
provided. |
||||
|
||||
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) |
||||
|
||||
.. versionadded:: 0.2 |
||||
|
||||
.. versionadded:: 0.5 |
||||
The `add_etags`, `cache_timeout` and `conditional` parameters were |
||||
added. The default behavior is now to attach etags. |
||||
|
||||
.. versionchanged:: 0.7 |
||||
mimetype guessing and etag support for file objects was |
||||
deprecated because it was unreliable. Pass a filename if you are |
||||
able to, otherwise attach an etag yourself. This functionality |
||||
will be removed in Flask 1.0 |
||||
|
||||
.. versionchanged:: 0.9 |
||||
cache_timeout pulls its default from application config, when None. |
||||
|
||||
:param filename_or_fp: the filename of the file to send. This is |
||||
relative to the :attr:`~Flask.root_path` if a |
||||
relative path is specified. |
||||
Alternatively a file object might be provided |
||||
in which case `X-Sendfile` might not work and |
||||
fall back to the traditional method. Make sure |
||||
that the file pointer is positioned at the start |
||||
of data to send before calling :func:`send_file`. |
||||
:param mimetype: the mimetype of the file if provided, otherwise |
||||
auto detection happens. |
||||
:param as_attachment: set to `True` if you want to send this file with |
||||
a ``Content-Disposition: attachment`` header. |
||||
:param attachment_filename: the filename for the attachment if it |
||||
differs from the file's filename. |
||||
:param add_etags: set to `False` to disable attaching of etags. |
||||
:param conditional: set to `True` to enable conditional responses. |
||||
|
||||
:param cache_timeout: the timeout in seconds for the headers. When `None` |
||||
(default), this value is set by |
||||
:meth:`~Flask.get_send_file_max_age` of |
||||
:data:`~flask.current_app`. |
||||
""" |
||||
mtime = None |
||||
if isinstance(filename_or_fp, string_types): |
||||
filename = filename_or_fp |
||||
file = None |
||||
else: |
||||
from warnings import warn |
||||
file = filename_or_fp |
||||
filename = getattr(file, 'name', None) |
||||
|
||||
# XXX: this behavior is now deprecated because it was unreliable. |
||||
# removed in Flask 1.0 |
||||
if not attachment_filename and not mimetype \ |
||||
and isinstance(filename, string_types): |
||||
warn(DeprecationWarning('The filename support for file objects ' |
||||
'passed to send_file is now deprecated. Pass an ' |
||||
'attach_filename if you want mimetypes to be guessed.'), |
||||
stacklevel=2) |
||||
if add_etags: |
||||
warn(DeprecationWarning('In future flask releases etags will no ' |
||||
'longer be generated for file objects passed to the send_file ' |
||||
'function because this behavior was unreliable. Pass ' |
||||
'filenames instead if possible, otherwise attach an etag ' |
||||
'yourself based on another value'), stacklevel=2) |
||||
|
||||
if filename is not None: |
||||
if not os.path.isabs(filename): |
||||
filename = os.path.join(current_app.root_path, filename) |
||||
if mimetype is None and (filename or attachment_filename): |
||||
mimetype = mimetypes.guess_type(filename or attachment_filename)[0] |
||||
if mimetype is None: |
||||
mimetype = 'application/octet-stream' |
||||
|
||||
headers = Headers() |
||||
if as_attachment: |
||||
if attachment_filename is None: |
||||
if filename is None: |
||||
raise TypeError('filename unavailable, required for ' |
||||
'sending as attachment') |
||||
attachment_filename = os.path.basename(filename) |
||||
headers.add('Content-Disposition', 'attachment', |
||||
filename=attachment_filename) |
||||
|
||||
if current_app.use_x_sendfile and filename: |
||||
if file is not None: |
||||
file.close() |
||||
headers['X-Sendfile'] = filename |
||||
headers['Content-Length'] = os.path.getsize(filename) |
||||
data = None |
||||
else: |
||||
if file is None: |
||||
file = open(filename, 'rb') |
||||
mtime = os.path.getmtime(filename) |
||||
headers['Content-Length'] = os.path.getsize(filename) |
||||
data = wrap_file(request.environ, file) |
||||
|
||||
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 |
||||
# the time of the last modification. |
||||
if mtime is not None: |
||||
rv.last_modified = int(mtime) |
||||
|
||||
rv.cache_control.public = True |
||||
if cache_timeout is None: |
||||
cache_timeout = current_app.get_send_file_max_age(filename) |
||||
if cache_timeout is not None: |
||||
rv.cache_control.max_age = cache_timeout |
||||
rv.expires = int(time() + cache_timeout) |
||||
|
||||
if add_etags and filename is not None: |
||||
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 |
||||
)) |
||||
if conditional: |
||||
rv = rv.make_conditional(request) |
||||
# make sure we don't send x-sendfile for servers that |
||||
# ignore the 304 status code for x-sendfile. |
||||
if rv.status_code == 304: |
||||
rv.headers.pop('x-sendfile', None) |
||||
return rv |
||||
|
||||
|
||||
def safe_join(directory, filename): |
||||
"""Safely join `directory` and `filename`. |
||||
|
||||
Example usage:: |
||||
|
||||
@app.route('/wiki/<path:filename>') |
||||
def wiki_page(filename): |
||||
filename = safe_join(app.config['WIKI_FOLDER'], filename) |
||||
with open(filename, 'rb') as fd: |
||||
content = fd.read() # Read and process the file content... |
||||
|
||||
:param directory: the base directory. |
||||
:param filename: the untrusted filename relative to that directory. |
||||
:raises: :class:`~werkzeug.exceptions.NotFound` if the resulting path |
||||
would fall out of `directory`. |
||||
""" |
||||
filename = posixpath.normpath(filename) |
||||
for sep in _os_alt_seps: |
||||
if sep in filename: |
||||
raise NotFound() |
||||
if os.path.isabs(filename) or \ |
||||
filename == '..' or \ |
||||
filename.startswith('../'): |
||||
raise NotFound() |
||||
return os.path.join(directory, filename) |
||||
|
||||
|
||||
def send_from_directory(directory, filename, **options): |
||||
"""Send a file from a given directory with :func:`send_file`. This |
||||
is a secure way to quickly expose static files from an upload folder |
||||
or something similar. |
||||
|
||||
Example usage:: |
||||
|
||||
@app.route('/uploads/<path:filename>') |
||||
def download_file(filename): |
||||
return send_from_directory(app.config['UPLOAD_FOLDER'], |
||||
filename, as_attachment=True) |
||||
|
||||
.. admonition:: Sending files and Performance |
||||
|
||||
It is strongly recommended to activate either `X-Sendfile` support in |
||||
your webserver or (if no authentication happens) to tell the webserver |
||||
to serve files for the given path on its own without calling into the |
||||
web application for improved performance. |
||||
|
||||
.. versionadded:: 0.5 |
||||
|
||||
:param directory: the directory where all the files are stored. |
||||
:param filename: the filename relative to that directory to |
||||
download. |
||||
:param options: optional keyword arguments that are directly |
||||
forwarded to :func:`send_file`. |
||||
""" |
||||
filename = safe_join(directory, filename) |
||||
if not os.path.isfile(filename): |
||||
raise NotFound() |
||||
options.setdefault('conditional', True) |
||||
return send_file(filename, **options) |
||||
|
||||
|
||||
def get_root_path(import_name): |
||||
"""Returns the path to a package or cwd if that cannot be found. This |
||||
returns the path of a package or the folder that contains a module. |
||||
|
||||
Not to be confused with the package path returned by :func:`find_package`. |
||||
""" |
||||
# Module already imported and has a file attribute. Use that first. |
||||
mod = sys.modules.get(import_name) |
||||
if mod is not None and hasattr(mod, '__file__'): |
||||
return os.path.dirname(os.path.abspath(mod.__file__)) |
||||
|
||||
# Next attempt: check the loader. |
||||
loader = pkgutil.get_loader(import_name) |
||||
|
||||
# Loader does not exist or we're referring to an unloaded main module |
||||
# or a main module without path (interactive sessions), go with the |
||||
# current working directory. |
||||
if loader is None or import_name == '__main__': |
||||
return os.getcwd() |
||||
|
||||
# For .egg, zipimporter does not have get_filename until Python 2.7. |
||||
# Some other loaders might exhibit the same behavior. |
||||
if hasattr(loader, 'get_filename'): |
||||
filepath = loader.get_filename(import_name) |
||||
else: |
||||
# Fall back to imports. |
||||
__import__(import_name) |
||||
filepath = sys.modules[import_name].__file__ |
||||
|
||||
# filepath is import_name.py for a module, or __init__.py for a package. |
||||
return os.path.dirname(os.path.abspath(filepath)) |
||||
|
||||
|
||||
def find_package(import_name): |
||||
"""Finds a package and returns the prefix (or None if the package is |
||||
not installed) as well as the folder that contains the package or |
||||
module as a tuple. The package path returned is the module that would |
||||
have to be added to the pythonpath in order to make it possible to |
||||
import the module. The prefix is the path below which a UNIX like |
||||
folder structure exists (lib, share etc.). |
||||
""" |
||||
root_mod_name = import_name.split('.')[0] |
||||
loader = pkgutil.get_loader(root_mod_name) |
||||
if loader is None or import_name == '__main__': |
||||
# import name is not found, or interactive/main module |
||||
package_path = os.getcwd() |
||||
else: |
||||
# For .egg, zipimporter does not have get_filename until Python 2.7. |
||||
if hasattr(loader, 'get_filename'): |
||||
filename = loader.get_filename(root_mod_name) |
||||
elif hasattr(loader, 'archive'): |
||||
# zipimporter's loader.archive points to the .egg or .zip |
||||
# archive filename is dropped in call to dirname below. |
||||
filename = loader.archive |
||||
else: |
||||
# At least one loader is missing both get_filename and archive: |
||||
# Google App Engine's HardenedModulesHook |
||||
# |
||||
# Fall back to imports. |
||||
__import__(import_name) |
||||
filename = sys.modules[import_name].__file__ |
||||
package_path = os.path.abspath(os.path.dirname(filename)) |
||||
# package_path ends with __init__.py for a package |
||||
if loader.is_package(root_mod_name): |
||||
package_path = os.path.dirname(package_path) |
||||
|
||||
site_parent, site_folder = os.path.split(package_path) |
||||
py_prefix = os.path.abspath(sys.prefix) |
||||
if package_path.startswith(py_prefix): |
||||
return py_prefix, package_path |
||||
elif site_folder.lower() == 'site-packages': |
||||
parent, folder = os.path.split(site_parent) |
||||
# Windows like installations |
||||
if folder.lower() == 'lib': |
||||
base_dir = parent |
||||
# UNIX like installations |
||||
elif os.path.basename(parent).lower() == 'lib': |
||||
base_dir = os.path.dirname(parent) |
||||
else: |
||||
base_dir = site_parent |
||||
return base_dir, package_path |
||||
return None, package_path |
||||
|
||||
|
||||
class locked_cached_property(object): |
||||
"""A decorator that converts a function into a lazy property. The |
||||
function wrapped is called the first time to retrieve the result |
||||
and then that calculated result is used the next time you access |
||||
the value. Works like the one in Werkzeug but has a lock for |
||||
thread safety. |
||||
""" |
||||
|
||||
def __init__(self, func, name=None, doc=None): |
||||
self.__name__ = name or func.__name__ |
||||
self.__module__ = func.__module__ |
||||
self.__doc__ = doc or func.__doc__ |
||||
self.func = func |
||||
self.lock = RLock() |
||||
|
||||
def __get__(self, obj, type=None): |
||||
if obj is None: |
||||
return self |
||||
with self.lock: |
||||
value = obj.__dict__.get(self.__name__, _missing) |
||||
if value is _missing: |
||||
value = self.func(obj) |
||||
obj.__dict__[self.__name__] = value |
||||
return value |
||||
|
||||
|
||||
class _PackageBoundObject(object): |
||||
|
||||
def __init__(self, import_name, template_folder=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 |
||||
#: exposed. |
||||
self.template_folder = template_folder |
||||
|
||||
#: Where is the app root located? |
||||
self.root_path = get_root_path(self.import_name) |
||||
|
||||
self._static_folder = None |
||||
self._static_url_path = None |
||||
|
||||
def _get_static_folder(self): |
||||
if self._static_folder is not None: |
||||
return os.path.join(self.root_path, self._static_folder) |
||||
def _set_static_folder(self, value): |
||||
self._static_folder = value |
||||
static_folder = property(_get_static_folder, _set_static_folder) |
||||
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 |
||||
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) |
||||
del _get_static_url_path, _set_static_url_path |
||||
|
||||
@property |
||||
def has_static_folder(self): |
||||
"""This is `True` if the package bound object's container has a |
||||
folder named ``'static'``. |
||||
|
||||
.. versionadded:: 0.5 |
||||
""" |
||||
return self.static_folder is not None |
||||
|
||||
@locked_cached_property |
||||
def jinja_loader(self): |
||||
"""The Jinja loader for this package bound object. |
||||
|
||||
.. versionadded:: 0.5 |
||||
""" |
||||
if self.template_folder is not None: |
||||
return FileSystemLoader(os.path.join(self.root_path, |
||||
self.template_folder)) |
||||
|
||||
def get_send_file_max_age(self, filename): |
||||
"""Provides default cache_timeout for the :func:`send_file` functions. |
||||
|
||||
By default, this function returns ``SEND_FILE_MAX_AGE_DEFAULT`` from |
||||
the configuration of :data:`~flask.current_app`. |
||||
|
||||
Static file functions such as :func:`send_from_directory` use this |
||||
function, and :func:`send_file` calls this function on |
||||
:data:`~flask.current_app` when the given cache_timeout is `None`. If a |
||||
cache_timeout is given in :func:`send_file`, that timeout is used; |
||||
otherwise, this method is called. |
||||
|
||||
This allows subclasses to change the behavior when sending files based |
||||
on the filename. For example, to set the cache timeout for .js files |
||||
to 60 seconds:: |
||||
|
||||
class MyFlask(flask.Flask): |
||||
def get_send_file_max_age(self, name): |
||||
if name.lower().endswith('.js'): |
||||
return 60 |
||||
return flask.Flask.get_send_file_max_age(self, name) |
||||
|
||||
.. versionadded:: 0.9 |
||||
""" |
||||
return current_app.config['SEND_FILE_MAX_AGE_DEFAULT'] |
||||
|
||||
def send_static_file(self, filename): |
||||
"""Function used internally to send static files from the static |
||||
folder to the browser. |
||||
|
||||
.. versionadded:: 0.5 |
||||
""" |
||||
if not self.has_static_folder: |
||||
raise RuntimeError('No static folder for this object') |
||||
# Ensure get_send_file_max_age is called in all cases. |
||||
# Here, we ensure get_send_file_max_age is called for Blueprints. |
||||
cache_timeout = self.get_send_file_max_age(filename) |
||||
return send_from_directory(self.static_folder, filename, |
||||
cache_timeout=cache_timeout) |
||||
|
||||
def open_resource(self, resource, mode='rb'): |
||||
"""Opens a resource from the application's resource folder. To see |
||||
how this works, consider the following folder structure:: |
||||
|
||||
/myapplication.py |
||||
/schema.sql |
||||
/static |
||||
/style.css |
||||
/templates |
||||
/layout.html |
||||
/index.html |
||||
|
||||
If you want to open the `schema.sql` file you would do the |
||||
following:: |
||||
|
||||
with app.open_resource('schema.sql') as f: |
||||
contents = f.read() |
||||
do_something_with(contents) |
||||
|
||||
:param resource: the name of the resource. To access resources within |
||||
subfolders use forward slashes as separator. |
||||
:param mode: resource file opening mode, default is 'rb'. |
||||
""" |
||||
if mode not in ('r', 'rb'): |
||||
raise ValueError('Resources can only be opened for reading') |
||||
return open(os.path.join(self.root_path, resource), mode) |
@ -1,243 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.jsonimpl |
||||
~~~~~~~~~~~~~~ |
||||
|
||||
Implementation helpers for the JSON support in Flask. |
||||
|
||||
:copyright: (c) 2012 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
import io |
||||
import uuid |
||||
from datetime import datetime |
||||
from .globals import current_app, request |
||||
from ._compat import text_type, PY2 |
||||
|
||||
from werkzeug.http import http_date |
||||
from jinja2 import Markup |
||||
|
||||
# Use the same json implementation as itsdangerous on which we |
||||
# depend anyways. |
||||
try: |
||||
from itsdangerous import simplejson as _json |
||||
except ImportError: |
||||
from itsdangerous import json as _json |
||||
|
||||
|
||||
# figure out if simplejson escapes slashes. This behavior was changed |
||||
# from one version to another without reason. |
||||
_slash_escape = '\\/' not in _json.dumps('/') |
||||
|
||||
|
||||
__all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump', |
||||
'htmlsafe_dumps', 'JSONDecoder', 'JSONEncoder', |
||||
'jsonify'] |
||||
|
||||
|
||||
def _wrap_reader_for_text(fp, encoding): |
||||
if isinstance(fp.read(0), bytes): |
||||
fp = io.TextIOWrapper(io.BufferedReader(fp), encoding) |
||||
return fp |
||||
|
||||
|
||||
def _wrap_writer_for_text(fp, encoding): |
||||
try: |
||||
fp.write('') |
||||
except TypeError: |
||||
fp = io.TextIOWrapper(fp, encoding) |
||||
return fp |
||||
|
||||
|
||||
class JSONEncoder(_json.JSONEncoder): |
||||
"""The default Flask JSON encoder. This one extends the default simplejson |
||||
encoder by also supporting ``datetime`` objects, ``UUID`` as well as |
||||
``Markup`` objects which are serialized as RFC 822 datetime strings (same |
||||
as the HTTP date format). In order to support more data types override the |
||||
:meth:`default` method. |
||||
""" |
||||
|
||||
def default(self, o): |
||||
"""Implement this method in a subclass such that it returns a |
||||
serializable object for ``o``, or calls the base implementation (to |
||||
raise a ``TypeError``). |
||||
|
||||
For example, to support arbitrary iterators, you could implement |
||||
default like this:: |
||||
|
||||
def default(self, o): |
||||
try: |
||||
iterable = iter(o) |
||||
except TypeError: |
||||
pass |
||||
else: |
||||
return list(iterable) |
||||
return JSONEncoder.default(self, o) |
||||
""" |
||||
if isinstance(o, datetime): |
||||
return http_date(o) |
||||
if isinstance(o, uuid.UUID): |
||||
return str(o) |
||||
if hasattr(o, '__html__'): |
||||
return text_type(o.__html__()) |
||||
return _json.JSONEncoder.default(self, o) |
||||
|
||||
|
||||
class JSONDecoder(_json.JSONDecoder): |
||||
"""The default JSON decoder. This one does not change the behavior from |
||||
the default simplejson encoder. Consult the :mod:`json` documentation |
||||
for more information. This decoder is not only used for the load |
||||
functions of this module but also :attr:`~flask.Request`. |
||||
""" |
||||
|
||||
|
||||
def _dump_arg_defaults(kwargs): |
||||
"""Inject default arguments for dump functions.""" |
||||
if current_app: |
||||
kwargs.setdefault('cls', current_app.json_encoder) |
||||
if not current_app.config['JSON_AS_ASCII']: |
||||
kwargs.setdefault('ensure_ascii', False) |
||||
kwargs.setdefault('sort_keys', current_app.config['JSON_SORT_KEYS']) |
||||
else: |
||||
kwargs.setdefault('sort_keys', True) |
||||
kwargs.setdefault('cls', JSONEncoder) |
||||
|
||||
|
||||
def _load_arg_defaults(kwargs): |
||||
"""Inject default arguments for load functions.""" |
||||
if current_app: |
||||
kwargs.setdefault('cls', current_app.json_decoder) |
||||
else: |
||||
kwargs.setdefault('cls', JSONDecoder) |
||||
|
||||
|
||||
def dumps(obj, **kwargs): |
||||
"""Serialize ``obj`` to a JSON formatted ``str`` by using the application's |
||||
configured encoder (:attr:`~flask.Flask.json_encoder`) if there is an |
||||
application on the stack. |
||||
|
||||
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. |
||||
""" |
||||
_dump_arg_defaults(kwargs) |
||||
encoding = kwargs.pop('encoding', None) |
||||
rv = _json.dumps(obj, **kwargs) |
||||
if encoding is not None and isinstance(rv, text_type): |
||||
rv = rv.encode(encoding) |
||||
return rv |
||||
|
||||
|
||||
def dump(obj, fp, **kwargs): |
||||
"""Like :func:`dumps` but writes into a file object.""" |
||||
_dump_arg_defaults(kwargs) |
||||
encoding = kwargs.pop('encoding', None) |
||||
if encoding is not None: |
||||
fp = _wrap_writer_for_text(fp, encoding) |
||||
_json.dump(obj, fp, **kwargs) |
||||
|
||||
|
||||
def loads(s, **kwargs): |
||||
"""Unserialize a JSON object from a string ``s`` by using the application's |
||||
configured decoder (:attr:`~flask.Flask.json_decoder`) if there is an |
||||
application on the stack. |
||||
""" |
||||
_load_arg_defaults(kwargs) |
||||
if isinstance(s, bytes): |
||||
s = s.decode(kwargs.pop('encoding', None) or 'utf-8') |
||||
return _json.loads(s, **kwargs) |
||||
|
||||
|
||||
def load(fp, **kwargs): |
||||
"""Like :func:`loads` but reads from a file object. |
||||
""" |
||||
_load_arg_defaults(kwargs) |
||||
if not PY2: |
||||
fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8') |
||||
return _json.load(fp, **kwargs) |
||||
|
||||
|
||||
def htmlsafe_dumps(obj, **kwargs): |
||||
"""Works exactly like :func:`dumps` but is safe for use in ``<script>`` |
||||
tags. It accepts the same arguments and returns a JSON string. Note that |
||||
this is available in templates through the ``|tojson`` filter which will |
||||
also mark the result as safe. Due to how this function escapes certain |
||||
characters this is safe even if used outside of ``<script>`` tags. |
||||
|
||||
The following characters are escaped in strings: |
||||
|
||||
- ``<`` |
||||
- ``>`` |
||||
- ``&`` |
||||
- ``'`` |
||||
|
||||
This makes it safe to embed such strings in any place in HTML with the |
||||
notable exception of double quoted attributes. In that case single |
||||
quote your attributes or HTML escape it in addition. |
||||
|
||||
.. versionchanged:: 0.10 |
||||
This function's return value is now always safe for HTML usage, even |
||||
if outside of script tags or if used in XHTML. This rule does not |
||||
hold true when using this function in HTML attributes that are double |
||||
quoted. Always single quote attributes if you use the ``|tojson`` |
||||
filter. Alternatively use ``|tojson|forceescape``. |
||||
""" |
||||
rv = dumps(obj, **kwargs) \ |
||||
.replace(u'<', u'\\u003c') \ |
||||
.replace(u'>', u'\\u003e') \ |
||||
.replace(u'&', u'\\u0026') \ |
||||
.replace(u"'", u'\\u0027') |
||||
if not _slash_escape: |
||||
rv = rv.replace('\\/', '/') |
||||
return rv |
||||
|
||||
|
||||
def htmlsafe_dump(obj, fp, **kwargs): |
||||
"""Like :func:`htmlsafe_dumps` but writes into a file object.""" |
||||
fp.write(unicode(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. |
||||
|
||||
Example usage:: |
||||
|
||||
from flask import jsonify |
||||
|
||||
@app.route('/_get_current_user') |
||||
def get_current_user(): |
||||
return jsonify(username=g.user.username, |
||||
email=g.user.email, |
||||
id=g.user.id) |
||||
|
||||
This will send a JSON response like this to the browser:: |
||||
|
||||
{ |
||||
"username": "admin", |
||||
"email": "admin@localhost", |
||||
"id": 42 |
||||
} |
||||
|
||||
For security reasons only objects are supported toplevel. For more |
||||
information about this, have a look at :ref:`json-security`. |
||||
|
||||
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. |
||||
|
||||
.. versionadded:: 0.2 |
||||
""" |
||||
indent = None |
||||
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') |
||||
|
||||
|
||||
def tojson_filter(obj, **kwargs): |
||||
return Markup(htmlsafe_dumps(obj, **kwargs)) |
@ -1,45 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.logging |
||||
~~~~~~~~~~~~~ |
||||
|
||||
Implements the logging support for Flask. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
from __future__ import absolute_import |
||||
|
||||
from logging import getLogger, StreamHandler, Formatter, getLoggerClass, DEBUG |
||||
|
||||
|
||||
def create_logger(app): |
||||
"""Creates a logger for the given application. This logger works |
||||
similar to a regular Python logger but changes the effective logging |
||||
level based on the application's debug flag. Furthermore this |
||||
function also removes all attached handlers in case there was a |
||||
logger with the log name before. |
||||
""" |
||||
Logger = getLoggerClass() |
||||
|
||||
class DebugLogger(Logger): |
||||
def getEffectiveLevel(x): |
||||
if x.level == 0 and app.debug: |
||||
return DEBUG |
||||
return Logger.getEffectiveLevel(x) |
||||
|
||||
class DebugHandler(StreamHandler): |
||||
def emit(x, record): |
||||
StreamHandler.emit(x, record) if app.debug else None |
||||
|
||||
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) |
||||
return logger |
@ -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' |
@ -1,332 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.sessions |
||||
~~~~~~~~~~~~~~ |
||||
|
||||
Implements cookie based sessions based on itsdangerous. |
||||
|
||||
:copyright: (c) 2012 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 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. |
||||
""" |
||||
|
||||
def _get_permanent(self): |
||||
return self.get('_permanent', False) |
||||
|
||||
def _set_permanent(self, value): |
||||
self['_permanent'] = bool(value) |
||||
|
||||
#: this reflects the ``'_permanent'`` key in the dict. |
||||
permanent = property(_get_permanent, _set_permanent) |
||||
del _get_permanent, _set_permanent |
||||
|
||||
#: 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. |
||||
new = False |
||||
|
||||
#: 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. |
||||
modified = True |
||||
|
||||
|
||||
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 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: |
||||
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): |
||||
def object_hook(obj): |
||||
if len(obj) != 1: |
||||
return obj |
||||
the_key, the_value = next(iteritems(obj)) |
||||
if the_key == ' t': |
||||
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': |
||||
return parse_date(the_value) |
||||
return obj |
||||
return json.loads(value, object_hook=object_hook) |
||||
|
||||
|
||||
session_json_serializer = TaggedJSONSerializer() |
||||
|
||||
|
||||
class SecureCookieSession(CallbackDict, SessionMixin): |
||||
"""Baseclass for sessions based on signed cookies.""" |
||||
|
||||
def __init__(self, initial=None): |
||||
def on_update(self): |
||||
self.modified = True |
||||
CallbackDict.__init__(self, initial, on_update) |
||||
self.modified = False |
||||
|
||||
|
||||
class NullSession(SecureCookieSession): |
||||
"""Class used to generate nicer error messages if sessions are not |
||||
available. Will still allow read-only access to the empty session |
||||
but fail on setting. |
||||
""" |
||||
|
||||
def _fail(self, *args, **kwargs): |
||||
raise RuntimeError('the session is unavailable because no secret ' |
||||
'key was set. Set the secret_key on the ' |
||||
'application to something unique and secret.') |
||||
__setitem__ = __delitem__ = clear = pop = popitem = \ |
||||
update = setdefault = _fail |
||||
del _fail |
||||
|
||||
|
||||
class SessionInterface(object): |
||||
"""The basic interface you have to implement in order to replace the |
||||
default session interface which uses werkzeug's securecookie |
||||
implementation. The only methods you have to implement are |
||||
:meth:`open_session` and :meth:`save_session`, the others have |
||||
useful defaults which you don't need to change. |
||||
|
||||
The session object returned by the :meth:`open_session` method has to |
||||
provide a dictionary like interface plus the properties and methods |
||||
from the :class:`SessionMixin`. We recommend just subclassing a dict |
||||
and adding that mixin:: |
||||
|
||||
class Session(dict, SessionMixin): |
||||
pass |
||||
|
||||
If :meth:`open_session` returns `None` Flask will call into |
||||
:meth:`make_null_session` to create a session that acts as replacement |
||||
if the session support cannot work because some requirement is not |
||||
fulfilled. The default :class:`NullSession` class that is created |
||||
will complain that the secret key was not set. |
||||
|
||||
To replace the session interface on an application all you have to do |
||||
is to assign :attr:`flask.Flask.session_interface`:: |
||||
|
||||
app = Flask(__name__) |
||||
app.session_interface = MySessionInterface() |
||||
|
||||
.. versionadded:: 0.8 |
||||
""" |
||||
|
||||
#: :meth:`make_null_session` will look here for the class that should |
||||
#: be created when a null session is requested. Likewise the |
||||
#: :meth:`is_null_session` method will perform a typecheck against |
||||
#: this type. |
||||
null_session_class = NullSession |
||||
|
||||
#: A flag that indicates if the session interface is pickle based. |
||||
#: This can be used by flask extensions to make a decision in regards |
||||
#: to how to deal with the session object. |
||||
#: |
||||
#: .. versionadded:: 0.10 |
||||
pickle_based = False |
||||
|
||||
def make_null_session(self, app): |
||||
"""Creates a null session which acts as a replacement object if the |
||||
real session support could not be loaded due to a configuration |
||||
error. This mainly aids the user experience because the job of the |
||||
null session is to still support lookup without complaining but |
||||
modifications are answered with a helpful error message of what |
||||
failed. |
||||
|
||||
This creates an instance of :attr:`null_session_class` by default. |
||||
""" |
||||
return self.null_session_class() |
||||
|
||||
def is_null_session(self, obj): |
||||
"""Checks if a given object is a null session. Null sessions are |
||||
not asked to be saved. |
||||
|
||||
This checks if the object is an instance of :attr:`null_session_class` |
||||
by default. |
||||
""" |
||||
return isinstance(obj, self.null_session_class) |
||||
|
||||
def get_cookie_domain(self, app): |
||||
"""Helpful helper method that returns the cookie domain that should |
||||
be used for the session cookie if session cookies are used. |
||||
""" |
||||
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 |
||||
rv = '.' + app.config['SERVER_NAME'].rsplit(':', 1)[0] |
||||
|
||||
# Google chrome does not like cookies set to .localhost, so |
||||
# we just go with no domain then. Flask documents anyways that |
||||
# cross domain cookies need a fully qualified domain name |
||||
if rv == '.localhost': |
||||
rv = None |
||||
|
||||
# If we infer the cookie domain from the server name we need |
||||
# to check if we are in a subpath. In that case we can't |
||||
# set a cross domain cookie. |
||||
if rv is not None: |
||||
path = self.get_cookie_path(app) |
||||
if path != '/': |
||||
rv = rv.lstrip('.') |
||||
|
||||
return rv |
||||
|
||||
def get_cookie_path(self, app): |
||||
"""Returns the path for which the cookie should be valid. The |
||||
default implementation uses the value from the SESSION_COOKIE_PATH`` |
||||
config var if it's set, and falls back to ``APPLICATION_ROOT`` or |
||||
uses ``/`` if it's `None`. |
||||
""" |
||||
return app.config['SESSION_COOKIE_PATH'] or \ |
||||
app.config['APPLICATION_ROOT'] or '/' |
||||
|
||||
def get_cookie_httponly(self, app): |
||||
"""Returns True if the session cookie should be httponly. This |
||||
currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` |
||||
config var. |
||||
""" |
||||
return app.config['SESSION_COOKIE_HTTPONLY'] |
||||
|
||||
def get_cookie_secure(self, app): |
||||
"""Returns True if the cookie should be secure. This currently |
||||
just returns the value of the ``SESSION_COOKIE_SECURE`` setting. |
||||
""" |
||||
return app.config['SESSION_COOKIE_SECURE'] |
||||
|
||||
def get_expiration_time(self, app, session): |
||||
"""A helper method that returns an expiration date for the session |
||||
or `None` if the session is linked to the browser session. The |
||||
default implementation returns now + the permanent session |
||||
lifetime configured on the application. |
||||
""" |
||||
if session.permanent: |
||||
return datetime.utcnow() + app.permanent_session_lifetime |
||||
|
||||
def open_session(self, app, request): |
||||
"""This method has to be implemented and must either return `None` |
||||
in case the loading failed because of a configuration error or an |
||||
instance of a session object which implements a dictionary like |
||||
interface + the methods and attributes on :class:`SessionMixin`. |
||||
""" |
||||
raise NotImplementedError() |
||||
|
||||
def save_session(self, app, session, response): |
||||
"""This is called for actual sessions returned by :meth:`open_session` |
||||
at the end of the request. This is still called during a request |
||||
context so if you absolutely need access to the request you can do |
||||
that. |
||||
""" |
||||
raise NotImplementedError() |
||||
|
||||
|
||||
class SecureCookieSessionInterface(SessionInterface): |
||||
"""The default session interface that stores sessions in signed cookies |
||||
through the :mod:`itsdangerous` module. |
||||
""" |
||||
#: the salt that should be applied on top of the secret key for the |
||||
#: signing of cookie based sessions. |
||||
salt = 'cookie-session' |
||||
#: the hash function to use for the signature. The default is sha1 |
||||
digest_method = staticmethod(hashlib.sha1) |
||||
#: the name of the itsdangerous supported key derivation. The default |
||||
#: is hmac. |
||||
key_derivation = 'hmac' |
||||
#: A python serializer for the payload. The default is a compact |
||||
#: JSON derived serializer with support for some extra Python types |
||||
#: such as datetime objects or tuples. |
||||
serializer = session_json_serializer |
||||
session_class = SecureCookieSession |
||||
|
||||
def get_signing_serializer(self, app): |
||||
if not app.secret_key: |
||||
return None |
||||
signer_kwargs = dict( |
||||
key_derivation=self.key_derivation, |
||||
digest_method=self.digest_method |
||||
) |
||||
return URLSafeTimedSerializer(app.secret_key, salt=self.salt, |
||||
serializer=self.serializer, |
||||
signer_kwargs=signer_kwargs) |
||||
|
||||
def open_session(self, app, request): |
||||
s = self.get_signing_serializer(app) |
||||
if s is None: |
||||
return None |
||||
val = request.cookies.get(app.session_cookie_name) |
||||
if not val: |
||||
return self.session_class() |
||||
max_age = total_seconds(app.permanent_session_lifetime) |
||||
try: |
||||
data = s.loads(val, max_age=max_age) |
||||
return self.session_class(data) |
||||
except BadSignature: |
||||
return self.session_class() |
||||
|
||||
def save_session(self, app, session, response): |
||||
domain = self.get_cookie_domain(app) |
||||
path = self.get_cookie_path(app) |
||||
if not session: |
||||
if session.modified: |
||||
response.delete_cookie(app.session_cookie_name, |
||||
domain=domain, path=path) |
||||
return |
||||
httponly = self.get_cookie_httponly(app) |
||||
secure = self.get_cookie_secure(app) |
||||
expires = self.get_expiration_time(app, session) |
||||
val = self.get_signing_serializer(app).dumps(dict(session)) |
||||
response.set_cookie(app.session_cookie_name, val, |
||||
expires=expires, httponly=httponly, |
||||
domain=domain, path=path, secure=secure) |
||||
|
||||
|
||||
from flask.debughelpers import UnexpectedUnicodeError |
@ -1,55 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.signals |
||||
~~~~~~~~~~~~~ |
||||
|
||||
Implements signals based on blinker if available, otherwise |
||||
falls silently back to a noop |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
signals_available = False |
||||
try: |
||||
from blinker import Namespace |
||||
signals_available = True |
||||
except ImportError: |
||||
class Namespace(object): |
||||
def signal(self, name, doc=None): |
||||
return _FakeSignal(name, doc) |
||||
|
||||
class _FakeSignal(object): |
||||
"""If blinker is unavailable, create a fake class with the same |
||||
interface that allows sending of signals but will fail with an |
||||
error on anything else. Instead of doing anything on send, it |
||||
will just ignore the arguments and do nothing instead. |
||||
""" |
||||
|
||||
def __init__(self, name, doc=None): |
||||
self.name = name |
||||
self.__doc__ = doc |
||||
def _fail(self, *args, **kwargs): |
||||
raise RuntimeError('signalling support is unavailable ' |
||||
'because the blinker library is ' |
||||
'not installed.') |
||||
send = lambda *a, **kw: None |
||||
connect = disconnect = has_receivers_for = receivers_for = \ |
||||
temporarily_connected_to = connected_to = _fail |
||||
del _fail |
||||
|
||||
# the namespace for code signals. If you are not flask code, do |
||||
# not put signals in here. Create your own namespace instead. |
||||
_signals = Namespace() |
||||
|
||||
|
||||
# core signals. For usage examples grep the sourcecode or consult |
||||
# the API documentation in docs/api.rst as well as docs/signals.rst |
||||
template_rendered = _signals.signal('template-rendered') |
||||
request_started = _signals.signal('request-started') |
||||
request_finished = _signals.signal('request-finished') |
||||
request_tearing_down = _signals.signal('request-tearing-down') |
||||
got_request_exception = _signals.signal('got-request-exception') |
||||
appcontext_tearing_down = _signals.signal('appcontext-tearing-down') |
||||
appcontext_pushed = _signals.signal('appcontext-pushed') |
||||
appcontext_popped = _signals.signal('appcontext-popped') |
||||
message_flashed = _signals.signal('message-flashed') |
@ -1,143 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.templating |
||||
~~~~~~~~~~~~~~~~ |
||||
|
||||
Implements the bridge to Jinja2. |
||||
|
||||
:copyright: (c) 2011 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 |
||||
|
||||
|
||||
def _default_template_ctx_processor(): |
||||
"""Default template context processor. Injects `request`, |
||||
`session` and `g`. |
||||
""" |
||||
reqctx = _request_ctx_stack.top |
||||
appctx = _app_ctx_stack.top |
||||
rv = {} |
||||
if appctx is not None: |
||||
rv['g'] = appctx.g |
||||
if reqctx is not None: |
||||
rv['request'] = reqctx.request |
||||
rv['session'] = reqctx.session |
||||
return rv |
||||
|
||||
|
||||
class Environment(BaseEnvironment): |
||||
"""Works like a regular Jinja2 environment but has some additional |
||||
knowledge of how Flask's blueprint works so that it can prepend the |
||||
name of the blueprint to referenced templates if necessary. |
||||
""" |
||||
|
||||
def __init__(self, app, **options): |
||||
if 'loader' not in options: |
||||
options['loader'] = app.create_global_jinja_loader() |
||||
BaseEnvironment.__init__(self, **options) |
||||
self.app = app |
||||
|
||||
|
||||
class DispatchingJinjaLoader(BaseLoader): |
||||
"""A loader that looks for templates in the application and all |
||||
the blueprint folders. |
||||
""" |
||||
|
||||
def __init__(self, app): |
||||
self.app = app |
||||
|
||||
def get_source(self, environment, template): |
||||
for loader, local_name in self._iter_loaders(template): |
||||
try: |
||||
return loader.get_source(environment, local_name) |
||||
except TemplateNotFound: |
||||
pass |
||||
|
||||
raise TemplateNotFound(template) |
||||
|
||||
def _iter_loaders(self, template): |
||||
loader = self.app.jinja_loader |
||||
if loader is not None: |
||||
yield loader, template |
||||
|
||||
# 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 |
||||
loader = blueprint.jinja_loader |
||||
if loader is not None: |
||||
yield loader, template |
||||
|
||||
def list_templates(self): |
||||
result = set() |
||||
loader = self.app.jinja_loader |
||||
if loader is not None: |
||||
result.update(loader.list_templates()) |
||||
|
||||
for name, blueprint in iteritems(self.app.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) |
||||
|
||||
return list(result) |
||||
|
||||
|
||||
def _render(template, context, app): |
||||
"""Renders the template and fires the signal""" |
||||
rv = template.render(context) |
||||
template_rendered.send(app, template=template, context=context) |
||||
return rv |
||||
|
||||
|
||||
def render_template(template_name_or_list, **context): |
||||
"""Renders a template from the template folder with the given |
||||
context. |
||||
|
||||
:param template_name_or_list: the name of the template to be |
||||
rendered, or an iterable with template names |
||||
the first one existing will be rendered |
||||
:param context: the variables that should be available in the |
||||
context of the template. |
||||
""" |
||||
ctx = _app_ctx_stack.top |
||||
ctx.app.update_template_context(context) |
||||
return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list), |
||||
context, ctx.app) |
||||
|
||||
|
||||
def render_template_string(source, **context): |
||||
"""Renders a template from the given template source string |
||||
with the given context. |
||||
|
||||
:param source: the sourcecode of the template to be |
||||
rendered |
||||
:param context: the variables that should be available in the |
||||
context of the template. |
||||
""" |
||||
ctx = _app_ctx_stack.top |
||||
ctx.app.update_template_context(context) |
||||
return _render(ctx.app.jinja_env.from_string(source), |
||||
context, ctx.app) |
@ -1,124 +0,0 @@
|
||||
# -*- coding: utf-8 -*- |
||||
""" |
||||
flask.testing |
||||
~~~~~~~~~~~~~ |
||||
|
||||
Implements test support helpers. This module is lazily imported |
||||
and usually not used in production environments. |
||||
|
||||
:copyright: (c) 2011 by Armin Ronacher. |
||||
:license: BSD, see LICENSE for more details. |
||||
""" |
||||
|
||||
from contextlib import contextmanager |
||||
from werkzeug.test import Client, EnvironBuilder |
||||
from flask import _request_ctx_stack |
||||
|
||||
try: |
||||
from werkzeug.urls import url_parse |
||||
except ImportError: |
||||
from urlparse import urlsplit as url_parse |
||||
|
||||
|
||||
def make_test_environ_builder(app, path='/', base_url=None, *args, **kwargs): |
||||
"""Creates a new test builder with some application defaults thrown in.""" |
||||
http_host = app.config.get('SERVER_NAME') |
||||
app_root = app.config.get('APPLICATION_ROOT') |
||||
if base_url is None: |
||||
url = url_parse(path) |
||||
base_url = 'http://%s/' % (url.netloc or http_host or 'localhost') |
||||
if app_root: |
||||
base_url += app_root.lstrip('/') |
||||
if url.netloc: |
||||
path = url.path |
||||
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`. |
||||
|
||||
Basic usage is outlined in the :ref:`testing` chapter. |
||||
""" |
||||
|
||||
preserve_context = False |
||||
|
||||
@contextmanager |
||||
def session_transaction(self, *args, **kwargs): |
||||
"""When used in combination with a with statement this opens a |
||||
session transaction. This can be used to modify the session that |
||||
the test client uses. Once the with block is left the session is |
||||
stored back. |
||||
|
||||
with client.session_transaction() as session: |
||||
session['value'] = 42 |
||||
|
||||
Internally this is implemented by going through a temporary test |
||||
request context and since session handling could depend on |
||||
request variables this function accepts the same arguments as |
||||
:meth:`~flask.Flask.test_request_context` which are directly |
||||
passed through. |
||||
""" |
||||
if self.cookie_jar is None: |
||||
raise RuntimeError('Session transactions only make sense ' |
||||
'with cookies enabled.') |
||||
app = self.application |
||||
environ_overrides = kwargs.setdefault('environ_overrides', {}) |
||||
self.cookie_jar.inject_wsgi(environ_overrides) |
||||
outer_reqctx = _request_ctx_stack.top |
||||
with app.test_request_context(*args, **kwargs) as c: |
||||
sess = app.open_session(c.request) |
||||
if sess is None: |
||||
raise RuntimeError('Session backend did not open a session. ' |
||||
'Check the configuration') |
||||
|
||||
# Since we have to open a new request context for the session |
||||
# handling we want to make sure that we hide out own context |
||||
# from the caller. By pushing the original request context |
||||
# (or None) on top of this and popping it we get exactly that |
||||
# behavior. It's important to not use the push and pop |
||||
# methods of the actual request context object since that would |
||||
# mean that cleanup handlers are called |
||||
_request_ctx_stack.push(outer_reqctx) |
||||
try: |
||||
yield sess |
||||
finally: |
||||
_request_ctx_stack.pop() |
||||
|
||||
resp = app.response_class() |
||||
if not app.session_interface.is_null_session(sess): |
||||
app.save_session(sess, resp) |
||||
headers = resp.get_wsgi_headers(c.request.environ) |
||||
self.cookie_jar.extract_wsgi(c.request.environ, headers) |
||||
|
||||
def open(self, *args, **kwargs): |
||||
kwargs.setdefault('environ_overrides', {}) \ |
||||
['flask._preserve_context'] = self.preserve_context |
||||
|
||||
as_tuple = kwargs.pop('as_tuple', False) |
||||
buffered = kwargs.pop('buffered', False) |
||||
follow_redirects = kwargs.pop('follow_redirects', False) |
||||
builder = make_test_environ_builder(self.application, *args, **kwargs) |
||||
|
||||
return Client.open(self, builder, |
||||
as_tuple=as_tuple, |
||||
buffered=buffered, |
||||
follow_redirects=follow_redirects) |
||||
|
||||
def __enter__(self): |
||||
if self.preserve_context: |
||||
raise RuntimeError('Cannot nest client invocations') |
||||
self.preserve_context = True |
||||
return self |
||||
|
||||
def __exit__(self, exc_type, exc_value, tb): |
||||
self.preserve_context = False |
||||
|
||||
# on exit we want to clean up earlier. Normally the request context |
||||
# stays preserved until the next request in the same thread comes |
||||
# in. See RequestGlobals.push() for the general behavior. |
||||
top = _request_ctx_stack.top |
||||
if top is not None and top.preserved: |
||||
top.pop() |
@ -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) |
@ -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 |
File diff suppressed because it is too large
Load Diff
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -1,593 +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"') |
||||
rv = render('{{ "\'"|tojson }}') |
||||
self.assert_equal(rv, '"\\u0027"') |
||||
rv = render("<a ng-data='{{ data|tojson }}'></a>", |
||||
data={'x': ["foo", "bar", "baz'"]}) |
||||
self.assert_equal(rv, |
||||
'<a ng-data=\'{"x": ["foo", "bar", "baz\\u0027"]}\'></a>') |
||||
|
||||
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 |
@ -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 |
@ -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 |
@ -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 +0,0 @@
|
||||
<h1>Hello World!</h1> |
@ -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 +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 +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 %} |
@ -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 |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue