diff --git a/CHANGES b/CHANGES index d1529526..cac78f73 100644 --- a/CHANGES +++ b/CHANGES @@ -94,6 +94,8 @@ Version 0.10.2 - Changed logic of before first request handlers to flip the flag after invoking. This will allow some uses that are potentially dangerous but should probably be permitted. +- Fixed Python 3 bug when a handler from `app.url_build_error_handlers` + reraises the `BuildError`. Version 0.10.1 -------------- diff --git a/docs/deploying/wsgi-standalone.rst b/docs/deploying/wsgi-standalone.rst index 5bdd0483..bd7b1006 100644 --- a/docs/deploying/wsgi-standalone.rst +++ b/docs/deploying/wsgi-standalone.rst @@ -31,7 +31,7 @@ Gevent ------- `Gevent`_ is a coroutine-based Python networking library that uses -`greenlet`_ to provide a high-level synchronous API on top of `libevent`_ +`greenlet`_ to provide a high-level synchronous API on top of `libev`_ event loop:: from gevent.wsgi import WSGIServer @@ -42,7 +42,7 @@ event loop:: .. _Gevent: http://www.gevent.org/ .. _greenlet: http://greenlet.readthedocs.org/en/latest/ -.. _libevent: http://libevent.org/ +.. _libev: http://software.schmorp.de/pkg/libev.html Twisted Web ----------- diff --git a/docs/patterns/wtforms.rst b/docs/patterns/wtforms.rst index 38e652e8..88602b6c 100644 --- a/docs/patterns/wtforms.rst +++ b/docs/patterns/wtforms.rst @@ -1,7 +1,7 @@ Form Validation with WTForms ============================ -When you have to work with form data submitted by a browser view code +When you have to work with form data submitted by a browser view, code quickly becomes very hard to read. There are libraries out there designed to make this process easier to manage. One of them is `WTForms`_ which we will handle here. If you find yourself in the situation of having many @@ -12,10 +12,10 @@ first. I recommend breaking up the application into multiple modules (:ref:`larger-applications`) for that and adding a separate module for the forms. -.. admonition:: Getting most of WTForms with an Extension +.. admonition:: Getting the most out of WTForms with an Extension - The `Flask-WTF`_ extension expands on this pattern and adds a few - handful little helpers that make working with forms and Flask more + The `Flask-WTF`_ extension expands on this pattern and adds a + few little helpers that make working with forms and Flask more fun. You can get it from `PyPI `_. @@ -54,8 +54,8 @@ In the view function, the usage of this form looks like this:: return redirect(url_for('login')) return render_template('register.html', form=form) -Notice that we are implying that the view is using SQLAlchemy here -(:ref:`sqlalchemy-pattern`) but this is no requirement of course. Adapt +Notice we're implying that the view is using SQLAlchemy here +(:ref:`sqlalchemy-pattern`), but that's not a requirement, of course. Adapt the code as necessary. Things to remember: @@ -64,14 +64,14 @@ Things to remember: the data is submitted via the HTTP ``POST`` method and :attr:`~flask.request.args` if the data is submitted as ``GET``. 2. to validate the data, call the :func:`~wtforms.form.Form.validate` - method which will return ``True`` if the data validates, ``False`` + method, which will return ``True`` if the data validates, ``False`` otherwise. 3. to access individual values from the form, access `form..data`. Forms in Templates ------------------ -Now to the template side. When you pass the form to the templates you can +Now to the template side. When you pass the form to the templates, you can easily render them there. Look at the following example template to see how easy this is. WTForms does half the form generation for us already. To make it even nicer, we can write a macro that renders a field with @@ -95,14 +95,14 @@ Here's an example :file:`_formhelpers.html` template with such a macro: {% endmacro %} This macro accepts a couple of keyword arguments that are forwarded to -WTForm's field function that renders the field for us. The keyword -arguments will be inserted as HTML attributes. So for example you can +WTForm's field function, which renders the field for us. The keyword +arguments will be inserted as HTML attributes. So, for example, you can call ``render_field(form.username, class='username')`` to add a class to the input element. Note that WTForms returns standard Python unicode -strings, so we have to tell Jinja2 that this data is already HTML escaped +strings, so we have to tell Jinja2 that this data is already HTML-escaped with the ``|safe`` filter. -Here the :file:`register.html` template for the function we used above which +Here is the :file:`register.html` template for the function we used above, which takes advantage of the :file:`_formhelpers.html` template: .. sourcecode:: html+jinja diff --git a/examples/jqueryexample/jqueryexample.py b/examples/jqueryexample/jqueryexample.py index d1fca62b..39b81951 100644 --- a/examples/jqueryexample/jqueryexample.py +++ b/examples/jqueryexample/jqueryexample.py @@ -23,3 +23,6 @@ def add_numbers(): @app.route('/') def index(): return render_template('index.html') + +if __name__ == '__main__': + app.run() diff --git a/flask/_compat.py b/flask/_compat.py index 8ea7719f..bfe607d6 100644 --- a/flask/_compat.py +++ b/flask/_compat.py @@ -54,23 +54,14 @@ else: def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" # 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__ + # itself with the actual metaclass. + class metaclass(type): 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, {}) + return type.__new__(metaclass, 'temporary_class', (), {}) # Certain versions of pypy have a bug where clearing the exception stack diff --git a/flask/app.py b/flask/app.py index 5b186577..e03ff221 100644 --- a/flask/app.py +++ b/flask/app.py @@ -1771,8 +1771,9 @@ class Flask(_PackageBoundObject): rv = handler(error, endpoint, values) if rv is not None: return rv - except BuildError as error: - pass + except BuildError as e: + # make error available outside except block (py3) + error = e # 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, diff --git a/tests/test_basic.py b/tests/test_basic.py index 08e03aca..f6edbd98 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1069,6 +1069,18 @@ def test_build_error_handler(): assert flask.url_for('spam') == '/test_handler/' +def test_build_error_handler_reraise(): + app = flask.Flask(__name__) + + # Test a custom handler which reraises the BuildError + def handler_raises_build_error(error, endpoint, values): + raise error + app.url_build_error_handlers.append(handler_raises_build_error) + + with app.test_request_context(): + pytest.raises(BuildError, flask.url_for, 'not.existing') + + def test_custom_converters(): from werkzeug.routing import BaseConverter