mirror of https://github.com/pallets/flask.git
				
				
				
			Started work on new request dispatching. Unittests not yet updated
This commit is contained in:
		
							parent
							
								
									e3f2dd8f08
								
							
						
					
					
						commit
						e71a5ff8de
					
				
							
								
								
									
										51
									
								
								docs/api.rst
								
								
								
								
							
							
						
						
									
										51
									
								
								docs/api.rst
								
								
								
								
							|  | @ -310,6 +310,9 @@ Configuration | ||||||
| Useful Internals | Useful Internals | ||||||
| ---------------- | ---------------- | ||||||
| 
 | 
 | ||||||
|  | .. autoclass:: flask.ctx.RequestContext | ||||||
|  |    :members: | ||||||
|  | 
 | ||||||
| .. data:: _request_ctx_stack | .. data:: _request_ctx_stack | ||||||
| 
 | 
 | ||||||
|    The internal :class:`~werkzeug.local.LocalStack` that is used to implement |    The internal :class:`~werkzeug.local.LocalStack` that is used to implement | ||||||
|  | @ -347,23 +350,6 @@ Useful Internals | ||||||
|           if ctx is not None: |           if ctx is not None: | ||||||
|               return ctx.session |               return ctx.session | ||||||
| 
 | 
 | ||||||
|    .. versionchanged:: 0.4 |  | ||||||
| 
 |  | ||||||
|    The request context is automatically popped at the end of the request |  | ||||||
|    for you.  In debug mode the request context is kept around if |  | ||||||
|    exceptions happen so that interactive debuggers have a chance to |  | ||||||
|    introspect the data.  With 0.4 this can also be forced for requests |  | ||||||
|    that did not fail and outside of `DEBUG` mode.  By setting |  | ||||||
|    ``'flask._preserve_context'`` to `True` on the WSGI environment the |  | ||||||
|    context will not pop itself at the end of the request.  This is used by |  | ||||||
|    the :meth:`~flask.Flask.test_client` for example to implement the |  | ||||||
|    deferred cleanup functionality. |  | ||||||
| 
 |  | ||||||
|    You might find this helpful for unittests where you need the |  | ||||||
|    information from the context local around for a little longer.  Make |  | ||||||
|    sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in |  | ||||||
|    that situation, otherwise your unittests will leak memory. |  | ||||||
| 
 |  | ||||||
| Signals | Signals | ||||||
| ------- | ------- | ||||||
| 
 | 
 | ||||||
|  | @ -401,6 +387,12 @@ Signals | ||||||
|    in debug mode, where no exception handling happens.  The exception |    in debug mode, where no exception handling happens.  The exception | ||||||
|    itself is passed to the subscriber as `exception`. |    itself is passed to the subscriber as `exception`. | ||||||
| 
 | 
 | ||||||
|  | .. data:: request_tearing_down | ||||||
|  | 
 | ||||||
|  |    This signal is sent when the application is tearing down the request. | ||||||
|  |    This is always called, even if an error happened.  No arguments are | ||||||
|  |    provided. | ||||||
|  | 
 | ||||||
| .. currentmodule:: None | .. currentmodule:: None | ||||||
| 
 | 
 | ||||||
| .. class:: flask.signals.Namespace | .. class:: flask.signals.Namespace | ||||||
|  | @ -418,28 +410,3 @@ Signals | ||||||
|       operations, including connecting. |       operations, including connecting. | ||||||
| 
 | 
 | ||||||
| .. _blinker: http://pypi.python.org/pypi/blinker | .. _blinker: http://pypi.python.org/pypi/blinker | ||||||
| 
 |  | ||||||
| .. _notes-on-proxies: |  | ||||||
| 
 |  | ||||||
| Notes On Proxies |  | ||||||
| ---------------- |  | ||||||
| 
 |  | ||||||
| Some of the objects provided by Flask are proxies to other objects.  The |  | ||||||
| reason behind this is that these proxies are shared between threads and |  | ||||||
| they have to dispatch to the actual object bound to a thread behind the |  | ||||||
| scenes as necessary. |  | ||||||
| 
 |  | ||||||
| Most of the time you don't have to care about that, but there are some |  | ||||||
| exceptions where it is good to know that this object is an actual proxy: |  | ||||||
| 
 |  | ||||||
| -   The proxy objects do not fake their inherited types, so if you want to |  | ||||||
|     perform actual instance checks, you have to do that on the instance |  | ||||||
|     that is being proxied (see `_get_current_object` below). |  | ||||||
| -   if the object reference is important (so for example for sending |  | ||||||
|     :ref:`signals`) |  | ||||||
| 
 |  | ||||||
| If you need to get access to the underlying object that is proxied, you |  | ||||||
| can use the :meth:`~werkzeug.local.LocalProxy._get_current_object` method:: |  | ||||||
| 
 |  | ||||||
|     app = current_app._get_current_object() |  | ||||||
|     my_signal.send(app) |  | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ The following configuration values are used internally by Flask: | ||||||
| 
 | 
 | ||||||
| .. tabularcolumns:: |p{6.5cm}|p{8.5cm}| | .. tabularcolumns:: |p{6.5cm}|p{8.5cm}| | ||||||
| 
 | 
 | ||||||
