Browse Source

Merge branch 'sprint-branch'

pull/753/merge
Armin Ronacher 12 years ago
parent
commit
29e63e01ab
  1. 7
      .travis.yml
  2. 5
      CHANGES
  3. 5
      Makefile
  4. 2
      docs/extensiondev.rst
  5. 2
      docs/installation.rst
  6. 4
      docs/patterns/jquery.rst
  7. 2
      docs/patterns/sqlite3.rst
  8. 9
      docs/tutorial/dbinit.rst
  9. 4
      examples/flaskr/flaskr.py
  10. 16
      examples/flaskr/flaskr_tests.py
  11. 4
      examples/minitwit/minitwit.py
  12. 56
      examples/minitwit/minitwit_tests.py
  13. 111
      flask/_compat.py
  14. 74
      flask/app.py
  15. 10
      flask/config.py
  16. 20
      flask/ctx.py
  17. 6
      flask/debughelpers.py
  18. 3
      flask/exthook.py
  19. 19
      flask/helpers.py
  20. 40
      flask/json.py
  21. 9
      flask/sessions.py
  22. 5
      flask/templating.py
  23. 10
      flask/testing.py
  24. 38
      flask/testsuite/__init__.py
  25. 5
      flask/testsuite/appctx.py
  26. 250
      flask/testsuite/basic.py
  27. 161
      flask/testsuite/blueprints.py
  28. 35
      flask/testsuite/config.py
  29. 19
      flask/testsuite/deprecations.py
  30. 35
      flask/testsuite/ext.py
  31. 92
      flask/testsuite/helpers.py
  32. 8
      flask/testsuite/regression.py
  33. 36
      flask/testsuite/reqctx.py
  34. 9
      flask/testsuite/signals.py
  35. 6
      flask/testsuite/subclassing.py
  36. 68
      flask/testsuite/templating.py
  37. 47
      flask/testsuite/testing.py
  38. 20
      flask/testsuite/views.py
  39. 5
      flask/views.py
  40. 4
      flask/wrappers.py
  41. 4
      scripts/flask-07-upgrade.py
  42. 2
      scripts/flaskext_test.py
  43. 10
      setup.py
  44. 6
      tox.ini

7
.travis.yml

@ -4,6 +4,7 @@ python:
- 2.6
- 2.7
- pypy
- 3.3
install: pip install --editable .
@ -18,9 +19,3 @@ notifications:
# their own builder failure from us. Travis currently fails way
# too many times by itself.
email: false
irc:
channels:
- "irc.freenode.org#pocoo"
use_notice: true
skip_join: true

5
CHANGES

@ -57,6 +57,11 @@ Release date to be decided.
- Removed custom JSON HTTP exception subclasses. If you were relying on them
you can reintroduce them again yourself trivially. Using them however is
strongly discouraged as the interface was flawed.
- Python requirements changed: requiring Python 2.6 or 2.7 now to prepare
for Python 3.3 port.
- Changed how the teardown system is informed about exceptions. This is now
more reliable in case something handles an exception halfway through
the error handling process.
Version 0.9
-----------

5
Makefile

@ -1,10 +1,13 @@
.PHONY: clean-pyc ext-test test test-with-mem upload-docs docs audit
.PHONY: clean-pyc ext-test test tox-test test-with-mem upload-docs docs audit
all: clean-pyc test
test:
python run-tests.py
tox-test:
tox
test-with-mem:
RUN_FLASK_MEMORY_TESTS=1 python run-tests.py

2
docs/extensiondev.rst

@ -390,7 +390,7 @@ extension to be approved you have to follow these guidelines:
(``PackageName==dev``).
9. The ``zip_safe`` flag in the setup script must be set to ``False``,
even if the extension would be safe for zipping.
10. An extension currently has to support Python 2.5, 2.6 as well as
10. An extension currently has to support Python 2.6 as well as
Python 2.7

2
docs/installation.rst

@ -13,7 +13,7 @@ So how do you get all that on your computer quickly? There are many ways you
could do that, but the most kick-ass method is virtualenv, so let's have a look
at that first.
You will need Python 2.5 or higher to get started, so be sure to have an
You will need Python 2.6 or higher to get started, so be sure to have an
up-to-date Python 2.x installation. Python 3.x is not supported.
.. _virtualenv:

4
docs/patterns/jquery.rst

@ -11,11 +11,7 @@ Python primitives (numbers, strings, dicts and lists) look like which is
widely supported and very easy to parse. It became popular a few years
ago and quickly replaced XML as transport format in web applications.
If you have Python 2.6 JSON will work out of the box, in Python 2.5 you
will have to install the `simplejson`_ library from PyPI.
.. _jQuery: http://jquery.com/
.. _simplejson: http://pypi.python.org/pypi/simplejson
Loading jQuery
--------------

2
docs/patterns/sqlite3.rst

@ -124,7 +124,7 @@ can do that for you::
def init_db():
with app.app_context():
db = get_db()
with app.open_resource('schema.sql') as f:
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()

9
docs/tutorial/dbinit.rst

@ -21,12 +21,9 @@ errors. It's a good idea to add a function that initializes the database
for you to the application.
If you want to do that, you first have to import the
:func:`contextlib.closing` function from the contextlib package. If you
want to use Python 2.5 it's also necessary to enable the `with` statement
first (`__future__` imports must be the very first import). Accordingly,
add the following lines to your existing imports in `flaskr.py`::
:func:`contextlib.closing` function from the contextlib package.
Accordingly, add the following lines to your existing imports in `flaskr.py`::
from __future__ import with_statement
from contextlib import closing
Next we can create a function called `init_db` that initializes the
@ -36,7 +33,7 @@ earlier. Just add that function below the `connect_db` function in
def init_db():
with closing(connect_db()) as db:
with app.open_resource('schema.sql') as f:
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()

4
examples/flaskr/flaskr.py

@ -9,7 +9,7 @@
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
from sqlite3 import dbapi2 as sqlite3
from flask import Flask, request, session, g, redirect, url_for, abort, \
render_template, flash, _app_ctx_stack
@ -31,7 +31,7 @@ def init_db():
"""Creates the database tables."""
with app.app_context():
db = get_db()
with app.open_resource('schema.sql') as f:
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()

16
examples/flaskr/flaskr_tests.py

@ -42,21 +42,21 @@ class FlaskrTestCase(unittest.TestCase):
def test_empty_db(self):
"""Start with a blank database."""
rv = self.app.get('/')
assert 'No entries here so far' in rv.data
assert b'No entries here so far' in rv.data
def test_login_logout(self):
"""Make sure login and logout works"""
rv = self.login(flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'])
assert 'You were logged in' in rv.data
assert b'You were logged in' in rv.data
rv = self.logout()
assert 'You were logged out' in rv.data
assert b'You were logged out' in rv.data
rv = self.login(flaskr.app.config['USERNAME'] + 'x',
flaskr.app.config['PASSWORD'])
assert 'Invalid username' in rv.data
assert b'Invalid username' in rv.data
rv = self.login(flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'] + 'x')
assert 'Invalid password' in rv.data
assert b'Invalid password' in rv.data
def test_messages(self):
"""Test that messages work"""
@ -66,9 +66,9 @@ class FlaskrTestCase(unittest.TestCase):
title='<Hello>',
text='<strong>HTML</strong> allowed here'
), follow_redirects=True)
assert 'No entries here so far' not in rv.data
assert '&lt;Hello&gt;' in rv.data
assert '<strong>HTML</strong> allowed here' in rv.data
assert b'No entries here so far' not in rv.data
assert b'&lt;Hello&gt;' in rv.data
assert b'<strong>HTML</strong> allowed here' in rv.data
if __name__ == '__main__':

4
examples/minitwit/minitwit.py

@ -8,7 +8,7 @@
:copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import time
from sqlite3 import dbapi2 as sqlite3
from hashlib import md5
@ -53,7 +53,7 @@ def init_db():
"""Creates the database tables."""
with app.app_context():
db = get_db()
with app.open_resource('schema.sql') as f:
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()

56
examples/minitwit/minitwit_tests.py

@ -63,7 +63,7 @@ class MiniTwitTestCase(unittest.TestCase):
rv = self.app.post('/add_message', data={'text': text},
follow_redirects=True)
if text:
assert 'Your message was recorded' in rv.data
assert b'Your message was recorded' in rv.data
return rv
# testing functions
@ -71,29 +71,29 @@ class MiniTwitTestCase(unittest.TestCase):
def test_register(self):
"""Make sure registering works"""
rv = self.register('user1', 'default')
assert 'You were successfully registered ' \
'and can login now' in rv.data
assert b'You were successfully registered ' \
b'and can login now' in rv.data
rv = self.register('user1', 'default')
assert 'The username is already taken' in rv.data
assert b'The username is already taken' in rv.data
rv = self.register('', 'default')
assert 'You have to enter a username' in rv.data
assert b'You have to enter a username' in rv.data
rv = self.register('meh', '')
assert 'You have to enter a password' in rv.data
assert b'You have to enter a password' in rv.data
rv = self.register('meh', 'x', 'y')
assert 'The two passwords do not match' in rv.data
assert b'The two passwords do not match' in rv.data
rv = self.register('meh', 'foo', email='broken')
assert 'You have to enter a valid email address' in rv.data
assert b'You have to enter a valid email address' in rv.data
def test_login_logout(self):
"""Make sure logging in and logging out works"""
rv = self.register_and_login('user1', 'default')
assert 'You were logged in' in rv.data
assert b'You were logged in' in rv.data
rv = self.logout()
assert 'You were logged out' in rv.data
assert b'You were logged out' in rv.data
rv = self.login('user1', 'wrongpassword')
assert 'Invalid password' in rv.data
assert b'Invalid password' in rv.data
rv = self.login('user2', 'wrongpassword')
assert 'Invalid username' in rv.data
assert b'Invalid username' in rv.data
def test_message_recording(self):
"""Check if adding messages works"""
@ -101,8 +101,8 @@ class MiniTwitTestCase(unittest.TestCase):
self.add_message('test message 1')
self.add_message('<test message 2>')
rv = self.app.get('/')
assert 'test message 1' in rv.data
assert '&lt;test message 2&gt;' in rv.data
assert b'test message 1' in rv.data
assert b'&lt;test message 2&gt;' in rv.data
def test_timelines(self):
"""Make sure that timelines work"""
@ -112,37 +112,37 @@ class MiniTwitTestCase(unittest.TestCase):
self.register_and_login('bar', 'default')
self.add_message('the message by bar')
rv = self.app.get('/public')
assert 'the message by foo' in rv.data
assert 'the message by bar' in rv.data
assert b'the message by foo' in rv.data
assert b'the message by bar' in rv.data
# bar's timeline should just show bar's message
rv = self.app.get('/')
assert 'the message by foo' not in rv.data
assert 'the message by bar' in rv.data
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
# now let's follow foo
rv = self.app.get('/foo/follow', follow_redirects=True)
assert 'You are now following &#34;foo&#34;' in rv.data
assert b'You are now following &#34;foo&#34;' in rv.data
# we should now see foo's message
rv = self.app.get('/')
assert 'the message by foo' in rv.data
assert 'the message by bar' in rv.data
assert b'the message by foo' in rv.data
assert b'the message by bar' in rv.data
# but on the user's page we only want the user's message
rv = self.app.get('/bar')
assert 'the message by foo' not in rv.data
assert 'the message by bar' in rv.data
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
rv = self.app.get('/foo')
assert 'the message by foo' in rv.data
assert 'the message by bar' not in rv.data
assert b'the message by foo' in rv.data
assert b'the message by bar' not in rv.data
# now unfollow and check if that worked
rv = self.app.get('/foo/unfollow', follow_redirects=True)
assert 'You are no longer following &#34;foo&#34;' in rv.data
assert b'You are no longer following &#34;foo&#34;' in rv.data
rv = self.app.get('/')
assert 'the message by foo' not in rv.data
assert 'the message by bar' in rv.data
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
if __name__ == '__main__':

111
flask/_compat.py

@ -0,0 +1,111 @@
# -*- 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
PYPY = hasattr(sys, 'pypy_translation_info')
_identity = lambda x: x
if not PY2:
unichr = chr
range_type = range
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())
import pickle
from io import BytesIO, StringIO
NativeStringIO = StringIO
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
ifilter = filter
imap = map
izip = zip
intern = sys.intern
implements_iterator = _identity
implements_to_string = _identity
encode_filename = _identity
get_next = lambda x: x.__next__
else:
unichr = unichr
text_type = unicode
range_type = xrange
string_types = (str, unicode)
integer_types = (int, long)
iterkeys = lambda d: d.iterkeys()
itervalues = lambda d: d.itervalues()
iteritems = lambda d: d.iteritems()
import cPickle as pickle
from cStringIO import StringIO as BytesIO, StringIO
NativeStringIO = BytesIO
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
from itertools import imap, izip, ifilter
intern = intern
def implements_iterator(cls):
cls.next = cls.__next__
del cls.__next__
return cls
def implements_to_string(cls):
cls.__unicode__ = cls.__str__
cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
return cls
get_next = lambda x: x.next
def encode_filename(filename):
if isinstance(filename, unicode):
return filename.encode('utf-8')
return filename
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, {})
try:
from urllib.parse import quote_from_bytes as url_quote
except ImportError:
from urllib import quote as url_quote

74
flask/app.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import sys
from threading import Lock
@ -36,6 +34,7 @@ from .templating import DispatchingJinjaLoader, Environment, \
_default_template_ctx_processor
from .signals import request_started, request_finished, got_request_exception, \
request_tearing_down, appcontext_tearing_down
from ._compat import reraise, string_types, integer_types
# a lock used for logger initialization
_logger_lock = Lock()
@ -178,7 +177,7 @@ class Flask(_PackageBoundObject):
#: The debug flag. Set this to `True` to enable debugging of the
#: application. In debug mode the debugger will kick in when an unhandled
#: exception ocurrs and the integrated server will automatically reload
#: exception occurs and the integrated server will automatically reload
#: the application if changes in the code are detected.
#:
#: This attribute can also be configured from the config with the `DEBUG`
@ -523,7 +522,7 @@ class Flask(_PackageBoundObject):
"""The name of the application. This is usually the import name
with the difference that it's guessed from the run file if the
import name is main. This name is used as a display name when
Flask needs the name of the application. It can be set and overriden
Flask needs the name of the application. It can be set and overridden
to change the value.
.. versionadded:: 0.8
@ -585,21 +584,7 @@ class Flask(_PackageBoundObject):
@locked_cached_property
def jinja_env(self):
"""The Jinja2 environment used to load templates."""
rv = self.create_jinja_environment()
# Hack to support the init_jinja_globals method which is supported
# until 1.0 but has an API deficiency.
if getattr(self.init_jinja_globals, 'im_func', None) is not \
Flask.init_jinja_globals.im_func:
from warnings import warn
warn(DeprecationWarning('This flask class uses a customized '
'init_jinja_globals() method which is deprecated. '
'Move the code from that method into the '
'create_jinja_environment() method instead.'))
self.__dict__['jinja_env'] = rv
self.init_jinja_globals()
return rv
return self.create_jinja_environment()
@property
def got_first_request(self):
@ -645,6 +630,7 @@ class Flask(_PackageBoundObject):
:param resource: the name of the resource. To access resources within
subfolders use forward slashes as separator.
:param mode: resource file opening mode, default is 'rb'.
"""
return open(os.path.join(self.instance_path, resource), mode)
@ -711,7 +697,7 @@ class Flask(_PackageBoundObject):
This injects request, session, config and g into the template
context as well as everything template context processors want
to inject. Note that the as of Flask 0.6, the original values
in the context will not be overriden if a context processor
in the context will not be overridden if a context processor
decides to return a value with the same key.
:param context: the context as a dictionary that is updated in place
@ -1059,7 +1045,7 @@ class Flask(_PackageBoundObject):
app.error_handler_spec[None][404] = page_not_found
Setting error handlers via assignments to :attr:`error_handler_spec`
however is discouraged as it requires fidling with nested dictionaries
however is discouraged as it requires fiddling with nested dictionaries
and the special case for arbitrary exception types.
The first `None` refers to the active blueprint. If the error
@ -1090,7 +1076,7 @@ class Flask(_PackageBoundObject):
def _register_error_handler(self, key, code_or_exception, f):
if isinstance(code_or_exception, HTTPException):
code_or_exception = code_or_exception.code
if isinstance(code_or_exception, (int, long)):
if isinstance(code_or_exception, integer_types):
assert code_or_exception != 500 or key is None, \
'It is currently not possible to register a 500 internal ' \
'server error on a per-blueprint level.'
@ -1137,7 +1123,7 @@ class Flask(_PackageBoundObject):
def is_prime(n):
if n == 2:
return True
for i in xrange(2, int(math.ceil(math.sqrt(n))) + 1):
for i in range(2, int(math.ceil(math.sqrt(n))) + 1):
if n % i == 0:
return False
return True
@ -1383,7 +1369,7 @@ class Flask(_PackageBoundObject):
if isinstance(e, typecheck):
return handler(e)
raise exc_type, exc_value, tb
reraise(exc_type, exc_value, tb)
def handle_exception(self, e):
"""Default exception handling that kicks in when an exception
@ -1405,7 +1391,7 @@ class Flask(_PackageBoundObject):
# (the function was actually called from the except part)
# otherwise, we just raise the error again
if exc_value is e:
raise exc_type, exc_value, tb
reraise(exc_type, exc_value, tb)
else:
raise e
@ -1478,7 +1464,7 @@ class Flask(_PackageBoundObject):
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
except Exception, e:
except Exception as e:
rv = self.handle_user_exception(e)
response = self.make_response(rv)
response = self.process_response(response)
@ -1516,14 +1502,24 @@ class Flask(_PackageBoundObject):
methods = []
try:
adapter.match(method='--')
except MethodNotAllowed, e:
except MethodNotAllowed as e:
methods = e.valid_methods
except HTTPException, e:
except HTTPException as e:
pass
rv = self.response_class()
rv.allow.update(methods)
return rv
def should_ignore_error(self, error):
"""This is called to figure out if an error should be ignored
or not as far as the teardown system is concerned. If this
function returns `True` then the teardown handlers will not be
passed the error.
.. versionadded:: 0.10
"""
return False
def make_response(self, rv):
"""Converts the return value from a view function to a real
response object that is an instance of :attr:`response_class`.
@ -1564,15 +1560,15 @@ class Flask(_PackageBoundObject):
# When we create a response object directly, we let the constructor
# set the headers and status. We do this because there can be
# some extra logic involved when creating these objects with
# specific values (like defualt content type selection).
if isinstance(rv, basestring):
# specific values (like default content type selection).
if isinstance(rv, string_types + (bytes, )):
rv = self.response_class(rv, headers=headers, status=status)
headers = status = None
else:
rv = self.response_class.force_type(rv, request.environ)
if status is not None:
if isinstance(status, basestring):
if isinstance(status, string_types):
rv.status = status
else:
rv.status_code = status
@ -1626,14 +1622,14 @@ class Flask(_PackageBoundObject):
rv = handler(error, endpoint, values)
if rv is not None:
return rv
except BuildError, error:
except BuildError as error:
pass
# At this point we want to reraise the exception. If the error is
# still the same one we can reraise it with the original traceback,
# otherwise we raise it from here.
if error is exc_value:
raise exc_type, exc_value, tb
reraise(exc_type, exc_value, tb)
raise error
def preprocess_request(self):
@ -1804,12 +1800,20 @@ class Flask(_PackageBoundObject):
a list of headers and an optional
exception context to start the response
"""
with self.request_context(environ):
ctx = self.request_context(environ)
ctx.push()
error = None
try:
try:
response = self.full_dispatch_request()
except Exception, e:
except Exception as e:
error = e
response = self.make_response(self.handle_exception(e))
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
@property
def modules(self):

10
flask/config.py

@ -9,13 +9,12 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import imp
import os
import errno
from werkzeug.utils import import_string
from ._compat import string_types
class ConfigAttribute(object):
@ -126,8 +125,9 @@ class Config(dict):
d = imp.new_module('config')
d.__file__ = filename
try:
execfile(filename, d.__dict__)
except IOError, e:
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
@ -158,7 +158,7 @@ class Config(dict):
:param obj: an import name or object
"""
if isinstance(obj, basestring):
if isinstance(obj, string_types):
obj = import_string(obj)
for key in dir(obj):
if key.isupper():

20
flask/ctx.py

@ -281,12 +281,12 @@ class RequestContext(object):
url_rule, self.request.view_args = \
self.url_adapter.match(return_rule=True)
self.request.url_rule = url_rule
except HTTPException, e:
except HTTPException as e:
self.request.routing_exception = e
def push(self):
"""Binds the request context to the current context."""
# If an exception ocurrs in debug mode or if context preservation is
# 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
@ -334,6 +334,9 @@ class RequestContext(object):
if exc is None:
exc = sys.exc_info()[1]
self.app.do_teardown_request(exc)
request_close = getattr(self.request, 'close', None)
if request_close is not None:
request_close()
clear_request = True
rv = _request_ctx_stack.pop()
@ -349,6 +352,13 @@ class RequestContext(object):
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
else:
self.pop(exc)
def __enter__(self):
self.push()
return self
@ -359,11 +369,7 @@ class RequestContext(object):
# 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.
if self.request.environ.get('flask._preserve_context') or \
(tb is not None and self.app.preserve_context_on_exception):
self.preserved = True
else:
self.pop(exc_value)
self.auto_pop(exc_value)
def __repr__(self):
return '<%s \'%s\' [%s] of %s>' % (

6
flask/debughelpers.py

@ -8,6 +8,7 @@
:copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from ._compat import implements_to_string
class UnexpectedUnicodeError(AssertionError, UnicodeError):
@ -16,6 +17,7 @@ class UnexpectedUnicodeError(AssertionError, UnicodeError):
"""
@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.
@ -33,7 +35,7 @@ class DebugFilesKeyError(KeyError, AssertionError):
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).encode('utf-8')
self.msg = ''.join(buf)
def __str__(self):
return self.msg
@ -76,7 +78,7 @@ def attach_enctype_error_multidict(request):
def __getitem__(self, key):
try:
return oldcls.__getitem__(self, key)
except KeyError, e:
except KeyError as e:
if key not in request.form:
raise
raise DebugFilesKeyError(request, key)

3
flask/exthook.py

@ -21,6 +21,7 @@
"""
import sys
import os
from ._compat import reraise
class ExtensionImporter(object):
@ -77,7 +78,7 @@ class ExtensionImporter(object):
# 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):
raise exc_type, exc_value, tb.tb_next
reraise(exc_type, exc_value, tb.tb_next)
continue
module = sys.modules[fullname] = sys.modules[realname]
if '.' not in modname:

19
flask/helpers.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import sys
import pkgutil
@ -38,6 +36,7 @@ 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
@ -128,7 +127,7 @@ def stream_with_context(generator_or_function):
# pushed. This item is discarded. Then when the iteration continues the
# real generator is executed.
wrapped_g = generator()
wrapped_g.next()
next(wrapped_g)
return wrapped_g
@ -301,7 +300,7 @@ def url_for(endpoint, **values):
try:
rv = url_adapter.build(endpoint, values, method=method,
force_external=external)
except BuildError, error:
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
@ -331,7 +330,7 @@ def get_template_attribute(template_name, attribute):
.. versionadded:: 0.2
:param template_name: the name of the template
:param attribute: the name of the variable of macro to acccess
:param attribute: the name of the variable of macro to access
"""
return getattr(current_app.jinja_env.get_template(template_name).module,
attribute)
@ -399,7 +398,7 @@ def get_flashed_messages(with_categories=False, category_filter=[]):
_request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \
if '_flashes' in session else []
if category_filter:
flashes = filter(lambda f: f[0] in category_filter, flashes)
flashes = list(filter(lambda f: f[0] in category_filter, flashes))
if not with_categories:
return [x[1] for x in flashes]
return flashes
@ -466,7 +465,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
:data:`~flask.current_app`.
"""
mtime = None
if isinstance(filename_or_fp, basestring):
if isinstance(filename_or_fp, string_types):
filename = filename_or_fp
file = None
else:
@ -477,7 +476,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
# 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, basestring):
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.'),
@ -517,6 +516,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
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,
@ -539,7 +539,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
os.path.getmtime(filename),
os.path.getsize(filename),
adler32(
filename.encode('utf-8') if isinstance(filename, unicode)
filename.encode('utf-8') if isinstance(filename, text_type)
else filename
) & 0xffffffff
))
@ -839,6 +839,7 @@ class _PackageBoundObject(object):
: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')

40
flask/json.py

