summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-12-04 19:27:46 -0500
committerChris McDonough <chrism@plope.com>2011-12-04 19:27:46 -0500
commit5d462f0c660f939c773862b0fab81728c9ba62c7 (patch)
tree658df249d53de844c2f422ab04c4c26ee4feb86d /docs
parentd5666e630a08c943a22682540aa51174cee6851f (diff)
parenta78b58dd5cf665f7a7aaa18e9e7f6cae3fc7f749 (diff)
downloadpyramid-5d462f0c660f939c773862b0fab81728c9ba62c7.tar.gz
pyramid-5d462f0c660f939c773862b0fab81728c9ba62c7.tar.bz2
pyramid-5d462f0c660f939c773862b0fab81728c9ba62c7.zip
merge feature.introspection branch
Diffstat (limited to 'docs')
-rw-r--r--docs/api/config.rst17
-rw-r--r--docs/api/interfaces.rst8
-rw-r--r--docs/api/registry.rst30
-rw-r--r--docs/glossary.rst42
-rw-r--r--docs/index.rst6
-rw-r--r--docs/latexindex.rst7
-rw-r--r--docs/narr/advconfig.rst79
-rw-r--r--docs/narr/extconfig.rst366
-rw-r--r--docs/narr/introspector.rst542
-rw-r--r--docs/narr/tb_introspector.pngbin0 -> 46164 bytes
10 files changed, 1015 insertions, 82 deletions
diff --git a/docs/api/config.rst b/docs/api/config.rst
index a8c193b60..dbfbb1761 100644
--- a/docs/api/config.rst
+++ b/docs/api/config.rst
@@ -94,6 +94,23 @@
.. automethod:: set_renderer_globals_factory(factory)
+ .. attribute:: introspectable
+
+ A shortcut attribute which points to the
+ :class:`pyramid.registry.Introspectable` class (used during
+ directives to provide introspection to actions).
+
+ This attribute is new as of :app:`Pyramid` 1.3.
+
+ .. attribute:: introspector
+
+ The :term:`introspector` related to this configuration. It is an
+ instance implementing the :class:`pyramid.interfaces.IIntrospector`
+ interface. If the Configurator constructor was supplied with an
+ ``introspector`` argument, this attribute will be that value.
+ Otherwise, it will be an instance of a default introspector type.
+
+ This attribute is new as of :app:`Pyramid` 1.3.
.. attribute:: global_registries
diff --git a/docs/api/interfaces.rst b/docs/api/interfaces.rst
index b336e549d..5b190b53b 100644
--- a/docs/api/interfaces.rst
+++ b/docs/api/interfaces.rst
@@ -68,3 +68,11 @@ Other Interfaces
.. autointerface:: IResponse
:members:
+ .. autointerface:: IIntrospectable
+ :members:
+
+ .. autointerface:: IIntrospector
+ :members:
+
+ .. autointerface:: IActionInfo
+ :members:
diff --git a/docs/api/registry.rst b/docs/api/registry.rst
index 4d327370a..25192f3ed 100644
--- a/docs/api/registry.rst
+++ b/docs/api/registry.rst
@@ -14,3 +14,33 @@
accessed as ``request.registry.settings`` or
``config.registry.settings`` in a typical Pyramid application.
+ .. attribute:: introspector
+
+ When a registry is set up (or created) by a :term:`Configurator`, the
+ registry will be decorated with an instance named ``introspector``
+ implementing the :class:`pyramid.interfaces.IIntrospector` interface.
+ See also :attr:`pyramid.config.Configurator.introspector``.
+
+ When a registry is created "by hand", however, this attribute will not
+ exist until set up by a configurator.
+
+ This attribute is often accessed as ``request.registry.introspector`` in
+ a typical Pyramid application.
+
+ This attribute is new as of :app:`Pyramid` 1.3.
+
+.. class:: Introspectable
+
+ The default implementation of the interface
+ :class:`pyramid.interfaces.IIntrospectable` used by framework exenders.
+ An instance of this class is is created when
+ :attr:`pyramid.config.Configurator.introspectable` is called.
+
+ This class is new as of :app:`Pyramid` 1.3.
+
+.. class:: noop_introspector
+
+ An introspector which throws away all registrations, useful for disabling
+ introspection altogether (pass as ``introspector`` to the
+ :term:`Configurator` constructor).
+
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 0d69fbb0d..399b78cdf 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -563,9 +563,8 @@ Glossary
also `PEP 318 <http://www.python.org/dev/peps/pep-0318/>`_.
configuration declaration
- An individual method call made to an instance of a :app:`Pyramid`
- :term:`Configurator` object which performs an arbitrary action, such as
- registering a :term:`view configuration` (via the
+ An individual method call made to a :term:`configuration directive`,
+ such as registering a :term:`view configuration` (via the
:meth:`~pyramid.config.Configurator.add_view` method of the
configurator) or :term:`route configuration` (via the
:meth:`~pyramid.config.Configurator.add_route` method of the
@@ -941,3 +940,40 @@ Glossary
directory of a Python installation or virtualenv as the result of
running ``setup.py install`` or ``setup.py develop``.
+ introspector
+ An object with the methods described by
+ :class:`pyramid.interfaces.IIntrospector` that is available in both
+ configuration code (for registration) and at runtime (for querying) that
+ allows a developer to introspect configuration statements and
+ relationships between those statements.
+
+ conflict resolution
+ Pyramid attempts to resolve ambiguous configuration statements made by
+ application developers via automatic conflict resolution. Automatic
+ conflict resolution is described in
+ :ref:`automatic_conflict_resolution`. If Pyramid cannot resolve
+ ambiguous configuration statements, it is possible to manually resolve
+ them as described in :ref:`manually_resolving_conflicts`.
+
+ configuration directive
+ A method of the :term:`Configurator` which causes a configuration action
+ to occur. The method :meth:`pyramid.config.Configurator.add_view` is a
+ configuration directive, and application developers can add their own
+ directives as necessary (see :ref:`add_directive`).
+
+ action
+ Represents a pending configuration statement generated by a call to a
+ :term:`configuration directive`. The set of pending configuration
+ actions are processed when :meth:`pyramid.config.Configurator.commit` is
+ called.
+
+ discriminator
+ The unique identifier of an :term:`action`.
+
+ introspectable
+ An object which implements the attributes and methods described in
+ :class:`pyramid.interfaces.IIntrospectable`. Introspectables are used
+ by the :term:`introspector` to display configuration information about
+ a running Pyramid application. An introspectable is associated with a
+ :term:`action` by virtue of the
+ :meth:`pyramid.config.Configurator.action` method.
diff --git a/docs/index.rst b/docs/index.rst
index e4de8b0c8..ceb29d108 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -65,6 +65,7 @@ Narrative documentation in chapter form explaining how to use
narr/configuration
narr/project
narr/startup
+ narr/router
narr/urldispatch
narr/views
narr/renderers
@@ -87,9 +88,10 @@ Narrative documentation in chapter form explaining how to use
narr/security
narr/hybrid
narr/hooks
- narr/advconfig
+ narr/introspector
narr/extending
- narr/router
+ narr/advconfig
+ narr/extconfig
narr/threadlocals
narr/zca
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 584dd3825..4db5b64b2 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -31,6 +31,8 @@ Narrative Documentation
narr/configuration
narr/firstapp
narr/project
+ narr/startup
+ narr/router
narr/urldispatch
narr/views
narr/renderers
@@ -53,9 +55,10 @@ Narrative Documentation
narr/security
narr/hybrid
narr/hooks
- narr/advconfig
+ narr/introspector
narr/extending
- narr/startup
+ narr/advconfig
+ narr/extconfig
narr/threadlocals
narr/zca
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index 7b62b1a73..3a7bf2805 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -87,8 +87,8 @@ that ends something like this:
Conflicting configuration actions
For: ('view', None, '', None, <InterfaceClass pyramid.interfaces.IView>,
None, None, None, None, None, False, None, None, None)
- ('app.py', 14, '<module>', 'config.add_view(hello_world)')
- ('app.py', 17, '<module>', 'config.add_view(hello_world)')
+ Line 14 of file app.py in <module>: 'config.add_view(hello_world)'
+ Line 17 of file app.py in <module>: 'config.add_view(goodbye_world)'
This traceback is trying to tell us:
@@ -115,6 +115,8 @@ Conflict detection happens for any kind of configuration: imperative
configuration or configuration that results from the execution of a
:term:`scan`.
+.. _manually_resolving_conflicts:
+
Manually Resolving Conflicts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -397,76 +399,3 @@ constraints: the routes they imply require relative ordering. Such ordering
constraints are not absolved by two-phase configuration. Routes are still
added in configuration execution order.
-.. index::
- single: add_directive
- pair: configurator; adding directives
-
-.. _add_directive:
-
-Adding Methods to the Configurator via ``add_directive``
---------------------------------------------------------
-
-Framework extension writers can add arbitrary methods to a
-:term:`Configurator` by using the
-:meth:`pyramid.config.Configurator.add_directive` method of the configurator.
-This makes it possible to extend a Pyramid configurator in arbitrary ways,
-and allows it to perform application-specific tasks more succinctly.
-
-The :meth:`~pyramid.config.Configurator.add_directive` method accepts two
-positional arguments: a method name and a callable object. The callable
-object is usually a function that takes the configurator instance as its
-first argument and accepts other arbitrary positional and keyword arguments.
-For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.events import NewRequest
- from pyramid.config import Configurator
-
- def add_newrequest_subscriber(config, subscriber):
- config.add_subscriber(subscriber, NewRequest).
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_directive('add_newrequest_subscriber',
- add_newrequest_subscriber)
-
-Once :meth:`~pyramid.config.Configurator.add_directive` is called, a user can
-then call the method by its given name as if it were a built-in method of the
-Configurator:
-
-.. code-block:: python
- :linenos:
-
- def mysubscriber(event):
- print event.request
-
- config.add_newrequest_subscriber(mysubscriber)
-
-A call to :meth:`~pyramid.config.Configurator.add_directive` is often
-"hidden" within an ``includeme`` function within a "frameworky" package meant
-to be included as per :ref:`including_configuration` via
-:meth:`~pyramid.config.Configurator.include`. For example, if you put this
-code in a package named ``pyramid_subscriberhelpers``:
-
-.. code-block:: python
- :linenos:
-
- def includeme(config)
- config.add_directive('add_newrequest_subscriber',
- add_newrequest_subscriber)
-
-The user of the add-on package ``pyramid_subscriberhelpers`` would then be
-able to install it and subsequently do:
-
-.. code-block:: python
- :linenos:
-
- def mysubscriber(event):
- print event.request
-
- from pyramid.config import Configurator
- config = Configurator()
- config.include('pyramid_subscriberhelpers')
- config.add_newrequest_subscriber(mysubscriber)
diff --git a/docs/narr/extconfig.rst b/docs/narr/extconfig.rst
new file mode 100644
index 000000000..856654377
--- /dev/null
+++ b/docs/narr/extconfig.rst
@@ -0,0 +1,366 @@
+.. index::
+ single: extending configuration
+
+.. _extconfig_narr:
+
+Extending Pyramid Configuration
+===============================
+
+Pyramid allows you to extend its Configurator with custom directives. Custom
+directives can use other directives, they can add a custom :term:`action`,
+they can participate in :term:`conflict resolution`, and they can provide
+some number of :term:`introspectable` objects.
+
+.. index::
+ single: add_directive
+ pair: configurator; adding directives
+
+.. _add_directive:
+
+Adding Methods to the Configurator via ``add_directive``
+--------------------------------------------------------
+
+Framework extension writers can add arbitrary methods to a
+:term:`Configurator` by using the
+:meth:`pyramid.config.Configurator.add_directive` method of the configurator.
+Using :meth:`~pyramid.config.Configurator.add_directive` makes it possible to
+extend a Pyramid configurator in arbitrary ways, and allows it to perform
+application-specific tasks more succinctly.
+
+The :meth:`~pyramid.config.Configurator.add_directive` method accepts two
+positional arguments: a method name and a callable object. The callable
+object is usually a function that takes the configurator instance as its
+first argument and accepts other arbitrary positional and keyword arguments.
+For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.events import NewRequest
+ from pyramid.config import Configurator
+
+ def add_newrequest_subscriber(config, subscriber):
+ config.add_subscriber(subscriber, NewRequest).
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_newrequest_subscriber',
+ add_newrequest_subscriber)
+
+Once :meth:`~pyramid.config.Configurator.add_directive` is called, a user can
+then call the added directive by its given name as if it were a built-in
+method of the Configurator:
+
+.. code-block:: python
+ :linenos:
+
+ def mysubscriber(event):
+ print event.request
+
+ config.add_newrequest_subscriber(mysubscriber)
+
+A call to :meth:`~pyramid.config.Configurator.add_directive` is often
+"hidden" within an ``includeme`` function within a "frameworky" package meant
+to be included as per :ref:`including_configuration` via
+:meth:`~pyramid.config.Configurator.include`. For example, if you put this
+code in a package named ``pyramid_subscriberhelpers``:
+
+.. code-block:: python
+ :linenos:
+
+ def includeme(config)
+ config.add_directive('add_newrequest_subscriber',
+ add_newrequest_subscriber)
+
+The user of the add-on package ``pyramid_subscriberhelpers`` would then be
+able to install it and subsequently do:
+
+.. code-block:: python
+ :linenos:
+
+ def mysubscriber(event):
+ print event.request
+
+ from pyramid.config import Configurator
+ config = Configurator()
+ config.include('pyramid_subscriberhelpers')
+ config.add_newrequest_subscriber(mysubscriber)
+
+Using ``config.action`` in a Directive
+--------------------------------------
+
+If a custom directive can't do its work exclusively in terms of existing
+configurator methods (such as
+:meth:`pyramid.config.Configurator.add_subscriber`, as above), the directive
+may need to make use of the :meth:`pyramid.config.Configurator.action`
+method. This method adds an entry to the list of "actions" that Pyramid will
+attempt to process when :meth:`pyramid.config.Configurator.commit` is called.
+An action is simply a dictionary that includes a :term:`discriminator`,
+possibly a callback function, and possibly other metadata used by Pyramid's
+action system.
+
+Here's an example directive which uses the "action" method:
+
+.. code-block:: python
+ :linenos:
+
+ def add_jammyjam(config, jammyjam):
+ def register():
+ config.registry.jammyjam = jammyjam
+ config.action('jammyjam', register)
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_jammyjam', add_jammyjam)
+
+Fancy, but what does it do? The action method accepts a number of arguments.
+In the above directive named ``add_jammyjam``, we call
+:meth:`~pyramid.config.Configurator.action` with two arguments: the string
+``jammyjam`` is passed as the first argument named ``discriminator``, and the
+closure function named ``register`` is passed as the second argument named
+``callable``.
+
+When the :meth:`~pyramid.config.Configurator.action` method is called, it
+appends an action to the list of pending configuration actions. All pending
+actions with the same discriminator value are potentially in conflict with
+one another (see :ref:`conflict_detection`). When the
+:meth:`~pyramid.config.Configurator.commit` method of the Configurator is
+called (either explicitly or as the result of calling
+:meth:`~pyramid.config.Configurator.make_wsgi_app`), conflicting actions are
+potentially automatically resolved as per
+:ref:`automatic_conflict_resolution`. If a conflict cannot be automatically
+resolved, a ConfigurationConflictError is raised and application startup is
+prevented.
+
+In our above example, therefore, if a consumer of our ``add_jammyjam``
+directive did this:
+
+.. code-block:: python
+ :linenos:
+
+ config.add_jammyjam('first')
+ config.add_jammyjam('second')
+
+When the action list was committed resulting from the set of calls above, our
+user's application would not start, because the discriminators of the actions
+generated by the two calls are in direct conflict. Automatic conflict
+resolution cannot resolve the conflict (because no ``config.include`` is
+involved), and the user provided no intermediate
+:meth:`pyramid.config.Configurator.commit` call between the calls to
+``add_jammyjam`` to ensure that the successive calls did not conflict with
+each other.
+
+This demonstrates the purpose of the discriminator argument to the action
+method: it's used to indicate a uniqueness constraint for an action. Two
+actions with the same discriminator will conflict unless the conflict is
+automatically or manually resolved. A discriminator can be any hashable
+object, but it is generally a string or a tuple. *You use a discriminator to
+declaratively ensure that the user doesn't provide ambiguous configuration
+statements.*
+
+But let's imagine that a consumer of ``add_jammyjam`` used it in such a way
+that no configuration conflicts are generated.
+
+.. code-block:: python
+ :linenos:
+
+ config.add_jammyjam('first')
+
+What happens now? When the ``add_jammyjam`` method is called, an action is
+appended to the pending actions list. When the pending configuration actions
+are processed during :meth:`~pyramid.config.Configurator.commit`, and no
+conflicts occur, the *callable* provided as the second argument to the
+:meth:`~pyramid.config.Configurator.action` method within ``add_jammyjam`` is
+called with no arguments. The callable in ``add_jammyjam`` is the
+``register`` closure function. It simply sets the value
+``config.registry.jammyjam`` to whatever the user passed in as the
+``jammyjam`` argument to the ``add_jammyjam`` function. Therefore, the
+result of the user's call to our directive will set the ``jammyjam``
+attribute of the registry to the string ``first``. *A callable is used by a
+directive to defer the result of a user's call to the directive until
+conflict detection has had a chance to do its job*.
+
+Other arguments exist to the :meth:`~pyramid.config.Configurator.action`
+method, including ``args``, ``kw``, ``order``, and ``introspectables``.
+
+``args`` and ``kw`` exist as values, which, if passed, will be used as
+arguments to the ``callable`` function when it is called back. For example
+our directive might use them like so:
+
+.. code-block:: python
+ :linenos:
+
+ def add_jammyjam(config, jammyjam):
+ def register(*arg, **kw):
+ config.registry.jammyjam_args = arg
+ config.registry.jammyjam_kw = kw
+ config.registry.jammyjam = jammyjam
+ config.action('jammyjam', register, args=('one',), kw={'two':'two'})
+
+In the above example, when this directive is used to generate an action, and
+that action is committed, ``config.registry.jammyjam_args`` will be set to
+``('one',)`` and ``config.registry.jammyjam_kw`` will be set to
+``{'two':'two'}``. ``args`` and ``kw`` are honestly not very useful when
+your ``callable`` is a closure function, because you already usually have
+access to every local in the directive without needing them to be passed
+back. They can be useful, however, if you don't use a closure as a callable.
+
+``order`` is a crude order control mechanism. ``order`` defaults to the
+integer ``0``; it can be set to any other integer. All actions that share an
+order will be called before other actions that share a higher order. This
+makes it possible to write a directive with callable logic that relies on the
+execution of the callable of another directive being done first. For
+example, Pyramid's :meth:`pyramid.config.Configurator.add_view` directive
+registers an action with a higher order than the
+:meth:`pyramid.config.Configurator.add_route` method. Due to this, the
+``add_view`` method's callable can assume that, if a ``route_name`` was
+passed to it, that a route by this name was already registered by
+``add_route``, and if such a route has not already been registered, it's a
+configuration error (a view that names a nonexistent route via its
+``route_name`` parameter will never be called).
+
+``introspectables`` is a sequence of :term:`introspectable` objects. You can
+pass a sequence of introspectables to the
+:meth:`~pyramid.config.Configurator.action` method, which allows you to
+augment Pyramid's configuration introspection system.
+
+.. _introspection:
+
+Configuration Introspection
+---------------------------
+
+.. warning::
+
+ The introspection subsystem is new in Pyramid 1.3.
+
+Pyramid provides a configuration introspection system that can be used by
+debugging tools to provide visibility into the configuration of a running
+application.
+
+All built-in Pyramid directives (such as
+:meth:`pyramid.config.Configurator.add_view` and
+:meth:`pyramid.config.Configurator.add_route`) register a set of
+introspectables when called. For example, when you register a view via
+``add_view``, the directive registers at least one introspectable: an
+introspectable about the view registration itself, providing human-consumable
+values for the arguments it was passed. You can later use the introspection
+query system to determine whether a particular view uses a renderer, or
+whether a particular view is limited to a particular request method, or which
+routes a particular view is registered against. The Pyramid "debug toolbar"
+makes use of the introspection system in various ways to display information
+to Pyramid developers.
+
+Introspection values are set when a sequence of :term:`introspectable`
+objects is passed to the :meth:`~pyramid.config.Configurator.action` method.
+Here's an example of a directive which uses introspectables:
+
+.. code-block:: python
+ :linenos:
+
+ def add_jammyjam(config, value):
+ def register():
+ config.registry.jammyjam = value
+ intr = config.introspectable(category_name='jammyjams',
+ discriminator='jammyjam',
+ title='a jammyjam',
+ type_name=None)
+ intr['value'] = value
+ config.action('jammyjam', register, introspectables=(intr,))
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_jammyjam', add_jammyjam)
+
+If you notice, the above directive uses the ``introspectable`` attribute of a
+Configurator (:attr:`pyramid.config.Configurator.introspectable`) to create
+an introspectable object. The introspectable object's constructor requires
+at least four arguments: the ``category_name``, the ``discriminator``, the
+``title``, and the ``type_name``.
+
+The ``category_name`` is a string representing the logical category for this
+introspectable. Usually the category_name is a pluralization of the type of
+object being added via the action.
+
+The ``discriminator`` is a value unique **within the category** (unlike the
+action discriminator, which must be unique within the entire set of actions).
+It is typically a string or tuple representing the values unique to this
+introspectable within the category. It is used to generate links and as part
+of a relationship-forming target for other introspectables.
+
+The ``title`` is a human-consumable string that can be used by introspection
+system frontends to show a friendly summary of this introspectable.
+
+The ``type_name`` is a value that can be used to subtype this introspectable
+within its category for for sorting and presentation purposes. It can be any
+value.
+
+An introspectable is also dictionary-like. It can contain any set of
+key/value pairs, typically related to the arguments passed to its related
+directive. While the category_name, discriminator, title and type_name are
+*metadata* about the introspectable, the values provided as key/value pairs
+are the actual data provided by the introspectable. In the above example, we
+set the ``value`` key to the value of the ``value`` argument passed to the
+directive.
+
+Our directive above mutates the introspectable, and passes it in to the
+``action`` method as the first element of a tuple as the value of the
+``introspectable`` keyword argument. This associates this introspectable
+with the action. Introspection tools will then display this introspectable
+in their index.
+
+Introspectable Relationships
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Two introspectables may have relationships between each other.
+
+.. code-block:: python
+ :linenos:
+
+ def add_jammyjam(config, value, template):
+ def register():
+ config.registry.jammyjam = (value, template)
+ intr = config.introspectable(category_name='jammyjams',
+ discriminator='jammyjam',
+ title='a jammyjam',
+ type_name=None)
+ intr['value'] = value
+ tmpl_intr = config.introspectable(category_name='jammyjam templates',
+ discriminator=template,
+ title=template,
+ type_name=None)
+ tmpl_intr['value'] = template
+ intr.relate('jammyjam templates', template)
+ config.action('jammyjam', register, introspectables=(intr, tmpl_intr))
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_directive('add_jammyjam', add_jammyjam)
+
+In the above example, the ``add_jammyjam`` directive registers two
+introspectables. The first is related to the ``value`` passed to the
+directive; the second is related to the ``template`` passed to the directive.
+If you believe a concept within a directive is important enough to have its
+own introspectable, you can cause the same directive to register more than
+one introspectable, registering one introspectable for the "main idea" and
+another for a related concept.
+
+The call to ``intr.relate`` above
+(:meth:`pyramid.interfaces.IIntrospectable.relate`) is passed two arguments:
+a category name and a directive. The example above effectively indicates
+that the directive wishes to form a relationship between the ``intr``
+introspectable and the ``tmpl_intr`` introspectable; the arguments passed to
+``relate`` are the category name and discriminator of the ``tmpl_intr``
+introspectable.
+
+Relationships need not be made between two introspectables created by the
+same directive. Instead, a relationship can be formed between an
+introspectable created in one directive and another introspectable created in
+another by calling ``relate`` on either side with the other directive's
+category name and discriminator. An error will be raised at configuration
+commit time if you attempt to relate an introspectable with another
+nonexistent introspectable, however.
+
+Introspectable relationships will show up in frontend system renderings of
+introspection values. For example, if a view registration names a route
+name, the introspectable related to the view callable will show a reference
+to the route to which it relates to and vice versa.
diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst
new file mode 100644
index 000000000..cfc6144dd
--- /dev/null
+++ b/docs/narr/introspector.rst
@@ -0,0 +1,542 @@
+.. index::
+ single: introspection
+ single: introspector
+
+.. _using_introspection:
+
+Pyramid Configuration Introspection
+===================================
+
+When Pyramid starts up, each call to a :term:`configuration directive` causes
+one or more :term:`introspectable` objects to be registered with an
+:term:`introspector`. The introspector can be queried by application code to
+obtain information about the configuration of the running application. This
+feature is useful for debug toolbars, command-line scripts which show some
+aspect of configuration, and for runtime reporting of startup-time
+configuration settings.
+
+.. warning::
+
+ Introspection is new in Pyramid 1.3.
+
+Using the Introspector
+----------------------
+
+Here's an example of using Pyramid's introspector from within a view
+callable:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(route_name='bar')
+ def route_accepts(request):
+ introspector = request.registry.introspector
+ route_name = request.matched_route.name
+ route_intr = introspector.get('routes', route_name)
+ return Response(str(route_intr['pattern']))
+
+This view will return a response that contains the "pattern" argument
+provided to the ``add_route`` method of the route which matched when the view
+was called. It uses the :meth:`pyramid.interfaces.IIntrospector.get` method
+to return an introspectable in the category ``routes`` with a
+:term:`discriminator` equal to the matched route name. It then uses the
+returned introspectable to obtain an "pattern" value.
+
+The introspectable returned by the query methods of the introspector has
+methods and attributes described by
+:class:`pyramid.interfaces.IIntrospectable`. In particular, the
+:meth:`~pyramid.interfaces.IIntrospector.get`,
+:meth:`~pyramid.interfaces.IIntrospector.get_category`,
+:meth:`~pyramid.interfaces.IIntrospector.categories`,
+:meth:`~pyramid.interfaces.IIntrospector.categorized`, and
+:meth:`~pyramid.interfaces.IIntrospector.related` methods of an introspector
+can be used to query for introspectables.
+
+Introspectable Objects
+----------------------
+
+Introspectable objects are returned from query methods of an introspector.
+Each introspectable object implements the attributes and methods the
+documented at :class:`pyramid.interfaces.IIntrospectable`.
+
+The important attributes shared by all introspectables are the following:
+
+``title``
+
+ A human-readable text title describing the introspectable
+
+``category_name``
+
+ A text category name describing the introspection category to which this
+ introspectable belongs. It is often a plural if there are expected to be
+ more than one introspectable registered within the category.
+
+``discriminator``
+
+ A hashable object representing the unique value of this introspectable
+ within its category.
+
+``discriminator_hash``
+
+ The integer hash of the discriminator (useful for using in HTML links).
+
+``type_name``
+
+ The text name of a subtype within this introspectable's category. If there
+ is only one type name in this introspectable's category, this value will
+ often be a singular version of the category name but it can be an arbitrary
+ value.
+
+``action_info``
+
+ An object describing the directive call site which caused this
+ introspectable to be registered; contains attributes described in
+ :class:`pyramid.interfaces.IActionInfo`.
+
+Besides having the attributes described above, an introspectable is a
+dictionary-like object. An introspectable can be queried for data values via
+its ``__getitem__``, ``get``, ``keys``, ``values``, or ``items`` methods.
+For example:
+
+.. code-block:: python
+ :linenos:
+
+ route_intr = introspector.get('routes', 'edit_user')
+ pattern = route_intr['pattern']
+
+Pyramid Introspection Categories
+--------------------------------
+
+The list of concrete introspection categories provided by built-in Pyramid
+configuration directives follows. Add-on packages may supply other
+introspectables in categories not described here.
+
+``subscribers``
+
+ Each introspectable in the ``subscribers`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_subscriber` (or the decorator
+ equivalent); each will have the following data.
+
+ ``subscriber``
+
+ The subscriber callable object (the resolution of the ``subscriber``
+ argument passed to ``add_susbcriber``).
+
+ ``interfaces``
+
+ A sequence of interfaces (or classes) that are subscribed to (the
+ resolution of the ``ifaces`` argument passed to ``add_subscriber``).
+
+``response adapters``
+
+ Each introspectable in the ``response adapters`` category represents a call
+ to :meth:`pyramid.config.Configurator.add_response_adapter` (or a decorator
+ equivalent); each will have the following data.
+
+ ``adapter``
+
+ The adapter object (the resolved ``adapter`` argument to
+ ``add_response_adapter``).
+
+ ``type``
+
+ The resolved ``type_or_iface`` argument passed to
+ ``add_response_adapter``.
+
+``root factories``
+
+ Each introspectable in the ``root factories`` category represents a call to
+ :meth:`pyramid.config.Configurator.set_root_factory` (or the Configurator
+ constructor equivalent) *or* a ``factory`` argument passed to
+ :meth:`pyramid.config.Configurator.add_route`; each will have the following
+ data.
+
+ ``factory``
+
+ The factory object (the resolved ``factory`` argument to
+ ``set_root_factory``).
+
+ ``route_name``
+
+ The name of the route which will use this factory. If this is the
+ *default* root factory (if it's registered during a call to
+ ``set_root_factory``), this value will be ``None``.
+
+``session factory``
+
+ Only one introspectable will exist in the ``session factory`` category. It
+ represents a call to :meth:`pyramid.config.Configurator.set_session_factory`
+ (or the Configurator constructor equivalent); it will have the following
+ data.
+
+ ``factory``
+
+ The factory object (the resolved ``factory`` argument to
+ ``set_session_factory``).
+
+``request factory``
+
+ Only one introspectable will exist in the ``request factory`` category. It
+ represents a call to :meth:`pyramid.config.Configurator.set_request_factory`
+ (or the Configurator constructor equivalent); it will have the following
+ data.
+
+ ``factory``
+
+ The factory object (the resolved ``factory`` argument to
+ ``set_request_factory``).
+
+``locale negotiator``
+
+ Only one introspectable will exist in the ``locale negotiator`` category.
+ It represents a call to
+ :meth:`pyramid.config.Configurator.set_locale_negotiator` (or the
+ Configurator constructor equivalent); it will have the following data.
+
+ ``negotiator``
+
+ The factory object (the resolved ``negotiator`` argument to
+ ``set_locale_negotiator``).
+
+``renderer factories``
+
+ Each introspectable in the ``renderer factories`` category represents a
+ call to :meth:`pyramid.config.Configurator.add_renderer` (or the
+ Configurator constructor equivalent); each will have the following data.
+
+ ``name``
+
+ The name of the renderer (the value of the ``name`` argument to
+ ``add_renderer``).
+
+ ``factory``
+
+ The factory object (the resolved ``factory`` argument to
+ ``add_renderer``).
+
+``renderer globals factory``
+
+ There will be one and only one introspectable in the ``renderer globals
+ factory`` category. It represents a call to
+ :meth:`pyramid.config.Configurator.set_renderer_globals_factory`; it will
+ have the following data.
+
+ ``factory``
+
+ The factory object (the resolved ``factory`` argument to
+ ``set_renderer_globals_factory``).
+
+``routes``
+
+ Each introspectable in the ``routes`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_route`; each will have the following
+ data.
+
+ ``name``
+
+ The ``name`` argument passed to ``add_route``.
+
+ ``pattern``
+
+ The ``pattern`` argument passed to ``add_route``.
+
+ ``factory``
+
+ The (resolved) ``factory`` argument passed to ``add_route``.
+
+ ``xhr``
+
+ The ``xhr`` argument passed to ``add_route``.
+
+ ``request_method``
+
+ The ``request_method`` argument passed to ``add_route``.
+
+ ``request_methods``
+
+ A sequence of request method names implied by the ``request_method``
+ argument passed to ``add_route`` or the value ``None`` if a
+ ``request_method`` argument was not supplied.
+
+ ``path_info``
+
+ The ``path_info`` argument passed to ``add_route``.
+
+ ``request_param``
+
+ The ``request_param`` argument passed to ``add_route``.
+
+ ``header``
+
+ The ``header`` argument passed to ``add_route``.
+
+ ``accept``
+
+ The ``accept`` argument passed to ``add_route``.
+
+ ``traverse``
+
+ The ``traverse`` argument passed to ``add_route``.
+
+ ``custom_predicates``
+
+ The ``custom_predicates`` argument passed to ``add_route``.
+
+ ``pregenerator``
+
+ The ``pregenerator`` argument passed to ``add_route``.
+
+ ``pregenerator``
+
+ The ``static`` argument passed to ``add_route``.
+
+ ``pregenerator``
+
+ The ``use_global_views`` argument passed to ``add_route``.
+
+ ``object``
+
+ The :class:`pyramid.interfaces.IRoute` object that is used to perform
+ matching and generation for this route.
+
+``authentication policy``
+
+ There will be one and only one introspectable in the ``authentication
+ policy`` category. It represents a call to the
+ :meth:`pyramid.config.Configurator.set_authentication_policy` method (or
+ its Configurator constructor equivalent); it will have the following data.
+
+ ``policy``
+
+ The policy object (the resolved ``policy`` argument to
+ ``set_authentication_policy``).
+
+``authorization policy``
+
+ There will be one and only one introspectable in the ``authorization
+ policy`` category. It represents a call to the
+ :meth:`pyramid.config.Configurator.set_authorization_policy` method (or its
+ Configurator constructor equivalent); it will have the following data.
+
+ ``policy``
+
+ The policy object (the resolved ``policy`` argument to
+ ``set_authorization_policy``).
+
+``default permission``
+
+ There will be one and only one introspectable in the ``default permission``
+ category. It represents a call to the
+ :meth:`pyramid.config.Configurator.set_default_permission` method (or its
+ Configurator constructor equivalent); it will have the following data.
+
+ ``value``
+
+ The permission name passed to ``set_default_permission``.
+
+``views``
+
+ Each introspectable in the ``views`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_view`; each will have the following
+ data.
+
+ ``name``
+
+ The ``name`` argument passed to ``add_view``.
+
+ ``context``
+
+ The (resolved) ``context`` argument passed to ``add_view``.
+
+ ``containment``
+
+ The (resolved) ``containment`` argument passed to ``add_view``.
+
+ ``request_param``
+
+ The ``request_param`` argument passed to ``add_view``.
+
+ ``request_methods``
+
+ A sequence of request method names implied by the ``request_method``
+ argument passed to ``add_view`` or the value ``None`` if a
+ ``request_method`` argument was not supplied.
+
+ ``route_name``
+
+ The ``route_name`` argument passed to ``add_view``.
+
+ ``attr``
+
+ The ``attr`` argument passed to ``add_view``.
+
+ ``xhr``
+
+ The ``xhr`` argument passed to ``add_view``.
+
+ ``accept``
+
+ The ``accept`` argument passed to ``add_view``.
+
+ ``header``
+
+ The ``header`` argument passed to ``add_view``.
+
+ ``path_info``
+
+ The ``path_info`` argument passed to ``add_view``.
+
+ ``match_param``
+
+ The ``match_param`` argument passed to ``add_view``.
+
+ ``callable``
+
+ The (resolved) ``view`` argument passed to ``add_view``. Represents the
+ "raw" view callable.
+
+ ``derived_callable``
+
+ The view callable derived from the ``view`` argument passed to
+ ``add_view``. Represents the view callable which Pyramid itself calls
+ (wrapped in security and other wrappers).
+
+ ``mapper``
+
+ The (resolved) ``mapper`` argument passed to ``add_view``.
+
+ ``decorator``
+
+ The (resolved) ``decorator`` argument passed to ``add_view``.
+
+``permissions``
+
+ Each introspectable in the ``permissions`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_view` that has an explicit
+ ``permission`` argument to *or* a call to
+ :meth:`pyramid.config.Configurator.set_default_permission`; each will have
+ the following data.
+
+ ``value``
+
+ The permission name passed to ``add_view`` or ``set_default_permission``.
+
+``templates``
+
+ Each introspectable in the ``templates`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_view` that has a ``renderer``
+ argument which points to a template; each will have the following data.
+
+ ``name``
+
+ The renderer's name (a string).
+
+ ``type``
+
+ The renderer's type (a string).
+
+ ``renderer``
+
+ The :class:`pyramid.interfaces.IRendererInfo` object which represents
+ this template's renderer.
+
+``view mapper``
+
+ Each introspectable in the ``permissions`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_view` that has an explicit
+ ``mapper`` argument to *or* a call to
+ :meth:`pyramid.config.Configurator.set_view_mapper`; each will have
+ the following data.
+
+ ``mapper``
+
+ The (resolved) ``mapper`` argument passed to ``add_view`` or
+ ``set_view_mapper``.
+
+``asset overrides``
+
+ Each introspectable in the ``asset overrides`` category represents a call
+ to :meth:`pyramid.config.Configurator.override_asset`; each will have the
+ following data.
+
+ ``to_override``
+
+ The ``to_override`` argument (an asset spec) passed to
+ ``override_asset``.
+
+ ``override_with``
+
+ The ``override_with`` argument (an asset spec) passed to
+ ``override_asset``.
+
+``translation directories``
+
+ Each introspectable in the ``asset overrides`` category represents an
+ individual element in a ``specs`` argument passed to to
+ :meth:`pyramid.config.Configurator.add_translation_dirs`; each will have
+ the following data.
+
+ ``directory``
+
+ The absolute path of the translation directory.
+
+ ``spec``
+
+ The asset specification passed to ``add_translation_dirs``.
+
+``tweens``
+
+ Each introspectable in the ``tweens`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_tween`; each will have the following
+ data.
+
+ ``name``
+
+ The dotted name to the tween factory as a string (passed as
+ the ``tween_factory`` argument to ``add_tween``).
+
+ ``factory``
+
+ The (resolved) tween factory object.
+
+ ``type``
+
+ ``implict`` or ``explicit`` as a string.
+
+ ``under``
+
+ The ``under`` argument passed to ``add_tween`` (a string).
+
+ ``over``
+
+ The ``over`` argument passed to ``add_tween`` (a string).
+
+Introspection in the Toolbar
+----------------------------
+
+The Pyramid debug toolbar (part of the ``pyramid_debugtoolbar`` package)
+provides a canned view of all registered introspectables and their
+relationships. It looks something like this:
+
+.. image:: tb_introspector.png
+
+Disabling Introspection
+-----------------------
+
+You can disable Pyramid introspection by passing the object
+:attr:`pyramid.registry.noop_introspector` to the :term:`Configurator`
+constructor in your application setup:
+
+.. code-block:: python
+
+ from pyramid.config import Configurator
+ from pyramid.registry import noop_introspector
+ config = Configurator(..., introspector=noop_introspector)
+
+When the noop introspector is active, all introspectables generated by
+configuration directives are thrown away. A noop introspector behaves just
+like a "real" introspector, but the methods of a noop introspector do nothing
+and return null values.
diff --git a/docs/narr/tb_introspector.png b/docs/narr/tb_introspector.png
new file mode 100644
index 000000000..231a094f7
--- /dev/null
+++ b/docs/narr/tb_introspector.png
Binary files differ