Browse Source

Merge branch 'master' of github.com:mitsuhiko/flask

pull/1017/head
Armin Ronacher 11 years ago
parent
commit
5fd81f702c
  1. 4
      CHANGES
  2. 15
      docs/blueprints.rst
  3. 9
      docs/config.rst
  4. 68
      docs/installation.rst
  5. 2
      docs/patterns/sqlalchemy.rst
  6. 2
      docs/unicode.rst
  7. 2
      examples/flaskr/schema.sql
  8. 12
      flask/app.py
  9. 11
      flask/blueprints.py
  10. 14
      flask/helpers.py
  11. 2
      flask/json.py
  12. 2
      flask/sessions.py
  13. 4
      flask/signals.py
  14. 33
      flask/testsuite/blueprints.py
  15. 4
      flask/testsuite/ext.py
  16. 2
      flask/testsuite/helpers.py
  17. 8
      flask/testsuite/templating.py
  18. 10
      flask/views.py
  19. 12
      flask/wrappers.py
  20. 5
      scripts/make-release.py

4
CHANGES

@ -21,6 +21,10 @@ Version 1.0
- Added :attr:`flask.Flask.config_class`.
- Added :meth:`flask.config.Config.get_namespace`.
- Added ``TEMPLATES_AUTO_RELOAD`` config key. If disabled the
templates will be reloaded only if the application is running in
debug mode. For higher performance it’s possible to disable that.
Version 0.10.2
--------------

15
docs/blueprints.rst

@ -202,3 +202,18 @@ you can use relative redirects by prefixing the endpoint with a dot only::
This will link to ``admin.index`` for instance in case the current request
was dispatched to any other admin blueprint endpoint.
Error Handlers
--------------
Blueprints support the errorhandler decorator just like the :class:`Flask`
application object, so it is easy to make Blueprint-specific custom error
pages.
Here is an example for a "404 Page Not Found" exception::
@simple_page.errorhandler(404)
def page_not_found(e):
return render_template('pages/404.html')
More information on error handling see :ref:`errorpages`.

9
docs/config.rst

@ -174,6 +174,12 @@ The following configuration values are used internally by Flask:
if they are not requested by an
XMLHttpRequest object (controlled by
the ``X-Requested-With`` header)
``TEMPLATES_AUTO_RELOAD`` Flask checks if template was modified each
time it is requested and reloads it if
necessary. But disk I/O is costly and it may
be viable to disable this feature by setting
this key to ``False``. This option does not
affect debug mode.
================================= =========================================
.. admonition:: More on ``SERVER_NAME``
@ -222,6 +228,9 @@ The following configuration values are used internally by Flask:
.. versionadded:: 1.0
``SESSION_REFRESH_EACH_REQUEST``
.. versionadded:: 1.0
``TEMPLATES_AUTO_RELOAD``
Configuring from Files
----------------------

68
docs/installation.rst