@ -8,14 +8,16 @@
: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
# Use the same json implementation as itsdangerous on which we
# depend anyways. This name changed at one point so support both.
# depend anyways.
try:
from itsdangerous import simplejson as _json
except ImportError:
@ -32,6 +34,20 @@ __all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump',
'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
@ -62,7 +78,7 @@ class JSONEncoder(_json.JSONEncoder):
if isinstance(o, uuid.UUID):
return str(o)
if hasattr(o, '__html__'):
return unicode(o.__html__())
return text_type(o.__html__())
return _json.JSONEncoder.default(self, o)
@ -99,13 +115,20 @@ def dumps(obj, **kwargs):
and can be overriden by the simplejson ``ensure_ascii`` parameter.
"""
_dump_arg_defaults(kwargs)
return _json.dumps(obj, **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)
return _json.dump(obj, fp, **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):
@ -114,6 +137,8 @@ def loads(s, **kwargs):
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)
@ -121,6 +146,8 @@ 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)
@ -147,7 +174,7 @@ def jsonify(*args, **kwargs):
to this function are the same as to the :class:`dict` constructor.
Example usage::
from flask import jsonify
@app.route('/_get_current_user')
@ -164,8 +191,7 @@ def jsonify(*args, **kwargs):
"id": 42
}
This requires Python 2.6 or an installed version of simplejson. For
security reasons only objects are supported toplevel. For more
For security reasons only objects are supported toplevel. For more
information about this, have a look at :ref:`json-security`.
.. versionadded:: 0.2

9
flask/sessions.py

@ -15,6 +15,7 @@ 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
@ -62,16 +63,16 @@ class TaggedJSONSerializer(object):
elif isinstance(value, uuid.UUID):
return {' u': value.hex}
elif callable(getattr(value, '__html__', None)):
return {' m': unicode(value.__html__())}
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 value.iteritems())
return dict((k, _tag(v)) for k, v in iteritems(value))
elif isinstance(value, str):
try:
return unicode(value)
return text_type(value)
except UnicodeError:
raise UnexpectedUnicodeError(u'A byte string with '
u'non-ASCII data was passed to the session system '
@ -84,7 +85,7 @@ class TaggedJSONSerializer(object):
def object_hook(obj):
if len(obj) != 1:
return obj
the_key, the_value = obj.iteritems().next()
the_key, the_value = next(iteritems(obj))
if the_key == ' t':
return tuple(the_value)
elif the_key == ' u':

5
flask/templating.py

@ -15,6 +15,7 @@ from jinja2 import BaseLoader, Environment as BaseEnvironment, \
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():
@ -79,7 +80,7 @@ class DispatchingJinjaLoader(BaseLoader):
except (ValueError, KeyError):
pass
for blueprint in self.app.blueprints.itervalues():
for blueprint in itervalues(self.app.blueprints):
if blueprint_is_module(blueprint):
continue
loader = blueprint.jinja_loader
@ -92,7 +93,7 @@ class DispatchingJinjaLoader(BaseLoader):
if loader is not None:
result.update(loader.list_templates())
for name, blueprint in self.app.blueprints.iteritems():
for name, blueprint in iteritems(self.app.blueprints):
loader = blueprint.jinja_loader
if loader is not None:
for template in loader.list_templates():

10
flask/testing.py

@ -10,12 +10,14 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
from contextlib import contextmanager
from werkzeug.test import Client, EnvironBuilder
from flask import _request_ctx_stack
from urlparse import urlparse
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):
@ -23,7 +25,7 @@ def make_test_environ_builder(app, path='/', base_url=None, *args, **kwargs):
http_host = app.config.get('SERVER_NAME')
app_root = app.config.get('APPLICATION_ROOT')
if base_url is None:
url = urlparse(path)
url = url_parse(path)
base_url = 'http://%s/' % (url.netloc or http_host or 'localhost')
if app_root:
base_url += app_root.lstrip('/')

38
flask/testsuite/__init__.py

@ -10,17 +10,17 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
from __future__ import print_function
import os
import sys
import flask
import warnings
import unittest
from StringIO import StringIO
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):
@ -101,9 +101,9 @@ def emits_module_deprecation_warning(f):
def new_f(self, *args, **kwargs):
with catch_warnings() as log:
f(self, *args, **kwargs)
self.assert_(log, 'expected deprecation warning')
self.assert_true(log, 'expected deprecation warning')
for entry in log:
self.assert_('Modules are deprecated' in str(entry['message']))
self.assert_in('Modules are deprecated', str(entry['message']))
return update_wrapper(new_f, f)
@ -116,7 +116,10 @@ class FlaskTestCase(unittest.TestCase):
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
self.assert_equal(flask._request_ctx_stack.top, None)
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
@ -142,6 +145,25 @@ class FlaskTestCase(unittest.TestCase):
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):
@ -158,7 +180,7 @@ class _ExceptionCatcher(object):
self.test_case.fail('Expected exception of type %r' %
exception_name)
elif not issubclass(exc_type, self.exc_type):
raise exc_type, exc_value, tb
reraise(exc_type, exc_value, tb)
return True
@ -220,5 +242,5 @@ def main():
"""Runs the testsuite as command line application."""
try:
unittest.main(testLoader=BetterLoader(), defaultTest='suite')
except Exception, e:
print 'Error: %s' % e
except Exception as e:
print('Error: %s' % e)

5
flask/testsuite/appctx.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import flask
import unittest
from flask.testsuite import FlaskTestCase
@ -89,8 +87,9 @@ class AppContextTestCase(FlaskTestCase):
with flask._app_ctx_stack.top:
with flask._request_ctx_stack.top:
pass
self.assert_(flask._request_ctx_stack.request.environ
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'])

250
flask/testsuite/basic.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import re
import uuid
import flask
@ -19,6 +17,7 @@ import unittest
from datetime import datetime
from threading import Thread
from flask.testsuite import FlaskTestCase, emits_module_deprecation_warning
from flask._compat import text_type
from werkzeug.exceptions import BadRequest, NotFound
from werkzeug.http import parse_date
from werkzeug.routing import BuildError
@ -33,7 +32,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return 'Hello World'
rv = app.test_client().open('/', method='OPTIONS')
self.assert_equal(sorted(rv.allow), ['GET', 'HEAD', 'OPTIONS', 'POST'])
self.assert_equal(rv.data, '')
self.assert_equal(rv.data, b'')
def test_options_on_multiple_rules(self):
app = flask.Flask(__name__)
@ -73,15 +72,15 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return flask.request.method
c = app.test_client()
self.assert_equal(c.get('/').data, 'GET')
self.assert_equal(c.get('/').data, b'GET')
rv = c.post('/')
self.assert_equal(rv.status_code, 405)
self.assert_equal(sorted(rv.allow), ['GET', 'HEAD', 'OPTIONS'])
rv = c.head('/')
self.assert_equal(rv.status_code, 200)
self.assert_(not rv.data) # head truncates
self.assert_equal(c.post('/more').data, 'POST')
self.assert_equal(c.get('/more').data, 'GET')
self.assert_false(rv.data) # head truncates
self.assert_equal(c.post('/more').data, b'POST')
self.assert_equal(c.get('/more').data, b'GET')
rv = c.delete('/more')
self.assert_equal(rv.status_code, 405)
self.assert_equal(sorted(rv.allow), ['GET', 'HEAD', 'OPTIONS', 'POST'])
@ -97,15 +96,15 @@ class BasicFunctionalityTestCase(FlaskTestCase):
app.add_url_rule('/more', 'more', more, methods=['GET', 'POST'])
c = app.test_client()
self.assert_equal(c.get('/').data, 'GET')
self.assert_equal(c.get('/').data, b'GET')
rv = c.post('/')
self.assert_equal(rv.status_code, 405)
self.assert_equal(sorted(rv.allow), ['GET', 'HEAD', 'OPTIONS'])
rv = c.head('/')
self.assert_equal(rv.status_code, 200)
self.assert_(not rv.data) # head truncates
self.assert_equal(c.post('/more').data, 'POST')
self.assert_equal(c.get('/more').data, 'GET')
self.assert_false(rv.data) # head truncates
self.assert_equal(c.post('/more').data, b'POST')
self.assert_equal(c.get('/more').data, b'GET')
rv = c.delete('/more')
self.assert_equal(rv.status_code, 405)
self.assert_equal(sorted(rv.allow), ['GET', 'HEAD', 'OPTIONS', 'POST'])
@ -125,8 +124,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
app.view_functions['index'] = index
c = app.test_client()
self.assert_equal(c.get('/foo/').data, 'index')
self.assert_equal(c.get('/foo/bar').data, 'bar')
self.assert_equal(c.get('/foo/').data, b'index')
self.assert_equal(c.get('/foo/bar').data, b'bar')
def test_endpoint_decorator(self):
from werkzeug.routing import Submount, Rule
@ -145,8 +144,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return 'index'
c = app.test_client()
self.assert_equal(c.get('/foo/').data, 'index')
self.assert_equal(c.get('/foo/bar').data, 'bar')
self.assert_equal(c.get('/foo/').data, b'index')
self.assert_equal(c.get('/foo/bar').data, b'bar')
def test_session(self):
app = flask.Flask(__name__)
@ -160,8 +159,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return flask.session['value']
c = app.test_client()
self.assert_equal(c.post('/set', data={'value': '42'}).data, 'value set')
self.assert_equal(c.get('/get').data, '42')
self.assert_equal(c.post('/set', data={'value': '42'}).data, b'value set')
self.assert_equal(c.get('/get').data, b'42')
def test_session_using_server_name(self):
app = flask.Flask(__name__)
@ -174,8 +173,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
flask.session['testing'] = 42
return 'Hello World'
rv = app.test_client().get('/', 'http://example.com/')
self.assert_('domain=.example.com' in rv.headers['set-cookie'].lower())
self.assert_('httponly' in rv.headers['set-cookie'].lower())
self.assert_in('domain=.example.com', rv.headers['set-cookie'].lower())
self.assert_in('httponly', rv.headers['set-cookie'].lower())
def test_session_using_server_name_and_port(self):
app = flask.Flask(__name__)
@ -188,8 +187,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
flask.session['testing'] = 42
return 'Hello World'
rv = app.test_client().get('/', 'http://example.com:8080/')
self.assert_('domain=.example.com' in rv.headers['set-cookie'].lower())
self.assert_('httponly' in rv.headers['set-cookie'].lower())
self.assert_in('domain=.example.com', rv.headers['set-cookie'].lower())
self.assert_in('httponly', rv.headers['set-cookie'].lower())
def test_session_using_server_name_port_and_path(self):
app = flask.Flask(__name__)
@ -203,9 +202,9 @@ class BasicFunctionalityTestCase(FlaskTestCase):
flask.session['testing'] = 42
return 'Hello World'
rv = app.test_client().get('/', 'http://example.com:8080/foo')
self.assert_('domain=example.com' in rv.headers['set-cookie'].lower())
self.assert_('path=/foo' in rv.headers['set-cookie'].lower())
self.assert_('httponly' in rv.headers['set-cookie'].lower())
self.assert_in('domain=example.com', rv.headers['set-cookie'].lower())
self.assert_in('path=/foo', rv.headers['set-cookie'].lower())
self.assert_in('httponly', rv.headers['set-cookie'].lower())
def test_session_using_application_root(self):
class PrefixPathMiddleware(object):
@ -227,7 +226,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
flask.session['testing'] = 42
return 'Hello World'
rv = app.test_client().get('/', 'http://example.com:8080/')
self.assert_('path=/bar' in rv.headers['set-cookie'].lower())
self.assert_in('path=/bar', rv.headers['set-cookie'].lower())
def test_session_using_session_settings(self):
app = flask.Flask(__name__)
@ -246,22 +245,22 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return 'Hello World'
rv = app.test_client().get('/', 'http://www.example.com:8080/test/')
cookie = rv.headers['set-cookie'].lower()
self.assert_('domain=.example.com' in cookie)
self.assert_('path=/;' in cookie)
self.assert_('secure' in cookie)
self.assert_('httponly' not in cookie)
self.assert_in('domain=.example.com', cookie)
self.assert_in('path=/;', cookie)
self.assert_in('secure', cookie)
self.assert_not_in('httponly', cookie)
def test_missing_session(self):
app = flask.Flask(__name__)
def expect_exception(f, *args, **kwargs):
try:
f(*args, **kwargs)
except RuntimeError, e:
self.assert_(e.args and 'session is unavailable' in e.args[0])
except RuntimeError as e:
self.assert_true(e.args and 'session is unavailable' in e.args[0])
else:
self.assert_(False, 'expected exception')
self.assert_true(False, 'expected exception')
with app.test_request_context():
self.assert_(flask.session.get('missing_key') is None)
self.assert_true(flask.session.get('missing_key') is None)
expect_exception(flask.session.__setitem__, 'foo', 42)
expect_exception(flask.session.pop, 'foo')
@ -277,11 +276,11 @@ class BasicFunctionalityTestCase(FlaskTestCase):
@app.route('/test')
def test():
return unicode(flask.session.permanent)
return text_type(flask.session.permanent)
client = app.test_client()
rv = client.get('/')
self.assert_('set-cookie' in rv.headers)
self.assert_in('set-cookie', rv.headers)
match = re.search(r'\bexpires=([^;]+)', rv.headers['set-cookie'])
expires = parse_date(match.group())
expected = datetime.utcnow() + app.permanent_session_lifetime
@ -290,13 +289,13 @@ class BasicFunctionalityTestCase(FlaskTestCase):
self.assert_equal(expires.day, expected.day)
rv = client.get('/test')
self.assert_equal(rv.data, 'True')
self.assert_equal(rv.data, b'True')
permanent = False
rv = app.test_client().get('/')
self.assert_('set-cookie' in rv.headers)
self.assert_in('set-cookie', rv.headers)
match = re.search(r'\bexpires=([^;]+)', rv.headers['set-cookie'])
self.assert_(match is None)
self.assert_true(match is None)
def test_session_stored_last(self):
app = flask.Flask(__name__)
@ -312,8 +311,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return repr(flask.session.get('foo'))
c = app.test_client()
self.assert_equal(c.get('/').data, 'None')
self.assert_equal(c.get('/').data, '42')
self.assert_equal(c.get('/').data, b'None')
self.assert_equal(c.get('/').data, b'42')
def test_session_special_types(self):
app = flask.Flask(__name__)
@ -348,11 +347,11 @@ class BasicFunctionalityTestCase(FlaskTestCase):
app.secret_key = 'testkey'
with app.test_request_context():
self.assert_(not flask.session.modified)
self.assert_false(flask.session.modified)
flask.flash('Zap')
flask.session.modified = False
flask.flash('Zip')
self.assert_(flask.session.modified)
self.assert_true(flask.session.modified)
self.assert_equal(list(flask.get_flashed_messages()), ['Zap', 'Zip'])
def test_extended_flashing(self):
@ -444,18 +443,18 @@ class BasicFunctionalityTestCase(FlaskTestCase):
evts.append('before')
@app.after_request
def after_request(response):
response.data += '|after'
response.data += b'|after'
evts.append('after')
return response
@app.route('/')
def index():
self.assert_('before' in evts)
self.assert_('after' not in evts)
self.assert_in('before', evts)
self.assert_not_in('after', evts)
return 'request'
self.assert_('after' not in evts)
self.assert_not_in('after', evts)
rv = app.test_client().get('/').data
self.assert_('after' in evts)
self.assert_equal(rv, 'request|after')
self.assert_in('after', evts)
self.assert_equal(rv, b'request|after')
def test_after_request_processing(self):
app = flask.Flask(__name__)
@ -484,7 +483,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return "Response"
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 200)
self.assert_('Response' in rv.data)
self.assert_in(b'Response', rv.data)
self.assert_equal(len(called), 1)
def test_teardown_request_handler_debug_mode(self):
@ -500,7 +499,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return "Response"
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 200)
self.assert_('Response' in rv.data)
self.assert_in(b'Response', rv.data)
self.assert_equal(len(called), 1)
def test_teardown_request_handler_error(self):
@ -514,7 +513,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
# test that all teardown_requests get passed the same original
# exception.
try:
raise TypeError
raise TypeError()
except:
pass
@app.teardown_request
@ -525,15 +524,15 @@ class BasicFunctionalityTestCase(FlaskTestCase):
# test that all teardown_requests get passed the same original
# exception.
try:
raise TypeError
raise TypeError()
except:
pass
@app.route('/')
def fails():
1/0
1 // 0
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500)
self.assert_('Internal Server Error' in rv.data)
self.assert_in(b'Internal Server Error', rv.data)
self.assert_equal(len(called), 2)
def test_before_after_request_order(self):
@ -563,7 +562,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
def index():
return '42'
rv = app.test_client().get('/')
self.assert_equal(rv.data, '42')
self.assert_equal(rv.data, b'42')
self.assert_equal(called, [1, 2, 3, 4, 5, 6])
def test_error_handling(self):
@ -583,10 +582,10 @@ class BasicFunctionalityTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.status_code, 404)
self.assert_equal(rv.data, 'not found')
self.assert_equal(rv.data, b'not found')
rv = c.get('/error')
self.assert_equal(rv.status_code, 500)
self.assert_equal('internal server error', rv.data)
self.assert_equal(b'internal server error', rv.data)
def test_before_request_and_routing_errors(self):
app = flask.Flask(__name__)
@ -598,7 +597,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return flask.g.something, 404
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 404)
self.assert_equal(rv.data, 'value')
self.assert_equal(rv.data, b'value')
def test_user_error_handling(self):
class MyException(Exception):
@ -607,14 +606,14 @@ class BasicFunctionalityTestCase(FlaskTestCase):
app = flask.Flask(__name__)
@app.errorhandler(MyException)
def handle_my_exception(e):
self.assert_(isinstance(e, MyException))
self.assert_true(isinstance(e, MyException))
return '42'
@app.route('/')
def index():
raise MyException()
c = app.test_client()
self.assert_equal(c.get('/').data, '42')
self.assert_equal(c.get('/').data, b'42')
def test_trapping_of_bad_request_key_errors(self):
app = flask.Flask(__name__)
@ -629,8 +628,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
c = app.test_client()
try:
c.get('/fail')
except KeyError, e:
self.assert_(isinstance(e, BadRequest))
except KeyError as e:
self.assert_true(isinstance(e, BadRequest))
else:
self.fail('Expected exception')
@ -645,7 +644,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
c = app.test_client()
try:
c.get('/fail')
except NotFound, e:
except NotFound as e:
pass
else:
self.fail('Expected exception')
@ -664,9 +663,9 @@ class BasicFunctionalityTestCase(FlaskTestCase):
with app.test_client() as c:
try:
c.post('/fail', data={'foo': 'index.txt'})
except DebugFilesKeyError, e:
self.assert_('no file contents were transmitted' in str(e))
self.assert_('This was submitted: "index.txt"' in str(e))
except DebugFilesKeyError as e:
self.assert_in('no file contents were transmitted', str(e))
self.assert_in('This was submitted: "index.txt"', str(e))
else:
self.fail('Expected exception')
@ -688,7 +687,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
self.assert_equal(c.get('/unicode').data, u'Hällo Wörld'.encode('utf-8'))
self.assert_equal(c.get('/string').data, u'Hällo Wörld'.encode('utf-8'))
rv = c.get('/args')
self.assert_equal(rv.data, 'Meh')
self.assert_equal(rv.data, b'Meh')
self.assert_equal(rv.headers['X-Foo'], 'Testing')
self.assert_equal(rv.status_code, 400)
self.assert_equal(rv.mimetype, 'text/plain')
@ -698,17 +697,17 @@ class BasicFunctionalityTestCase(FlaskTestCase):
with app.test_request_context():
rv = flask.make_response()
self.assert_equal(rv.status_code, 200)
self.assert_equal(rv.data, '')
self.assert_equal(rv.data, b'')
self.assert_equal(rv.mimetype, 'text/html')
rv = flask.make_response('Awesome')
self.assert_equal(rv.status_code, 200)
self.assert_equal(rv.data, 'Awesome')
self.assert_equal(rv.data, b'Awesome')
self.assert_equal(rv.mimetype, 'text/html')
rv = flask.make_response('W00t', 404)
self.assert_equal(rv.status_code, 404)
self.assert_equal(rv.data, 'W00t')
self.assert_equal(rv.data, b'W00t')
self.assert_equal(rv.mimetype, 'text/html')
def test_make_response_with_response_instance(self):
@ -717,14 +716,13 @@ class BasicFunctionalityTestCase(FlaskTestCase):
rv = flask.make_response(
flask.jsonify({'msg': 'W00t'}), 400)
self.assertEqual(rv.status_code, 400)
self.assertEqual(rv.data,
'{\n "msg": "W00t"\n}')
self.assertEqual(rv.data, b'{\n "msg": "W00t"\n}')
self.assertEqual(rv.mimetype, 'application/json')
rv = flask.make_response(
flask.Response(''), 400)
self.assertEqual(rv.status_code, 400)
self.assertEqual(rv.data, '')
self.assertEqual(rv.data, b'')
self.assertEqual(rv.mimetype, 'text/html')
rv = flask.make_response(
@ -755,8 +753,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
try:
with app.test_request_context():
flask.url_for('spam')
except BuildError, error:
pass
except BuildError as err:
error = err
try:
raise RuntimeError('Test case where BuildError is not current.')
except RuntimeError:
@ -784,16 +782,18 @@ class BasicFunctionalityTestCase(FlaskTestCase):
def index(args):
return '|'.join(args)
c = app.test_client()
self.assert_equal(c.get('/1,2,3').data, '1|2|3')
self.assert_equal(c.get('/1,2,3').data, b'1|2|3')
def test_static_files(self):
app = flask.Flask(__name__)
app.testing = True
rv = app.test_client().get('/static/index.html')
self.assert_equal(rv.status_code, 200)
self.assert_equal(rv.data.strip(), '<h1>Hello World!</h1>')
self.assert_equal(rv.data.strip(), b'<h1>Hello World!</h1>')
with app.test_request_context():
self.assert_equal(flask.url_for('static', filename='index.html'),
'/static/index.html')
rv.close()
def test_none_response(self):
app = flask.Flask(__name__)
@ -802,11 +802,11 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return None
try:
app.test_client().get('/')
except ValueError, e:
except ValueError as e:
self.assert_equal(str(e), 'View function did not return a response')
pass
else:
self.assert_("Expected ValueError")
self.assert_true("Expected ValueError")
def test_request_locals(self):
self.assert_equal(repr(flask.g), '<LocalProxy unbound>')
@ -826,24 +826,24 @@ class BasicFunctionalityTestCase(FlaskTestCase):
return 'Foo SubDomain'
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'Foo')
self.assert_equal(rv.data, b'Foo')
rv = app.test_client().get('/', 'http://localhost.localdomain:5000')
self.assert_equal(rv.data, 'Foo')
self.assert_equal(rv.data, b'Foo')
rv = app.test_client().get('/', 'https://localhost.localdomain:5000')
self.assert_equal(rv.data, 'Foo')
self.assert_equal(rv.data, b'Foo')
app.config.update(SERVER_NAME='localhost.localdomain')
rv = app.test_client().get('/', 'https://localhost.localdomain')
self.assert_equal(rv.data, 'Foo')
self.assert_equal(rv.data, b'Foo')
try:
app.config.update(SERVER_NAME='localhost.localdomain:443')
rv = app.test_client().get('/', 'https://localhost.localdomain')
# Werkzeug 0.8
self.assert_equal(rv.status_code, 404)
except ValueError, e:
except ValueError as e:
# Werkzeug 0.7
self.assert_equal(str(e), "the server name provided " +
"('localhost.localdomain:443') does not match the " + \
@ -854,21 +854,21 @@ class BasicFunctionalityTestCase(FlaskTestCase):
rv = app.test_client().get('/', 'http://foo.localhost')
# Werkzeug 0.8
self.assert_equal(rv.status_code, 404)
except ValueError, e:
except ValueError as e:
# Werkzeug 0.7
self.assert_equal(str(e), "the server name provided " + \
"('localhost.localdomain') does not match the " + \
"server name from the WSGI environment ('foo.localhost')")
rv = app.test_client().get('/', 'http://foo.localhost.localdomain')
self.assert_equal(rv.data, 'Foo SubDomain')
self.assert_equal(rv.data, b'Foo SubDomain')
def test_exception_propagation(self):
def apprunner(configkey):
app = flask.Flask(__name__)
@app.route('/')
def index():
1/0
1 // 0
c = app.test_client()
if config_key is not None:
app.config[config_key] = True
@ -896,18 +896,18 @@ class BasicFunctionalityTestCase(FlaskTestCase):
@app.before_request
def always_first():
flask.request.form['myfile']
self.assert_(False)
self.assert_true(False)
@app.route('/accept', methods=['POST'])
def accept_file():
flask.request.form['myfile']
self.assert_(False)
self.assert_true(False)
@app.errorhandler(413)
def catcher(error):
return '42'
c = app.test_client()
rv = c.post('/accept', data={'myfile': 'foo' * 100})
self.assert_equal(rv.data, '42')
self.assert_equal(rv.data, b'42')
def test_url_processors(self):
app = flask.Flask(__name__)
@ -936,13 +936,13 @@ class BasicFunctionalityTestCase(FlaskTestCase):
c = app.test_client()
self.assert_equal(c.get('/de/').data, '/de/about')
self.assert_equal(c.get('/de/about').data, '/foo')
self.assert_equal(c.get('/foo').data, '/en/about')
self.assert_equal(c.get('/de/').data, b'/de/about')
self.assert_equal(c.get('/de/about').data, b'/foo')
self.assert_equal(c.get('/foo').data, b'/en/about')
def test_inject_blueprint_url_defaults(self):
app = flask.Flask(__name__)
bp = flask.Blueprint('foo.bar.baz', __name__,
bp = flask.Blueprint('foo.bar.baz', __name__,
template_folder='template')
@bp.url_defaults
@ -969,14 +969,14 @@ class BasicFunctionalityTestCase(FlaskTestCase):
@app.route('/')
def index():
return 'Awesome'
self.assert_(not app.got_first_request)
self.assert_equal(app.test_client().get('/').data, 'Awesome')
self.assert_false(app.got_first_request)
self.assert_equal(app.test_client().get('/').data, b'Awesome')
try:
@app.route('/foo')
def broken():
return 'Meh'
except AssertionError, e:
self.assert_('A setup function was called' in str(e))
except AssertionError as e:
self.assert_in('A setup function was called', str(e))
else:
self.fail('Expected exception')
@ -984,8 +984,8 @@ class BasicFunctionalityTestCase(FlaskTestCase):
@app.route('/foo')
def working():
return 'Meh'
self.assert_equal(app.test_client().get('/foo').data, 'Meh')
self.assert_(app.got_first_request)
self.assert_equal(app.test_client().get('/foo').data, b'Meh')
self.assert_true(app.got_first_request)
def test_before_first_request_functions(self):
got = []
@ -998,7 +998,7 @@ class BasicFunctionalityTestCase(FlaskTestCase):
self.assert_equal(got, [42])
c.get('/')
self.assert_equal(got, [42])
self.assert_(app.got_first_request)
self.assert_true(app.got_first_request)
def test_routing_redirect_debugging(self):
app = flask.Flask(__name__)
@ -1009,20 +1009,20 @@ class BasicFunctionalityTestCase(FlaskTestCase):
with app.test_client() as c:
try:
c.post('/foo', data={})
except AssertionError, e:
self.assert_('http://localhost/foo/' in str(e))
self.assert_('Make sure to directly send your POST-request '
'to this URL' in str(e))
except AssertionError as e:
self.assert_in('http://localhost/foo/', str(e))
self.assert_in('Make sure to directly send your POST-request '
'to this URL', str(e))
else:
self.fail('Expected exception')
rv = c.get('/foo', data={}, follow_redirects=True)
self.assert_equal(rv.data, 'success')
self.assert_equal(rv.data, b'success')
app.debug = False
with app.test_client() as c:
rv = c.post('/foo', data={}, follow_redirects=True)
self.assert_equal(rv.data, 'success')
self.assert_equal(rv.data, b'success')
def test_route_decorator_custom_endpoint(self):
app = flask.Flask(__name__)
@ -1046,9 +1046,9 @@ class BasicFunctionalityTestCase(FlaskTestCase):
assert flask.url_for('123') == '/bar/123'
c = app.test_client()
self.assertEqual(c.get('/foo/').data, 'foo')
self.assertEqual(c.get('/bar/').data, 'bar')
self.assertEqual(c.get('/bar/123').data, '123')
self.assertEqual(c.get('/foo/').data, b'foo')
self.assertEqual(c.get('/bar/').data, b'bar')
self.assertEqual(c.get('/bar/123').data, b'123')
def test_preserve_only_once(self):
app = flask.Flask(__name__)
@ -1056,19 +1056,19 @@ class BasicFunctionalityTestCase(FlaskTestCase):
@app.route('/fail')
def fail_func():
1/0
1 // 0
c = app.test_client()
for x in xrange(3):
for x in range(3):
with self.assert_raises(ZeroDivisionError):
c.get('/fail')
self.assert_(flask._request_ctx_stack.top is not None)
self.assert_(flask._app_ctx_stack.top is not None)
self.assert_true(flask._request_ctx_stack.top is not None)
self.assert_true(flask._app_ctx_stack.top is not None)
# implicit appctx disappears too
flask._request_ctx_stack.top.pop()
self.assert_(flask._request_ctx_stack.top is None)
self.assert_(flask._app_ctx_stack.top is None)
self.assert_true(flask._request_ctx_stack.top is None)
self.assert_true(flask._app_ctx_stack.top is None)
class SubdomainTestCase(FlaskTestCase):
@ -1085,10 +1085,10 @@ class SubdomainTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/', 'http://localhost/')
self.assert_equal(rv.data, 'normal index')
self.assert_equal(rv.data, b'normal index')
rv = c.get('/', 'http://test.localhost/')
self.assert_equal(rv.data, 'test index')
self.assert_equal(rv.data, b'test index')
@emits_module_deprecation_warning
def test_module_static_path_subdomain(self):
@ -1098,7 +1098,9 @@ class SubdomainTestCase(FlaskTestCase):
app.register_module(mod)
c = app.test_client()
rv = c.get('/static/hello.txt', 'http://foo.example.com/')
self.assert_equal(rv.data.strip(), 'Hello Subdomain')
rv.direct_passthrough = False
self.assert_equal(rv.data.strip(), b'Hello Subdomain')
rv.close()
def test_subdomain_matching(self):
app = flask.Flask(__name__)
@ -1109,7 +1111,7 @@ class SubdomainTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/', 'http://mitsuhiko.localhost/')
self.assert_equal(rv.data, 'index for mitsuhiko')
self.assert_equal(rv.data, b'index for mitsuhiko')
def test_subdomain_matching_with_ports(self):
app = flask.Flask(__name__)
@ -1120,7 +1122,7 @@ class SubdomainTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/', 'http://mitsuhiko.localhost:3000/')
self.assert_equal(rv.data, 'index for mitsuhiko')
self.assert_equal(rv.data, b'index for mitsuhiko')
@emits_module_deprecation_warning
def test_module_subdomain_support(self):
@ -1140,9 +1142,9 @@ class SubdomainTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/test', 'http://testing.localhost/')
self.assert_equal(rv.data, 'Test')
self.assert_equal(rv.data, b'Test')
rv = c.get('/outside', 'http://xtesting.localhost/')
self.assert_equal(rv.data, 'Outside')
self.assert_equal(rv.data, b'Outside')
def suite():

161
flask/testsuite/blueprints.py

@ -9,12 +9,11 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
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
@ -47,10 +46,10 @@ class ModuleTestCase(FlaskTestCase):
return 'the index'
app.register_module(admin)
c = app.test_client()
self.assert_equal(c.get('/').data, 'the index')
self.assert_equal(c.get('/admin/').data, 'admin index')
self.assert_equal(c.get('/admin/login').data, 'admin login')
self.assert_equal(c.get('/admin/logout').data, 'admin logout')
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):
@ -61,7 +60,7 @@ class ModuleTestCase(FlaskTestCase):
mod.add_url_rule('/', view_func=index)
app.register_module(mod)
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'Awesome')
self.assert_equal(rv.data, b'Awesome')
with app.test_request_context():
self.assert_equal(flask.url_for('frontend.index'), '/')
@ -93,11 +92,11 @@ class ModuleTestCase(FlaskTestCase):
app.register_module(admin)
c = app.test_client()
self.assert_equal(c.get('/').data, 'the index')
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, 'the admin')
self.assert_equal(c.get('/admin/').data, b'the admin')
self.assert_equal(catched, ['before-app', 'before-admin',
'after-admin', 'after-app'])
@ -106,7 +105,7 @@ class ModuleTestCase(FlaskTestCase):
app = flask.Flask(__name__)
admin = flask.Module(__name__, 'admin', url_prefix='/admin')
@app.context_processor
def inject_all_regualr():
def inject_all_regular():
return {'a': 1}
@admin.context_processor
def inject_admin():
@ -122,8 +121,8 @@ class ModuleTestCase(FlaskTestCase):
return flask.render_template_string('{{ a }}{{ b }}{{ c }}')
app.register_module(admin)
c = app.test_client()
self.assert_equal(c.get('/').data, '13')
self.assert_equal(c.get('/admin/').data, '123')
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):
@ -133,7 +132,7 @@ class ModuleTestCase(FlaskTestCase):
def index():
return '42'
app.register_module(admin, url_prefix='/admin')
self.assert_equal(app.test_client().get('/admin/').data, '42')
self.assert_equal(app.test_client().get('/admin/').data, b'42')
@emits_module_deprecation_warning
def test_error_handling(self):
@ -155,10 +154,10 @@ class ModuleTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.status_code, 404)
self.assert_equal(rv.data, 'not found')
self.assert_equal(rv.data, b'not found')
rv = c.get('/error')
self.assert_equal(rv.status_code, 500)
self.assert_equal('internal server error', rv.data)
self.assert_equal(b'internal server error', rv.data)
def test_templates_and_static(self):
app = moduleapp
@ -166,15 +165,17 @@ class ModuleTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, 'Hello from the Frontend')
self.assert_equal(rv.data, b'Hello from the Frontend')
rv = c.get('/admin/')
self.assert_equal(rv.data, 'Hello from the Admin')
self.assert_equal(rv.data, b'Hello from the Admin')
rv = c.get('/admin/index2')
self.assert_equal(rv.data, 'Hello from the Admin')
self.assert_equal(rv.data, b'Hello from the Admin')
rv = c.get('/admin/static/test.txt')
self.assert_equal(rv.data.strip(), 'Admin File')
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(), '/* nested file */')
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'),
@ -183,10 +184,10 @@ class ModuleTestCase(FlaskTestCase):
with app.test_request_context():
try:
flask.render_template('missing.html')
except TemplateNotFound, e:
except TemplateNotFound as e:
self.assert_equal(e.name, 'missing.html')
else:
self.assert_(0, 'expected exception')
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')
@ -202,13 +203,13 @@ class ModuleTestCase(FlaskTestCase):
except NotFound:
pass
else:
self.assert_(0, 'expected exception')
self.assert_true(0, 'expected exception')
try:
f('../__init__.py')
except NotFound:
pass
else:
self.assert_(0, 'expected exception')
self.assert_true(0, 'expected exception')
# testcase for a security issue that may exist on windows systems
import os
@ -221,7 +222,7 @@ class ModuleTestCase(FlaskTestCase):
except NotFound:
pass
else:
self.assert_(0, 'expected exception')
self.assert_true(0, 'expected exception')
finally:
os.path = old_path
@ -249,8 +250,8 @@ class ModuleTestCase(FlaskTestCase):
app.register_module(module)
c = app.test_client()
self.assert_equal(c.get('/foo/').data, 'index')
self.assert_equal(c.get('/foo/bar').data, 'bar')
self.assert_equal(c.get('/foo/').data, b'index')
self.assert_equal(c.get('/foo/bar').data, b'bar')
class BlueprintTestCase(FlaskTestCase):
@ -291,9 +292,9 @@ class BlueprintTestCase(FlaskTestCase):
c = app.test_client()
self.assert_equal(c.get('/frontend-no').data, 'frontend says no')
self.assert_equal(c.get('/backend-no').data, 'backend says no')
self.assert_equal(c.get('/what-is-a-sideend').data, 'application itself says no')
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__)
@ -304,17 +305,17 @@ class BlueprintTestCase(FlaskTestCase):
@bp.route('/bar')
def bar(bar):
return unicode(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, u'23/42')
self.assert_equal(c.get('/2/foo').data, u'19/42')
self.assert_equal(c.get('/1/bar').data, u'23')
self.assert_equal(c.get('/2/bar').data, u'19')
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>')
@ -340,23 +341,25 @@ class BlueprintTestCase(FlaskTestCase):
c = app.test_client()
self.assert_equal(c.get('/de/').data, '/de/about')
self.assert_equal(c.get('/de/about').data, '/de/')
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, 'Hello from the Frontend')
self.assert_equal(rv.data, b'Hello from the Frontend')
rv = c.get('/admin/')
self.assert_equal(rv.data, 'Hello from the Admin')
self.assert_equal(rv.data, b'Hello from the Admin')
rv = c.get('/admin/index2')
self.assert_equal(rv.data, 'Hello from the Admin')
self.assert_equal(rv.data, b'Hello from the Admin')
rv = c.get('/admin/static/test.txt')
self.assert_equal(rv.data.strip(), 'Admin File')
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(), '/* nested file */')
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']
@ -368,6 +371,7 @@ class BlueprintTestCase(FlaskTestCase):
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
@ -378,10 +382,10 @@ class BlueprintTestCase(FlaskTestCase):
with app.test_request_context():
try:
flask.render_template('missing.html')
except TemplateNotFound, e:
except TemplateNotFound as e:
self.assert_equal(e.name, 'missing.html')
else:
self.assert_(0, 'expected exception')
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')
@ -406,6 +410,7 @@ class BlueprintTestCase(FlaskTestCase):
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
@ -436,9 +441,9 @@ class BlueprintTestCase(FlaskTestCase):
app.register_blueprint(backend)
c = app.test_client()
self.assert_equal(c.get('/fe').data.strip(), '/be')
self.assert_equal(c.get('/fe2').data.strip(), '/fe')
self.assert_equal(c.get('/be').data.strip(), '/fe')
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_empty_url_defaults(self):
bp = flask.Blueprint('bp', __name__)
@ -452,8 +457,8 @@ class BlueprintTestCase(FlaskTestCase):
app.register_blueprint(bp)
c = app.test_client()
self.assert_equal(c.get('/').data, '1')
self.assert_equal(c.get('/page/2').data, '2')
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):
@ -483,11 +488,11 @@ class BlueprintTestCase(FlaskTestCase):
return flask.request.endpoint
c = app.test_client()
self.assertEqual(c.get('/').data, 'index')
self.assertEqual(c.get('/py/foo').data, 'bp.foo')
self.assertEqual(c.get('/py/bar').data, 'bp.bar')
self.assertEqual(c.get('/py/bar/123').data, 'bp.123')
self.assertEqual(c.get('/py/bar/foo').data, 'bp.bar_foo')
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__)
@ -534,8 +539,8 @@ class BlueprintTestCase(FlaskTestCase):
app.register_blueprint(bp, url_prefix='/py')
c = app.test_client()
self.assertEqual(c.get('/py/foo').data, 'bp.foo')
# The rule's din't actually made it through
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')
@ -548,7 +553,7 @@ class BlueprintTestCase(FlaskTestCase):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('my_reverse' in app.jinja_env.filters.keys())
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')
@ -559,7 +564,7 @@ class BlueprintTestCase(FlaskTestCase):
bp.add_app_template_filter(my_reverse)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('my_reverse' in app.jinja_env.filters.keys())
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')
@ -570,7 +575,7 @@ class BlueprintTestCase(FlaskTestCase):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('strrev' in app.jinja_env.filters.keys())
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')
@ -581,7 +586,7 @@ class BlueprintTestCase(FlaskTestCase):
bp.add_app_template_filter(my_reverse, 'strrev')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('strrev' in app.jinja_env.filters.keys())
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')
@ -596,7 +601,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_template_filter_after_route_with_template(self):
app = flask.Flask(__name__)
@ -609,7 +614,7 @@ class BlueprintTestCase(FlaskTestCase):
return s[::-1]
app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_template(self):
bp = flask.Blueprint('bp', __name__)
@ -622,7 +627,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_template_filter_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
@ -635,7 +640,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
@ -648,7 +653,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_template_test(self):
bp = flask.Blueprint('bp', __name__)
@ -657,9 +662,9 @@ class BlueprintTestCase(FlaskTestCase):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('is_boolean' in app.jinja_env.tests.keys())
self.assert_in('is_boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean)
self.assert_(app.jinja_env.tests['is_boolean'](False))
self.assert_true(app.jinja_env.tests['is_boolean'](False))
def test_add_template_test(self):
bp = flask.Blueprint('bp', __name__)
@ -668,9 +673,9 @@ class BlueprintTestCase(FlaskTestCase):
bp.add_app_template_test(is_boolean)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('is_boolean' in app.jinja_env.tests.keys())
self.assert_in('is_boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean)
self.assert_(app.jinja_env.tests['is_boolean'](False))
self.assert_true(app.jinja_env.tests['is_boolean'](False))
def test_template_test_with_name(self):
bp = flask.Blueprint('bp', __name__)
@ -679,9 +684,9 @@ class BlueprintTestCase(FlaskTestCase):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('boolean' in app.jinja_env.tests.keys())
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_(app.jinja_env.tests['boolean'](False))
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_add_template_test_with_name(self):
bp = flask.Blueprint('bp', __name__)
@ -690,9 +695,9 @@ class BlueprintTestCase(FlaskTestCase):
bp.add_app_template_test(is_boolean, 'boolean')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_('boolean' in app.jinja_env.tests.keys())
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_(app.jinja_env.tests['boolean'](False))
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_template_test_with_template(self):
bp = flask.Blueprint('bp', __name__)
@ -705,7 +710,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def test_template_test_after_route_with_template(self):
app = flask.Flask(__name__)
@ -718,7 +723,7 @@ class BlueprintTestCase(FlaskTestCase):
return isinstance(value, bool)
app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_template(self):
bp = flask.Blueprint('bp', __name__)
@ -731,7 +736,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def test_template_test_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
@ -744,7 +749,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
@ -757,7 +762,7 @@ class BlueprintTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def suite():
suite = unittest.TestSuite()

35
flask/testsuite/config.py

@ -8,7 +8,6 @@
:copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import sys
@ -29,7 +28,7 @@ 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_('ConfigTestCase' not in app.config)
self.assert_not_in('ConfigTestCase', app.config)
def test_config_from_file(self):
app = flask.Flask(__name__)
@ -57,14 +56,14 @@ class ConfigTestCase(FlaskTestCase):
app = flask.Flask(__name__)
try:
app.config.from_envvar('FOO_SETTINGS')
except RuntimeError, e:
self.assert_("'FOO_SETTINGS' is not set" in str(e))
except RuntimeError as e:
self.assert_true("'FOO_SETTINGS' is not set" in str(e))
else:
self.assert_(0, 'expected exception')
self.assert_(not app.config.from_envvar('FOO_SETTINGS', silent=True))
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_(app.config.from_envvar('FOO_SETTINGS'))
self.assert_true(app.config.from_envvar('FOO_SETTINGS'))
self.common_object_test(app)
finally:
os.environ = env
@ -76,11 +75,11 @@ class ConfigTestCase(FlaskTestCase):
try:
app = flask.Flask(__name__)
app.config.from_envvar('FOO_SETTINGS')
except IOError, e:
except IOError as e:
msg = str(e)
self.assert_(msg.startswith('[Errno 2] Unable to load configuration '
self.assert_true(msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):'))
self.assert_(msg.endswith("missing.cfg'"))
self.assert_true(msg.endswith("missing.cfg'"))
else:
self.fail('expected IOError')
self.assertFalse(app.config.from_envvar('FOO_SETTINGS', silent=True))
@ -91,14 +90,14 @@ class ConfigTestCase(FlaskTestCase):
app = flask.Flask(__name__)
try:
app.config.from_pyfile('missing.cfg')
except IOError, e:
except IOError as e:
msg = str(e)
self.assert_(msg.startswith('[Errno 2] Unable to load configuration '
self.assert_true(msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):'))
self.assert_(msg.endswith("missing.cfg'"))
self.assert_true(msg.endswith("missing.cfg'"))
else:
self.assert_(0, 'expected config')
self.assert_(not app.config.from_pyfile('missing.cfg', silent=True))
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__)
@ -113,7 +112,7 @@ class LimitedLoaderMockWrapper(object):
def __getattr__(self, name):
if name in ('archive', 'get_filename'):
msg = 'Mocking a loader which does not have `%s.`' % name
raise AttributeError, msg
raise AttributeError(msg)
return getattr(self.loader, name)
@ -141,8 +140,8 @@ class InstanceTestCase(FlaskTestCase):
here = os.path.abspath(os.path.dirname(__file__))
try:
flask.Flask(__name__, instance_path='instance')
except ValueError, e:
self.assert_('must be absolute' in str(e))
except ValueError as e:
self.assert_in('must be absolute', str(e))
else:
self.fail('Expected value error')

19
flask/testsuite/deprecations.py

@ -9,30 +9,13 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import flask
import unittest
from flask.testsuite import FlaskTestCase, catch_warnings
class DeprecationsTestCase(FlaskTestCase):
def test_init_jinja_globals(self):
class MyFlask(flask.Flask):
def init_jinja_globals(self):
self.jinja_env.globals['foo'] = '42'
with catch_warnings() as log:
app = MyFlask(__name__)
@app.route('/')
def foo():
return app.jinja_env.globals['foo']
c = app.test_client()
self.assert_equal(c.get('/').data, '42')
self.assert_equal(len(log), 1)
self.assert_('init_jinja_globals' in str(log[0]['message']))
"""not used currently"""
def suite():

35
flask/testsuite/ext.py

@ -8,12 +8,15 @@
:copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
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):
@ -22,14 +25,14 @@ class ExtImportHookTestCase(FlaskTestCase):
# 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 sys.modules.items():
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(ext)
reload_module(ext)
# reloading must not add more hooks
import_hooks = 0
@ -43,7 +46,7 @@ class ExtImportHookTestCase(FlaskTestCase):
def teardown(self):
from flask import ext
for key in ext.__dict__:
self.assert_('.' not in key)
self.assert_not_in('.', key)
def test_flaskext_new_simple_import_normal(self):
from flask.ext.newext_simple import ext_id
@ -100,7 +103,7 @@ class ExtImportHookTestCase(FlaskTestCase):
self.assert_equal(test_function(), 42)
def test_flaskext_broken_package_no_module_caching(self):
for x in xrange(2):
for x in range(2):
with self.assert_raises(ImportError):
import flask.ext.broken
@ -109,12 +112,20 @@ class ExtImportHookTestCase(FlaskTestCase):
import flask.ext.broken
except ImportError:
exc_type, exc_value, tb = sys.exc_info()
self.assert_(exc_type is ImportError)
self.assert_equal(str(exc_value), 'No module named missing_module')
self.assert_(tb.tb_frame.f_globals is globals())
next = tb.tb_next
self.assert_('flask_broken/__init__.py' in next.tb_frame.f_code.co_filename)
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():

92
flask/testsuite/helpers.py

@ -9,15 +9,13 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import flask
import unittest
from logging import StreamHandler
from StringIO import StringIO
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, implements_iterator
def has_encoding(name):
@ -35,7 +33,7 @@ class JSONTestCase(FlaskTestCase):
app = flask.Flask(__name__)
@app.route('/json', methods=['POST'])
def return_json():
return flask.jsonify(foo=unicode(flask.request.json))
return flask.jsonify(foo=text_type(flask.request.json))
c = app.test_client()
rv = c.post('/json', data='malformed', content_type='application/json')
self.assert_equal(rv.status_code, 400)
@ -84,11 +82,11 @@ class JSONTestCase(FlaskTestCase):
app = flask.Flask(__name__)
@app.route('/add', methods=['POST'])
def add():
return unicode(flask.request.json['a'] + flask.request.json['b'])
return text_type(flask.request.json['a'] + flask.request.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, '3')
self.assert_equal(rv.data, b'3')
def test_template_escaping(self):
app = flask.Flask(__name__)
@ -129,12 +127,13 @@ class JSONTestCase(FlaskTestCase):
rv = c.post('/', data=flask.json.dumps({
'x': {'_foo': 42}
}), content_type='application/json')
self.assertEqual(rv.data, '"<42>"')
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'
@ -156,21 +155,24 @@ class SendfileTestCase(FlaskTestCase):
app = flask.Flask(__name__)
with app.test_request_context():
rv = flask.send_file('static/index.html')
self.assert_(rv.direct_passthrough)
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_(rv.direct_passthrough)
self.assert_('x-sendfile' in rv.headers)
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__)
@ -178,9 +180,11 @@ class SendfileTestCase(FlaskTestCase):
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)
@ -190,9 +194,10 @@ class SendfileTestCase(FlaskTestCase):
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_('x-sendfile' in rv.headers)
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)
@ -201,15 +206,19 @@ class SendfileTestCase(FlaskTestCase):
with catch_warnings() as captured:
f = StringIO('Test')
rv = flask.send_file(f)
self.assert_equal(rv.data, 'Test')
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')
self.assert_equal(rv.data, 'Test')
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)
@ -218,7 +227,8 @@ class SendfileTestCase(FlaskTestCase):
with app.test_request_context():
f = StringIO('Test')
rv = flask.send_file(f)
self.assert_('x-sendfile' not in rv.headers)
self.assert_not_in('x-sendfile', rv.headers)
rv.close()
# etags
self.assert_equal(len(captured), 1)
@ -230,6 +240,7 @@ class SendfileTestCase(FlaskTestCase):
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)
@ -239,6 +250,7 @@ class SendfileTestCase(FlaskTestCase):
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,
@ -248,6 +260,7 @@ class SendfileTestCase(FlaskTestCase):
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__)
@ -257,20 +270,24 @@ class SendfileTestCase(FlaskTestCase):
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
@ -280,10 +297,12 @@ class SendfileTestCase(FlaskTestCase):
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):
@ -291,10 +310,10 @@ class LoggingTestCase(FlaskTestCase):
def test_logger_cache(self):
app = flask.Flask(__name__)
logger1 = app.logger
self.assert_(app.logger is logger1)
self.assert_true(app.logger is logger1)
self.assert_equal(logger1.name, __name__)
app.logger_name = __name__ + '/test_logger_cache'
self.assert_(app.logger is not logger1)
self.assert_true(app.logger is not logger1)
def test_debug_log(self):
app = flask.Flask(__name__)
@ -308,16 +327,16 @@ class LoggingTestCase(FlaskTestCase):
@app.route('/exc')
def exc():
1/0
1 // 0
with app.test_client() as c:
with catch_stderr() as err:
c.get('/')
out = err.getvalue()
self.assert_('WARNING in helpers [' in out)
self.assert_(os.path.basename(__file__.rsplit('.', 1)[0] + '.py') in out)
self.assert_('the standard library is dead' in out)
self.assert_('this is a debug statement' in out)
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:
@ -325,7 +344,7 @@ class LoggingTestCase(FlaskTestCase):
except ZeroDivisionError:
pass
else:
self.assert_(False, 'debug log ate the exception')
self.assert_true(False, 'debug log ate the exception')
def test_debug_log_override(self):
app = flask.Flask(__name__)
@ -342,28 +361,28 @@ class LoggingTestCase(FlaskTestCase):
@app.route('/')
def index():
1/0
1 // 0
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500)
self.assert_('Internal Server Error' in rv.data)
self.assert_in(b'Internal Server Error', rv.data)
err = out.getvalue()
self.assert_('Exception on / [GET]' in err)
self.assert_('Traceback (most recent call last):' in err)
self.assert_('1/0' in err)
self.assert_('ZeroDivisionError:' in err)
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
1 // 0
@app.after_request
def after_request(response):
if trigger == 'after':
1/0
1 // 0
return response
@app.route('/')
def index():
@ -374,7 +393,7 @@ class LoggingTestCase(FlaskTestCase):
for trigger in 'before', 'after':
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500)
self.assert_equal(rv.data, 'Hello Server Error')
self.assert_equal(rv.data, b'Hello Server Error')
def test_url_for_with_anchor(self):
app = flask.Flask(__name__)
@ -466,7 +485,7 @@ class StreamingTestCase(FlaskTestCase):
return flask.Response(flask.stream_with_context(generate()))
c = app.test_client()
rv = c.get('/?name=World')
self.assertEqual(rv.data, 'Hello World!')
self.assertEqual(rv.data, b'Hello World!')
def test_streaming_with_context_as_decorator(self):
app = flask.Flask(__name__)
@ -481,12 +500,13 @@ class StreamingTestCase(FlaskTestCase):
return flask.Response(generate())
c = app.test_client()
rv = c.get('/?name=World')
self.assertEqual(rv.data, 'Hello 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 = []
@implements_iterator
class Wrapper(object):
def __init__(self, gen):
self._gen = gen
@ -494,8 +514,8 @@ class StreamingTestCase(FlaskTestCase):
return self
def close(self):
called.append(42)
def next(self):
return self._gen.next()
def __next__(self):
return next(self._gen)
@app.route('/')
def index():
def generate():
@ -506,7 +526,7 @@ class StreamingTestCase(FlaskTestCase):
Wrapper(generate())))
c = app.test_client()
rv = c.get('/?name=World')
self.assertEqual(rv.data, 'Hello World!')
self.assertEqual(rv.data, b'Hello World!')
self.assertEqual(called, [42])

8
flask/testsuite/regression.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import gc
import sys
@ -68,7 +66,7 @@ class MemoryTestCase(FlaskTestCase):
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.status_code, 200)
self.assert_equal(rv.data, '<h1>42</h1>')
self.assert_equal(rv.data, b'<h1>42</h1>')
# Trigger caches
fire()
@ -77,7 +75,7 @@ class MemoryTestCase(FlaskTestCase):
if sys.version_info >= (2, 7) and \
not hasattr(sys, 'pypy_translation_info'):
with self.assert_no_leak():
for x in xrange(10):
for x in range(10):
fire()
def test_safe_join_toplevel_pardir(self):
@ -107,7 +105,7 @@ class ExceptionTestCase(FlaskTestCase):
rv = c.get('/')
self.assertEqual(rv.headers['Location'], 'http://localhost/test')
rv = c.get('/test')
self.assertEqual(rv.data, '42')
self.assertEqual(rv.data, b'42')
def suite():

36
flask/testsuite/reqctx.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import flask
import unittest
try:
@ -58,8 +56,8 @@ class RequestContextTestCase(FlaskTestCase):
try:
with app.test_request_context('/', environ_overrides={'HTTP_HOST': 'localhost'}):
pass
except Exception, e:
self.assert_(isinstance(e, ValueError))
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')")
@ -68,7 +66,7 @@ class RequestContextTestCase(FlaskTestCase):
app.config.update(SERVER_NAME='localhost')
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost'}):
pass
except ValueError, e:
except ValueError as e:
raise ValueError(
"No ValueError exception should have been raised \"%s\"" % e
)
@ -77,7 +75,7 @@ class RequestContextTestCase(FlaskTestCase):
app.config.update(SERVER_NAME='localhost:80')
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost:80'}):
pass
except ValueError, e:
except ValueError as e:
raise ValueError(
"No ValueError exception should have been raised \"%s\"" % e
)
@ -95,17 +93,17 @@ class RequestContextTestCase(FlaskTestCase):
self.assert_equal(index(), 'Hello World!')
with app.test_request_context('/meh'):
self.assert_equal(meh(), 'http://localhost/meh')
self.assert_(flask._request_ctx_stack.top is None)
self.assert_true(flask._request_ctx_stack.top is None)
def test_context_test(self):
app = flask.Flask(__name__)
self.assert_(not flask.request)
self.assert_(not flask.has_request_context())
self.assert_false(flask.request)
self.assert_false(flask.has_request_context())
ctx = app.test_request_context()
ctx.push()
try:
self.assert_(flask.request)
self.assert_(flask.has_request_context())
self.assert_true(flask.request)
self.assert_true(flask.has_request_context())
finally:
ctx.pop()
@ -124,7 +122,7 @@ class RequestContextTestCase(FlaskTestCase):
except RuntimeError:
pass
else:
self.assert_(0, 'expected runtime error')
self.assert_true(0, 'expected runtime error')
def test_greenlet_context_copying(self):
app = flask.Flask(__name__)
@ -134,20 +132,20 @@ class RequestContextTestCase(FlaskTestCase):
def index():
reqctx = flask._request_ctx_stack.top.copy()
def g():
self.assert_(not flask.request)
self.assert_(not flask.current_app)
self.assert_false(flask.request)
self.assert_false(flask.current_app)
with reqctx:
self.assert_(flask.request)
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_(not flask.request)
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, 'Hello World!')
self.assert_equal(rv.data, b'Hello World!')
result = greenlets[0].run()
self.assert_equal(result, 42)
@ -161,7 +159,7 @@ class RequestContextTestCase(FlaskTestCase):
reqctx = flask._request_ctx_stack.top.copy()
@flask.copy_current_request_context
def g():
self.assert_(flask.request)
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')
@ -170,7 +168,7 @@ class RequestContextTestCase(FlaskTestCase):
return 'Hello World!'
rv = app.test_client().get('/?foo=bar')
self.assert_equal(rv.data, 'Hello World!')
self.assert_equal(rv.data, b'Hello World!')
result = greenlets[0].run()
self.assert_equal(result, 42)

9
flask/testsuite/signals.py

@ -8,7 +8,6 @@
:copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import flask
import unittest
@ -46,7 +45,7 @@ class SignalsTestCase(FlaskTestCase):
calls.append('before-signal')
def after_request_signal(sender, response):
self.assert_equal(response.data, 'stuff')
self.assert_equal(response.data, b'stuff')
calls.append('after-signal')
@app.before_request
@ -69,7 +68,7 @@ class SignalsTestCase(FlaskTestCase):
try:
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'stuff')
self.assert_equal(rv.data, b'stuff')
self.assert_equal(calls, ['before-signal', 'before-handler',
'handler', 'after-handler',
@ -84,7 +83,7 @@ class SignalsTestCase(FlaskTestCase):
@app.route('/')
def index():
1/0
1 // 0
def record(sender, exception):
recorded.append(exception)
@ -93,7 +92,7 @@ class SignalsTestCase(FlaskTestCase):
try:
self.assert_equal(app.test_client().get('/').status_code, 500)
self.assert_equal(len(recorded), 1)
self.assert_(isinstance(recorded[0], ZeroDivisionError))
self.assert_true(isinstance(recorded[0], ZeroDivisionError))
finally:
flask.got_request_exception.disconnect(record, app)

6
flask/testsuite/subclassing.py

@ -11,9 +11,9 @@
"""
import flask
import unittest
from StringIO import StringIO
from logging import StreamHandler
from flask.testsuite import FlaskTestCase
from flask._compat import StringIO
class FlaskSubclassingTestCase(FlaskTestCase):
@ -30,11 +30,11 @@ class FlaskSubclassingTestCase(FlaskTestCase):
@app.route('/')
def index():
1/0
1 // 0
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500)
self.assert_('Internal Server Error' in rv.data)
self.assert_in(b'Internal Server Error', rv.data)
err = out.getvalue()
self.assert_equal(err, '')

