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. 38
      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. 246
      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.6
- 2.7 - 2.7
- pypy - pypy
- 3.3
install: pip install --editable . install: pip install --editable .
@ -18,9 +19,3 @@ notifications:
# their own builder failure from us. Travis currently fails way # their own builder failure from us. Travis currently fails way
# too many times by itself. # too many times by itself.
email: false 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 - Removed custom JSON HTTP exception subclasses. If you were relying on them
you can reintroduce them again yourself trivially. Using them however is you can reintroduce them again yourself trivially. Using them however is
strongly discouraged as the interface was flawed. 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 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 all: clean-pyc test
test: test:
python run-tests.py python run-tests.py
tox-test:
tox
test-with-mem: test-with-mem:
RUN_FLASK_MEMORY_TESTS=1 python run-tests.py 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``). (``PackageName==dev``).
9. The ``zip_safe`` flag in the setup script must be set to ``False``, 9. The ``zip_safe`` flag in the setup script must be set to ``False``,
even if the extension would be safe for zipping. 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 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 could do that, but the most kick-ass method is virtualenv, so let's have a look
at that first. 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. up-to-date Python 2.x installation. Python 3.x is not supported.
.. _virtualenv: .. _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 widely supported and very easy to parse. It became popular a few years
ago and quickly replaced XML as transport format in web applications. 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/ .. _jQuery: http://jquery.com/
.. _simplejson: http://pypi.python.org/pypi/simplejson
Loading jQuery Loading jQuery
-------------- --------------

2
docs/patterns/sqlite3.rst

@ -124,7 +124,7 @@ can do that for you::
def init_db(): def init_db():
with app.app_context(): with app.app_context():
db = get_db() 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.cursor().executescript(f.read())
db.commit() 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. for you to the application.
If you want to do that, you first have to import the If you want to do that, you first have to import the
:func:`contextlib.closing` function from the contextlib package. If you :func:`contextlib.closing` function from the contextlib package.
want to use Python 2.5 it's also necessary to enable the `with` statement Accordingly, add the following lines to your existing imports in `flaskr.py`::
first (`__future__` imports must be the very first import). Accordingly,
add the following lines to your existing imports in `flaskr.py`::
from __future__ import with_statement
from contextlib import closing from contextlib import closing
Next we can create a function called `init_db` that initializes the 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(): def init_db():
with closing(connect_db()) as 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.cursor().executescript(f.read())
db.commit() db.commit()

4
examples/flaskr/flaskr.py

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

16
examples/flaskr/flaskr_tests.py

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

4
examples/minitwit/minitwit.py