| =============================== ========================================= | ================================= ========================================= | ||||||
| ``DEBUG``                         enable/disable debug mode | ``DEBUG``                         enable/disable debug mode | ||||||
| ``TESTING``                       enable/disable testing mode | ``TESTING``                       enable/disable testing mode | ||||||
| ``PROPAGATE_EXCEPTIONS``          explicitly enable or disable the | ``PROPAGATE_EXCEPTIONS``          explicitly enable or disable the | ||||||
|  | @ -59,6 +59,15 @@ The following configuration values are used internally by Flask: | ||||||
|                                   explicitly set to `None` this is |                                   explicitly set to `None` this is | ||||||
|                                   implicitly true if either `TESTING` or |                                   implicitly true if either `TESTING` or | ||||||
|                                   `DEBUG` is true. |                                   `DEBUG` is true. | ||||||
|  | ``PRESERVE_CONTEXT_ON_EXCEPTION`` By default if the application is in | ||||||
|  |                                   debug mode the request context is not | ||||||
|  |                                   popped on exceptions to enable debuggers | ||||||
|  |                                   to introspect the data.  This can be | ||||||
|  |                                   disabled by this key.  You can also use | ||||||
|  |                                   this setting to force-enable it for non | ||||||
|  |                                   debug execution which might be useful to | ||||||
|  |                                   debug production applications (but also | ||||||
|  |                                   very risky). | ||||||
| ``SECRET_KEY``                    the secret key | ``SECRET_KEY``                    the secret key | ||||||
| ``SESSION_COOKIE_NAME``           the name of the session cookie | ``SESSION_COOKIE_NAME``           the name of the session cookie | ||||||
| ``PERMANENT_SESSION_LIFETIME``    the lifetime of a permanent session as | ``PERMANENT_SESSION_LIFETIME``    the lifetime of a permanent session as | ||||||
|  | @ -71,7 +80,7 @@ The following configuration values are used internally by Flask: | ||||||
|                                   reject incoming requests with a |                                   reject incoming requests with a | ||||||
|                                   content length greater than this by |                                   content length greater than this by | ||||||
|                                   returning a 413 status code. |                                   returning a 413 status code. | ||||||
| =============================== ========================================= | ================================= ========================================= | ||||||
| 
 | 
 | ||||||
| .. admonition:: More on ``SERVER_NAME`` | .. admonition:: More on ``SERVER_NAME`` | ||||||
| 
 | 
 | ||||||
|  | @ -102,7 +111,7 @@ The following configuration values are used internally by Flask: | ||||||
|    ``MAX_CONTENT_LENGTH`` |    ``MAX_CONTENT_LENGTH`` | ||||||
| 
 | 
 | ||||||
| .. versionadded:: 0.7 | .. versionadded:: 0.7 | ||||||
|    ``PROPAGATE_EXCEPTIONS`` |    ``PROPAGATE_EXCEPTIONS``, ``PRESERVE_CONTEXT_ON_EXCEPTION`` | ||||||
| 
 | 
 | ||||||
| Configuring from Files | Configuring from Files | ||||||
| ---------------------- | ---------------------- | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ instructions for web development with Flask. | ||||||
|    errorhandling |    errorhandling | ||||||
|    config |    config | ||||||
|    signals |    signals | ||||||
|  |    reqcontext | ||||||
|    shell |    shell | ||||||
|    patterns/index |    patterns/index | ||||||
|    deploying/index |    deploying/index | ||||||
|  |  | ||||||
|  | @ -0,0 +1,230 @@ | ||||||
|  | .. _request-context: | ||||||
|  | 
 | ||||||
|  | The Request Context | ||||||
|  | =================== | ||||||
|  | 
 | ||||||
|  | This document describes the behavior in Flask 0.7 which is mostly in line | ||||||
|  | with the old behavior but has some small, subtle differences. | ||||||
|  | 
 | ||||||
|  | One of the design ideas behind Flask is that there are two different | ||||||
|  | “states” in which code is executed.  The application setup state in which | ||||||
|  | the application implicitly is on the module level.  It starts when the | ||||||
|  | :class:`Flask` object is instantiated, and it implicitly ends when the | ||||||
|  | first request comes in.  While the application is in this state a few | ||||||
|  | assumptions are true: | ||||||
|  | 
 | ||||||
|  | -   the programmer can modify the application object safely. | ||||||
|  | -   no request handling happened so far | ||||||
|  | -   you have to have a reference to the application object in order to | ||||||
|  |     modify it, there is no magic proxy that can give you a reference to | ||||||
|  |     the application object you're currently creating or modifying. | ||||||
|  | 
 | ||||||
|  | On the contrast, during request handling, a couple of other rules exist: | ||||||
|  | 
 | ||||||
|  | -   while a request is active, the context local objects | ||||||
|  |     (:data:`flask.request` and others) point to the current request. | ||||||
|  | -   any code can get hold of these objects at any time. | ||||||
|  | 
 | ||||||
|  | The magic that makes this works is internally referred in Flask as the | ||||||
|  | “request context”. | ||||||
|  | 
 | ||||||
|  | Diving into Context Locals | ||||||
|  | -------------------------- | ||||||
|  | 
 | ||||||
|  | Say you have a utility function that returns the URL the user should be | ||||||
|  | redirected to.  Imagine it would always redirect to the URL's ``next`` | ||||||
|  | parameter or the HTTP referrer or the index page:: | ||||||
|  | 
 | ||||||
|  |     from flask import request, url_for | ||||||
|  | 
 | ||||||
|  |     def redirect_url(): | ||||||
|  |         return request.args.get('next') or \ | ||||||
|  |                request.referrer or \ | ||||||
|  |                url_for('index') | ||||||
|  | 
 | ||||||
|  | As you can see, it accesses the request object.  If you try to run this | ||||||
|  | from a plain Python shell, this is the exception you will see: | ||||||
|  | 
 | ||||||
|  | >>> redirect_url() | ||||||
|  | Traceback (most recent call last): | ||||||
|  |   File "<stdin>", line 1, in <module> | ||||||
|  | AttributeError: 'NoneType' object has no attribute 'request' | ||||||
|  | 
 | ||||||
|  | That makes a lot of sense because we currently do not have a request we | ||||||
|  | could access.  So we have to make a request and bind it to the current | ||||||
|  | context.  The :attr:`~flask.Flask.test_request_context` method can create | ||||||
|  | us a :class:`~flask.ctx.RequestContext`: | ||||||
|  | 
 | ||||||
|  | >>> ctx = app.test_request_context('/?next=http://example.com/') | ||||||
|  | 
 | ||||||
|  | This context can be used in two ways.  Either with the `with` statement | ||||||
|  | or by calling the :meth:`~flask.ctx.RequestContext.push` and | ||||||
|  | :meth:`~flask.ctx.RequestContext.pop` methods: | ||||||
|  | 
 | ||||||