68
flask/testsuite/templating.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import flask
import unittest
from flask.testsuite import FlaskTestCase
@ -27,7 +25,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('context_template.html', value=23)
rv = app.test_client().get('/')
self.assert_equal(rv.data, '<p>23|42')
self.assert_equal(rv.data, b'<p>23|42')
def test_original_win(self):
app = flask.Flask(__name__)
@ -35,7 +33,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template_string('{{ config }}', config=42)
rv = app.test_client().get('/')
self.assert_equal(rv.data, '42')
self.assert_equal(rv.data, b'42')
def test_request_less_rendering(self):
app = flask.Flask(__name__)
@ -63,7 +61,7 @@ class TemplatingTestCase(FlaskTestCase):
{{ session.test }}
''')
rv = app.test_client().get('/?foo=42')
self.assert_equal(rv.data.split(), ['42', '23', 'False', 'aha'])
self.assert_equal(rv.data.split(), [b'42', b'23', b'False', b'aha'])
def test_escaping(self):
text = '<p>Hello World!'
@ -74,12 +72,12 @@ class TemplatingTestCase(FlaskTestCase):
html=flask.Markup(text))
lines = app.test_client().get('/').data.splitlines()
self.assert_equal(lines, [
'&lt;p&gt;Hello World!',
'<p>Hello World!',
'<p>Hello World!',
'<p>Hello World!',
'&lt;p&gt;Hello World!',
'<p>Hello World!'
b'&lt;p&gt;Hello World!',
b'<p>Hello World!',
b'<p>Hello World!',
b'<p>Hello World!',
b'&lt;p&gt;Hello World!',
b'<p>Hello World!'
])
def test_no_escaping(self):
@ -101,7 +99,7 @@ class TemplatingTestCase(FlaskTestCase):
@app.template_filter()
def my_reverse(s):
return s[::-1]
self.assert_('my_reverse' in app.jinja_env.filters.keys())
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')
@ -110,7 +108,7 @@ class TemplatingTestCase(FlaskTestCase):
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse)
self.assert_('my_reverse' in app.jinja_env.filters.keys())
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')
@ -119,7 +117,7 @@ class TemplatingTestCase(FlaskTestCase):
@app.template_filter('strrev')
def my_reverse(s):
return s[::-1]
self.assert_('strrev' in app.jinja_env.filters.keys())
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')
@ -128,7 +126,7 @@ class TemplatingTestCase(FlaskTestCase):
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse, 'strrev')
self.assert_('strrev' in app.jinja_env.filters.keys())
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')
@ -141,7 +139,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_template(self):
app = flask.Flask(__name__)
@ -152,7 +150,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_template_filter_with_name_and_template(self):
app = flask.Flask(__name__)
@ -163,7 +161,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_name_and_template(self):
app = flask.Flask(__name__)
@ -174,43 +172,43 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, 'dcba')
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_('boolean' in app.jinja_env.tests.keys())
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], boolean)
self.assert_(app.jinja_env.tests['boolean'](False))
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_('boolean' in app.jinja_env.tests.keys())
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], boolean)
self.assert_(app.jinja_env.tests['boolean'](False))
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_('boolean' in app.jinja_env.tests.keys())
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_(app.jinja_env.tests['boolean'](False))
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_('boolean' in app.jinja_env.tests.keys())
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_(app.jinja_env.tests['boolean'](False))
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_template_test_with_template(self):
app = flask.Flask(__name__)
@ -221,7 +219,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_template(self):
app = flask.Flask(__name__)
@ -232,7 +230,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def test_template_test_with_name_and_template(self):
app = flask.Flask(__name__)
@ -243,7 +241,7 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_name_and_template(self):
app = flask.Flask(__name__)
@ -254,16 +252,16 @@ class TemplatingTestCase(FlaskTestCase):
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_('Success!' in rv.data)
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_('get_stuff' in app.jinja_env.globals.keys())
self.assert_in('get_stuff', app.jinja_env.globals.keys())
self.assert_equal(app.jinja_env.globals['get_stuff'], get_stuff)
self.assert_(app.jinja_env.globals['get_stuff'](), 42)
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')
@ -279,7 +277,7 @@ class TemplatingTestCase(FlaskTestCase):
return flask.render_template('index.html')
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, 'Hello Custom World!')
self.assert_equal(rv.data, b'Hello Custom World!')
def test_iterable_loader(self):
app = flask.Flask(__name__)
@ -295,7 +293,7 @@ class TemplatingTestCase(FlaskTestCase):
value=23)
rv = app.test_client().get('/')
self.assert_equal(rv.data, '<h1>Jameson</h1>')
self.assert_equal(rv.data, b'<h1>Jameson</h1>')
def suite():

47
flask/testsuite/testing.py

@ -9,11 +9,10 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import flask
import unittest
from flask.testsuite import FlaskTestCase
from flask._compat import text_type
class TestToolsTestCase(FlaskTestCase):
@ -31,7 +30,7 @@ class TestToolsTestCase(FlaskTestCase):
self.assert_equal(ctx.request.url, 'http://example.com:1234/foo/')
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.data, 'http://example.com:1234/foo/')
self.assert_equal(rv.data, b'http://example.com:1234/foo/')
def test_environ_defaults(self):
app = flask.Flask(__name__)
@ -44,7 +43,7 @@ class TestToolsTestCase(FlaskTestCase):
self.assert_equal(ctx.request.url, 'http://localhost/')
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.data, 'http://localhost/')
self.assert_equal(rv.data, b'http://localhost/')
def test_redirect_keep_session(self):
app = flask.Flask(__name__)
@ -63,20 +62,20 @@ class TestToolsTestCase(FlaskTestCase):
with app.test_client() as c:
rv = c.get('/getsession')
assert rv.data == '<missing>'
assert rv.data == b'<missing>'
rv = c.get('/')
assert rv.data == 'index'
assert rv.data == b'index'
assert flask.session.get('data') == 'foo'
rv = c.post('/', data={}, follow_redirects=True)
assert rv.data == 'foo'
assert rv.data == b'foo'
# This support requires a new Werkzeug version
if not hasattr(c, 'redirect_client'):
assert flask.session.get('data') == 'foo'
rv = c.get('/getsession')
assert rv.data == 'foo'
assert rv.data == b'foo'
def test_session_transactions(self):
app = flask.Flask(__name__)
@ -85,7 +84,7 @@ class TestToolsTestCase(FlaskTestCase):
@app.route('/')
def index():
return unicode(flask.session['foo'])
return text_type(flask.session['foo'])
with app.test_client() as c:
with c.session_transaction() as sess:
@ -93,7 +92,7 @@ class TestToolsTestCase(FlaskTestCase):
sess['foo'] = [42]
self.assert_equal(len(sess), 1)
rv = c.get('/')
self.assert_equal(rv.data, '[42]')
self.assert_equal(rv.data, b'[42]')
with c.session_transaction() as sess:
self.assert_equal(len(sess), 1)
self.assert_equal(sess['foo'], [42])
@ -106,8 +105,8 @@ class TestToolsTestCase(FlaskTestCase):
try:
with c.session_transaction() as sess:
pass
except RuntimeError, e:
self.assert_('Session backend did not open a session' in str(e))
except RuntimeError as e:
self.assert_in('Session backend did not open a session', str(e))
else:
self.fail('Expected runtime error')
@ -119,9 +118,9 @@ class TestToolsTestCase(FlaskTestCase):
with app.test_client() as c:
rv = c.get('/')
req = flask.request._get_current_object()
self.assert_(req is not None)
self.assert_true(req is not None)
with c.session_transaction():
self.assert_(req is flask.request._get_current_object())
self.assert_true(req is flask.request._get_current_object())
def test_session_transaction_needs_cookies(self):
app = flask.Flask(__name__)
@ -130,8 +129,8 @@ class TestToolsTestCase(FlaskTestCase):
try:
with c.session_transaction() as s:
pass
except RuntimeError, e:
self.assert_('cookies' in str(e))
except RuntimeError as e:
self.assert_in('cookies', str(e))
else:
self.fail('Expected runtime error')
@ -144,17 +143,17 @@ class TestToolsTestCase(FlaskTestCase):
@app.route('/other')
def other():
1/0
1 // 0
with app.test_client() as c:
resp = c.get('/')
self.assert_equal(flask.g.value, 42)
self.assert_equal(resp.data, 'Hello World!')
self.assert_equal(resp.data, b'Hello World!')
self.assert_equal(resp.status_code, 200)
resp = c.get('/other')
self.assert_(not hasattr(flask.g, 'value'))
self.assert_('Internal Server Error' in resp.data)
self.assert_false(hasattr(flask.g, 'value'))
self.assert_in(b'Internal Server Error', resp.data)
self.assert_equal(resp.status_code, 500)
flask.g.value = 23
@ -220,8 +219,8 @@ class SubdomainTestCase(FlaskTestCase):
url = flask.url_for('view', company_id='xxx')
response = self.client.get(url)
self.assertEquals(200, response.status_code)
self.assertEquals('xxx', response.data)
self.assert_equal(200, response.status_code)
self.assert_equal(b'xxx', response.data)
def test_nosubdomain(self):
@ -232,8 +231,8 @@ class SubdomainTestCase(FlaskTestCase):
url = flask.url_for('view', company_id='xxx')
response = self.client.get(url)
self.assertEquals(200, response.status_code)
self.assertEquals('xxx', response.data)
self.assert_equal(200, response.status_code)
self.assert_equal(b'xxx', response.data)
def suite():

20
flask/testsuite/views.py

@ -8,7 +8,7 @@
:copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import flask
import flask.views
import unittest
@ -20,8 +20,8 @@ class ViewTestCase(FlaskTestCase):
def common_test(self, app):
c = app.test_client()
self.assert_equal(c.get('/').data, 'GET')
self.assert_equal(c.post('/').data, 'POST')
self.assert_equal(c.get('/').data, b'GET')
self.assert_equal(c.post('/').data, b'POST')
self.assert_equal(c.put('/').status_code, 405)
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
self.assert_equal(sorted(meths), ['GET', 'HEAD', 'OPTIONS', 'POST'])
@ -55,9 +55,9 @@ class ViewTestCase(FlaskTestCase):
class Index(flask.views.MethodView):
def get(self):
1/0
1 // 0
def post(self):
1/0
1 // 0
class Other(Index):
def get(self):
@ -108,7 +108,7 @@ class ViewTestCase(FlaskTestCase):
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.headers['X-Parachute'], 'awesome')
self.assert_equal(rv.data, 'Awesome')
self.assert_equal(rv.data, b'Awesome')
def test_implicit_head(self):
app = flask.Flask(__name__)
@ -122,10 +122,10 @@ class ViewTestCase(FlaskTestCase):
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, 'Blub')
self.assert_equal(rv.data, b'Blub')
self.assert_equal(rv.headers['X-Method'], 'GET')
rv = c.head('/')
self.assert_equal(rv.data, '')
self.assert_equal(rv.data, b'')
self.assert_equal(rv.headers['X-Method'], 'HEAD')
def test_explicit_head(self):
@ -140,9 +140,9 @@ class ViewTestCase(FlaskTestCase):
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, 'GET')
self.assert_equal(rv.data, b'GET')
rv = c.head('/')
self.assert_equal(rv.data, '')
self.assert_equal(rv.data, b'')
self.assert_equal(rv.headers['X-Method'], 'HEAD')
def test_endpoint_override(self):

5
flask/views.py

@ -9,6 +9,7 @@
:license: BSD, see LICENSE for more details.
"""
from .globals import request
from ._compat import with_metaclass
http_method_funcs = frozenset(['get', 'post', 'head', 'options',
@ -119,7 +120,7 @@ class MethodViewType(type):
return rv
class MethodView(View):
class MethodView(with_metaclass(MethodViewType, View)):
"""Like a regular class-based view but that dispatches requests to
particular methods. For instance if you implement a method called
:meth:`get` it means you will response to ``'GET'`` requests and
@ -138,8 +139,6 @@ class MethodView(View):
app.add_url_rule('/counter', view_func=CounterAPI.as_view('counter'))
"""
__metaclass__ = MethodViewType
def dispatch_request(self, *args, **kwargs):
meth = getattr(self, request.method.lower(), None)
# if the request method is HEAD and we don't have a handler for it

4
flask/wrappers.py

@ -92,8 +92,6 @@ class Request(RequestBase):
def json(self):
"""If the mimetype is `application/json` this will contain the
parsed JSON data. Otherwise this will be `None`.
This requires Python 2.6 or an installed version of simplejson.
"""
if self.mimetype == 'application/json':
request_charset = self.mimetype_params.get('charset')
@ -101,7 +99,7 @@ class Request(RequestBase):
if request_charset is not None:
return json.loads(self.data, encoding=request_charset)
return json.loads(self.data)
except ValueError, e:
except ValueError as e:
return self.on_json_loading_failed(e)
def on_json_loading_failed(self, e):

4
scripts/flask-07-upgrade.py

@ -287,9 +287,7 @@ def main():
args = ['.']
if ast is None:
parser.error('Python 2.6 or later is required to run the upgrade script.\n'
'The runtime requirements for Flask 0.7 however are still '
'Python 2.5.')
parser.error('Python 2.6 or later is required to run the upgrade script.')
for path in args:
scan_path(path, teardown=not options.no_teardown)

2
scripts/flaskext_test.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import sys
import shutil

10
setup.py

@ -38,6 +38,7 @@ Links
<http://github.com/mitsuhiko/flask/zipball/master#egg=Flask-dev>`_
"""
from __future__ import print_function
from setuptools import Command, setup
class run_audit(Command):
@ -59,7 +60,7 @@ class run_audit(Command):
try:
import pyflakes.scripts.pyflakes as flakes
except ImportError:
print "Audit requires PyFlakes installed in your system."
print("Audit requires PyFlakes installed in your system.")
sys.exit(-1)
warns = 0
@ -71,9 +72,9 @@ class run_audit(Command):
if file != '__init__.py' and file.endswith('.py') :
warns += flakes.checkPath(os.path.join(root, file))
if warns > 0:
print "Audit finished with total %d warnings." % warns
print("Audit finished with total %d warnings." % warns)
else:
print "No problems found in sourcecode."
print("No problems found in sourcecode.")
setup(
name='Flask',
@ -92,7 +93,7 @@ setup(
install_requires=[
'Werkzeug>=0.7',
'Jinja2>=2.4',
'itsdangerous>=0.17'
'itsdangerous>=0.21'
],
classifiers=[
'Development Status :: 4 - Beta',
@ -101,7 +102,6 @@ setup(
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',

6
tox.ini

@ -0,0 +1,6 @@
[tox]
envlist = py26, py27, pypy, py33
[testenv]
deps = -egit+git://github.com/mitsuhiko/werkzeug.git@sprint-branch#egg=werkzeug
commands = python run-tests.py []
Loading…
Cancel
Save