From 85ad4ffb605eee37cae9ffa1f82c5b6bb95c7820 Mon Sep 17 00:00:00 2001 From: Dmitry Shevchenko Date: Thu, 1 Mar 2012 02:07:26 -0600 Subject: [PATCH 01/17] Blueprint example app --- examples/blueprintexample/blueprintexample.py | 11 ++++++++ .../blueprintexample/simple_page/__init__.py | 0 .../simple_page/simple_page.py | 13 ++++++++++ .../simple_page/templates/pages/hello.html | 5 ++++ .../simple_page/templates/pages/index.html | 5 ++++ .../simple_page/templates/pages/layout.html | 25 +++++++++++++++++++ .../simple_page/templates/pages/world.html | 5 ++++ 7 files changed, 64 insertions(+) create mode 100644 examples/blueprintexample/blueprintexample.py create mode 100644 examples/blueprintexample/simple_page/__init__.py create mode 100644 examples/blueprintexample/simple_page/simple_page.py create mode 100644 examples/blueprintexample/simple_page/templates/pages/hello.html create mode 100644 examples/blueprintexample/simple_page/templates/pages/index.html create mode 100644 examples/blueprintexample/simple_page/templates/pages/layout.html create mode 100644 examples/blueprintexample/simple_page/templates/pages/world.html diff --git a/examples/blueprintexample/blueprintexample.py b/examples/blueprintexample/blueprintexample.py new file mode 100644 index 00000000..bc0e41d4 --- /dev/null +++ b/examples/blueprintexample/blueprintexample.py @@ -0,0 +1,11 @@ +from flask import Flask +from simple_page.simple_page import simple_page + +app = Flask(__name__) +app.register_blueprint(simple_page) +# Blueprint can be registered many times +app.register_blueprint(simple_page, url_prefix='/pages') + + +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file diff --git a/examples/blueprintexample/simple_page/__init__.py b/examples/blueprintexample/simple_page/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/blueprintexample/simple_page/simple_page.py b/examples/blueprintexample/simple_page/simple_page.py new file mode 100644 index 00000000..cb82cc37 --- /dev/null +++ b/examples/blueprintexample/simple_page/simple_page.py @@ -0,0 +1,13 @@ +from flask import Blueprint, render_template, abort +from jinja2 import TemplateNotFound + +simple_page = Blueprint('simple_page', __name__, + template_folder='templates') + +@simple_page.route('/', defaults={'page': 'index'}) +@simple_page.route('/') +def show(page): + try: + return render_template('pages/%s.html' % page) + except TemplateNotFound: + abort(404) diff --git a/examples/blueprintexample/simple_page/templates/pages/hello.html b/examples/blueprintexample/simple_page/templates/pages/hello.html new file mode 100644 index 00000000..7fca6668 --- /dev/null +++ b/examples/blueprintexample/simple_page/templates/pages/hello.html @@ -0,0 +1,5 @@ +{% extends "pages/layout.html" %} + +{% block body %} + Hello +{% endblock %} \ No newline at end of file diff --git a/examples/blueprintexample/simple_page/templates/pages/index.html b/examples/blueprintexample/simple_page/templates/pages/index.html new file mode 100644 index 00000000..0ca3ffe2 --- /dev/null +++ b/examples/blueprintexample/simple_page/templates/pages/index.html @@ -0,0 +1,5 @@ +{% extends "pages/layout.html" %} + +{% block body %} + Blueprint example page +{% endblock %} \ No newline at end of file diff --git a/examples/blueprintexample/simple_page/templates/pages/layout.html b/examples/blueprintexample/simple_page/templates/pages/layout.html new file mode 100644 index 00000000..2efccb95 --- /dev/null +++ b/examples/blueprintexample/simple_page/templates/pages/layout.html @@ -0,0 +1,25 @@ + +Simple Page Blueprint +
+

This is blueprint example

+

+ A simple page blueprint is registered under / and /pages
+ you can access it using this urls: +

+

+

+ Also you can register the same blueprint under another path +

+