|  | >>> ctx.push() | ||||||
|  | 
 | ||||||
|  | From that point onwards you can work with the request object: | ||||||
|  | 
 | ||||||
|  | >>> redirect_url() | ||||||
|  | u'http://example.com/' | ||||||
|  | 
 | ||||||
|  | Until you call `pop`: | ||||||
|  | 
 | ||||||
|  | >>> ctx.pop() | ||||||
|  | 
 | ||||||
|  | Because the request context is internally maintained as a stack you can | ||||||
|  | push and pop multiple times.  This is very handy to implement things like | ||||||
|  | internal redirects. | ||||||
|  | 
 | ||||||
|  | For more information of how to utilize the request context from the | ||||||
|  | interactive Python shell, head over to the :ref:`shell` chapter. | ||||||
|  | 
 | ||||||
|  | How the Context Works | ||||||
|  | --------------------- | ||||||
|  | 
 | ||||||
|  | If you look into how the Flask WSGI application internally works, you will | ||||||
|  | find a piece of code that looks very much like this:: | ||||||
|  | 
 | ||||||
|  |     def wsgi_app(self, environ): | ||||||
|  |         with self.request_context(environ): | ||||||
|  |             try: | ||||||
|  |                 response = self.full_dispatch_request() | ||||||
|  |             except Exception, e: | ||||||
|  |                 response = self.make_response(self.handle_exception(e)) | ||||||
|  |             return response(environ, start_response) | ||||||
|  | 
 | ||||||
|  | The method :meth:`~Flask.request_context` returns a new | ||||||
|  | :class:`~flask.ctx.RequestContext` object and uses it in combination with | ||||||
|  | the `with` statement to bind the context.  Everything that is called from | ||||||
|  | the same thread from this point onwards until the end of the `with` | ||||||
|  | statement will have access to the request globals (:data:`flask.request` | ||||||
|  | and others). | ||||||
|  | 
 | ||||||
|  | The request context internally works like a stack: The topmost level on | ||||||
|  | the stack is the current active request. | ||||||
|  | :meth:`~flask.ctx.RequestContext.push` adds the context to the stack on | ||||||
|  | the very top, :meth:`~flask.ctx.RequestContext.pop` removes it from the | ||||||
|  | stack again.  On popping the application's | ||||||
|  | :func:`~flask.Flask.teardown_request` functions are also executed. | ||||||
|  | 
 | ||||||
|  | .. _callbacks-and-errors: | ||||||
|  | 
 | ||||||
|  | Callbacks and Errors | ||||||
|  | -------------------- | ||||||
|  | 
 | ||||||
|  | What happens if an error occurs in Flask during request processing?  This | ||||||
|  | particular behavior changed in 0.7 because we wanted to make it easier to | ||||||
|  | understand what is actually happening.  The new behavior is quite simple: | ||||||
|  | 
 | ||||||
|  | 1.  Before each request, :meth:`~flask.Flask.before_request` functions are | ||||||
|  |     executed.  If one of these functions return a response, the other | ||||||
|  |     functions are no longer called.  In any case however the return value | ||||||
|  |     is treated as a replacement for the view's return value. | ||||||
|  | 
 | ||||||
|  | 2.  If the :meth:`~flask.Flask.before_request` functions did not return a | ||||||
|  |     response, the regular request handling kicks in and the view function | ||||||
|  |     that was matched has the chance to return a response. | ||||||
|  | 
 | ||||||
|  | 3.  The return value of the view is then converted into an actual response | ||||||
|  |     object and handed over to the :meth:`~flask.Flask.after_request` | ||||||
|  |     functions which have the chance to replace it or modify it in place. | ||||||
|  | 
 | ||||||
|  | 4.  At the end of the request the :meth:`~flask.Flask.teardown_request` | ||||||
|  |     functions are executed.  This always happens, even in case of an | ||||||
|  |     unhandled exception down the road. | ||||||
|  | 
 | ||||||
|  | Now what happens on errors?  In production mode if an exception is not | ||||||
|  | caught, the 500 internal server handler is called.  In development mode | ||||||
|  | however the exception is not further processed and bubbles up to the WSGI | ||||||
|  | server.  That way things like the interactive debugger can provide helpful | ||||||
|  | debug information. | ||||||
|  | 
 | ||||||
|  | An important change in 0.7 is that the internal server error is now no | ||||||
|  | longer post processed by the after request callbacks and after request | ||||||
|  | callbacks are no longer guaranteed to be executed.  This way the internal | ||||||
|  | dispatching code looks cleaner and is easier to customize and understand. | ||||||
|  | 
 | ||||||
|  | The new teardown functions are supposed to be used as a replacement for | ||||||
|  | things that absolutely need to happen at the end of request. | ||||||
|  | 
 | ||||||
|  | Teardown Callbacks | ||||||
|  | ------------------ | ||||||
|  | 
 | ||||||
|  | The teardown callbacks are special callbacks in that they are executed at | ||||||
|  | at different point.  Strictly speaking they are independent of the actual | ||||||
|  | request handling as they are bound to the lifecycle of the | ||||||
|  | :class:`~flask.ctx.RequestContext` object.  When the request context is | ||||||
|  | popped, the :meth:`~flask.Flask.teardown_request` functions are called. | ||||||
|  | 
 | ||||||
|  | This is important to know if the life of the request context is prolonged | ||||||
|  | by using the test client in a with statement of when using the request | ||||||
|  | context from the command line:: | ||||||
|  | 
 | ||||||
|  |     with app.test_client() as client: | ||||||
|  |         resp = client.get('/foo') | ||||||
|  |         # the teardown functions are still not called at that point | ||||||
|  |         # even though the response ended and you have the response | ||||||
|  |         # object in your hand | ||||||
|  | 
 | ||||||
|  |     # only when the code reaches this point the teardown functions | ||||||
|  |     # are called.  Alternatively the same thing happens if another | ||||||
|  |     # request was triggered from the test client | ||||||
|  | 
 | ||||||