@ -8,7 +8,7 @@
:copyright: (c) 2010 by Armin Ronacher. :copyright: (c) 2010 by Armin Ronacher.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import time import time
from sqlite3 import dbapi2 as sqlite3 from sqlite3 import dbapi2 as sqlite3
from hashlib import md5 from hashlib import md5
@ -53,7 +53,7 @@ def init_db():
"""Creates the database tables.""" """Creates the database tables."""
with app.app_context(): with app.app_context():
db = get_db() 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.cursor().executescript(f.read())
db.commit() 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}, rv = self.app.post('/add_message', data={'text': text},
follow_redirects=True) follow_redirects=True)
if text: if text:
assert 'Your message was recorded' in rv.data assert b'Your message was recorded' in rv.data
return rv return rv
# testing functions # testing functions
@ -71,29 +71,29 @@ class MiniTwitTestCase(unittest.TestCase):
def test_register(self): def test_register(self):
"""Make sure registering works""" """Make sure registering works"""
rv = self.register('user1', 'default') rv = self.register('user1', 'default')
assert 'You were successfully registered ' \ assert b'You were successfully registered ' \
'and can login now' in rv.data b'and can login now' in rv.data
rv = self.register('user1', 'default') 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') 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', '') 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') 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') 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): def test_login_logout(self):
"""Make sure logging in and logging out works""" """Make sure logging in and logging out works"""
rv = self.register_and_login('user1', 'default') 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() 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') rv = self.login('user1', 'wrongpassword')
assert 'Invalid password' in rv.data assert b'Invalid password' in rv.data
rv = self.login('user2', 'wrongpassword') rv = self.login('user2', 'wrongpassword')
assert 'Invalid username' in rv.data assert b'Invalid username' in rv.data
def test_message_recording(self): def test_message_recording(self):
"""Check if adding messages works""" """Check if adding messages works"""
@ -101,8 +101,8 @@ class MiniTwitTestCase(unittest.TestCase):
self.add_message('test message 1') self.add_message('test message 1')
self.add_message('<test message 2>') self.add_message('<test message 2>')
rv = self.app.get('/') rv = self.app.get('/')
assert 'test message 1' in rv.data assert b'test message 1' in rv.data
assert '&lt;test message 2&gt;' in rv.data assert b'&lt;test message 2&gt;' in rv.data
def test_timelines(self): def test_timelines(self):
"""Make sure that timelines work""" """Make sure that timelines work"""
@ -112,37 +112,37 @@ class MiniTwitTestCase(unittest.TestCase):
self.register_and_login('bar', 'default') self.register_and_login('bar', 'default')
self.add_message('the message by bar') self.add_message('the message by bar')
rv = self.app.get('/public') rv = self.app.get('/public')
assert 'the message by foo' in rv.data assert b'the message by foo' in rv.data
assert 'the message by bar' in rv.data assert b'the message by bar' in rv.data
# bar's timeline should just show bar's message # bar's timeline should just show bar's message
rv = self.app.get('/') rv = self.app.get('/')
assert 'the message by foo' not in rv.data assert b'the message by foo' not in rv.data
assert 'the message by bar' in rv.data assert b'the message by bar' in rv.data
# now let's follow foo # now let's follow foo
rv = self.app.get('/foo/follow', follow_redirects=True) 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 # we should now see foo's message
rv = self.app.get('/') rv = self.app.get('/')
assert 'the message by foo' in rv.data assert b'the message by foo' in rv.data
assert 'the message by bar' 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 # but on the user's page we only want the user's message
rv = self.app.get('/bar') rv = self.app.get('/bar')
assert 'the message by foo' not in rv.data assert b'the message by foo' not in rv.data
assert 'the message by bar' in rv.data assert b'the message by bar' in rv.data
rv = self.app.get('/foo') rv = self.app.get('/foo')
assert 'the message by foo' in rv.data assert b'the message by foo' in rv.data
assert 'the message by bar' not in rv.data assert b'the message by bar' not in rv.data
# now unfollow and check if that worked # now unfollow and check if that worked
rv = self.app.get('/foo/unfollow', follow_redirects=True) 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('/') rv = self.app.get('/')
assert 'the message by foo' not in rv.data assert b'the message by foo' not in rv.data
assert 'the message by bar' in rv.data assert b'the message by bar' in rv.data
if __name__ == '__main__': 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. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import os import os
import sys import sys
from threading import Lock from threading import Lock
@ -36,6 +34,7 @@ from .templating import DispatchingJinjaLoader, Environment, \
_default_template_ctx_processor _default_template_ctx_processor
from .signals import request_started, request_finished, got_request_exception, \ from .signals import request_started, request_finished, got_request_exception, \
request_tearing_down, appcontext_tearing_down request_tearing_down, appcontext_tearing_down
from ._compat import reraise, string_types, integer_types
# a lock used for logger initialization # a lock used for logger initialization
_logger_lock = Lock() _logger_lock = Lock()
@ -178,7 +177,7 @@ class Flask(_PackageBoundObject):
#: The debug flag. Set this to `True` to enable debugging of the #: The debug flag. Set this to `True` to enable debugging of the
#: application. In debug mode the debugger will kick in when an unhandled #: 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. #: the application if changes in the code are detected.
#: #:
#: This attribute can also be configured from the config with the `DEBUG` #: 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 """The name of the application. This is usually the import name
with the difference that it's guessed from the run file if the 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 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. to change the value.
.. versionadded:: 0.8 .. versionadded:: 0.8
@ -585,21 +584,7 @@ class Flask(_PackageBoundObject):
@locked_cached_property @locked_cached_property
def jinja_env(self): def jinja_env(self):
"""The Jinja2 environment used to load templates.""" """The Jinja2 environment used to load templates."""
rv = self.create_jinja_environment() return 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
@property @property
def got_first_request(self): def got_first_request(self):
@ -645,6 +630,7 @@ class Flask(_PackageBoundObject):
:param resource: the name of the resource. To access resources within :param resource: the name of the resource. To access resources within
subfolders use forward slashes as separator. 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) 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 This injects request, session, config and g into the template
context as well as everything template context processors want context as well as everything template context processors want
to inject. Note that the as of Flask 0.6, the original values 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. decides to return a value with the same key.
:param context: the context as a dictionary that is updated in place :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 app.error_handler_spec[None][404] = page_not_found
Setting error handlers via assignments to :attr:`error_handler_spec` 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. and the special case for arbitrary exception types.
The first `None` refers to the active blueprint. If the error 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): def _register_error_handler(self, key, code_or_exception, f):
if isinstance(code_or_exception, HTTPException): if isinstance(code_or_exception, HTTPException):
code_or_exception = code_or_exception.code 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, \ assert code_or_exception != 500 or key is None, \
'It is currently not possible to register a 500 internal ' \ 'It is currently not possible to register a 500 internal ' \
'server error on a per-blueprint level.' 'server error on a per-blueprint level.'
@ -1137,7 +1123,7 @@ class Flask(_PackageBoundObject):
def is_prime(n): def is_prime(n):
if n == 2: if n == 2:
return True 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: if n % i == 0:
return False return False
return True return True
@ -1383,7 +1369,7 @@ class Flask(_PackageBoundObject):
if isinstance(e, typecheck): if isinstance(e, typecheck):
return handler(e) return handler(e)
raise exc_type, exc_value, tb reraise(exc_type, exc_value, tb)
def handle_exception(self, e): def handle_exception(self, e):
"""Default exception handling that kicks in when an exception """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) # (the function was actually called from the except part)
# otherwise, we just raise the error again # otherwise, we just raise the error again
if exc_value is e: if exc_value is e:
raise exc_type, exc_value, tb reraise(exc_type, exc_value, tb)
else: else:
raise e raise e
@ -1478,7 +1464,7 @@ class Flask(_PackageBoundObject):
rv = self.preprocess_request() rv = self.preprocess_request()
if rv is None: if rv is None:
rv = self.dispatch_request() rv = self.dispatch_request()
except Exception, e: except Exception as e:
rv = self.handle_user_exception(e) rv = self.handle_user_exception(e)
response = self.make_response(rv) response = self.make_response(rv)
response = self.process_response(response) response = self.process_response(response)
@ -1516,14 +1502,24 @@ class Flask(_PackageBoundObject):
methods = [] methods = []
try: try:
adapter.match(method='--') adapter.match(method='--')
except MethodNotAllowed, e: except MethodNotAllowed as e:
methods = e.valid_methods methods = e.valid_methods
except HTTPException, e: except HTTPException as e:
pass pass
rv = self.response_class() rv = self.response_class()
rv.allow.update(methods) rv.allow.update(methods)
return rv 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): def make_response(self, rv):
"""Converts the return value from a view function to a real """Converts the return value from a view function to a real
response object that is an instance of :attr:`response_class`. 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 # When we create a response object directly, we let the constructor
# set the headers and status. We do this because there can be # set the headers and status. We do this because there can be
# some extra logic involved when creating these objects with # some extra logic involved when creating these objects with
# specific values (like defualt content type selection). # specific values (like default content type selection).
if isinstance(rv, basestring): if isinstance(rv, string_types + (bytes, )):
rv = self.response_class(rv, headers=headers, status=status) rv = self.response_class(rv, headers=headers, status=status)
headers = status = None headers = status = None
else: else:
rv = self.response_class.force_type(rv, request.environ) rv = self.response_class.force_type(rv, request.environ)
if status is not None: if status is not None:
if isinstance(status, basestring): if isinstance(status, string_types):
rv.status = status rv.status = status
else: else:
rv.status_code = status rv.status_code = status
@ -1626,14 +1622,14 @@ class Flask(_PackageBoundObject):
rv = handler(error, endpoint, values) rv = handler(error, endpoint, values)
if rv is not None: if rv is not None:
return rv return rv
except BuildError, error: except BuildError as error:
pass pass
# At this point we want to reraise the exception. If the error is # 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, # still the same one we can reraise it with the original traceback,
# otherwise we raise it from here. # otherwise we raise it from here.
if error is exc_value: if error is exc_value:
raise exc_type, exc_value, tb reraise(exc_type, exc_value, tb)
raise error raise error
def preprocess_request(self): def preprocess_request(self):
@ -1804,12 +1800,20 @@ class Flask(_PackageBoundObject):
a list of headers and an optional a list of headers and an optional
exception context to start the response exception context to start the response
""" """
with self.request_context(environ): ctx = self.request_context(environ)
ctx.push()
error = None
try:
try: try:
response = self.full_dispatch_request() response = self.full_dispatch_request()
except Exception, e: except Exception as e:
error = e
response = self.make_response(self.handle_exception(e)) response = self.make_response(self.handle_exception(e))
return response(environ, start_response) return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
@property @property
def modules(self): def modules(self):

