From f034d8d3451f590fca1badeac5da0230bed9b148 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 7 Oct 2012 12:51:46 +0200 Subject: [PATCH] Add @template_test() decorator for creating custom jinja2 tests, like existing @template_filter() for filters. Fixes #332 --- flask/app.py | 38 ++++++ flask/blueprints.py | 28 +++++ flask/testsuite/blueprints.py | 116 ++++++++++++++++++- flask/testsuite/templates/template_test.html | 3 + flask/testsuite/templating.py | 91 +++++++++++++-- 5 files changed, 265 insertions(+), 11 deletions(-) create mode 100644 flask/testsuite/templates/template_test.html diff --git a/flask/app.py b/flask/app.py index 08fc3248ef..7940a349cf 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1086,6 +1086,44 @@ def add_template_filter(self, f, name=None): """ self.jinja_env.filters[name or f.__name__] = f + @setupmethod + def template_test(self, name=None): + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in xrange(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_template_test(f, name=name) + return f + return decorator + + @setupmethod + def add_template_test(self, f, name=None): + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod def before_request(self, f): """Registers a function to run before each request.""" diff --git a/flask/blueprints.py b/flask/blueprints.py index 9c55702891..7ce23bbc5b 100644 --- a/flask/blueprints.py +++ b/flask/blueprints.py @@ -209,6 +209,34 @@ def register_template(state): state.app.jinja_env.filters[name or f.__name__] = f self.record_once(register_template) + def app_template_test(self, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.template_test` but for a blueprint. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def decorator(f): + self.add_app_template_test(f, name=name) + return f + return decorator + + def add_app_template_test(self, f, name=None): + """Register a custom template test, available application wide. Like + :meth:`Flask.add_template_test` but for a blueprint. Works exactly + like the :meth:`app_template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + def register_template(state): + state.app.jinja_env.tests[name or f.__name__] = f + self.record_once(register_template) + def before_request(self, f): """Like :meth:`Flask.before_request` but for a blueprint. This function is only executed before each request that is handled by a function of diff --git a/flask/testsuite/blueprints.py b/flask/testsuite/blueprints.py index c962212199..ea047918ea 100644 --- a/flask/testsuite/blueprints.py +++ b/flask/testsuite/blueprints.py @@ -548,7 +548,7 @@ def my_reverse(s): return s[::-1] app = flask.Flask(__name__) app.register_blueprint(bp, url_prefix='/py') - self.assert_('my_reverse' in app.jinja_env.filters.keys()) + self.assert_('my_reverse' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse) self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba') @@ -559,7 +559,7 @@ def my_reverse(s): bp.add_app_template_filter(my_reverse) app = flask.Flask(__name__) app.register_blueprint(bp, url_prefix='/py') - self.assert_('my_reverse' in app.jinja_env.filters.keys()) + self.assert_('my_reverse' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse) self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba') @@ -570,7 +570,7 @@ def my_reverse(s): return s[::-1] app = flask.Flask(__name__) app.register_blueprint(bp, url_prefix='/py') - self.assert_('strrev' in app.jinja_env.filters.keys()) + self.assert_('strrev' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['strrev'], my_reverse) self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba') @@ -581,7 +581,7 @@ def my_reverse(s): bp.add_app_template_filter(my_reverse, 'strrev') app = flask.Flask(__name__) app.register_blueprint(bp, url_prefix='/py') - self.assert_('strrev' in app.jinja_env.filters.keys()) + self.assert_('strrev' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['strrev'], my_reverse) self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba') @@ -650,6 +650,114 @@ def index(): rv = app.test_client().get('/') self.assert_equal(rv.data, 'dcba') + def test_template_test(self): + bp = flask.Blueprint('bp', __name__) + @bp.app_template_test() + def is_boolean(value): + return isinstance(value, bool) + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + self.assert_('is_boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean) + self.assert_(app.jinja_env.tests['is_boolean'](False)) + + def test_add_template_test(self): + bp = flask.Blueprint('bp', __name__) + def is_boolean(value): + return isinstance(value, bool) + bp.add_app_template_test(is_boolean) + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + self.assert_('is_boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean) + self.assert_(app.jinja_env.tests['is_boolean'](False)) + + def test_template_test_with_name(self): + bp = flask.Blueprint('bp', __name__) + @bp.app_template_test('boolean') + def is_boolean(value): + return isinstance(value, bool) + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + self.assert_('boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['boolean'], is_boolean) + self.assert_(app.jinja_env.tests['boolean'](False)) + + def test_add_template_test_with_name(self): + bp = flask.Blueprint('bp', __name__) + def is_boolean(value): + return isinstance(value, bool) + bp.add_app_template_test(is_boolean, 'boolean') + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + self.assert_('boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['boolean'], is_boolean) + self.assert_(app.jinja_env.tests['boolean'](False)) + + def test_template_test_with_template(self): + bp = flask.Blueprint('bp', __name__) + @bp.app_template_test() + def boolean(value): + return isinstance(value, bool) + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + + def test_template_test_after_route_with_template(self): + app = flask.Flask(__name__) + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + bp = flask.Blueprint('bp', __name__) + @bp.app_template_test() + def boolean(value): + return isinstance(value, bool) + app.register_blueprint(bp, url_prefix='/py') + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + + def test_add_template_test_with_template(self): + bp = flask.Blueprint('bp', __name__) + def boolean(value): + return isinstance(value, bool) + bp.add_app_template_test(boolean) + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + + def test_template_test_with_name_and_template(self): + bp = flask.Blueprint('bp', __name__) + @bp.app_template_test('boolean') + def is_boolean(value): + return isinstance(value, bool) + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + + def test_add_template_test_with_name_and_template(self): + bp = flask.Blueprint('bp', __name__) + def is_boolean(value): + return isinstance(value, bool) + bp.add_app_template_test(is_boolean, 'boolean') + app = flask.Flask(__name__) + app.register_blueprint(bp, url_prefix='/py') + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) def suite(): suite = unittest.TestSuite() diff --git a/flask/testsuite/templates/template_test.html b/flask/testsuite/templates/template_test.html new file mode 100644 index 0000000000..92d5561bdd --- /dev/null +++ b/flask/testsuite/templates/template_test.html @@ -0,0 +1,3 @@ +{% if value is boolean %} + Success! +{% endif %} diff --git a/flask/testsuite/templating.py b/flask/testsuite/templating.py index 4a0ebdbccd..1df4292d70 100644 --- a/flask/testsuite/templating.py +++ b/flask/testsuite/templating.py @@ -89,7 +89,7 @@ def test_template_filter(self): @app.template_filter() def my_reverse(s): return s[::-1] - self.assert_('my_reverse' in app.jinja_env.filters.keys()) + self.assert_('my_reverse' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse) self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba') @@ -98,7 +98,7 @@ def test_add_template_filter(self): def my_reverse(s): return s[::-1] app.add_template_filter(my_reverse) - self.assert_('my_reverse' in app.jinja_env.filters.keys()) + self.assert_('my_reverse' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse) self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba') @@ -107,7 +107,7 @@ def test_template_filter_with_name(self): @app.template_filter('strrev') def my_reverse(s): return s[::-1] - self.assert_('strrev' in app.jinja_env.filters.keys()) + self.assert_('strrev' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['strrev'], my_reverse) self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba') @@ -116,7 +116,7 @@ def test_add_template_filter_with_name(self): def my_reverse(s): return s[::-1] app.add_template_filter(my_reverse, 'strrev') - self.assert_('strrev' in app.jinja_env.filters.keys()) + self.assert_('strrev' in app.jinja_env.filters.keys()) self.assert_equal(app.jinja_env.filters['strrev'], my_reverse) self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba') @@ -164,6 +164,86 @@ def index(): rv = app.test_client().get('/') self.assert_equal(rv.data, 'dcba') + def test_template_test(self): + app = flask.Flask(__name__) + @app.template_test() + def boolean(value): + return isinstance(value, bool) + self.assert_('boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['boolean'], boolean) + self.assert_(app.jinja_env.tests['boolean'](False)) + + def test_add_template_test(self): + app = flask.Flask(__name__) + def boolean(value): + return isinstance(value, bool) + app.add_template_test(boolean) + self.assert_('boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['boolean'], boolean) + self.assert_(app.jinja_env.tests['boolean'](False)) + + def test_template_test_with_name(self): + app = flask.Flask(__name__) + @app.template_test('boolean') + def is_boolean(value): + return isinstance(value, bool) + self.assert_('boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['boolean'], is_boolean) + self.assert_(app.jinja_env.tests['boolean'](False)) + + def test_add_template_test_with_name(self): + app = flask.Flask(__name__) + def is_boolean(value): + return isinstance(value, bool) + app.add_template_test(is_boolean, 'boolean') + self.assert_('boolean' in app.jinja_env.tests.keys()) + self.assert_equal(app.jinja_env.tests['boolean'], is_boolean) + self.assert_(app.jinja_env.tests['boolean'](False)) + + def test_template_test_with_template(self): + app = flask.Flask(__name__) + @app.template_test() + def boolean(value): + return isinstance(value, bool) + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + + def test_add_template_test_with_template(self): + app = flask.Flask(__name__) + def boolean(value): + return isinstance(value, bool) + app.add_template_test(boolean) + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + + def test_template_test_with_name_and_template(self): + app = flask.Flask(__name__) + @app.template_test('boolean') + def is_boolean(value): + return isinstance(value, bool) + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + + def test_add_template_test_with_name_and_template(self): + app = flask.Flask(__name__) + def is_boolean(value): + return isinstance(value, bool) + app.add_template_test(is_boolean, 'boolean') + @app.route('/') + def index(): + return flask.render_template('template_test.html', value=False) + rv = app.test_client().get('/') + self.assert_('Success!' in rv.data) + def test_custom_template_loader(self): class MyFlask(flask.Flask): def create_global_jinja_loader(self): @@ -177,7 +257,6 @@ def index(): rv = c.get('/') self.assert_equal(rv.data, 'Hello Custom World!') - def test_iterable_loader(self): app = flask.Flask(__name__) @app.context_processor @@ -195,8 +274,6 @@ def index(): self.assert_equal(rv.data, '

Jameson

') - - def suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TemplatingTestCase))