|  | It's easy to see the behavior from the command line: | ||||||
|  | 
 | ||||||
|  | >>> app = Flask(__name__) | ||||||
|  | >>> @app.teardown_request | ||||||
|  | ... def after_request(exception=None): | ||||||
|  | ...     print 'after request' | ||||||
|  | ...  | ||||||
|  | >>> ctx = app.test_request_context() | ||||||
|  | >>> ctx.push() | ||||||
|  | >>> ctx.pop() | ||||||
|  | after request | ||||||
|  | 
 | ||||||
|  | .. _notes-on-proxies: | ||||||
|  | 
 | ||||||
|  | Notes On Proxies | ||||||
|  | ---------------- | ||||||
|  | 
 | ||||||
|  | Some of the objects provided by Flask are proxies to other objects.  The | ||||||
|  | reason behind this is that these proxies are shared between threads and | ||||||
|  | they have to dispatch to the actual object bound to a thread behind the | ||||||
|  | scenes as necessary. | ||||||
|  | 
 | ||||||
|  | Most of the time you don't have to care about that, but there are some | ||||||
|  | exceptions where it is good to know that this object is an actual proxy: | ||||||
|  | 
 | ||||||
|  | -   The proxy objects do not fake their inherited types, so if you want to | ||||||
|  |     perform actual instance checks, you have to do that on the instance | ||||||
|  |     that is being proxied (see `_get_current_object` below). | ||||||
|  | -   if the object reference is important (so for example for sending | ||||||
|  |     :ref:`signals`) | ||||||
|  | 
 | ||||||
|  | If you need to get access to the underlying object that is proxied, you | ||||||
|  | can use the :meth:`~werkzeug.local.LocalProxy._get_current_object` method:: | ||||||
|  | 
 | ||||||
|  |     app = current_app._get_current_object() | ||||||
|  |     my_signal.send(app) | ||||||
|  | 
 | ||||||
|  | Context Preservation on Error | ||||||
|  | ----------------------------- | ||||||
|  | 
 | ||||||
|  | If an error occurs or not, at the end of the request the request context | ||||||
|  | is popped and all data associated with it is destroyed.  During | ||||||
|  | development however that can be problematic as you might want to have the | ||||||
|  | information around for a longer time in case an exception occurred.  In | ||||||
|  | Flask 0.6 and earlier in debug mode, if an exception occurred, the | ||||||
|  | request context was not popped so that the interactive debugger can still | ||||||
|  | provide you with important information. | ||||||
|  | 
 | ||||||
|  | Starting with Flask 0.7 you have finer control over that behavior by | ||||||
|  | setting the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable.  By | ||||||
|  | default it's linked to the setting of ``DEBUG``.  If the application is in | ||||||
|  | debug mode the context is preserved, in production mode it's not. | ||||||
|  | 
 | ||||||
|  | Do not force activate ``PRESERVE_CONTEXT_ON_EXCEPTION`` in production mode | ||||||
|  | as it will cause your application to leak memory on exceptions.  However | ||||||
|  | it can be useful during development to get the same error preserving | ||||||
|  | behavior as in development mode when attempting to debug an error that | ||||||
|  | only occurs under production settings. | ||||||
|  | @ -1,3 +1,5 @@ | ||||||
|  | .. _shell: | ||||||
|  | 
 | ||||||
| Working with the Shell | Working with the Shell | ||||||
| ====================== | ====================== | ||||||
| 
 | 
 | ||||||
|  | @ -21,61 +23,37 @@ that these functions are not only there for interactive shell usage, but | ||||||
| also for unittesting and other situations that require a faked request | also for unittesting and other situations that require a faked request | ||||||
| context. | context. | ||||||
| 
 | 
 | ||||||
| Diving into Context Locals | Generally it's recommended that you read the :ref:`request-context` | ||||||
|  | chapter of the documentation first. | ||||||
|  | 
 | ||||||
|  | Creating a Request Context | ||||||
| -------------------------- | -------------------------- | ||||||
| 
 | 
 | ||||||
| Say you have a utility function that returns the URL the user should be | The easiest way to create a proper request context from the shell is by | ||||||
| redirected to.  Imagine it would always redirect to the URL's ``next`` | using the :attr:`~flask.Flask.test_request_context` method which creates | ||||||
| parameter or the HTTP referrer or the index page:: | us a :class:`~flask.ctx.RequestContext`: | ||||||
| 
 | 
 | ||||||
|     from flask import request, url_for | >>> ctx = app.test_request_context() | ||||||
| 
 | 
 | ||||||
|     def redirect_url(): | Normally you would use the `with` statement to make this request object | ||||||
|         return request.args.get('next') or \ | active, but in the shell it's easier to use the | ||||||
|                request.referrer or \ | :meth:`~flask.ctx.RequestContext.push` and | ||||||
|                url_for('index') | :meth:`~flask.ctx.RequestContext.pop` methods by hand: | ||||||
| 
 |  | ||||||
| As you can see, it accesses the request object.  If you try to run this |  | ||||||
| from a plain Python shell, this is the exception you will see: |  | ||||||
| 
 |  | ||||||
| >>> redirect_url() |  | ||||||
| Traceback (most recent call last): |  | ||||||
|   File "<stdin>", line 1, in <module> |  | ||||||
| AttributeError: 'NoneType' object has no attribute 'request' |  | ||||||
| 
 |  | ||||||
| That makes a lot of sense because we currently do not have a request we |  | ||||||
| could access.  So we have to make a request and bind it to the current |  | ||||||
| context.  The :attr:`~flask.Flask.test_request_context` method can create |  | ||||||
| us a request context: |  | ||||||
| 
 |  | ||||||
| >>> ctx = app.test_request_context('/?next=http://example.com/') |  | ||||||
| 
 |  | ||||||
| This context can be used in two ways.  Either with the `with` statement |  | ||||||
| (which unfortunately is not very handy for shell sessions).  The |  | ||||||
| alternative way is to call the `push` and `pop` methods: |  | ||||||
| 
 | 
 | ||||||