@ -3,7 +3,7 @@
Installation
============
Flask depends on two external libraries, `Werkzeug
Flask depends on some external libraries, like `Werkzeug
<http://werkzeug.pocoo.org/>`_ and `Jinja2 <http://jinja.pocoo.org/2/>`_.
Werkzeug is a toolkit for WSGI, the standard Python interface between web
applications and a variety of servers for both development and deployment.
@ -13,7 +13,7 @@ So how do you get all that on your computer quickly? There are many ways you
could do that, but the most kick-ass method is virtualenv, so let's have a look
at that first.
You will need Python 2.6 or higher to get started, so be sure to have an
You will need Python 2.6 or newer to get started, so be sure to have an
up-to-date Python 2.x installation. For using Flask with Python 3 have a
look at :ref:`python3-support`.
@ -67,7 +67,7 @@ folder within::
$ cd myproject
$ virtualenv venv
New python executable in venv/bin/python
Installing distribute............done.
Installing setuptools, pip............done.
Now, whenever you want to work on a project, you only have to activate the
corresponding environment. On OS X and Linux, do the following::
@ -113,9 +113,9 @@ Get the git checkout in a new virtualenv and run in development mode::
$ git clone http://github.com/mitsuhiko/flask.git
Initialized empty Git repository in ~/dev/flask/.git/
$ cd flask
$ virtualenv venv --distribute
$ virtualenv venv
New python executable in venv/bin/python
Installing distribute............done.
Installing setuptools, pip............done.
$ . venv/bin/activate
$ python setup.py develop
...
@ -129,45 +129,53 @@ To just get the development version without git, do this instead::
$ mkdir flask
$ cd flask
$ virtualenv venv --distribute
$ virtualenv venv
$ . venv/bin/activate
New python executable in venv/bin/python
Installing distribute............done.
Installing setuptools, pip............done.
$ pip install Flask==dev
...
Finished processing dependencies for Flask==dev
.. _windows-easy-install:
`pip` and `distribute` on Windows
-----------------------------------
`pip` and `setuptools` on Windows
---------------------------------
Sometimes getting the standard "Python packaging tools" like *pip*, *setuptools*
and *virtualenv* can be a little trickier, but nothing very hard. The two crucial
packages you will need are setuptools and pip - these will let you install
anything else (like virtualenv). Fortunately there are two "bootstrap scripts"
you can run to install either.
If you don't currently have either, then `get-pip.py` will install both for you
(you won't need to run ez_setup.py).
`get-pip.py`_
On Windows, installation of `easy_install` is a little bit trickier, but still
quite easy. The easiest way to do it is to download the
`distribute_setup.py`_ file and run it. The easiest way to run the file is to
open your downloads folder and double-click on the file.
To install the latest setuptools, you can use its bootstrap file:
Next, add the `easy_install` command and other Python scripts to the
command search path, by adding your Python installation's Scripts folder
to the `PATH` environment variable. To do that, right-click on the
"Computer" icon on the Desktop or in the Start menu, and choose "Properties".
Then click on "Advanced System settings" (in Windows XP, click on the
"Advanced" tab instead). Then click on the "Environment variables" button.
Finally, double-click on the "Path" variable in the "System variables" section,
and add the path of your Python interpreter's Scripts folder. Be sure to
delimit it from existing values with a semicolon. Assuming you are using
Python 2.7 on the default path, add the following value::
`ez_setup.py`_
Either should be double-clickable once you download them. If you already have pip,
you can upgrade them by running::
;C:\Python27\Scripts
> pip install --upgrade pip setuptools
And you are done! To check that it worked, open the Command Prompt and execute
``easy_install``. If you have User Account Control enabled on Windows Vista or
Windows 7, it should prompt you for administrator privileges.
Most often, once you pull up a command prompt you want to be able to type ``pip``
and ``python`` which will run those things, but this might not automatically happen
on Windows, because it doesn't know where those executables are (give either a try!).
Now that you have ``easy_install``, you can use it to install ``pip``::
To fix this, you should be able to navigate to your Python install directory
(e.g ``C:\Python27``), then go to ``Tools``, then ``Scripts``; then find the
``win_add2path.py`` file and run that. Open a **new** Command Prompt and
check that you can now just type ``python`` to bring up the interpreter.
> easy_install pip
Finally, to install `virtualenv`_, you can simply run::
> pip install virtualenv
Then you can be off on your way following the installation instructions above.
.. _distribute_setup.py: http://python-distribute.org/distribute_setup.py
.. _get-pip.py: https://raw.github.com/pypa/pip/master/contrib/get-pip.py
.. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py

2
docs/patterns/sqlalchemy.rst

@ -185,6 +185,8 @@ you basically only need the engine::
Then you can either declare the tables in your code like in the examples
above, or automatically load them::
from sqlalchemy import Table
users = Table('users', metadata, autoload=True)
To insert data you can use the `insert` method. We have to get a

2
docs/unicode.rst

@ -1,7 +1,7 @@
Unicode in Flask
================
Flask like Jinja2 and Werkzeug is totally Unicode based when it comes to
Flask, like Jinja2 and Werkzeug, is totally Unicode based when it comes to
text. Not only these libraries, also the majority of web related Python
libraries that deal with text. If you don't know Unicode so far, you
should probably read `The Absolute Minimum Every Software Developer

2
examples/flaskr/schema.sql

@ -2,5 +2,5 @@ drop table if exists entries;
create table entries (
id integer primary key autoincrement,
title text not null,
text text not null
'text' text not null
);

12
flask/app.py

@ -305,6 +305,7 @@ class Flask(_PackageBoundObject):
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': True,
'TEMPLATES_AUTO_RELOAD': True,
})
#: The rule object to use for URL rules created. This is used by
@ -655,10 +656,16 @@ class Flask(_PackageBoundObject):
this function to customize the behavior.
.. versionadded:: 0.5
.. versionchanged:: 1.0
``Environment.auto_reload`` set in accordance with
``TEMPLATES_AUTO_RELOAD`` configuration option.
"""
options = dict(self.jinja_options)
if 'autoescape' not in options:
options['autoescape'] = self.select_jinja_autoescape
if 'auto_reload' not in options:
options['auto_reload'] = self.debug \
or self.config['TEMPLATES_AUTO_RELOAD']
rv = Environment(self, **options)
rv.globals.update(
url_for=url_for,
@ -1070,6 +1077,11 @@ class Flask(_PackageBoundObject):
The first `None` refers to the active blueprint. If the error
handler should be application wide `None` shall be used.
.. versionadded:: 0.7
Use :meth:`register_error_handler` instead of modifying
:attr:`error_handler_spec` directly, for application wide error
handlers.
.. versionadded:: 0.7
One can now additionally also register custom exception types
that do not necessarily have to be a subclass of the

11
flask/blueprints.py

@ -399,3 +399,14 @@ class Blueprint(_PackageBoundObject):
self.name, code_or_exception, f))
return f
return decorator
def register_error_handler(self, code_or_exception, f):
"""Non-decorator version of the :meth:`errorhandler` error attach
function, akin to the :meth:`~flask.Flask.register_error_handler`
application-wide function of the :class:`~flask.Flask` object but
for error handlers limited to this blueprint.
.. versionadded:: 0.11
"""
self.record_once(lambda s: s.app._register_error_handler(
self.name, code_or_exception, f))

14
flask/helpers.py

@ -199,16 +199,16 @@ def url_for(endpoint, **values):
For more information, head over to the :ref:`Quickstart <url-building>`.
To integrate applications, :class:`Flask` has a hook to intercept URL build
errors through :attr:`Flask.build_error_handler`. The `url_for` function
results in a :exc:`~werkzeug.routing.BuildError` when the current app does
not have a URL for the given endpoint and values. When it does, the
:data:`~flask.current_app` calls its :attr:`~Flask.build_error_handler` if
errors through :attr:`Flask.url_build_error_handlers`. The `url_for`
function results in a :exc:`~werkzeug.routing.BuildError` when the current
app does not have a URL for the given endpoint and values. When it does, the
:data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if
it is not `None`, which can return a string to use as the result of
`url_for` (instead of `url_for`'s default to raise the
:exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception.
An example::
def external_url_handler(error, endpoint, **values):
def external_url_handler(error, endpoint, values):
"Looks up an external URL when `url_for` cannot build a URL."
# This is an example of hooking the build_error_handler.
# Here, lookup_url is some utility function you've built
@ -225,10 +225,10 @@ def url_for(endpoint, **values):
# url_for will use this result, instead of raising BuildError.
return url
app.build_error_handler = external_url_handler
app.url_build_error_handlers.append(external_url_handler)
Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and
`endpoint` and `**values` are the arguments passed into `url_for`. Note
`endpoint` and `values` are the arguments passed into `url_for`. Note
that this is for building URLs outside the current application, and not for
handling 404 NotFound errors.

2
flask/json.py

@ -25,7 +25,7 @@ except ImportError:
from itsdangerous import json as _json
# figure out if simplejson escapes slashes. This behavior was changed
# Figure out if simplejson escapes slashes. This behavior was changed
# from one version to another without reason.
_slash_escape = '\\/' not in _json.dumps('/')

2
flask/sessions.py

@ -223,7 +223,7 @@ class SessionInterface(object):
def get_cookie_path(self, app):
"""Returns the path for which the cookie should be valid. The
default implementation uses the value from the SESSION_COOKIE_PATH``
default implementation uses the value from the ``SESSION_COOKIE_PATH``
config var if it's set, and falls back to ``APPLICATION_ROOT`` or
uses ``/`` if it's `None`.
"""

4
flask/signals.py

@ -37,12 +37,12 @@ except ImportError:
temporarily_connected_to = connected_to = _fail
del _fail
# the namespace for code signals. If you are not flask code, do
# The namespace for code signals. If you are not flask code, do
# not put signals in here. Create your own namespace instead.
_signals = Namespace()
# core signals. For usage examples grep the sourcecode or consult
# Core signals. For usage examples grep the sourcecode or consult
# the API documentation in docs/api.rst as well as docs/signals.rst
template_rendered = _signals.signal('template-rendered')
request_started = _signals.signal('request-started')

33
flask/testsuite/blueprints.py

@ -296,6 +296,39 @@ class BlueprintTestCase(FlaskTestCase):
self.assert_equal(c.get('/backend-no').data, b'backend says no')
self.assert_equal(c.get('/what-is-a-sideend').data, b'application itself says no')
def test_blueprint_specific_user_error_handling(self):
class MyDecoratorException(Exception):
pass
class MyFunctionException(Exception):
pass
blue = flask.Blueprint('blue', __name__)
@blue.errorhandler(MyDecoratorException)
def my_decorator_exception_handler(e):
self.assert_true(isinstance(e, MyDecoratorException))
return 'boom'
def my_function_exception_handler(e):
self.assert_true(isinstance(e, MyFunctionException))
return 'bam'
blue.register_error_handler(MyFunctionException, my_function_exception_handler)
@blue.route('/decorator')
def blue_deco_test():
raise MyDecoratorException()
@blue.route('/function')
def blue_func_test():
raise MyFunctionException()
app = flask.Flask(__name__)
app.register_blueprint(blue)
c = app.test_client()
self.assert_equal(c.get('/decorator').data, b'boom')
self.assert_equal(c.get('/function').data, b'bam')
def test_blueprint_url_definitions(self):
bp = flask.Blueprint('test', __name__)

4
flask/testsuite/ext.py

@ -125,7 +125,9 @@ class ExtImportHookTestCase(FlaskTestCase):
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)
import os.path
self.assert_in(os.path.join('flask_broken', '__init__.py'), next.tb_frame.f_code.co_filename)
def suite():

2
flask/testsuite/helpers.py

@ -269,7 +269,7 @@ class SendfileTestCase(FlaskTestCase):
app = flask.Flask(__name__)
with catch_warnings() as captured:
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'), mode='rb')
rv = flask.send_file(f)
rv.direct_passthrough = False
with app.open_resource('static/index.html') as f:

8
flask/testsuite/templating.py

@ -295,6 +295,14 @@ class TemplatingTestCase(FlaskTestCase):
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'<h1>Jameson</h1>')
def test_templates_auto_reload(self):
app = flask.Flask(__name__)
self.assert_true(app.config['TEMPLATES_AUTO_RELOAD'])
self.assert_true(app.jinja_env.auto_reload)
app = flask.Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = False
self.assert_false(app.jinja_env.auto_reload)
def suite():
suite = unittest.TestSuite()

10
flask/views.py

@ -60,7 +60,7 @@ class View(object):
#: view function is created the result is automatically decorated.
#:
#: .. versionadded:: 0.8
decorators = []
decorators = ()
def dispatch_request(self):
"""Subclasses have to override this method to implement the
@ -89,7 +89,7 @@ class View(object):
for decorator in cls.decorators:
view = decorator(view)
# we attach the view class to the view function for two reasons:
# We attach the view class to the view function for two reasons:
# first of all it allows us to easily figure out what class-based
# view this thing came from, secondly it's also used for instantiating
# the view class so you can actually replace it with something else
@ -111,7 +111,7 @@ class MethodViewType(type):
for key in d:
if key in http_method_funcs:
methods.add(key.upper())
# if we have no method at all in there we don't want to
# If we have no method at all in there we don't want to
# add a method list. (This is for instance the case for
# the baseclass or another subclass of a base method view
# that does not introduce new methods).
@ -141,8 +141,8 @@ class MethodView(with_metaclass(MethodViewType, View)):
"""
def dispatch_request(self, *args, **kwargs):
meth = getattr(self, request.method.lower(), None)
# if the request method is HEAD and we don't have a handler for it
# retry with GET
# If the request method is HEAD and we don't have a handler for it
# retry with GET.
if meth is None and request.method == 'HEAD':
meth = getattr(self, 'get', None)
assert meth is not None, 'Unimplemented method %r' % request.method

12
flask/wrappers.py

@ -40,25 +40,25 @@ class Request(RequestBase):
specific ones.
"""
#: the internal URL rule that matched the request. This can be
#: The internal URL rule that matched the request. This can be
#: useful to inspect which methods are allowed for the URL from
#: a before/after handler (``request.url_rule.methods``) etc.
#:
#: .. versionadded:: 0.6
url_rule = None
#: a dict of view arguments that matched the request. If an exception
#: A dict of view arguments that matched the request. If an exception
#: happened when matching, this will be `None`.
view_args = None
#: if matching the URL failed, this is the exception that will be
#: If matching the URL failed, this is the exception that will be
#: raised / was raised as part of the request handling. This is
#: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
#: something similar.
routing_exception = None
# switched by the request context until 1.0 to opt in deprecated
# module functionality
# Switched by the request context until 1.0 to opt in deprecated
# module functionality.
_is_old_module = False
@property
@ -179,7 +179,7 @@ class Request(RequestBase):
def _load_form_data(self):
RequestBase._load_form_data(self)
# in debug mode we're replacing the files multidict with an ad-hoc
# In debug mode we're replacing the files multidict with an ad-hoc
# subclass that raises a different error for key errors.
ctx = _request_ctx_stack.top
if ctx is not None and ctx.app.debug and \

5
scripts/make-release.py

@ -26,7 +26,6 @@ def parse_changelog():
match = re.search('^Version\s+(.*)', line.strip())
if match is None:
continue
length = len(match.group(1))
version = match.group(1).strip()
if lineiter.next().count('-') != len(match.group(0)):
continue
@ -60,6 +59,7 @@ def parse_date(string):
def set_filename_version(filename, version_number, pattern):
changed = []
def inject_version(match):
before, old, after = match.groups()
changed.append(True)
@ -133,7 +133,8 @@ def main():
if version in tags:
fail('Version "%s" is already tagged', version)
if release_date.date() != date.today():
fail('Release date is not today (%s != %s)')
fail('Release date is not today (%s != %s)',
release_date.date(), date.today())
if not git_is_clean():
fail('You have uncommitted changes in git')

Loading…
Cancel
Save