+ + + + {% block body %} + {% endblock %} +
\ No newline at end of file diff --git a/examples/blueprintexample/simple_page/templates/pages/world.html b/examples/blueprintexample/simple_page/templates/pages/world.html new file mode 100644 index 00000000..bdb5b16b --- /dev/null +++ b/examples/blueprintexample/simple_page/templates/pages/world.html @@ -0,0 +1,5 @@ +{% extends "pages/layout.html" %} + +{% block body %} + World +{% endblock %} \ No newline at end of file From 62621ccd133ffcbe2c88d18841c0669d03739ac0 Mon Sep 17 00:00:00 2001 From: Dmitry Shevchenko Date: Thu, 1 Mar 2012 02:24:56 -0600 Subject: [PATCH 02/17] Blueprint example tests --- .../blueprintexample/blueprintexample_test.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 examples/blueprintexample/blueprintexample_test.py diff --git a/examples/blueprintexample/blueprintexample_test.py b/examples/blueprintexample/blueprintexample_test.py new file mode 100644 index 00000000..b8f93414 --- /dev/null +++ b/examples/blueprintexample/blueprintexample_test.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +""" + Blueprint Example Tests + ~~~~~~~~~~~~~~ + + Tests the Blueprint example app +""" +import blueprintexample +import unittest + + +class BlueprintExampleTestCase(unittest.TestCase): + + def setUp(self): + self.app = blueprintexample.app.test_client() + + def test_urls(self): + r = self.app.get('/') + self.assertEquals(r.status_code, 200) + + r = self.app.get('/hello') + self.assertEquals(r.status_code, 200) + + r = self.app.get('/world') + self.assertEquals(r.status_code, 200) + + #second blueprint instance + r = self.app.get('/pages/hello') + self.assertEquals(r.status_code, 200) + + r = self.app.get('/pages/world') + self.assertEquals(r.status_code, 200) + + +if __name__ == '__main__': + unittest.main() From 9c48387072128c32dde06dc9a6e812195f18012d Mon Sep 17 00:00:00 2001 From: Dmitry Shevchenko Date: Sun, 8 Apr 2012 18:09:12 -0500 Subject: [PATCH 03/17] Removed unneeded print statements form mongokit pattern doc --- docs/patterns/mongokit.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/patterns/mongokit.rst b/docs/patterns/mongokit.rst index b50cf456..b4b6fc01 100644 --- a/docs/patterns/mongokit.rst +++ b/docs/patterns/mongokit.rst @@ -122,9 +122,6 @@ collection first, this is somewhat the same as a table in the SQL world. >>> user = {'name': u'admin', 'email': u'admin@localhost'} >>> collection.insert(user) -print list(collection.find()) -print collection.find_one({'name': u'admin'}) - MongoKit will automatically commit for us. To query your database, you use the collection directly: From 36194697ae8371f42d3041c1f89b6f2e77c34826 Mon Sep 17 00:00:00 2001 From: ekoka Date: Sat, 21 Apr 2012 23:36:08 -0300 Subject: [PATCH 04/17] Update flask/app.py --- flask/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flask/app.py b/flask/app.py index 4c00c36b..4328c35b 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1468,7 +1468,7 @@ class Flask(_PackageBoundObject): """ funcs = self.url_default_functions.get(None, ()) if '.' in endpoint: - bp = endpoint.split('.', 1)[0] + bp = endpoint.rsplit('.', 1)[0] funcs = chain(funcs, self.url_default_functions.get(bp, ())) for func in funcs: func(endpoint, values) From 12dcba8849d153c7e13e99b6bcf57922e1a97240 Mon Sep 17 00:00:00 2001 From: ekoka Date: Tue, 24 Apr 2012 05:32:52 -0300 Subject: [PATCH 05/17] Update flask/testsuite/basic.py --- flask/testsuite/basic.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/flask/testsuite/basic.py b/flask/testsuite/basic.py index 0a4b1d9c..c2acca57 100644 --- a/flask/testsuite/basic.py +++ b/flask/testsuite/basic.py @@ -911,6 +911,29 @@ class BasicFunctionalityTestCase(FlaskTestCase): self.assert_equal(c.get('/de/').data, '/de/about') self.assert_equal(c.get('/de/about').data, '/foo') self.assert_equal(c.get('/foo').data, '/en/about') + + def test_inject_blueprint_url_defaults(self): + app = flask.Flask(__name__) + bp = flask.Blueprint('foo.bar.baz', __name__, + template_folder='template') + + @bp.url_defaults + def bp_defaults(endpoint, values): + values['page'] = 'login' + @bp.route('/') + def view(page): pass + + app.register_blueprint(bp) + + values = dict() + app.inject_url_defaults('foo.bar.baz.view', values) + expected = dict(page='login') + self.assert_equal(values, expected) + + with app.test_request_context('/somepage'): + url = flask.url_for('foo.bar.baz.view') + expected = '/login' + self.assert_equal(url, expected) def test_debug_mode_complains_after_first_request(self): app = flask.Flask(__name__) From 444698d42b6cd2bb356d3ac6a7fa9f2be7e0df55 Mon Sep 17 00:00:00 2001 From: Alex Vykalyuk Date: Mon, 14 May 2012 23:39:27 +0300 Subject: [PATCH 06/17] Changed docstring according to docs. --- scripts/flaskext_compat.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/flaskext_compat.py b/scripts/flaskext_compat.py index 2f58ccc4..cb0b436c 100644 --- a/scripts/flaskext_compat.py +++ b/scripts/flaskext_compat.py @@ -9,6 +9,7 @@ Usage:: import flaskext_compat + flaskext_compat.activate() from flask.ext import foo :copyright: (c) 2011 by Armin Ronacher. From 447afc3525b009ed369943e13437d98e07898bdc Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 27 May 2012 18:02:54 -0700 Subject: [PATCH 07/17] Fix failing test: "AssertionError: 'application/javascript' != 'application/json'" in flask/testsuite/helpers.py", line 88 --- flask/helpers.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/flask/helpers.py b/flask/helpers.py index e633e1b9..72a961a8 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -133,13 +133,17 @@ def jsonify(*args, **kwargs): """ if __debug__: _assert_have_json() + + padded = kwargs.get('padded', False) if 'padded' in kwargs: - if isinstance(kwargs['padded'], str): - callback = request.args.get(kwargs['padded']) or 'jsonp' + del kwargs['padded'] + + if padded: + if isinstance(padded, str): + callback = request.args.get(padded) or 'jsonp' else: callback = request.args.get('callback') or \ request.args.get('jsonp') or 'jsonp' - del kwargs['padded'] json_str = json.dumps(dict(*args, **kwargs), indent=None) content = str(callback) + "(" + json_str + ")" return current_app.response_class(content, mimetype='application/javascript') From 2c8cbeb0c0b577f8588aa832c4bb763b8e5b3b82 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Sun, 27 May 2012 18:31:07 -0700 Subject: [PATCH 08/17] Add .travis.yml --- .travis.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..d02cae02 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +language: python + +python: + - 2.5 + - 2.6 + - 2.7 + - pypy + +before_install: pip install simplejson + +script: python setup.py test From 99aaacb1a99891aa2eb57f6fe9b8a0c3f87cb454 Mon Sep 17 00:00:00 2001 From: Natan L Date: Wed, 30 May 2012 20:23:02 -0700 Subject: [PATCH 09/17] Emended extensiondev.rst. --- docs/extensiondev.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/extensiondev.rst b/docs/extensiondev.rst index 59ca76c5..d266e1a2 100644 --- a/docs/extensiondev.rst +++ b/docs/extensiondev.rst @@ -47,10 +47,10 @@ registered on PyPI. Also the development checkout link should work so that people can easily install the development version into their virtualenv without having to download the library by hand. -Flask extensions must be licensed as BSD or MIT or a more liberal license -to be enlisted on the Flask Extension Registry. Keep in mind that the -Flask Extension Registry is a moderated place and libraries will be -reviewed upfront if they behave as required. +Flask extensions must be licensed under a BSD, MIT or more liberal license +to be able to be enlisted in the Flask Extension Registry. Keep in mind +that the Flask Extension Registry is a moderated place and libraries will +be reviewed upfront if they behave as required. "Hello Flaskext!" ----------------- From 5c2aa7a9210acb4b16b86d5cda5264a2f5d11aa2 Mon Sep 17 00:00:00 2001 From: Ben Rousch Date: Tue, 12 Jun 2012 14:26:10 -0300 Subject: [PATCH 10/17] Added link to extensions in "Hook. Extend." section. --- docs/becomingbig.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/becomingbig.rst b/docs/becomingbig.rst index ca803060..8d531620 100644 --- a/docs/becomingbig.rst +++ b/docs/becomingbig.rst @@ -25,8 +25,9 @@ The :ref:`api` docs are full of available overrides, hook points, and response objects. Dig deeper on the APIs you use, and look for the customizations which are available out of the box in a Flask release. Look for ways in which your project can be refactored into a collection of utilities and -Flask extensions. Explore the many extensions in the community, and look for -patterns to build your own extensions if you do not find the tools you need. +Flask extensions. Explore the many `extensions +` in the community, and look for patterns to +build your own extensions if you do not find the tools you need. Subclass. --------- From 4b21e2d38ccf66f236c5f1c8a10bd9d7904f2599 Mon Sep 17 00:00:00 2001 From: Massimo Santini Date: Wed, 13 Jun 2012 16:43:34 +0300 Subject: [PATCH 11/17] I think it should check that cache_timeout is not None to allow for a (I hope legale) value of 0 for such parameter. --- flask/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flask/helpers.py b/flask/helpers.py index 72a961a8..18502a53 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -533,7 +533,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False, rv.cache_control.public = True if cache_timeout is None: cache_timeout = current_app.get_send_file_max_age(filename) - if cache_timeout: + if cache_timeout is not None: rv.cache_control.max_age = cache_timeout rv.expires = int(time() + cache_timeout) From 5bbf8bdcd9619fa15a3380f99fe6d66d08b1f783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramiro=20G=C3=B3mez?= Date: Sun, 17 Jun 2012 02:22:02 +0300 Subject: [PATCH 12/17] Update master --- docs/deploying/fastcgi.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deploying/fastcgi.rst b/docs/deploying/fastcgi.rst index b2801560..0e2f6cdc 100644 --- a/docs/deploying/fastcgi.rst +++ b/docs/deploying/fastcgi.rst @@ -102,7 +102,7 @@ Set yourapplication.fcgi:: def __call__(self, environ, start_response): environ['SCRIPT_NAME'] = '' - return self.app(environ, start_response) + return self.app(environ, start_response) app = ScriptNameStripper(app) From 6809ffccf2b8b94633717f839b42ae8e3fbca1c3 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 17 Jun 2012 14:13:53 +0100 Subject: [PATCH 13/17] Don't build websites with travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index d02cae02..8cd434d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,7 @@ python: before_install: pip install simplejson script: python setup.py test + +branches: + except: + - website From b04827283ea36cc456367f1ac4e0700b90b71283 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 17 Jun 2012 14:17:22 +0100 Subject: [PATCH 14/17] Removed padded JSON (JSONP) again. The implementation was not clean and generally the needs for padded json are disappearing now that all browsers support cross site communication with the regular xmlhttprequest. --- flask/helpers.py | 26 -------------------------- flask/testsuite/helpers.py | 19 +------------------ 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/flask/helpers.py b/flask/helpers.py index 18502a53..71bc3142 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -118,35 +118,9 @@ def jsonify(*args, **kwargs): information about this, have a look at :ref:`json-security`. .. versionadded:: 0.2 - - .. versionadded:: 0.9 - If the ``padded`` argument is true, the JSON object will be padded - for JSONP calls and the response mimetype will be changed to - ``application/javascript``. By default, the request arguments ``callback`` - and ``jsonp`` will be used as the name for the callback function. - This will work with jQuery and most other JavaScript libraries - by default. - - If the ``padded`` argument is a string, jsonify will look for - the request argument with the same name and use that value as the - callback-function name. """ if __debug__: _assert_have_json() - - padded = kwargs.get('padded', False) - if 'padded' in kwargs: - del kwargs['padded'] - - if padded: - if isinstance(padded, str): - callback = request.args.get(padded) or 'jsonp' - else: - callback = request.args.get('callback') or \ - request.args.get('jsonp') or 'jsonp' - json_str = json.dumps(dict(*args, **kwargs), indent=None) - content = str(callback) + "(" + json_str + ")" - return current_app.response_class(content, mimetype='application/javascript') return current_app.response_class(json.dumps(dict(*args, **kwargs), indent=None if request.is_xhr else 2), mimetype='application/json') diff --git a/flask/testsuite/helpers.py b/flask/testsuite/helpers.py index a0e60aac..816f6cd8 100644 --- a/flask/testsuite/helpers.py +++ b/flask/testsuite/helpers.py @@ -73,28 +73,11 @@ class JSONTestCase(FlaskTestCase): @app.route('/dict') def return_dict(): return flask.jsonify(d) - @app.route("/unpadded") - def return_padded_false(): - return flask.jsonify(d, padded=False) - @app.route("/padded") - def return_padded_true(): - return flask.jsonify(d, padded=True) - @app.route("/padded_custom") - def return_padded_json_custom_callback(): - return flask.jsonify(d, padded='my_func_name') c = app.test_client() - for url in '/kw', '/dict', '/unpadded': + for url in '/kw', '/dict': rv = c.get(url) self.assert_equal(rv.mimetype, 'application/json') self.assert_equal(flask.json.loads(rv.data), d) - for get_arg in 'callback=funcName', 'jsonp=funcName': - rv = c.get('/padded?' + get_arg) - self.assert_( rv.data.startswith("funcName(") ) - self.assert_( rv.data.endswith(")") ) - rv_json = rv.data.split('(')[1].split(')')[0] - self.assert_equal(flask.json.loads(rv_json), d) - rv = c.get('/padded_custom?my_func_name=funcName') - self.assert_( rv.data.startswith("funcName(") ) def test_json_attr(self): app = flask.Flask(__name__) From 7b1c8fd15b619aee9eb6bc53dd50bd2d7e9bea3d Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 17 Jun 2012 14:22:15 +0100 Subject: [PATCH 15/17] Added #522 in modified version --- docs/deploying/cgi.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/deploying/cgi.rst b/docs/deploying/cgi.rst index a2fba90d..1de9bd2c 100644 --- a/docs/deploying/cgi.rst +++ b/docs/deploying/cgi.rst @@ -35,12 +35,23 @@ Usually there are two ways to configure the server. Either just copy the `.cgi` into a `cgi-bin` (and use `mod_rewrite` or something similar to rewrite the URL) or let the server point to the file directly. -In Apache for example you can put a like like this into the config: +In Apache for example you can put something like this into the config: .. sourcecode:: apache ScriptAlias /app /path/to/the/application.cgi +On shared webhosting, though, you might not have access to your Apache config. +In this case, a file called `.htaccess`, sitting in the public directory you want +your app to be available, works too but the `ScriptAlias` directive won't +work in that case: + +.. sourcecode:: apache + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f # Don't interfere with static files + RewriteRule ^(.*)$ /path/to/the/application.cgi/$1 [L] + For more information consult the documentation of your webserver. .. _App Engine: http://code.google.com/appengine/ From 1f3e667b5d9ffb60c218c250df27144793a5acdb Mon Sep 17 00:00:00 2001 From: Matt Wright Date: Mon, 18 Jun 2012 18:33:17 -0300 Subject: [PATCH 16/17] Fix documention for `after_this_request` --- flask/ctx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flask/ctx.py b/flask/ctx.py index 52eddcb2..f64ab04a 100644 --- a/flask/ctx.py +++ b/flask/ctx.py @@ -41,7 +41,7 @@ def after_this_request(f): @app.route('/') def index(): @after_this_request - def add_header(): + def add_header(response): response.headers['X-Foo'] = 'Parachute' return response return 'Hello World!' From 1f82d02b33dad8ac7a4aa49e690767027690fe1a Mon Sep 17 00:00:00 2001 From: bev-a-tron Date: Mon, 25 Jun 2012 13:31:11 -0400 Subject: [PATCH 17/17] Fixes #519 by adding return statement --- docs/quickstart.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index e8b71ca9..53ef38d4 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -514,8 +514,9 @@ attributes mentioned above:: return log_the_user_in(request.form['username']) else: error = 'Invalid username/password' - # this is executed if the request method was GET or the - # credentials were invalid + # the code below this is executed if the request method + # was GET or the credentials were invalid + return render_template('login.html', error=error) What happens if the key does not exist in the `form` attribute? In that case a special :exc:`KeyError` is raised. You can catch it like a