| >>> ctx.push() | >>> ctx.push() | ||||||
| 
 | 
 | ||||||
| From that point onwards you can work with the request object: | From that point onwards you can work with the request object until you | ||||||
| 
 | call `pop`: | ||||||
| >>> redirect_url() |  | ||||||
| u'http://example.com/' |  | ||||||
| 
 |  | ||||||
| Until you call `pop`: |  | ||||||
| 
 | 
 | ||||||
| >>> ctx.pop() | >>> ctx.pop() | ||||||
| >>> redirect_url() |  | ||||||
| Traceback (most recent call last): |  | ||||||
|   File "<stdin>", line 1, in <module> |  | ||||||
| AttributeError: 'NoneType' object has no attribute 'request' |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| Firing Before/After Request | Firing Before/After Request | ||||||
| --------------------------- | --------------------------- | ||||||
| 
 | 
 | ||||||
| By just creating a request context, you still don't have run the code that | By just creating a request context, you still don't have run the code that | ||||||
| is normally run before a request.  This probably results in your database | is normally run before a request.  This might result in your database | ||||||
| being unavailable, the current user not being stored on the | being unavailable if you are connecting to the database in a | ||||||
|  | before-request callback or the current user not being stored on the | ||||||
| :data:`~flask.g` object etc. | :data:`~flask.g` object etc. | ||||||
| 
 | 
 | ||||||
| This however can easily be done yourself.  Just call | This however can easily be done yourself.  Just call | ||||||
|  | @ -96,6 +74,11 @@ a response object: | ||||||
| <Response 0 bytes [200 OK]> | <Response 0 bytes [200 OK]> | ||||||
| >>> ctx.pop() | >>> ctx.pop() | ||||||
| 
 | 
 | ||||||
|  | The functions registered as :meth:`~flask.Flask.teardown_request` are | ||||||
|  | automatically called when the context is popped.  So this is the perfect | ||||||
|  | place to automatically tear down resources that were needed by the request | ||||||
|  | context (such as database connections). | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| Further Improving the Shell Experience | Further Improving the Shell Experience | ||||||
| -------------------------------------- | -------------------------------------- | ||||||
|  |  | ||||||
|  | @ -236,4 +236,20 @@ The following signals exist in Flask: | ||||||
|         from flask import got_request_exception |         from flask import got_request_exception | ||||||
|         got_request_exception.connect(log_exception, app) |         got_request_exception.connect(log_exception, app) | ||||||
| 
 | 
 | ||||||
|  | .. data:: flask.request_tearing_down | ||||||
|  |    :noindex: | ||||||
|  | 
 | ||||||
|  |    This signal is sent when the request is tearing down.  This is always | ||||||
|  |    called, even if an exception is caused.  Currently functions listening | ||||||
|  |    to this signal are called after the regular teardown handlers, but this | ||||||
|  |    is not something you can rely on. | ||||||
|  | 
 | ||||||
|  |    Example subscriber:: | ||||||
|  | 
 | ||||||
|  |         def close_db_connection(sender): | ||||||
|  |             session.close() | ||||||
|  | 
 | ||||||
|  |         from flask import request_tearing_down | ||||||
|  |         request_tearing_down.connect(close_db_connection, app) | ||||||
|  | 
 | ||||||
| .. _blinker: http://pypi.python.org/pypi/blinker | .. _blinker: http://pypi.python.org/pypi/blinker | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ from .session import Session | ||||||
| 
 | 
 | ||||||
| # the signals | # the signals | ||||||
| from .signals import signals_available, template_rendered, request_started, \ | from .signals import signals_available, template_rendered, request_started, \ | ||||||
|      request_finished, got_request_exception |      request_finished, got_request_exception, request_tearing_down | ||||||
| 
 | 
 | ||||||
| # only import json if it's available | # only import json if it's available | ||||||
| if json_available: | if json_available: | ||||||
|  |  | ||||||
							
								
								
									
										110
									
								
								flask/app.py
								
								
								
								
							
							
						
						
									
										110
									
								
								flask/app.py
								
								
								
								
							|  | @ -27,13 +27,14 @@ from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \ | ||||||
|     _tojson_filter, _endpoint_from_view_func |     _tojson_filter, _endpoint_from_view_func | ||||||
| from .wrappers import Request, Response | from .wrappers import Request, Response | ||||||
| from .config import ConfigAttribute, Config | from .config import ConfigAttribute, Config | ||||||
| from .ctx import _RequestContext | from .ctx import RequestContext | ||||||
| from .globals import _request_ctx_stack, request | from .globals import _request_ctx_stack, request | ||||||
| from .session import Session, _NullSession | from .session import Session, _NullSession | ||||||
| from .module import _ModuleSetupState | from .module import _ModuleSetupState | ||||||
| from .templating import _DispatchingJinjaLoader, \ | from .templating import _DispatchingJinjaLoader, \ | ||||||
|     _default_template_ctx_processor |     _default_template_ctx_processor | ||||||
| from .signals import request_started, request_finished, got_request_exception | from .signals import request_started, request_finished, got_request_exception, \ | ||||||
|  |     request_tearing_down | ||||||
| 
 | 
 | ||||||
