Merge branch 'master' of github.com:mitsuhiko/flask
This commit is contained in:
commit
2e816f554a
21 changed files with 166 additions and 56 deletions
15
.travis.yml
Normal file
15
.travis.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
language: python
|
||||||
|
|
||||||
|
python:
|
||||||
|
- 2.5
|
||||||
|
- 2.6
|
||||||
|
- 2.7
|
||||||
|
- pypy
|
||||||
|
|
||||||
|
before_install: pip install simplejson
|
||||||
|
|
||||||
|
script: python setup.py test
|
||||||
|
|
||||||
|
branches:
|
||||||
|
except:
|
||||||
|
- website
|
||||||
|
|
@ -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
|
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
|
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
|
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
|
Flask extensions. Explore the many `extensions
|
||||||
patterns to build your own extensions if you do not find the tools you need.
|
<http://flask.pocoo.org/extensions/>` in the community, and look for patterns to
|
||||||
|
build your own extensions if you do not find the tools you need.
|
||||||
|
|
||||||
Subclass.
|
Subclass.
|
||||||
---------
|
---------
|
||||||
|
|
|
||||||
|
|
@ -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
|
`.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.
|
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
|
.. sourcecode:: apache
|
||||||
|
|
||||||
ScriptAlias /app /path/to/the/application.cgi
|
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.
|
For more information consult the documentation of your webserver.
|
||||||
|
|
||||||
.. _App Engine: http://code.google.com/appengine/
|
.. _App Engine: http://code.google.com/appengine/
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ Set yourapplication.fcgi::
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
environ['SCRIPT_NAME'] = ''
|
environ['SCRIPT_NAME'] = ''
|
||||||
return self.app(environ, start_response)
|
return self.app(environ, start_response)
|
||||||
|
|
||||||
app = ScriptNameStripper(app)
|
app = ScriptNameStripper(app)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
that people can easily install the development version into their
|
||||||
virtualenv without having to download the library by hand.
|
virtualenv without having to download the library by hand.
|
||||||
|
|
||||||
Flask extensions must be licensed as BSD or MIT or a more liberal license
|
Flask extensions must be licensed under a BSD, MIT or more liberal license
|
||||||
to be enlisted on the Flask Extension Registry. Keep in mind that the
|
to be able to be enlisted in the Flask Extension Registry. Keep in mind
|
||||||
Flask Extension Registry is a moderated place and libraries will be
|
that the Flask Extension Registry is a moderated place and libraries will
|
||||||
reviewed upfront if they behave as required.
|
be reviewed upfront if they behave as required.
|
||||||
|
|
||||||
"Hello Flaskext!"
|
"Hello Flaskext!"
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
||||||
|
|
@ -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'}
|
>>> user = {'name': u'admin', 'email': u'admin@localhost'}
|
||||||
>>> collection.insert(user)
|
>>> collection.insert(user)
|
||||||
|
|
||||||
print list(collection.find())
|
|
||||||
print collection.find_one({'name': u'admin'})
|
|
||||||
|
|
||||||
MongoKit will automatically commit for us.
|
MongoKit will automatically commit for us.
|
||||||
|
|
||||||
To query your database, you use the collection directly:
|
To query your database, you use the collection directly:
|
||||||
|
|
|
||||||
|
|
@ -514,8 +514,9 @@ attributes mentioned above::
|
||||||
return log_the_user_in(request.form['username'])
|
return log_the_user_in(request.form['username'])
|
||||||
else:
|
else:
|
||||||
error = 'Invalid username/password'
|
error = 'Invalid username/password'
|
||||||
# this is executed if the request method was GET or the
|
# the code below this is executed if the request method
|
||||||
# credentials were invalid
|
# 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
|
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
|
case a special :exc:`KeyError` is raised. You can catch it like a
|
||||||
|
|
|
||||||
11
examples/blueprintexample/blueprintexample.py
Normal file
11
examples/blueprintexample/blueprintexample.py
Normal file
|
|
@ -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)
|
||||||
36
examples/blueprintexample/blueprintexample_test.py
Normal file
36
examples/blueprintexample/blueprintexample_test.py
Normal file
|
|
@ -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()
|
||||||
0
examples/blueprintexample/simple_page/__init__.py
Normal file
0
examples/blueprintexample/simple_page/__init__.py
Normal file
13
examples/blueprintexample/simple_page/simple_page.py
Normal file
13
examples/blueprintexample/simple_page/simple_page.py
Normal file
|
|
@ -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('/<page>')
|
||||||
|
def show(page):
|
||||||
|
try:
|
||||||
|
return render_template('pages/%s.html' % page)
|
||||||
|
except TemplateNotFound:
|
||||||
|
abort(404)
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "pages/layout.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
Hello
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "pages/layout.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
Blueprint example page
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<!doctype html>
|
||||||
|
<title>Simple Page Blueprint</title>
|
||||||
|
<div class=page>
|
||||||
|
<h1>This is blueprint example</h1>
|
||||||
|
<p>
|
||||||
|
A simple page blueprint is registered under / and /pages<br/>
|
||||||
|
you can access it using this urls:
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{ url_for('simple_page.show', page='hello') }}">/hello</a></li>
|
||||||
|
<li><a href="{{ url_for('simple_page.show', page='world') }}">/world</a></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Also you can register the same blueprint under another path
|
||||||
|
<ul>
|
||||||
|
<li><a href="/pages/hello">/pages/hello</a></li>
|
||||||
|
<li><a href="/pages/world">/pages/world</a></li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "pages/layout.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
World
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -1490,7 +1490,7 @@ class Flask(_PackageBoundObject):
|
||||||
"""
|
"""
|
||||||
funcs = self.url_default_functions.get(None, ())
|
funcs = self.url_default_functions.get(None, ())
|
||||||
if '.' in endpoint:
|
if '.' in endpoint:
|
||||||
bp = endpoint.split('.', 1)[0]
|
bp = endpoint.rsplit('.', 1)[0]
|
||||||
funcs = chain(funcs, self.url_default_functions.get(bp, ()))
|
funcs = chain(funcs, self.url_default_functions.get(bp, ()))
|
||||||
for func in funcs:
|
for func in funcs:
|
||||||
func(endpoint, values)
|
func(endpoint, values)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ def after_this_request(f):
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
@after_this_request
|
@after_this_request
|
||||||
def add_header():
|
def add_header(response):
|
||||||
response.headers['X-Foo'] = 'Parachute'
|
response.headers['X-Foo'] = 'Parachute'
|
||||||
return response
|
return response
|
||||||
return 'Hello World!'
|
return 'Hello World!'
|
||||||
|
|
|
||||||
|
|
@ -118,31 +118,9 @@ def jsonify(*args, **kwargs):
|
||||||
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
|
||||||
|
|
||||||
.. 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__:
|
if __debug__:
|
||||||
_assert_have_json()
|
_assert_have_json()
|
||||||
if 'padded' in kwargs:
|
|
||||||
if isinstance(kwargs['padded'], str):
|
|
||||||
callback = request.args.get(kwargs['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')
|
|
||||||
return current_app.response_class(json.dumps(dict(*args, **kwargs),
|
return current_app.response_class(json.dumps(dict(*args, **kwargs),
|
||||||
indent=None if request.is_xhr else 2), mimetype='application/json')
|
indent=None if request.is_xhr else 2), mimetype='application/json')
|
||||||
|
|
||||||
|
|
@ -529,7 +507,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||||
rv.cache_control.public = True
|
rv.cache_control.public = True
|
||||||
if cache_timeout is None:
|
if cache_timeout is None:
|
||||||
cache_timeout = current_app.get_send_file_max_age(filename)
|
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.cache_control.max_age = cache_timeout
|
||||||
rv.expires = int(time() + cache_timeout)
|
rv.expires = int(time() + cache_timeout)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -953,6 +953,29 @@ class BasicFunctionalityTestCase(FlaskTestCase):
|
||||||
self.assert_equal(c.get('/de/').data, '/de/about')
|
self.assert_equal(c.get('/de/').data, '/de/about')
|
||||||
self.assert_equal(c.get('/de/about').data, '/foo')
|
self.assert_equal(c.get('/de/about').data, '/foo')
|
||||||
self.assert_equal(c.get('/foo').data, '/en/about')
|
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('/<page>')
|
||||||
|
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):
|
def test_debug_mode_complains_after_first_request(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
|
||||||
|
|
@ -73,28 +73,11 @@ class JSONTestCase(FlaskTestCase):
|
||||||
@app.route('/dict')
|
@app.route('/dict')
|
||||||
def return_dict():
|
def return_dict():
|
||||||
return flask.jsonify(d)
|
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()
|
c = app.test_client()
|
||||||
for url in '/kw', '/dict', '/unpadded':
|
for url in '/kw', '/dict':
|
||||||
rv = c.get(url)
|
rv = c.get(url)
|
||||||
self.assert_equal(rv.mimetype, 'application/json')
|
self.assert_equal(rv.mimetype, 'application/json')
|
||||||
self.assert_equal(flask.json.loads(rv.data), d)
|
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):
|
def test_json_attr(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
import flaskext_compat
|
import flaskext_compat
|
||||||
|
flaskext_compat.activate()
|
||||||
from flask.ext import foo
|
from flask.ext import foo
|
||||||
|
|
||||||
:copyright: (c) 2011 by Armin Ronacher.
|
:copyright: (c) 2011 by Armin Ronacher.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue