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.
Adding Methods to the Configurator via
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:
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:
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
The user of the add-on package
pyramid_subscriberhelpers would then be
able to install it and subsequently do:
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:
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
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 :exc:`ConfigurationConflictError` is raised and application startup is prevented.
In our above example, therefore, if a consumer of our
directive did this:
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
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
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.
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
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
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`
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:
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
config.registry.jammyjam_kw will be set to
kw are honestly not very useful when
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
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
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.
Adding Configuration Introspection
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_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:
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
title, and 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.
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.
title is a human-consumable string that can be used by introspection
system frontends to show a friendly summary of this introspectable.
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
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
value key to the value of the
value argument passed to the
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.
Two introspectables may have relationships between each other.
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
(: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
introspectable and the
tmpl_intr introspectable; the arguments passed to
relate are the category name and discriminator of the
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.