| # a lock used for logger initialization | # a lock used for logger initialization | ||||||
| _logger_lock = Lock() | _logger_lock = Lock() | ||||||
|  | @ -126,6 +127,9 @@ class Flask(_PackageBoundObject): | ||||||
|     #: For example this might activate unittest helpers that have an |     #: For example this might activate unittest helpers that have an | ||||||
|     #: additional runtime cost which should not be enabled by default. |     #: additional runtime cost which should not be enabled by default. | ||||||
|     #: |     #: | ||||||
|  |     #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the | ||||||
|  |     #: default it's implicitly enabled. | ||||||
|  |     #: | ||||||
|     #: This attribute can also be configured from the config with the |     #: This attribute can also be configured from the config with the | ||||||
|     #: `TESTING` configuration key.  Defaults to `False`. |     #: `TESTING` configuration key.  Defaults to `False`. | ||||||
|     testing = ConfigAttribute('TESTING') |     testing = ConfigAttribute('TESTING') | ||||||
|  | @ -191,6 +195,7 @@ class Flask(_PackageBoundObject): | ||||||
|         'DEBUG':                                False, |         'DEBUG':                                False, | ||||||
|         'TESTING':                              False, |         'TESTING':                              False, | ||||||
|         'PROPAGATE_EXCEPTIONS':                 None, |         'PROPAGATE_EXCEPTIONS':                 None, | ||||||
|  |         'PRESERVE_CONTEXT_ON_EXCEPTION':        None, | ||||||
|         'SECRET_KEY':                           None, |         'SECRET_KEY':                           None, | ||||||
|         'SESSION_COOKIE_NAME':                  'session', |         'SESSION_COOKIE_NAME':                  'session', | ||||||
|         'PERMANENT_SESSION_LIFETIME':           timedelta(days=31), |         'PERMANENT_SESSION_LIFETIME':           timedelta(days=31), | ||||||
|  | @ -334,6 +339,19 @@ class Flask(_PackageBoundObject): | ||||||
|             return rv |             return rv | ||||||
|         return self.testing or self.debug |         return self.testing or self.debug | ||||||
| 
 | 
 | ||||||
|  |     @property | ||||||
|  |     def preserve_context_on_exception(self): | ||||||
|  |         """Returns the value of the `PRESERVE_CONTEXT_ON_EXCEPTION` | ||||||
|  |         configuration value in case it's set, otherwise a sensible default | ||||||
|  |         is returned. | ||||||
|  | 
 | ||||||
|  |         .. versionadded:: 0.7 | ||||||
|  |         """ | ||||||
|  |         rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION'] | ||||||
|  |         if rv is not None: | ||||||
|  |             return rv | ||||||
|  |         return self.debug | ||||||
|  | 
 | ||||||
|     @property |     @property | ||||||
|     def logger(self): |     def logger(self): | ||||||
|         """A :class:`logging.Logger` object for this application.  The |         """A :class:`logging.Logger` object for this application.  The | ||||||
|  | @ -716,13 +734,35 @@ class Flask(_PackageBoundObject): | ||||||
|         """Register a function to be run after each request.  Your function |         """Register a function to be run after each request.  Your function | ||||||
|         must take one parameter, a :attr:`response_class` object and return |         must take one parameter, a :attr:`response_class` object and return | ||||||
|         a new response object or the same (see :meth:`process_response`). |         a new response object or the same (see :meth:`process_response`). | ||||||
|  | 
 | ||||||
|  |         As of Flask 0.7 this function might not be executed at the end of the | ||||||
|  |         request in case an unhandled exception ocurred. | ||||||
|         """ |         """ | ||||||
|         self.after_request_funcs.setdefault(None, []).append(f) |         self.after_request_funcs.setdefault(None, []).append(f) | ||||||
|         return f |         return f | ||||||
| 
 | 
 | ||||||
|     def teardown_request(self, f): |     def teardown_request(self, f): | ||||||
|         """Register a function to be run at the end of each request, |         """Register a function to be run at the end of each request, | ||||||
|         regardless of whether there was an exception or not. |         regardless of whether there was an exception or not.  These functions | ||||||
|  |         are executed when the request context is popped, even if not an | ||||||
|  |         actual request was performed. | ||||||
|  | 
 | ||||||
|  |         Example:: | ||||||
|  | 
 | ||||||
|  |             ctx = app.test_request_context() | ||||||
|  |             ctx.push() | ||||||
|  |             ... | ||||||
|  |             ctx.pop() | ||||||
|  | 
 | ||||||
|  |         When ``ctx.pop()`` is executed in the above example, the teardown | ||||||
|  |         functions are called just before the request context moves from the | ||||||
|  |         stack of active contexts.  This becomes relevant if you are using | ||||||
|  |         such constructs in tests. | ||||||
|  | 
 | ||||||
|  |         Generally teardown functions must take every necesary step to avoid | ||||||
|  |         that they will fail.  If they do execute code that might fail they | ||||||
|  |         will have to surround the execution of these code by try/except | ||||||
|  |         statements and log ocurring errors. | ||||||
|         """ |         """ | ||||||
|         self.teardown_request_funcs.setdefault(None, []).append(f) |         self.teardown_request_funcs.setdefault(None, []).append(f) | ||||||
|         return f |         return f | ||||||
|  | @ -770,9 +810,12 @@ class Flask(_PackageBoundObject): | ||||||
|         return value of the view or error handler.  This does not have to |         return value of the view or error handler.  This does not have to | ||||||
|         be a response object.  In order to convert the return value to a |         be a response object.  In order to convert the return value to a | ||||||
|         proper response object, call :func:`make_response`. |         proper response object, call :func:`make_response`. | ||||||
|  | 
 | ||||||
|  |         .. versionchanged:: 0.7 | ||||||
|  |            This no longer does the exception handling, this code was | ||||||
|  |            moved to the new :meth:`full_dispatch_request`. | ||||||
|         """ |         """ | ||||||
|         req = _request_ctx_stack.top.request |         req = _request_ctx_stack.top.request | ||||||
|         try: |  | ||||||
|         if req.routing_exception is not None: |         if req.routing_exception is not None: | ||||||
|             raise req.routing_exception |             raise req.routing_exception | ||||||
|         rule = req.url_rule |         rule = req.url_rule | ||||||
|  | @ -783,8 +826,23 @@ class Flask(_PackageBoundObject): | ||||||
|             return self.make_default_options_response() |             return self.make_default_options_response() | ||||||
|         # otherwise dispatch to the handler for that endpoint |         # otherwise dispatch to the handler for that endpoint | ||||||
|         return self.view_functions[rule.endpoint](**req.view_args) |         return self.view_functions[rule.endpoint](**req.view_args) | ||||||
|  | 
 | ||||||
