summaryrefslogtreecommitdiff
path: root/docs/narr
diff options
context:
space:
mode:
Diffstat (limited to 'docs/narr')
-rw-r--r--docs/narr/MyProject/README.txt3
-rw-r--r--docs/narr/MyProject/development.ini2
-rw-r--r--docs/narr/MyProject/myproject/__init__.py4
-rw-r--r--docs/narr/MyProject/myproject/resources.py3
-rw-r--r--docs/narr/MyProject/myproject/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/narr/MyProject/myproject/tests.py2
-rw-r--r--docs/narr/MyProject/myproject/views.py3
-rw-r--r--docs/narr/MyProject/production.ini4
-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/project.rst162
-rw-r--r--docs/narr/tb_introspector.pngbin0 -> 46164 bytes
13 files changed, 977 insertions, 193 deletions
diff --git a/docs/narr/MyProject/README.txt b/docs/narr/MyProject/README.txt
index 5e10949fc..c28d0d94a 100644
--- a/docs/narr/MyProject/README.txt
+++ b/docs/narr/MyProject/README.txt
@@ -1,4 +1 @@
MyProject README
-
-
-
diff --git a/docs/narr/MyProject/development.ini b/docs/narr/MyProject/development.ini
index 3a4758c44..d61da580f 100644
--- a/docs/narr/MyProject/development.ini
+++ b/docs/narr/MyProject/development.ini
@@ -41,6 +41,6 @@ level = NOTSET
formatter = generic
[formatter_generic]
-format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
# End logging configuration
diff --git a/docs/narr/MyProject/myproject/__init__.py b/docs/narr/MyProject/myproject/__init__.py
index ddcdd7162..31b02cf02 100644
--- a/docs/narr/MyProject/myproject/__init__.py
+++ b/docs/narr/MyProject/myproject/__init__.py
@@ -1,10 +1,10 @@
from pyramid.config import Configurator
-from .resources import Root
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
- config = Configurator(root_factory=Root, settings=settings)
+ config = Configurator(settings=settings)
config.add_static_view('static', 'static', cache_max_age=3600)
+ config.add_route('home', '/')
config.scan()
return config.make_wsgi_app()
diff --git a/docs/narr/MyProject/myproject/resources.py b/docs/narr/MyProject/myproject/resources.py
deleted file mode 100644
index 3d811895c..000000000
--- a/docs/narr/MyProject/myproject/resources.py
+++ /dev/null
@@ -1,3 +0,0 @@
-class Root(object):
- def __init__(self, request):
- self.request = request
diff --git a/docs/narr/MyProject/myproject/static/pyramid-small.png b/docs/narr/MyProject/myproject/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/narr/MyProject/myproject/static/pyramid-small.png
Binary files differ
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py
index a32165471..d8b764041 100644
--- a/docs/narr/MyProject/myproject/tests.py
+++ b/docs/narr/MyProject/myproject/tests.py
@@ -14,5 +14,3 @@ class ViewTests(unittest.TestCase):
request = testing.DummyRequest()
info = my_view(request)
self.assertEqual(info['project'], 'MyProject')
-
-
diff --git a/docs/narr/MyProject/myproject/views.py b/docs/narr/MyProject/myproject/views.py
index 5b5d230f2..f571a5976 100644
--- a/docs/narr/MyProject/myproject/views.py
+++ b/docs/narr/MyProject/myproject/views.py
@@ -1,6 +1,5 @@
from pyramid.view import view_config
-from .resources import Root
-@view_config(context=Root, renderer='templates/mytemplate.pt')
+@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
return {'project':'MyProject'}
diff --git a/docs/narr/MyProject/production.ini b/docs/narr/MyProject/production.ini
index 9d025715d..97050e8fe 100644
--- a/docs/narr/MyProject/production.ini
+++ b/docs/narr/MyProject/production.ini
@@ -25,11 +25,11 @@ keys = console
keys = generic
[logger_root]
-level = INFO
+level = WARN
handlers = console
[logger_myproject]
-level = INFO
+level = WARN
handlers =
qualname = myproject
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..a57c78105
--- /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:
+
+Adding 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/project.rst b/docs/narr/project.rst
index 4c528ab58..478e92b7e 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -46,24 +46,17 @@ each other on a number of axes:
The included scaffolds are these:
``starter``
- URL mapping via :term:`traversal` and no persistence mechanism.
+ URL mapping via :term:`URL dispatch` and no persistence mechanism.
``zodb``
- URL mapping via :term:`traversal` and persistence via :term:`ZODB`.
+ URL mapping via :term:`traversal` and persistence via :term:`ZODB`. *Note
+ that, as of this writing, this scaffold will not run under Python 3, only
+ under Python 2.*
``alchemy``
URL mapping via :term:`URL dispatch` and persistence via
:term:`SQLAlchemy`
-.. note::
-
- Rather than use any of the above scaffolds, Pylons 1 users may feel more
- comfortable installing the :term:`Akhet` development environment, which
- provides a scaffold named ``akhet``. This scaffold configures a Pyramid
- application in a "Pylons-esque" way, including the use of a :term:`view
- handler` to map URLs to code (a handler is much like a Pylons
- "controller").
-
.. index::
single: creating a project
single: project
@@ -382,7 +375,6 @@ structure:
|-- MANIFEST.in
|-- myproject
| |-- __init__.py
- | |-- resources.py
| |-- static
| | |-- favicon.ico
| | |-- logo.png
@@ -682,8 +674,6 @@ The ``myproject`` :term:`package` lives inside the ``MyProject``
``main`` function which is used as a entry point for commands such as
``pserve``, ``pshell``, ``pviews``, and others.
-#. A ``resources.py`` module, which contains :term:`resource` code.
-
#. A ``templates`` directory, which contains :term:`Chameleon` (or
other types of) templates.
@@ -719,23 +709,23 @@ also informs Python that the directory which contains it is a *package*.
#. Line 1 imports the :term:`Configurator` class from :mod:`pyramid.config`
that we use later.
-#. Line 2 imports the ``Root`` class from :mod:`myproject.resources` that we
- use later.
-
-#. Lines 4-10 define a function named ``main`` that returns a :app:`Pyramid`
+#. Lines 3-16 define a function named ``main`` that returns a :app:`Pyramid`
WSGI application. This function is meant to be called by the
:term:`PasteDeploy` framework as a result of running ``pserve``.
Within this function, application configuration is performed.
- Line 7 creates an instance of a :term:`Configurator`.
+ Line 6 creates an instance of a :term:`Configurator`.
- Line 8 registers a static view, which will serve up the files from the
+ Line 7 registers a static view, which will serve up the files from the
``mypackage:static`` :term:`asset specification` (the ``static``
directory of the ``mypackage`` package).
+ Line 8 adds a :term:`route` to the configuration. This route is later
+ used by a view in the ``views`` module.
+
Line 9 calls ``config.scan()``, which picks up view registrations declared
- elsewhere in the package (in this case, in the ``view.py`` module).
+ elsewhere in the package (in this case, in the ``views.py`` module).
Line 10 returns a :term:`WSGI` application to the caller of the function
(Pyramid's pserve).
@@ -755,20 +745,22 @@ and which returns a :term:`response`.
:language: python
:linenos:
-Lines 4-6 define and register a :term:`view callable` named ``my_view``. The
+Lines 3-5 define and register a :term:`view callable` named ``my_view``. The
function named ``my_view`` is decorated with a ``view_config`` decorator
(which is processed by the ``config.scan()`` line in our ``__init__.py``).
-The view_config decorator asserts that this view be found when the
-:term:`context` of the request is an instance of the
-:class:`myproject.resources.Root` class. The view_config decorator also
-names a ``renderer``, which in this case is a template that will be used to
-render the result of the view callable. This particular view declaration
-points at ``templates/mytemplate.pt``, which is a :term:`asset specification`
-that specifies the ``mytemplate.pt`` file within the ``templates`` directory
-of the ``myproject`` package. The asset specification could have also been
-specified as ``myproject:templates/mytemplate.pt``; the leading package name
-and colon is optional. The template file it actually points to is a
-:term:`Chameleon` ZPT template file.
+The view_config decorator asserts that this view be found when a
+:term:`route` named ``home`` is matched. In our case, because our
+``__init__.py`` maps the route named ``home`` to the URL pattern ``/``, this
+route will match when a visitor visits the root URL. The view_config
+decorator also names a ``renderer``, which in this case is a template that
+will be used to render the result of the view callable. This particular view
+declaration points at ``templates/mytemplate.pt``, which is a :term:`asset
+specification` that specifies the ``mytemplate.pt`` file within the
+``templates`` directory of the ``myproject`` package. The asset
+specification could have also been specified as
+``myproject:templates/mytemplate.pt``; the leading package name and colon is
+optional. The template file it actually points to is a :term:`Chameleon` ZPT
+template file.
This view callable function is handed a single piece of information: the
:term:`request`. The *request* is an instance of the :term:`WebOb`
@@ -778,8 +770,7 @@ This view returns a dictionary. When this view is invoked, a
:term:`renderer` converts the dictionary returned by the view into HTML, and
returns the result as the :term:`response`. This view is configured to
invoke a renderer which uses a :term:`Chameleon` ZPT template
-(``mypackage:templates/my_template.pt``, as specified in the ``__init__.py``
-file call to ``add_view``).
+(``templates/my_template.pt``).
See :ref:`views_which_use_a_renderer` for more information about how views,
renderers, and templates relate and cooperate.
@@ -795,35 +786,6 @@ renderers, and templates relate and cooperate.
the speed at which templates may be rendered.
.. index::
- single: resources.py
-
-.. _resourcespy_project_section:
-
-``resources.py``
-~~~~~~~~~~~~~~~~
-
-The ``resources.py`` module provides the :term:`resource` data and behavior
-for our application. Resources are objects which exist to provide site
-structure in applications which use :term:`traversal` to map URLs to code.
-We write a class named ``Root`` that provides the behavior for the root
-resource.
-
-.. literalinclude:: MyProject/myproject/resources.py
- :language: python
- :linenos:
-
-#. Lines 1-3 define the Root class. The Root class is a "root resource
- factory" function that will be called by the :app:`Pyramid` *Router* for
- each request when it wants to find the root of the resource tree.
-
-In a "real" application, the Root object would likely not be such a simple
-object. Instead, it might be an object that could access some persistent
-data store, such as a database. :app:`Pyramid` doesn't make any assumption
-about which sort of data storage you'll want to use, so the sample
-application uses an instance of :class:`myproject.resources.Root` to
-represent the root.
-
-.. index::
single: static directory
``static``
@@ -904,39 +866,12 @@ named ``views`` instead of within a single ``views.py`` file, you might:
can be empty, this just tells Python that the ``views`` directory is a
*package*.
-Then change the __init__.py of your myproject project (*not* the
-``__init__.py`` you just created in the ``views`` directory, the one in its
-parent directory). For example, from something like:
-
-.. code-block:: python
- :linenos:
-
- config.add_view('myproject.views.my_view',
- renderer='myproject:templates/mytemplate.pt')
-
-To this:
-
-.. code-block:: python
- :linenos:
-
- config.add_view('myproject.views.blog.my_view',
- renderer='myproject:templates/mytemplate.pt')
-
-You can then continue to add files to the ``views`` directory, and refer to
-view classes or functions within those files via the dotted name passed as
-the first argument to ``add_view``. For example, if you added a file named
-``anothermodule.py`` to the ``views`` subdirectory, and added a view callable
-named ``my_view`` to it:
-
-.. code-block:: python
- :linenos:
-
- config.add_view('myproject.views.anothermodule.my_view',
- renderer='myproject:templates/anothertemplate.pt')
-
-This pattern can be used to rearrage code referred to by any Pyramid API
-argument which accepts a :term:`dotted Python name` or direct object
-reference.
+You can then continue to add view callable functions to the ``blog.py``
+module, but you can also add other ``.py`` files which contain view callable
+functions to the ``views`` directory. As long as you use the
+``@view_config`` directive to register views in conjuction with
+``config.scan()`` they will be picked up automatically when the application
+is restarted.
Using the Interactive Shell
---------------------------
@@ -949,13 +884,34 @@ via ``pserve``. This can be a useful debugging tool. See
Using an Alternate WSGI Server
------------------------------
-The code generated by a :app:`Pyramid` scaffold assumes that you will be
+The code generated by :app:`Pyramid` scaffolding assumes that you will be
using the ``pserve`` command to start your application while you do
-development. However, ``pserve`` is by no means the only way to start up and
-serve a :app:`Pyramid` application. As we saw in :ref:`firstapp_chapter`,
-``pserve`` needn't be invoked at all to run a :app:`Pyramid` application.
-The use of ``pserve`` to run a :app:`Pyramid` application is purely
-conventional based on the output of its scaffold.
+development. The default rendering of Pyramid scaffolding uses the *wsgiref*
+WSGI server, which is a server that is ill-suited for production usage: its
+main feature is that it works on all platforms and all systems, making it a
+good choice as a default server from the perspective of Pyramid's developers.
+
+To use a server more suitable for production, you have a number of choices.
+Replace the ``use = egg:pyramid#wsgref`` line in your ``production.ini`` with
+one of the following.
+
+``use = egg:Paste#http``
+
+ ``paste.httpserver`` is Windows, UNIX, and Python 2 compatible. You'll
+ need to ``easy_install Paste`` into your Pyramid virtualenv for this server
+ to work.
+
+``use = egg:pyramid#cherrypy``
+
+ The ``CherryPy`` WSGI server is Windows, UNIX, Python 2, and Python 3
+ compatible. You'll need to ``easy_install CherryPy`` into your Pyramid
+ virtualenv for this server to work.
+
+``pserve`` is by no means the only way to start up and serve a :app:`Pyramid`
+application. As we saw in :ref:`firstapp_chapter`, ``pserve`` needn't be
+invoked at all to run a :app:`Pyramid` application. The use of ``pserve`` to
+run a :app:`Pyramid` application is purely conventional based on the output
+of its scaffold.
Any :term:`WSGI` server is capable of running a :app:`Pyramid` application.
Some WSGI servers don't require the :term:`PasteDeploy` framework's
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