10
flask/config.py

@ -9,13 +9,12 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import imp import imp
import os import os
import errno import errno
from werkzeug.utils import import_string from werkzeug.utils import import_string
from ._compat import string_types
class ConfigAttribute(object): class ConfigAttribute(object):
@ -126,8 +125,9 @@ class Config(dict):
d = imp.new_module('config') d = imp.new_module('config')
d.__file__ = filename d.__file__ = filename
try: try:
execfile(filename, d.__dict__) with open(filename) as config_file:
except IOError, e: exec(compile(config_file.read(), filename, 'exec'), d.__dict__)
except IOError as e:
if silent and e.errno in (errno.ENOENT, errno.EISDIR): if silent and e.errno in (errno.ENOENT, errno.EISDIR):
return False return False
e.strerror = 'Unable to load configuration file (%s)' % e.strerror e.strerror = 'Unable to load configuration file (%s)' % e.strerror
@ -158,7 +158,7 @@ class Config(dict):
:param obj: an import name or object :param obj: an import name or object
""" """
if isinstance(obj, basestring): if isinstance(obj, string_types):
obj = import_string(obj) obj = import_string(obj)
for key in dir(obj): for key in dir(obj):
if key.isupper(): if key.isupper():

20
flask/ctx.py

@ -281,12 +281,12 @@ class RequestContext(object):
url_rule, self.request.view_args = \ url_rule, self.request.view_args = \
self.url_adapter.match(return_rule=True) self.url_adapter.match(return_rule=True)
self.request.url_rule = url_rule self.request.url_rule = url_rule
except HTTPException, e: except HTTPException as e:
self.request.routing_exception = e self.request.routing_exception = e
def push(self): def push(self):
"""Binds the request context to the current context.""" """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 # activated under exception situations exactly one context stays
# on the stack. The rationale is that you want to access that # on the stack. The rationale is that you want to access that
# information under debug situations. However if someone forgets to # information under debug situations. However if someone forgets to
@ -334,6 +334,9 @@ class RequestContext(object):
if exc is None: if exc is None:
exc = sys.exc_info()[1] exc = sys.exc_info()[1]
self.app.do_teardown_request(exc) self.app.do_teardown_request(exc)
request_close = getattr(self.request, 'close', None)
if request_close is not None:
request_close()
clear_request = True clear_request = True
rv = _request_ctx_stack.pop() rv = _request_ctx_stack.pop()
@ -349,6 +352,13 @@ class RequestContext(object):
if app_ctx is not None: if app_ctx is not None:
app_ctx.pop(exc) 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): def __enter__(self):
self.push() self.push()
return self return self
@ -359,11 +369,7 @@ class RequestContext(object):
# access the request object in the interactive shell. Furthermore # access the request object in the interactive shell. Furthermore
# the context can be force kept alive for the test client. # the context can be force kept alive for the test client.
# See flask.testing for how this works. # See flask.testing for how this works.
if self.request.environ.get('flask._preserve_context') or \ self.auto_pop(exc_value)
(tb is not None and self.app.preserve_context_on_exception):
self.preserved = True
else:
self.pop(exc_value)
def __repr__(self): def __repr__(self):
return '<%s \'%s\' [%s] of %s>' % ( return '<%s \'%s\' [%s] of %s>' % (

6
flask/debughelpers.py

@ -8,6 +8,7 @@
:copyright: (c) 2011 by Armin Ronacher. :copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from ._compat import implements_to_string
class UnexpectedUnicodeError(AssertionError, UnicodeError): class UnexpectedUnicodeError(AssertionError, UnicodeError):
@ -16,6 +17,7 @@ class UnexpectedUnicodeError(AssertionError, UnicodeError):
""" """
@implements_to_string
class DebugFilesKeyError(KeyError, AssertionError): class DebugFilesKeyError(KeyError, AssertionError):
"""Raised from request.files during debugging. The idea is that it can """Raised from request.files during debugging. The idea is that it can
provide a better error message than just a generic KeyError/BadRequest. 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. ' buf.append('\n\nThe browser instead transmitted some file names. '
'This was submitted: %s' % ', '.join('"%s"' % x 'This was submitted: %s' % ', '.join('"%s"' % x
for x in form_matches)) for x in form_matches))
self.msg = ''.join(buf).encode('utf-8') self.msg = ''.join(buf)
def __str__(self): def __str__(self):
return self.msg return self.msg
@ -76,7 +78,7 @@ def attach_enctype_error_multidict(request):
def __getitem__(self, key): def __getitem__(self, key):
try: try:
return oldcls.__getitem__(self, key) return oldcls.__getitem__(self, key)
except KeyError, e: except KeyError as e:
if key not in request.form: if key not in request.form:
raise raise
raise DebugFilesKeyError(request, key) raise DebugFilesKeyError(request, key)

3
flask/exthook.py

@ -21,6 +21,7 @@
""" """
import sys import sys
import os import os
from ._compat import reraise
class ExtensionImporter(object): class ExtensionImporter(object):
@ -77,7 +78,7 @@ class ExtensionImporter(object):
# we swallow it and try the next choice. The skipped frame # we swallow it and try the next choice. The skipped frame
# is the one from __import__ above which we don't care about # is the one from __import__ above which we don't care about
if self.is_important_traceback(realname, tb): if self.is_important_traceback(realname, tb):
raise exc_type, exc_value, tb.tb_next reraise(exc_type, exc_value, tb.tb_next)
continue continue
module = sys.modules[fullname] = sys.modules[realname] module = sys.modules[fullname] = sys.modules[realname]
if '.' not in modname: if '.' not in modname:

19
flask/helpers.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import os import os
import sys import sys
import pkgutil import pkgutil
@ -38,6 +36,7 @@ from jinja2 import FileSystemLoader
from .signals import message_flashed from .signals import message_flashed
from .globals import session, _request_ctx_stack, _app_ctx_stack, \ from .globals import session, _request_ctx_stack, _app_ctx_stack, \
current_app, request current_app, request
from ._compat import string_types, text_type
# sentinel # sentinel
@ -128,7 +127,7 @@ def stream_with_context(generator_or_function):
# pushed. This item is discarded. Then when the iteration continues the # pushed. This item is discarded. Then when the iteration continues the
# real generator is executed. # real generator is executed.
wrapped_g = generator() wrapped_g = generator()
wrapped_g.next() next(wrapped_g)
return wrapped_g return wrapped_g
@ -301,7 +300,7 @@ def url_for(endpoint, **values):
try: try:
rv = url_adapter.build(endpoint, values, method=method, rv = url_adapter.build(endpoint, values, method=method,
force_external=external) force_external=external)
except BuildError, error: except BuildError as error:
# We need to inject the values again so that the app callback can # We need to inject the values again so that the app callback can
# deal with that sort of stuff. # deal with that sort of stuff.
values['_external'] = external values['_external'] = external
@ -331,7 +330,7 @@ def get_template_attribute(template_name, attribute):
.. versionadded:: 0.2 .. versionadded:: 0.2
:param template_name: the name of the template :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, return getattr(current_app.jinja_env.get_template(template_name).module,
attribute) attribute)
@ -399,7 +398,7 @@ def get_flashed_messages(with_categories=False, category_filter=[]):
_request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \ _request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \
if '_flashes' in session else [] if '_flashes' in session else []
if category_filter: 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: if not with_categories:
return [x[1] for x in flashes] return [x[1] for x in flashes]
return flashes return flashes
@ -466,7 +465,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
:data:`~flask.current_app`. :data:`~flask.current_app`.
""" """
mtime = None mtime = None
if isinstance(filename_or_fp, basestring): if isinstance(filename_or_fp, string_types):
filename = filename_or_fp filename = filename_or_fp
file = None file = None
else: 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. # XXX: this behavior is now deprecated because it was unreliable.
# removed in Flask 1.0 # removed in Flask 1.0
if not attachment_filename and not mimetype \ if not attachment_filename and not mimetype \
and isinstance(filename, basestring): and isinstance(filename, string_types):
warn(DeprecationWarning('The filename support for file objects ' warn(DeprecationWarning('The filename support for file objects '
'passed to send_file is now deprecated. Pass an ' 'passed to send_file is now deprecated. Pass an '
'attach_filename if you want mimetypes to be guessed.'), '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: if file is None:
file = open(filename, 'rb') file = open(filename, 'rb')
mtime = os.path.getmtime(filename) mtime = os.path.getmtime(filename)
headers['Content-Length'] = os.path.getsize(filename)
data = wrap_file(request.environ, file) data = wrap_file(request.environ, file)
rv = current_app.response_class(data, mimetype=mimetype, headers=headers, 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.getmtime(filename),
os.path.getsize(filename), os.path.getsize(filename),
adler32( adler32(
filename.encode('utf-8') if isinstance(filename, unicode) filename.encode('utf-8') if isinstance(filename, text_type)
else filename else filename
) & 0xffffffff ) & 0xffffffff
)) ))
@ -839,6 +839,7 @@ class _PackageBoundObject(object):
:param resource: the name of the resource. To access resources within :param resource: the name of the resource. To access resources within
subfolders use forward slashes as separator. subfolders use forward slashes as separator.
:param mode: resource file opening mode, default is 'rb'.
""" """
if mode not in ('r', 'rb'): if mode not in ('r', 'rb'):
raise ValueError('Resources can only be opened for reading') raise ValueError('Resources can only be opened for reading')

38
flask/json.py

@ -8,14 +8,16 @@
:copyright: (c) 2012 by Armin Ronacher. :copyright: (c) 2012 by Armin Ronacher.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import io
import uuid import uuid
from datetime import datetime from datetime import datetime
from .globals import current_app, request from .globals import current_app, request
from ._compat import text_type, PY2
from werkzeug.http import http_date from werkzeug.http import http_date
# Use the same json implementation as itsdangerous on which we # Use the same json implementation as itsdangerous on which we
# depend anyways. This name changed at one point so support both. # depend anyways.
try: try:
from itsdangerous import simplejson as _json from itsdangerous import simplejson as _json
except ImportError: except ImportError:
@ -32,6 +34,20 @@ __all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump',
'jsonify'] '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): class JSONEncoder(_json.JSONEncoder):
"""The default Flask JSON encoder. This one extends the default simplejson """The default Flask JSON encoder. This one extends the default simplejson
encoder by also supporting ``datetime`` objects, ``UUID`` as well as encoder by also supporting ``datetime`` objects, ``UUID`` as well as
@ -62,7 +78,7 @@ class JSONEncoder(_json.JSONEncoder):
if isinstance(o, uuid.UUID): if isinstance(o, uuid.UUID):
return str(o) return str(o)
if hasattr(o, '__html__'): if hasattr(o, '__html__'):
return unicode(o.__html__()) return text_type(o.__html__())
return _json.JSONEncoder.default(self, o) return _json.JSONEncoder.default(self, o)
@ -99,13 +115,20 @@ def dumps(obj, **kwargs):
and can be overriden by the simplejson ``ensure_ascii`` parameter. and can be overriden by the simplejson ``ensure_ascii`` parameter.
""" """
_dump_arg_defaults(kwargs) _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): def dump(obj, fp, **kwargs):
"""Like :func:`dumps` but writes into a file object.""" """Like :func:`dumps` but writes into a file object."""
_dump_arg_defaults(kwargs) _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): def loads(s, **kwargs):
@ -114,6 +137,8 @@ def loads(s, **kwargs):
application on the stack. application on the stack.
""" """
_load_arg_defaults(kwargs) _load_arg_defaults(kwargs)
if isinstance(s, bytes):
s = s.decode(kwargs.pop('encoding', None) or 'utf-8')
return _json.loads(s, **kwargs) return _json.loads(s, **kwargs)
@ -121,6 +146,8 @@ def load(fp, **kwargs):
"""Like :func:`loads` but reads from a file object. """Like :func:`loads` but reads from a file object.
""" """
_load_arg_defaults(kwargs) _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) return _json.load(fp, **kwargs)
@ -164,8 +191,7 @@ def jsonify(*args, **kwargs):
"id": 42 "id": 42
} }
This requires Python 2.6 or an installed version of simplejson. For For security reasons only objects are supported toplevel. For more
security reasons only objects are supported toplevel. For more
information about this, have a look at :ref:`json-security`. information about this, have a look at :ref:`json-security`.
.. versionadded:: 0.2 .. 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.http import http_date, parse_date
from werkzeug.datastructures import CallbackDict from werkzeug.datastructures import CallbackDict
from . import Markup, json from . import Markup, json
from ._compat import iteritems, text_type
from itsdangerous import URLSafeTimedSerializer, BadSignature from itsdangerous import URLSafeTimedSerializer, BadSignature
@ -62,16 +63,16 @@ class TaggedJSONSerializer(object):
elif isinstance(value, uuid.UUID): elif isinstance(value, uuid.UUID):
return {' u': value.hex} return {' u': value.hex}
elif callable(getattr(value, '__html__', None)): elif callable(getattr(value, '__html__', None)):
return {' m': unicode(value.__html__())} return {' m': text_type(value.__html__())}
elif isinstance(value, list): elif isinstance(value, list):
return [_tag(x) for x in value] return [_tag(x) for x in value]
elif isinstance(value, datetime): elif isinstance(value, datetime):
return {' d': http_date(value)} return {' d': http_date(value)}
elif isinstance(value, dict): 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): elif isinstance(value, str):
try: try:
return unicode(value) return text_type(value)
except UnicodeError: except UnicodeError:
raise UnexpectedUnicodeError(u'A byte string with ' raise UnexpectedUnicodeError(u'A byte string with '
u'non-ASCII data was passed to the session system ' u'non-ASCII data was passed to the session system '
@ -84,7 +85,7 @@ class TaggedJSONSerializer(object):
def object_hook(obj): def object_hook(obj):
if len(obj) != 1: if len(obj) != 1:
return obj return obj
the_key, the_value = obj.iteritems().next() the_key, the_value = next(iteritems(obj))
if the_key == ' t': if the_key == ' t':
return tuple(the_value) return tuple(the_value)
elif the_key == ' u': 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 .globals import _request_ctx_stack, _app_ctx_stack
from .signals import template_rendered from .signals import template_rendered
from .module import blueprint_is_module from .module import blueprint_is_module
from ._compat import itervalues, iteritems
def _default_template_ctx_processor(): def _default_template_ctx_processor():
@ -79,7 +80,7 @@ class DispatchingJinjaLoader(BaseLoader):
except (ValueError, KeyError): except (ValueError, KeyError):
pass pass
for blueprint in self.app.blueprints.itervalues(): for blueprint in itervalues(self.app.blueprints):
if blueprint_is_module(blueprint): if blueprint_is_module(blueprint):
continue continue
loader = blueprint.jinja_loader loader = blueprint.jinja_loader
@ -92,7 +93,7 @@ class DispatchingJinjaLoader(BaseLoader):
if loader is not None: if loader is not None:
result.update(loader.list_templates()) 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 loader = blueprint.jinja_loader
if loader is not None: if loader is not None:
for template in loader.list_templates(): for template in loader.list_templates():

10
flask/testing.py

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

38
flask/testsuite/__init__.py

@ -10,17 +10,17 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement from __future__ import print_function
import os import os
import sys import sys
import flask import flask
import warnings import warnings
import unittest import unittest
from StringIO import StringIO
from functools import update_wrapper from functools import update_wrapper
from contextlib import contextmanager from contextlib import contextmanager
from werkzeug.utils import import_string, find_modules from werkzeug.utils import import_string, find_modules
from flask._compat import reraise, StringIO
def add_to_path(path): def add_to_path(path):
@ -101,9 +101,9 @@ def emits_module_deprecation_warning(f):
def new_f(self, *args, **kwargs): def new_f(self, *args, **kwargs):
with catch_warnings() as log: with catch_warnings() as log:
f(self, *args, **kwargs) f(self, *args, **kwargs)
self.assert_(log, 'expected deprecation warning') self.assert_true(log, 'expected deprecation warning')
for entry in log: 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) return update_wrapper(new_f, f)
@ -116,7 +116,10 @@ class FlaskTestCase(unittest.TestCase):
def ensure_clean_request_context(self): def ensure_clean_request_context(self):
# make sure we're not leaking a request context since we are # make sure we're not leaking a request context since we are
# testing flask internally in debug mode in a few cases # 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): def setup(self):
pass pass
@ -142,6 +145,25 @@ class FlaskTestCase(unittest.TestCase):
with catcher: with catcher:
callable(*args, **kwargs) 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): class _ExceptionCatcher(object):
@ -158,7 +180,7 @@ class _ExceptionCatcher(object):
self.test_case.fail('Expected exception of type %r' % self.test_case.fail('Expected exception of type %r' %
exception_name) exception_name)
elif not issubclass(exc_type, self.exc_type): elif not issubclass(exc_type, self.exc_type):
raise exc_type, exc_value, tb reraise(exc_type, exc_value, tb)
return True return True
@ -220,5 +242,5 @@ def main():
"""Runs the testsuite as command line application.""" """Runs the testsuite as command line application."""
try: try:
unittest.main(testLoader=BetterLoader(), defaultTest='suite') unittest.main(testLoader=BetterLoader(), defaultTest='suite')
except Exception, e: except Exception as e:
print 'Error: %s' % e print('Error: %s' % e)

5
flask/testsuite/appctx.py

@ -9,8 +9,6 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import flask import flask
import unittest import unittest
from flask.testsuite import FlaskTestCase from flask.testsuite import FlaskTestCase
@ -89,8 +87,9 @@ class AppContextTestCase(FlaskTestCase):
with flask._app_ctx_stack.top: with flask._app_ctx_stack.top:
with flask._request_ctx_stack.top: with flask._request_ctx_stack.top:
pass pass
self.assert_(flask._request_ctx_stack.request.environ self.assert_true(flask._request_ctx_stack.top.request.environ
['werkzeug.request'] is not None) ['werkzeug.request'] is not None)
return u''
c = app.test_client() c = app.test_client()
c.get('/') c.get('/')
self.assertEqual(called, ['request', 'app']) self.assertEqual(called, ['request', 'app'])

246
flask/testsuite/basic.py

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

161
flask/testsuite/blueprints.py

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

35
flask/testsuite/config.py

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

19
flask/testsuite/deprecations.py

@ -9,30 +9,13 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import flask import flask
import unittest import unittest
from flask.testsuite import FlaskTestCase, catch_warnings from flask.testsuite import FlaskTestCase, catch_warnings
class DeprecationsTestCase(FlaskTestCase): class DeprecationsTestCase(FlaskTestCase):
"""not used currently"""
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']))
def suite(): def suite():

35
flask/testsuite/ext.py

@ -8,12 +8,15 @@
:copyright: (c) 2011 by Armin Ronacher. :copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import sys import sys
import unittest import unittest
try:
from imp import reload as reload_module
except ImportError:
reload_module = reload
from flask.testsuite import FlaskTestCase from flask.testsuite import FlaskTestCase
from flask._compat import PY2
class ExtImportHookTestCase(FlaskTestCase): class ExtImportHookTestCase(FlaskTestCase):
@ -22,14 +25,14 @@ class ExtImportHookTestCase(FlaskTestCase):
# that a real flaskext could be in there which would disable our # that a real flaskext could be in there which would disable our
# fake package. Secondly we want to make sure that the flaskext # fake package. Secondly we want to make sure that the flaskext
# import hook does not break on reloading. # 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 if (entry.startswith('flask.ext.') or
entry.startswith('flask_') or entry.startswith('flask_') or
entry.startswith('flaskext.') or entry.startswith('flaskext.') or
entry == 'flaskext') and value is not None: entry == 'flaskext') and value is not None:
sys.modules.pop(entry, None) sys.modules.pop(entry, None)
from flask import ext from flask import ext
reload(ext) reload_module(ext)
# reloading must not add more hooks # reloading must not add more hooks
import_hooks = 0 import_hooks = 0
@ -43,7 +46,7 @@ class ExtImportHookTestCase(FlaskTestCase):
def teardown(self): def teardown(self):
from flask import ext from flask import ext
for key in ext.__dict__: for key in ext.__dict__:
self.assert_('.' not in key) self.assert_not_in('.', key)
def test_flaskext_new_simple_import_normal(self): def test_flaskext_new_simple_import_normal(self):
from flask.ext.newext_simple import ext_id from flask.ext.newext_simple import ext_id
@ -100,7 +103,7 @@ class ExtImportHookTestCase(FlaskTestCase):
self.assert_equal(test_function(), 42) self.assert_equal(test_function(), 42)
def test_flaskext_broken_package_no_module_caching(self): def test_flaskext_broken_package_no_module_caching(self):
for x in xrange(2): for x in range(2):
with self.assert_raises(ImportError): with self.assert_raises(ImportError):
import flask.ext.broken import flask.ext.broken
@ -109,12 +112,20 @@ class ExtImportHookTestCase(FlaskTestCase):
import flask.ext.broken import flask.ext.broken
except ImportError: except ImportError:
exc_type, exc_value, tb = sys.exc_info() exc_type, exc_value, tb = sys.exc_info()
self.assert_(exc_type is ImportError) self.assert_true(exc_type is ImportError)
self.assert_equal(str(exc_value), 'No module named missing_module') if PY2:
self.assert_(tb.tb_frame.f_globals is globals()) message = 'No module named missing_module'
else:
next = tb.tb_next message = 'No module named \'missing_module\''
self.assert_('flask_broken/__init__.py' in next.tb_frame.f_code.co_filename) 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(): def suite():

92
flask/testsuite/helpers.py

@ -9,15 +9,13 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from __future__ import with_statement
import os import os
import flask import flask
import unittest import unittest
from logging import StreamHandler from logging import StreamHandler
from StringIO import StringIO
from flask.testsuite import FlaskTestCase, catch_warnings, catch_stderr from flask.testsuite import FlaskTestCase, catch_warnings, catch_stderr
from werkzeug.http import parse_cache_control_header, parse_options_header from werkzeug.http import parse_cache_control_header, parse_options_header
from flask._compat import StringIO, text_type, implements_iterator
def has_encoding(name): def has_encoding(name):
@ -35,7 +33,7 @@ class JSONTestCase(FlaskTestCase):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.route('/json', methods=['POST']) @app.route('/json', methods=['POST'])
def return_json(): def return_json():
return flask.jsonify(foo=unicode(flask.request.json)) return flask.jsonify(foo=text_type(flask.request.json))
c = app.test_client() c = app.test_client()
rv = c.post('/json', data='malformed', content_type='application/json') rv = c.post('/json', data='malformed', content_type='application/json')
self.assert_equal(rv.status_code, 400) self.assert_equal(rv.status_code, 400)
@ -84,11 +82,11 @@ class JSONTestCase(FlaskTestCase):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.route('/add', methods=['POST']) @app.route('/add', methods=['POST'])
def add(): 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() c = app.test_client()
rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}), rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}),
content_type='application/json') content_type='application/json')
self.assert_equal(rv.data, '3') self.assert_equal(rv.data, b'3')
def test_template_escaping(self): def test_template_escaping(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -129,12 +127,13 @@ class JSONTestCase(FlaskTestCase):
rv = c.post('/', data=flask.json.dumps({ rv = c.post('/', data=flask.json.dumps({
'x': {'_foo': 42} 'x': {'_foo': 42}
}), content_type='application/json') }), content_type='application/json')
self.assertEqual(rv.data, '"<42>"') self.assertEqual(rv.data, b'"<42>"')
def test_modified_url_encoding(self): def test_modified_url_encoding(self):
class ModifiedRequest(flask.Request): class ModifiedRequest(flask.Request):
url_charset = 'euc-kr' url_charset = 'euc-kr'
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.testing = True
app.request_class = ModifiedRequest app.request_class = ModifiedRequest
app.url_map.charset = 'euc-kr' app.url_map.charset = 'euc-kr'
@ -156,21 +155,24 @@ class SendfileTestCase(FlaskTestCase):
app = flask.Flask(__name__) app = flask.Flask(__name__)
with app.test_request_context(): with app.test_request_context():
rv = flask.send_file('static/index.html') 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') self.assert_equal(rv.mimetype, 'text/html')
with app.open_resource('static/index.html') as f: with app.open_resource('static/index.html') as f:
rv.direct_passthrough = False
self.assert_equal(rv.data, f.read()) self.assert_equal(rv.data, f.read())
rv.close()
def test_send_file_xsendfile(self): def test_send_file_xsendfile(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.use_x_sendfile = True app.use_x_sendfile = True
with app.test_request_context(): with app.test_request_context():
rv = flask.send_file('static/index.html') rv = flask.send_file('static/index.html')
self.assert_(rv.direct_passthrough) self.assert_true(rv.direct_passthrough)
self.assert_('x-sendfile' in rv.headers) self.assert_in('x-sendfile', rv.headers)
self.assert_equal(rv.headers['x-sendfile'], self.assert_equal(rv.headers['x-sendfile'],
os.path.join(app.root_path, 'static/index.html')) os.path.join(app.root_path, 'static/index.html'))
self.assert_equal(rv.mimetype, 'text/html') self.assert_equal(rv.mimetype, 'text/html')
rv.close()
def test_send_file_object(self): def test_send_file_object(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -178,9 +180,11 @@ class SendfileTestCase(FlaskTestCase):
with app.test_request_context(): with app.test_request_context():
f = open(os.path.join(app.root_path, 'static/index.html')) f = open(os.path.join(app.root_path, 'static/index.html'))
rv = flask.send_file(f) rv = flask.send_file(f)
rv.direct_passthrough = False
with app.open_resource('static/index.html') as f: with app.open_resource('static/index.html') as f:
self.assert_equal(rv.data, f.read()) self.assert_equal(rv.data, f.read())
self.assert_equal(rv.mimetype, 'text/html') self.assert_equal(rv.mimetype, 'text/html')
rv.close()
# mimetypes + etag # mimetypes + etag
self.assert_equal(len(captured), 2) self.assert_equal(len(captured), 2)
@ -190,9 +194,10 @@ class SendfileTestCase(FlaskTestCase):
f = open(os.path.join(app.root_path, 'static/index.html')) f = open(os.path.join(app.root_path, 'static/index.html'))
rv = flask.send_file(f) rv = flask.send_file(f)
self.assert_equal(rv.mimetype, 'text/html') 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'], self.assert_equal(rv.headers['x-sendfile'],
os.path.join(app.root_path, 'static/index.html')) os.path.join(app.root_path, 'static/index.html'))
rv.close()
# mimetypes + etag # mimetypes + etag
self.assert_equal(len(captured), 2) self.assert_equal(len(captured), 2)
@ -201,15 +206,19 @@ class SendfileTestCase(FlaskTestCase):
with catch_warnings() as captured: with catch_warnings() as captured:
f = StringIO('Test') f = StringIO('Test')
rv = flask.send_file(f) 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') self.assert_equal(rv.mimetype, 'application/octet-stream')
rv.close()
# etags # etags
self.assert_equal(len(captured), 1) self.assert_equal(len(captured), 1)
with catch_warnings() as captured: with catch_warnings() as captured:
f = StringIO('Test') f = StringIO('Test')
rv = flask.send_file(f, mimetype='text/plain') 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') self.assert_equal(rv.mimetype, 'text/plain')
rv.close()
# etags # etags
self.assert_equal(len(captured), 1) self.assert_equal(len(captured), 1)
@ -218,7 +227,8 @@ class SendfileTestCase(FlaskTestCase):
with app.test_request_context(): with app.test_request_context():
f = StringIO('Test') f = StringIO('Test')
rv = flask.send_file(f) rv = flask.send_file(f)
self.assert_('x-sendfile' not in rv.headers) self.assert_not_in('x-sendfile', rv.headers)
rv.close()
# etags # etags
self.assert_equal(len(captured), 1) self.assert_equal(len(captured), 1)
@ -230,6 +240,7 @@ class SendfileTestCase(FlaskTestCase):
rv = flask.send_file(f, as_attachment=True) rv = flask.send_file(f, as_attachment=True)
value, options = parse_options_header(rv.headers['Content-Disposition']) value, options = parse_options_header(rv.headers['Content-Disposition'])
self.assert_equal(value, 'attachment') self.assert_equal(value, 'attachment')
rv.close()
# mimetypes + etag # mimetypes + etag
self.assert_equal(len(captured), 2) self.assert_equal(len(captured), 2)
@ -239,6 +250,7 @@ class SendfileTestCase(FlaskTestCase):
value, options = parse_options_header(rv.headers['Content-Disposition']) value, options = parse_options_header(rv.headers['Content-Disposition'])
self.assert_equal(value, 'attachment') self.assert_equal(value, 'attachment')
self.assert_equal(options['filename'], 'index.html') self.assert_equal(options['filename'], 'index.html')
rv.close()
with app.test_request_context(): with app.test_request_context():
rv = flask.send_file(StringIO('Test'), as_attachment=True, 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']) value, options = parse_options_header(rv.headers['Content-Disposition'])
self.assert_equal(value, 'attachment') self.assert_equal(value, 'attachment')
self.assert_equal(options['filename'], 'index.txt') self.assert_equal(options['filename'], 'index.txt')
rv.close()
def test_static_file(self): def test_static_file(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -257,20 +270,24 @@ class SendfileTestCase(FlaskTestCase):
rv = app.send_static_file('index.html') rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 12 * 60 * 60) self.assert_equal(cc.max_age, 12 * 60 * 60)
rv.close()
# Test again with direct use of send_file utility. # Test again with direct use of send_file utility.
rv = flask.send_file('static/index.html') rv = flask.send_file('static/index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 12 * 60 * 60) self.assert_equal(cc.max_age, 12 * 60 * 60)
rv.close()
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600
with app.test_request_context(): with app.test_request_context():
# Test with static file handler. # Test with static file handler.
rv = app.send_static_file('index.html') rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 3600) self.assert_equal(cc.max_age, 3600)
rv.close()
# Test again with direct use of send_file utility. # Test again with direct use of send_file utility.
rv = flask.send_file('static/index.html') rv = flask.send_file('static/index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 3600) self.assert_equal(cc.max_age, 3600)
rv.close()
class StaticFileApp(flask.Flask): class StaticFileApp(flask.Flask):
def get_send_file_max_age(self, filename): def get_send_file_max_age(self, filename):
return 10 return 10
@ -280,10 +297,12 @@ class SendfileTestCase(FlaskTestCase):
rv = app.send_static_file('index.html') rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 10) self.assert_equal(cc.max_age, 10)
rv.close()
# Test again with direct use of send_file utility. # Test again with direct use of send_file utility.
rv = flask.send_file('static/index.html') rv = flask.send_file('static/index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 10) self.assert_equal(cc.max_age, 10)
rv.close()
class LoggingTestCase(FlaskTestCase): class LoggingTestCase(FlaskTestCase):
@ -291,10 +310,10 @@ class LoggingTestCase(FlaskTestCase):
def test_logger_cache(self): def test_logger_cache(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
logger1 = app.logger logger1 = app.logger
self.assert_(app.logger is logger1) self.assert_true(app.logger is logger1)
self.assert_equal(logger1.name, __name__) self.assert_equal(logger1.name, __name__)
app.logger_name = __name__ + '/test_logger_cache' 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): def test_debug_log(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -308,16 +327,16 @@ class LoggingTestCase(FlaskTestCase):
@app.route('/exc') @app.route('/exc')
def exc(): def exc():
1/0 1 // 0
with app.test_client() as c: with app.test_client() as c:
with catch_stderr() as err: with catch_stderr() as err:
c.get('/') c.get('/')
out = err.getvalue() out = err.getvalue()
self.assert_('WARNING in helpers [' in out) self.assert_in('WARNING in helpers [', out)
self.assert_(os.path.basename(__file__.rsplit('.', 1)[0] + '.py') in out) self.assert_in(os.path.basename(__file__.rsplit('.', 1)[0] + '.py'), out)
self.assert_('the standard library is dead' in out) self.assert_in('the standard library is dead', out)
self.assert_('this is a debug statement' in out) self.assert_in('this is a debug statement', out)
with catch_stderr() as err: with catch_stderr() as err:
try: try:
@ -325,7 +344,7 @@ class LoggingTestCase(FlaskTestCase):
except ZeroDivisionError: except ZeroDivisionError:
pass pass
else: else:
self.assert_(False, 'debug log ate the exception') self.assert_true(False, 'debug log ate the exception')
def test_debug_log_override(self): def test_debug_log_override(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -342,28 +361,28 @@ class LoggingTestCase(FlaskTestCase):
@app.route('/') @app.route('/')
def index(): def index():
1/0 1 // 0
rv = app.test_client().get('/') rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500) 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() err = out.getvalue()
self.assert_('Exception on / [GET]' in err) self.assert_in('Exception on / [GET]', err)
self.assert_('Traceback (most recent call last):' in err) self.assert_in('Traceback (most recent call last):', err)
self.assert_('1/0' in err) self.assert_in('1 // 0', err)
self.assert_('ZeroDivisionError:' in err) self.assert_in('ZeroDivisionError:', err)
def test_processor_exceptions(self): def test_processor_exceptions(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@app.before_request @app.before_request
def before_request(): def before_request():
if trigger == 'before': if trigger == 'before':
1/0 1 // 0
@app.after_request @app.after_request
def after_request(response): def after_request(response):
if trigger == 'after': if trigger == 'after':
1/0 1 // 0
return response return response
@app.route('/') @app.route('/')
def index(): def index():
@ -374,7 +393,7 @@ class LoggingTestCase(FlaskTestCase):
for trigger in 'before', 'after': for trigger in 'before', 'after':
rv = app.test_client().get('/') rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500) 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): def test_url_for_with_anchor(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -466,7 +485,7 @@ class StreamingTestCase(FlaskTestCase):
return flask.Response(flask.stream_with_context(generate())) return flask.Response(flask.stream_with_context(generate()))
c = app.test_client() c = app.test_client()
rv = c.get('/?name=World') 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): def test_streaming_with_context_as_decorator(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
@ -481,12 +500,13 @@ class StreamingTestCase(FlaskTestCase):
return flask.Response(generate()) return flask.Response(generate())
c = app.test_client() c = app.test_client()
rv = c.get('/?name=World') 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): def test_streaming_with_context_and_custom_close(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.testing = True app.testing = True
called = [] called = []
@implements_iterator
class Wrapper(object): class Wrapper(object):
def __init__(self, gen): def __init__(self, gen):
self._gen = gen self._gen = gen
@ -494,8 +514,8 @@ class StreamingTestCase(FlaskTestCase):
return self return self
def close(self): def close(self):
called.append(42) called.append(42)
def next(self): def __next__(self):
return self._gen.next() return next(self._gen)
@app.route('/') @app.route('/')
def index(): def index():
def generate(): def generate():
@ -506,7 +526,7 @@ class StreamingTestCase(FlaskTestCase):
Wrapper(generate()))) Wrapper(generate())))
c = app.test_client() c = app.test_client()
rv = c.get('/?name=World') rv = c.get('/?name=World')
self.assertEqual(rv.data, 'Hello World!') self.assertEqual(rv.data, b'Hello World!')
self.assertEqual(called, [42]) self.assertEqual(called, [42])

8
flask/testsuite/regression.py

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

36
flask/testsuite/reqctx.py

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

9
flask/testsuite/signals.py

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

6
flask/testsuite/subclassing.py

@ -11,9 +11,9 @@
""" """
import flask import flask
import unittest import unittest
from StringIO import StringIO
from logging import StreamHandler from logging import StreamHandler
from flask.testsuite import FlaskTestCase from flask.testsuite import FlaskTestCase
from flask._compat import StringIO
class FlaskSubclassingTestCase(FlaskTestCase): class FlaskSubclassingTestCase(FlaskTestCase):
@ -30,11 +30,11 @@ class FlaskSubclassingTestCase(FlaskTestCase):
@app.route('/') @app.route('/')
def index(): def index():
1/0 1 // 0
rv = app.test_client().get('/') rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500) 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() err = out.getvalue()
self.assert_equal(err, '') self.assert_equal(err, '')

68
flask/testsuite/templating.py

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

47
flask/testsuite/testing.py

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

20
flask/testsuite/views.py

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

5
flask/views.py

@ -9,6 +9,7 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
from .globals import request from .globals import request
from ._compat import with_metaclass
http_method_funcs = frozenset(['get', 'post', 'head', 'options', http_method_funcs = frozenset(['get', 'post', 'head', 'options',
@ -119,7 +120,7 @@ class MethodViewType(type):
return rv return rv
class MethodView(View): class MethodView(with_metaclass(MethodViewType, View)):
"""Like a regular class-based view but that dispatches requests to """Like a regular class-based view but that dispatches requests to
particular methods. For instance if you implement a method called particular methods. For instance if you implement a method called
:meth:`get` it means you will response to ``'GET'`` requests and :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')) app.add_url_rule('/counter', view_func=CounterAPI.as_view('counter'))
""" """
__metaclass__ = MethodViewType
def dispatch_request(self, *args, **kwargs): def dispatch_request(self, *args, **kwargs):
meth = getattr(self, request.method.lower(), None) meth = getattr(self, request.method.lower(), None)
# if the request method is HEAD and we don't have a handler for it # 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): def json(self):
"""If the mimetype is `application/json` this will contain the """If the mimetype is `application/json` this will contain the
parsed JSON data. Otherwise this will be `None`. parsed JSON data. Otherwise this will be `None`.
This requires Python 2.6 or an installed version of simplejson.
""" """
if self.mimetype == 'application/json': if self.mimetype == 'application/json':
request_charset = self.mimetype_params.get('charset') request_charset = self.mimetype_params.get('charset')
@ -101,7 +99,7 @@ class Request(RequestBase):
if request_charset is not None: if request_charset is not None:
return json.loads(self.data, encoding=request_charset) return json.loads(self.data, encoding=request_charset)
return json.loads(self.data) return json.loads(self.data)
except ValueError, e: except ValueError as e:
return self.on_json_loading_failed(e) return self.on_json_loading_failed(e)
def on_json_loading_failed(self, e): def on_json_loading_failed(self, e):

4
scripts/flask-07-upgrade.py

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

2
scripts/flaskext_test.py

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

10
setup.py

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