|  |     def full_dispatch_request(self): | ||||||
|  |         """Dispatches the request and on top of that performs request | ||||||
|  |         pre and postprocessing as well as HTTP exception catching and | ||||||
|  |         error handling. | ||||||
|  |         """ | ||||||
|  |         try: | ||||||
|  |             request_started.send(self) | ||||||
|  |             rv = self.preprocess_request() | ||||||
|  |             if rv is None: | ||||||
|  |                 rv = self.dispatch_request() | ||||||
|         except HTTPException, e: |         except HTTPException, e: | ||||||
|             return self.handle_http_exception(e) |             rv = self.handle_http_exception(e) | ||||||
|  |         response = self.make_response(rv) | ||||||
|  |         response = self.process_response(response) | ||||||
|  |         request_finished.send(self, response=response) | ||||||
|  |         return response | ||||||
| 
 | 
 | ||||||
|     def make_default_options_response(self): |     def make_default_options_response(self): | ||||||
|         """This method is called to create the default `OPTIONS` response. |         """This method is called to create the default `OPTIONS` response. | ||||||
|  | @ -894,7 +952,10 @@ class Flask(_PackageBoundObject): | ||||||
| 
 | 
 | ||||||
|     def do_teardown_request(self): |     def do_teardown_request(self): | ||||||
|         """Called after the actual request dispatching and will |         """Called after the actual request dispatching and will | ||||||
|         call every as :meth:`teardown_request` decorated function. |         call every as :meth:`teardown_request` decorated function.  This is | ||||||
|  |         not actually called by the :class:`Flask` object itself but is always | ||||||
|  |         triggered when the request context is popped.  That way we have a | ||||||
|  |         tighter control over certain resources under testing environments. | ||||||
|         """ |         """ | ||||||
|         funcs = reversed(self.teardown_request_funcs.get(None, ())) |         funcs = reversed(self.teardown_request_funcs.get(None, ())) | ||||||
|         mod = request.module |         mod = request.module | ||||||
|  | @ -905,12 +966,13 @@ class Flask(_PackageBoundObject): | ||||||
|             rv = func(exc) |             rv = func(exc) | ||||||
|             if rv is not None: |             if rv is not None: | ||||||
|                 return rv |                 return rv | ||||||
|  |         request_tearing_down.send(self) | ||||||
| 
 | 
 | ||||||
|     def request_context(self, environ): |     def request_context(self, environ): | ||||||
|         """Creates a request context from the given environment and binds |         """Creates a :class:`~flask.ctx.RequestContext` from the given | ||||||
|         it to the current context.  This must be used in combination with |         environment and binds it to the current context.  This must be used in | ||||||
|         the `with` statement because the request is only bound to the |         combination with the `with` statement because the request is only bound | ||||||
|         current context for the duration of the `with` block. |         to the current context for the duration of the `with` block. | ||||||
| 
 | 
 | ||||||
|         Example usage:: |         Example usage:: | ||||||
| 
 | 
 | ||||||
|  | @ -934,7 +996,7 @@ class Flask(_PackageBoundObject): | ||||||
| 
 | 
 | ||||||
|         :param environ: a WSGI environment |         :param environ: a WSGI environment | ||||||
|         """ |         """ | ||||||
|         return _RequestContext(self, environ) |         return RequestContext(self, environ) | ||||||
| 
 | 
 | ||||||
