Permalink
Browse files

Added notes on proxies

  • Loading branch information...
1 parent c0abdc4 commit 3b0eb0f3ca45786135cacfc380bfdb51e7744e46 @mitsuhiko mitsuhiko committed Jul 20, 2010
Showing with 63 additions and 18 deletions.
  1. +35 −0 docs/api.rst
  2. +28 −18 docs/signals.rst
View
35 docs/api.rst
@@ -38,6 +38,8 @@ Incoming Request Data
sure that you always get the correct data for the active thread if you
are in a multithreaded environment.
+ This is a proxy. See :ref:`notes-on-proxies` for more information.
+
The request object is an instance of a :class:`~werkzeug.Request`
subclass and provides all of the attributes Werkzeug defines. This
just shows a quick overview of the most important ones.
@@ -164,6 +166,8 @@ To access the current session you can use the :class:`session` object:
The session object works pretty much like an ordinary dict, with the
difference that it keeps track on modifications.
+ This is a proxy. See :ref:`notes-on-proxies` for more information.
+
The following attributes are interesting:
.. attribute:: new
@@ -206,6 +210,8 @@ thing, like it does for :class:`request` and :class:`session`.
Just store on this whatever you want. For example a database
connection or the user that is currently logged in.
+ This is a proxy. See :ref:`notes-on-proxies` for more information.
+
Useful Functions and Classes
----------------------------
@@ -216,6 +222,8 @@ Useful Functions and Classes
extensions that want to support multiple applications running side
by side.
+ This is a proxy. See :ref:`notes-on-proxies` for more information.
+
.. autofunction:: url_for
.. function:: abort(code)
@@ -389,6 +397,8 @@ Signals
in debug mode, where no exception handling happens. The exception
itself is passed to the subscriber as `exception`.
+.. currentmodule:: None
+
.. class:: flask.signals.Namespace
An alias for :class:`blinker.base.Namespace` if blinker is available,
@@ -404,3 +414,28 @@ Signals
operations, including connecting.
.. _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
+- 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.LocalProxy._get_current_object` method::
+
+ app = current_app._get_current_object()
+ my_signal.send(app)
View
46 docs/signals.rst
@@ -41,13 +41,9 @@ the optional second argument specifies a sender. To unsubscribe from a
signal, you can use the :meth:`~blinker.base.Signal.disconnect` method.
For all core Flask signals, the sender is the application that issued the
-signal. This however might not be true for Flask extensions, so consult
-the documentation when subscribing to signals.
-
-Additionally there is a convenient helper method that allows you to
-temporarily subscribe a function to a signal. This is especially helpful
-for unittests (:meth:`~blinker.base.Signal.temporarily_connected_to`).
-This has to be used in combination with the `with` statement.
+signal. When you subscribe to a signal, be sure to also provide a sender
+unless you really want to listen for signals of all applications. This is
+especially true if you are developing an extension.
Here for example a helper context manager that can be used to figure out
in a unittest which templates were rendered and what variables were passed
@@ -57,29 +53,43 @@ to the template::
from contextlib import contextmanager
@contextmanager
- def captured_templates():
+ def captured_templates(app):
recorded = []
def record(template, context):
recorded.append((template, context))
- template_rendered.connect(record)
+ template_rendered.connect(record, app)
try:
yield recorded
finally:
- template_rendered.disconnect(record)
+ template_rendered.disconnect(record, app)
This can now easily be paired with a test client::
- with captured_templates() as templates:
+ with captured_templates(app) as templates:
rv = app.test_client().get('/')
assert rv.status_code == 200
assert len(templates) == 1
template, context = templates[0]
assert template.name == 'index.html'
assert len(context['items']) == 10
-All the template rendering in the code, the `with` block wraps will now be
-recorded in the `templates` variable. Whenever a template is rendered,
-the template object as well as context is appended to it.
+All the template rendering in the code issued by the application `app`
+in the body of the `with` block will now be recorded in the `templates`
+variable. Whenever a template is rendered, the template object as well as
+context are appended to it.
+
+Additionally there is a convenient helper method
+(:meth:`~blinker.base.Signal.temporarily_connected_to`). that allows you
+to temporarily subscribe a function to a signal with is a context manager
+on its own which simplifies the example above::
+
+ from flask import template_rendered
+
+ def captured_templates(app):
+ recorded = []
+ def record(template, context):
+ recorded.append((template, context))
+ return template_rendered.temporarily_connected_to(record, app)
Creating Signals
----------------
@@ -153,7 +163,7 @@ The following signals exist in Flask:
context)
from flask import request_started
- request_started.connect(log_template_renders)
+ request_started.connect(log_template_renders, app)
.. data:: flask.request_started
:noindex:
@@ -169,7 +179,7 @@ The following signals exist in Flask:
sender.logger.debug('Request context is set up')
from flask import request_started
- request_started.connect(log_request)
+ request_started.connect(log_request, app)
.. data:: flask.request_finished
:noindex:
@@ -184,7 +194,7 @@ The following signals exist in Flask:
'Response: %s', response)
from flask import request_finished
- request_finished.connect(log_response)
+ request_finished.connect(log_response, app)
.. data:: flask.got_request_exception
:noindex:
@@ -200,6 +210,6 @@ The following signals exist in Flask:
sender.logger.debug('Got exception during processing: %s', exception)
from flask import got_request_exception
- got_request_exception.connect(log_exception)
+ got_request_exception.connect(log_exception, app)
.. _blinker: http://pypi.python.org/pypi/blinker

0 comments on commit 3b0eb0f

Please sign in to comment.