|     def test_request_context(self, *args, **kwargs): |     def test_request_context(self, *args, **kwargs): | ||||||
|         """Creates a WSGI environment from the given values (see |         """Creates a WSGI environment from the given values (see | ||||||
|  | @ -969,16 +1031,11 @@ class Flask(_PackageBoundObject): | ||||||
|         Then you still have the original application object around and |         Then you still have the original application object around and | ||||||
|         can continue to call methods on it. |         can continue to call methods on it. | ||||||
| 
 | 
 | ||||||
|         .. versionchanged:: 0.4 |  | ||||||
|            The :meth:`after_request` functions are now called even if an |  | ||||||
|            error handler took over request processing.  This ensures that |  | ||||||
|            even if an exception happens database have the chance to |  | ||||||
|            properly close the connection. |  | ||||||
| 
 |  | ||||||
|         .. versionchanged:: 0.7 |         .. versionchanged:: 0.7 | ||||||
|            The :meth:`teardown_request` functions get called at the very end of |            The behavior of the before and after request callbacks was changed | ||||||
|            processing the request. If an exception was thrown, it gets passed to |            under error conditions and a new callback was added that will | ||||||
|            each teardown_request function. |            always execute at the end of the request, independent on if an | ||||||
|  |            error ocurred or not.  See :ref:`callbacks-and-errors`. | ||||||
| 
 | 
 | ||||||
|         :param environ: a WSGI environment |         :param environ: a WSGI environment | ||||||
|         :param start_response: a callable accepting a status code, |         :param start_response: a callable accepting a status code, | ||||||
|  | @ -987,20 +1044,9 @@ class Flask(_PackageBoundObject): | ||||||
|         """ |         """ | ||||||
|         with self.request_context(environ): |         with self.request_context(environ): | ||||||
|             try: |             try: | ||||||
|                 request_started.send(self) |                 response = self.full_dispatch_request() | ||||||
|                 rv = self.preprocess_request() |  | ||||||
|                 if rv is None: |  | ||||||
|                     rv = self.dispatch_request() |  | ||||||
|                 response = self.make_response(rv) |  | ||||||
|             except Exception, e: |             except Exception, e: | ||||||
|                 response = self.make_response(self.handle_exception(e)) |                 response = self.make_response(self.handle_exception(e)) | ||||||
|             try: |  | ||||||
|                 response = self.process_response(response) |  | ||||||
|             except Exception, e: |  | ||||||
|                 response = self.make_response(self.handle_exception(e)) |  | ||||||
|             finally: |  | ||||||
|                 self.do_teardown_request() |  | ||||||
|             request_finished.send(self, response=response) |  | ||||||
|             return response(environ, start_response) |             return response(environ, start_response) | ||||||
| 
 | 
 | ||||||
|     def __call__(self, environ, start_response): |     def __call__(self, environ, start_response): | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								flask/ctx.py
								
								
								
								
							
							
						
						
									
										35
									
								
								flask/ctx.py
								
								
								
								
							|  | @ -51,11 +51,34 @@ def has_request_context(): | ||||||
|     return _request_ctx_stack.top is not None |     return _request_ctx_stack.top is not None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class _RequestContext(object): | class RequestContext(object): | ||||||
|     """The request context contains all request relevant information.  It is |     """The request context contains all request relevant information.  It is | ||||||
|     created at the beginning of the request and pushed to the |     created at the beginning of the request and pushed to the | ||||||
|     `_request_ctx_stack` and removed at the end of it.  It will create the |     `_request_ctx_stack` and removed at the end of it.  It will create the | ||||||
|     URL adapter and request object for the WSGI environment provided. |     URL adapter and request object for the WSGI environment provided. | ||||||
|  | 
 | ||||||
|  |     Do not attempt to use this class directly, instead use | ||||||
|  |     :meth:`~flask.Flask.test_request_context` and | ||||||
|  |     :meth:`~flask.Flask.request_context` to create this object. | ||||||
|  | 
 | ||||||
|  |     When the request context is popped, it will evaluate all the | ||||||
|  |     functions registered on the application for teardown execution | ||||||
|  |     (:meth:`~flask.Flask.teardown_request`). | ||||||
|  | 
 | ||||||
|  |     The request context is automatically popped at the end of the request | ||||||
|  |     for you.  In debug mode the request context is kept around if | ||||||
|  |     exceptions happen so that interactive debuggers have a chance to | ||||||
|  |     introspect the data.  With 0.4 this can also be forced for requests | ||||||
|  |     that did not fail and outside of `DEBUG` mode.  By setting | ||||||
|  |     ``'flask._preserve_context'`` to `True` on the WSGI environment the | ||||||
|  |     context will not pop itself at the end of the request.  This is used by | ||||||
|  |     the :meth:`~flask.Flask.test_client` for example to implement the | ||||||
|  |     deferred cleanup functionality. | ||||||
|  | 
 | ||||||
|  |     You might find this helpful for unittests where you need the | ||||||
|  |     information from the context local around for a little longer.  Make | ||||||
|  |     sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in | ||||||
|  |     that situation, otherwise your unittests will leak memory. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def __init__(self, app, environ): |     def __init__(self, app, environ): | ||||||
|  | @ -74,7 +97,7 @@ class _RequestContext(object): | ||||||
|             self.request.routing_exception = e |             self.request.routing_exception = e | ||||||
| 
 | 
 | ||||||
|     def push(self): |     def push(self): | ||||||
|         """Binds the request context.""" |         """Binds the request context to the current context.""" | ||||||
|         _request_ctx_stack.push(self) |         _request_ctx_stack.push(self) | ||||||
| 
 | 
 | ||||||
|         # Open the session at the moment that the request context is |         # Open the session at the moment that the request context is | ||||||
|  | @ -85,7 +108,11 @@ class _RequestContext(object): | ||||||
|             self.session = _NullSession() |             self.session = _NullSession() | ||||||
| 
 | 
 | ||||||
|     def pop(self): |     def pop(self): | ||||||
|         """Pops the request context.""" |         """Pops the request context and unbinds it by doing that.  This will | ||||||
|  |         also trigger the execution of functions registered by the | ||||||
|  |         :meth:`~flask.Flask.teardown_request` decorator. | ||||||
|  |         """ | ||||||
|  |         self.app.do_teardown_request() | ||||||
|         _request_ctx_stack.pop() |         _request_ctx_stack.pop() | ||||||
| 
 | 
 | ||||||
|     def __enter__(self): |     def __enter__(self): | ||||||
|  | @ -99,5 +126,5 @@ class _RequestContext(object): | ||||||
|         # the context can be force kept alive for the test client. |         # the context can be force kept alive for the test client. | ||||||
|         # See flask.testing for how this works. |         # See flask.testing for how this works. | ||||||
|         if not self.request.environ.get('flask._preserve_context') and \ |         if not self.request.environ.get('flask._preserve_context') and \ | ||||||
|            (tb is None or not self.app.debug): |            (tb is None or not self.app.preserve_context_on_exception): | ||||||
|             self.pop() |             self.pop() | ||||||
|  |  | ||||||
|  | @ -47,4 +47,5 @@ _signals = Namespace() | ||||||
| template_rendered = _signals.signal('template-rendered') | template_rendered = _signals.signal('template-rendered') | ||||||
| request_started = _signals.signal('request-started') | request_started = _signals.signal('request-started') | ||||||
| request_finished = _signals.signal('request-finished') | request_finished = _signals.signal('request-finished') | ||||||
|  | request_tearing_down = _signals.signal('request-tearing-down') | ||||||
| got_request_exception = _signals.signal('got-request-exception') | got_request_exception = _signals.signal('got-request-exception') | ||||||
|  |  | ||||||
|  | @ -784,8 +784,11 @@ class BasicFunctionalityTestCase(unittest.TestCase): | ||||||
| 
 | 
 | ||||||
|     def test_max_content_length(self): |     def test_max_content_length(self): | ||||||
|         app = flask.Flask(__name__) |         app = flask.Flask(__name__) | ||||||
|         app.debug = True |  | ||||||
|         app.config['MAX_CONTENT_LENGTH'] = 64 |         app.config['MAX_CONTENT_LENGTH'] = 64 | ||||||
|  |         @app.before_request | ||||||
|  |         def always_first(): | ||||||
|  |             flask.request.form['myfile'] | ||||||
|  |             assert False | ||||||
|         @app.route('/accept', methods=['POST']) |         @app.route('/accept', methods=['POST']) | ||||||
|         def accept_file(): |         def accept_file(): | ||||||
|             flask.request.form['myfile'] |             flask.request.form['myfile'] | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue