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__.py10
-rw-r--r--docs/narr/MyProject/myproject/resources.py3
-rw-r--r--docs/narr/MyProject/myproject/static/pylons.css15
-rw-r--r--docs/narr/MyProject/myproject/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/narr/MyProject/myproject/templates/mytemplate.pt76
-rw-r--r--docs/narr/MyProject/myproject/tests.py4
-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/commandline.rst24
-rw-r--r--docs/narr/extconfig.rst364
-rw-r--r--docs/narr/extending.rst4
-rw-r--r--docs/narr/firstapp.rst15
-rw-r--r--docs/narr/helloworld.py2
-rw-r--r--docs/narr/i18n.rst16
-rw-r--r--docs/narr/install.rst30
-rw-r--r--docs/narr/introduction.rst14
-rw-r--r--docs/narr/introspector.rst557
-rw-r--r--docs/narr/logging.rst4
-rw-r--r--docs/narr/muchadoabouttraversal.rst4
-rw-r--r--docs/narr/project.rst197
-rw-r--r--docs/narr/router.rst141
-rw-r--r--docs/narr/startup.rst38
-rw-r--r--docs/narr/tb_introspector.pngbin0 -> 95962 bytes
-rw-r--r--docs/narr/templates.rst8
-rw-r--r--docs/narr/testing.rst2
-rw-r--r--docs/narr/urldispatch.rst4
-rw-r--r--docs/narr/viewconfig.rst181
30 files changed, 1361 insertions, 443 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 04e219e36..31b02cf02 100644
--- a/docs/narr/MyProject/myproject/__init__.py
+++ b/docs/narr/MyProject/myproject/__init__.py
@@ -1,12 +1,10 @@
from pyramid.config import Configurator
-from myproject.resources import Root
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
- config = Configurator(root_factory=Root, settings=settings)
- config.add_view('myproject.views.my_view',
- context='myproject.resources.Root',
- renderer='myproject:templates/mytemplate.pt')
- config.add_static_view('static', 'myproject:static')
+ 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/pylons.css b/docs/narr/MyProject/myproject/static/pylons.css
index 33b21ac1a..c54499ddd 100644
--- a/docs/narr/MyProject/myproject/static/pylons.css
+++ b/docs/narr/MyProject/myproject/static/pylons.css
@@ -23,7 +23,7 @@ h2{font-size:1.5em;line-height:1.7em;font-family:helvetica,verdana;}
h3{font-size:1.25em;line-height:1.7em;font-family:helvetica,verdana;}
h4{font-size:1em;line-height:1.7em;font-family:helvetica,verdana;}
html,body{width:100%;height:100%;}
-body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
+body{margin:0;padding:0;background-color:#ffffff;position:relative;font:16px/24px "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
a{color:#1b61d6;text-decoration:none;}
a:hover{color:#e88f00;text-decoration:underline;}
body h1,
@@ -31,19 +31,20 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+body h6{font-family:"NeutonRegular","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
#wrap{min-height:100%;}
#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
#header{background:#000000;top:0;font-size:14px;}
#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#000000;height:230px;
-background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;}
+#top,#top-small,#bottom{width:100%;}
+#top{color:#000000;height:230px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;}
+#top-small{color:#000000;height:60px;background:#ffffff url(headerbg.png) repeat-x 0 top;position:relative;}
#bottom{color:#222;background-color:#ffffff;}
-.top,.middle,.bottom{width:750px;margin-right:auto;margin-left:auto;}
+.top,.top-small,.middle,.bottom{width:750px;margin-right:auto;margin-left:auto;}
.top{padding-top:40px;}
+.top-small{padding-top:10px;}
#middle{width:100%;height:100px;background:url(middlebg.png) repeat-x;border-top:2px solid #ffffff;border-bottom:2px solid #b2b2b2;}
.app-welcome{margin-top:25px;}
.app-name{color:#000000;font-weight:bold;}
@@ -58,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{width:205px;}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
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/templates/mytemplate.pt b/docs/narr/MyProject/myproject/templates/mytemplate.pt
index 97f1e1aa3..0bfac946e 100644
--- a/docs/narr/MyProject/myproject/templates/mytemplate.pt
+++ b/docs/narr/MyProject/myproject/templates/mytemplate.pt
@@ -1,42 +1,29 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"
- xml:lang="en"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
<title>The Pyramid Web Application Development Framework</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon"
- href="${request.static_url('myproject:static/favicon.ico')}" />
- <link rel="stylesheet"
- href="${request.static_url('myproject:static/pylons.css')}"
- type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet"
- href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin"
- type="text/css" media="screen" charset="utf-8" />
+ <link rel="shortcut icon" href="/static/favicon.ico" />
+ <link rel="stylesheet" href="/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
+ <link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
<!--[if lte IE 6]>
- <link rel="stylesheet"
- href="${request.static_url('myproject:static/ie6.css')}"
- type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="/static/ie6.css" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
</head>
<body>
<div id="wrap">
<div id="top">
<div class="top align-center">
- <div>
- <img src="${request.static_url('myproject:static/pyramid.png')}"
- width="750" height="169" alt="pyramid"/>
- </div>
+ <div><img src="/static/pyramid.png" width="750" height="169" alt="pyramid"/></div>
</div>
</div>
<div id="middle">
<div class="middle align-center">
<p class="app-welcome">
- Welcome to <span class="app-name">${project}</span>,
- an application generated by<br/>
+ Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
the Pyramid web application development framework.
</p>
</div>
@@ -45,62 +32,45 @@
<div class="bottom">
<div id="left" class="align-right">
<h2>Search documentation</h2>
- <form method="get"
- action="http://docs.pylonsproject.org/pyramid/current/search.html">
- <input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Go" />
- </form>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/current/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
</div>
<div id="right" class="align-left">
<h2>Pyramid links</h2>
<ul class="links">
<li>
- <a href="http://pylonsproject.org">
- Pylons Website
- </a>
+ <a href="http://pylonsproject.org">Pylons Website</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#narrative-documentation">
- Narrative Documentation
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/#narrative-documentation">Narrative Documentation</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#api-documentation">
- API Documentation
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/#reference-material">API Documentation</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#tutorials">
- Tutorials
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/#tutorials">Tutorials</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#change-history">
- Change History
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/#detailed-change-history">Change History</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#sample-applications">
- Sample Applications
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/#sample-applications">Sample Applications</a>
</li>
<li>
- <a href="http://docs.pylonsproject.org/projects/pyramid/current/#support-and-development">
- Support and Development
- </a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/#support-and-development">Support and Development</a>
</li>
<li>
- <a href="irc://irc.freenode.net#pyramid">
- IRC Channel
- </a>
+ <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
</li>
- </ul>
+ </ul>
</div>
</div>
</div>
</div>
<div id="footer">
- <div class="footer">&copy; Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">&copy; Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html>
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py
index 5fa710278..d8b764041 100644
--- a/docs/narr/MyProject/myproject/tests.py
+++ b/docs/narr/MyProject/myproject/tests.py
@@ -10,9 +10,7 @@ class ViewTests(unittest.TestCase):
testing.tearDown()
def test_my_view(self):
- from myproject.views import my_view
+ from .views import my_view
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 c43b34460..f571a5976 100644
--- a/docs/narr/MyProject/myproject/views.py
+++ b/docs/narr/MyProject/myproject/views.py
@@ -1,2 +1,5 @@
+from pyramid.view import view_config
+
+@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/commandline.rst b/docs/narr/commandline.rst
index 0dc41e919..66ef46671 100644
--- a/docs/narr/commandline.rst
+++ b/docs/narr/commandline.rst
@@ -111,6 +111,7 @@ For a URL that doesn't match any views, ``pviews`` will simply print out a
single: interactive shell
single: IPython
single: pshell
+ single: bpython
.. _interactive_shell:
@@ -267,23 +268,26 @@ exposed, and the request is configured to generate urls from the host
.. index::
single: IPython
+ single: bpython
-IPython
-~~~~~~~
+.. _ipython_or_bpython:
+
+IPython or bpython
+~~~~~~~~~~~~~~~~~~
-If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ installed in
-the interpreter you use to invoke the ``pshell`` command, ``pshell`` will use
-an IPython interactive shell instead of a standard Python interpreter shell.
-If you don't want this to happen, even if you have IPython installed, you can
-pass the ``--disable-ipython`` flag to the ``pshell`` command to use a
-standard Python interpreter shell unconditionally.
+If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ or
+`bpython <http://bpython-interpreter.org/>`_ or both installed in
+the interpreter you use to invoke the ``pshell`` command, ``pshell`` will
+autodiscover them and use the first respectively found in this order :
+IPython, bpython, standard Python interpreter. However you could
+specifically invoke one of your choice with the ``-p choice`` or
+``--python-shell choice`` option.
.. code-block:: text
- [chrism@vitaminf shellenv]$ ../bin/pshell --disable-ipython \
+ [chrism@vitaminf shellenv]$ ../bin/pshell -p ipython | bpython | python \
development.ini#MyProject
-
.. index::
pair: routes; printing
single: proutes
diff --git a/docs/narr/extconfig.rst b/docs/narr/extconfig.rst
new file mode 100644
index 000000000..5e7fe2753
--- /dev/null
+++ b/docs/narr/extconfig.rst
@@ -0,0 +1,364 @@
+.. 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 :exc:`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
+
+ 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
+
+ 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
+----------------------------------
+
+.. note::
+
+ 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/extending.rst b/docs/narr/extending.rst
index 9c96248f2..c464203f0 100644
--- a/docs/narr/extending.rst
+++ b/docs/narr/extending.rst
@@ -200,8 +200,8 @@ like this:
overridden elements, such as templates and static assets as necessary.
- Install the new package into the same Python environment as the original
- application (e.g. ``python setup.py develop`` or ``python setup.py
- install``).
+ application (e.g. ``$myvenv/bin/python setup.py develop`` or
+ ``$myvenv/bin/python setup.py install``).
- Change the ``main`` function in the new package's ``__init__.py`` to include
the original :app:`Pyramid` application's configuration functions via
diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst
index 45d65402c..c082f616b 100644
--- a/docs/narr/firstapp.rst
+++ b/docs/narr/firstapp.rst
@@ -71,11 +71,10 @@ named ``hello_world``.
:linenos:
:pyobject: hello_world
-This function doesn't do anything very difficult. The functions accepts a
-single argument (``request``). The ``hello_world`` function returns an
-instance of the :class:`pyramid.response.Response`. The single argument to
-the class' constructor is value computed from arguments matched from the url
-route. This value becomes the body of the response.
+The function accepts a single argument (``request``) and it returns an
+instance of the :class:`pyramid.response.Response` class. The single
+argument to the class' constructor is a string computed from parameters
+matched from the URL. This value becomes the body of the response.
This function is known as a :term:`view callable`. A view callable
accepts a single argument, ``request``. It is expected to return a
@@ -134,7 +133,7 @@ Using the ``if`` clause is necessary -- or at least best practice -- because
code in a Python ``.py`` file may be eventually imported via the Python
``import`` statement by another ``.py`` file. ``.py`` files that are
imported by other ``.py`` files are referred to as *modules*. By using the
-``if __name__ == 'main':`` idiom, the script above is indicating that it does
+``if __name__ == '__main__':`` idiom, the script above is indicating that it does
not want the code within the ``if`` statement to execute if this module is
imported from another; the code within the ``if`` block should only be run
during a direct script execution.
@@ -157,7 +156,7 @@ Adding Configuration
:lines: 10-11
First line above calls the :meth:`pyramid.config.Configurator.add_route`
-method, which registers a :term:`route` to match any url path that begins
+method, which registers a :term:`route` to match any URL path that begins
with ``/hello/`` followed by a string.
The second line, ``config.add_view(hello_world, route_name='hello')``,
@@ -208,7 +207,7 @@ WSGI Application Serving
Finally, we actually serve the application to requestors by starting up a
WSGI server. We happen to use the :func:`paste.httpserver.serve` WSGI server
runner, passing it the ``app`` object (a :term:`router`) as the application
-we wish to serve. We also pass in an argument ``host=='0.0.0.0'``, meaning
+we wish to serve. We also pass in an argument ``host='0.0.0.0'``, meaning
"listen on all TCP interfaces." By default, the HTTP server listens
only on the ``127.0.0.1`` interface, which is problematic if you're running
the server on a remote system and you wish to access it with a web browser
diff --git a/docs/narr/helloworld.py b/docs/narr/helloworld.py
index 93a403a13..7c26c8cdc 100644
--- a/docs/narr/helloworld.py
+++ b/docs/narr/helloworld.py
@@ -10,6 +10,6 @@ if __name__ == '__main__':
config.add_route('hello', '/hello/{name}')
config.add_view(hello_world, route_name='hello')
app = config.make_wsgi_app()
- server = make_server('0.0.0.0', 8080)
+ server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
index c2ecba9bb..e261f9a11 100644
--- a/docs/narr/i18n.rst
+++ b/docs/narr/i18n.rst
@@ -149,7 +149,7 @@ generated by using it. For example:
from pyramid.i18n import TranslationStringFactory
_ = TranslationStringFactory('pyramid')
- ts = _('Add ${number}', msgid='add-number', mapping={'number':1})
+ ts = _('add-number', default='Add ${number}', mapping={'number':1})
.. note:: We assigned the translation string factory to the name
``_``. This is a convention which will be supported by translation
@@ -170,7 +170,7 @@ to:
:linenos:
from pyramid.i18n import TranslationString as _
- ts = _('Add ${number}', msgid='add-number', mapping={'number':1},
+ ts = _('add-number', default='Add ${number}', mapping={'number':1},
domain='pyramid')
You can set up your own translation string factory much like the one
@@ -185,7 +185,7 @@ do something like this:
from pyramid.i18n import TranslationStringFactory
_ = TranslationStringFactory('form')
- ts = _('Add ${number}', msgid='add-number', mapping={'number':1})
+ ts = _('add-number', default='Add ${number}', mapping={'number':1})
Creating a unique domain for your application via a translation string
factory is best practice. Using your own unique translation domain
@@ -249,7 +249,7 @@ GNU gettext uses three types of files in the translation framework,
The tools for working with :term:`gettext` translation files related to a
:app:`Pyramid` application is :term:`Babel` and :term:`Lingua`. Lingua is a
-Balel extension that provides support for scraping i18n references out of
+Babel extension that provides support for scraping i18n references out of
Python and Chameleon files.
.. index::
@@ -347,7 +347,7 @@ extract the messages:
$ cd /place/where/myapplication/setup.py/lives
$ mkdir -p myapplication/locale
- $ python setup.py extract_messages
+ $ $myvenv/bin/python setup.py extract_messages
The message catalog ``.pot`` template will end up in:
@@ -439,7 +439,7 @@ init_catalog`` command:
.. code-block:: text
$ cd /place/where/myapplication/setup.py/lives
- $ python setup.py init_catalog -l es
+ $ $myvenv/bin/python setup.py init_catalog -l es
By default, the message catalog ``.po`` file will end up in:
@@ -471,7 +471,7 @@ Then use the ``setup.py update_catalog`` command.
.. code-block:: text
$ cd /place/where/myapplication/setup.py/lives
- $ python setup.py update_catalog
+ $ $myvenv/bin/python setup.py update_catalog
.. index::
pair: compiling; message catalog
@@ -487,7 +487,7 @@ translations, compile ``.po`` files to ``.mo`` files:
.. code-block:: text
$ cd /place/where/myapplication/setup.py/lives
- $ python setup.py compile_catalog
+ $ $myvenv/bin/python setup.py compile_catalog
This will create a ``.mo`` file for each ``.po`` file in your
application. As long as the :term:`translation directory` in which
diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index 66bcea706..3de4d6e27 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -9,19 +9,18 @@ Installing :app:`Pyramid`
Before You Install
------------------
-You will need `Python <http://python.org>`_ version 2.5 or better to
+You will need `Python <http://python.org>`_ version 2.6 or better to
run :app:`Pyramid`.
.. sidebar:: Python Versions
- As of this writing, :app:`Pyramid` has been tested under Python 2.5.5,
- Python 2.6.6, and Python 2.7.2. :app:`Pyramid` does not run under any
- version of Python before 2.5, and does not yet run under Python 3.X.
+ As of this writing, :app:`Pyramid` has been tested under Python 2.6.6,
+ Python 2.7.2, and Python 3.2. :app:`Pyramid` does not run under any
+ version of Python before 2.6.
:app:`Pyramid` is known to run on all popular UNIX-like systems such as
Linux, MacOS X, and FreeBSD as well as on Windows platforms. It is also
-known to run on Google's App Engine, :term:`PyPy` (1.5 and 1.6), and
-:term:`Jython` (2.5.2).
+known to run on Google's App Engine, and :term:`PyPy` (1.6+).
:app:`Pyramid` installation does not require the compilation of any
C code, so you need only a Python interpreter that meets the
@@ -325,25 +324,6 @@ Installing :app:`Pyramid` on Google App Engine
:ref:`appengine_tutorial` documents the steps required to install a
:app:`Pyramid` application on Google App Engine.
-.. index::
- single: installing on Jython
-
-Installing :app:`Pyramid` on Jython
---------------------------------------
-
-:app:`Pyramid` is known to work under :term:`Jython` version 2.5.1.
-Install :term:`Jython`, and then follow the installation steps for
-:app:`Pyramid` on your platform described in one of the sections
-entitled :ref:`installing_unix` or :ref:`installing_windows` above,
-replacing the ``python`` command with ``jython`` as necessary. The
-steps are exactly the same except you should use the ``jython``
-command name instead of the ``python`` command name.
-
-One caveat exists to using :app:`Pyramid` under Jython: the :term:`Chameleon`
-templating engine does not work on Jython. However, the :term:`Mako`
-templating system, which is also included with Pyramid, does work under
-Jython; use it instead.
-
What Gets Installed
-------------------
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index 547f88ef3..7c6ad00f3 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -219,7 +219,7 @@ that the Pyramid core doesn't. Add-on packages already exist which let you
easily send email, let you use the Jinja2 templating system, let you use
XML-RPC or JSON-RPC, let you integrate with jQuery Mobile, etc.
-Examples: https://docs.pylonsproject.org/docs/pyramid.html#pyramid-add-on-documentation
+Examples: http://docs.pylonsproject.org/docs/pyramid.html#pyramid-add-on-documentation
Class-based and function-based views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -808,11 +808,11 @@ Every release of Pyramid has 100% statement coverage via unit and integration
tests, as measured by the ``coverage`` tool available on PyPI. It also has
greater than 95% decision/condition coverage as measured by the
``instrumental`` tool available on PyPI. It is automatically tested by the
-Jenkins tool on Python 2.5, Python 2.6, Python 2.7, Jython and PyPy after
-each commit to its GitHub repository. Official Pyramid add-ons are held to a
-similar testing standard. We still find bugs in Pyramid and its official
-add-ons, but we've noticed we find a lot more of them while working on other
-projects that don't have a good testing regime.
+Jenkins tool on Python 2.6, Python 2.7, Python 3.2 and PyPy after each commit
+to its GitHub repository. Official Pyramid add-ons are held to a similar
+testing standard. We still find bugs in Pyramid and its official add-ons,
+but we've noticed we find a lot more of them while working on other projects
+that don't have a good testing regime.
Example: http://jenkins.pylonsproject.org/
@@ -842,7 +842,7 @@ official narrative docs. In any case, the Pyramid documentation is
comprehensive.
Example: The rest of this documentation and the cookbook at
-https://docs.pylonsproject.org/projects/pyramid_cookbook/dev/ .
+http://docs.pylonsproject.org/projects/pyramid_cookbook/dev/ .
.. index::
single: Pylons Project
diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst
new file mode 100644
index 000000000..11d779854
--- /dev/null
+++ b/docs/narr/introspector.rst
@@ -0,0 +1,557 @@
+.. 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 a "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
+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``.
+
+ ``static``
+
+ The ``static`` argument passed to ``add_route``.
+
+ ``use_global_views``
+
+ 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).
+
+``static views``
+
+ Each introspectable in the ``static views`` category represents a call to
+ :meth:`pyramid.config.Configurator.add_static_view`; each will have the
+ following data.
+
+ ``name``
+
+ The ``name`` argument provided to ``add_static_view``.
+
+ ``spec``
+
+ A normalized version of the ``spec`` argument provided to
+ ``add_static_view``.
+
+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/logging.rst b/docs/narr/logging.rst
index 5377d0c66..044655c1f 100644
--- a/docs/narr/logging.rst
+++ b/docs/narr/logging.rst
@@ -16,6 +16,8 @@ how to send log messages to loggers that you've configured.
a third-party scaffold which does not create these files, the
configuration information in this chapter will not be applicable.
+.. _logging_config:
+
Logging Configuration
---------------------
@@ -291,7 +293,7 @@ Logging Exceptions
To log (or email) exceptions generated by your :app:`Pyramid` application,
use the :term:`pyramid_exclog` package. Details about its configuration are
in its `documentation
-<https://docs.pylonsproject.org/projects/pyramid_exclog/dev/>`_.
+<http://docs.pylonsproject.org/projects/pyramid_exclog/dev/>`_.
Request Logging with Paste's TransLogger
----------------------------------------
diff --git a/docs/narr/muchadoabouttraversal.rst b/docs/narr/muchadoabouttraversal.rst
index a948e57cc..4a249ed0d 100644
--- a/docs/narr/muchadoabouttraversal.rst
+++ b/docs/narr/muchadoabouttraversal.rst
@@ -4,7 +4,9 @@
Much Ado About Traversal
========================
-.. note:: This chapter was adapted, with permission, from a blog post by `Rob
+.. note::
+
+ This chapter was adapted, with permission, from a blog post by `Rob
Miller <http://blog.nonsequitarian.org/>`_, originally published at
http://blog.nonsequitarian.org/2010/much-ado-about-traversal/ .
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 4f96448af..af8714573 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -28,7 +28,6 @@ as part of Pyramid.
single: starter scaffold
single: zodb scaffold
single: alchemy scaffold
- single: routesalchemy scaffold
.. _additional_paster_scaffolds:
@@ -47,27 +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`.
-
-``routesalchemy``
- URL mapping via :term:`URL dispatch` and persistence via
- :term:`SQLAlchemy`
+ 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:`traversal` and persistence via
+ 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
@@ -98,18 +87,18 @@ Or on Windows:
The above command uses the ``pcreate`` command to create a project with the
``starter`` scaffold. To use a different scaffold, such as
-``routesalchemy``, you'd just change the ``-s`` argument value. For example,
+``alchemy``, you'd just change the ``-s`` argument value. For example,
on UNIX:
.. code-block:: text
- $ bin/pcreate -s routesalchemy MyProject
+ $ bin/pcreate -s alchemy MyProject
Or on Windows:
.. code-block:: text
- $ Scripts\pcreate routesalchemy MyProject
+ $ Scripts\pcreate alchemy MyProject
Here's sample output from a run of ``pcreate`` on UNIX for a project we name
``MyProject``:
@@ -386,7 +375,6 @@ structure:
|-- MANIFEST.in
|-- myproject
| |-- __init__.py
- | |-- resources.py
| |-- static
| | |-- favicon.ico
| | |-- logo.png
@@ -686,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.
@@ -723,34 +709,25 @@ 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-12 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.
- Lines 8-10 register a "default view" (a view that has no ``name``
- attribute). It is registered so that it will be found when the
- :term:`context` of the request is an instance of the
- :class:`myproject.resources.Root` class. The first argument to
- ``add_view`` points at a Python function that does all the work for this
- view, also known as a :term:`view callable`, via a :term:`dotted Python
- name`. The view declaration 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
- ``myproject:templates/mytemplate.pt``, which is a :term:`asset
- specification` that specifies the ``mytemplate.pt`` file within the
- ``templates`` directory of the ``myproject`` package. The template file
- it actually points to is a :term:`Chameleon` ZPT template file.
-
- Line 11 registers a static view, which will serve up the files from the
+ Line 6 creates an instance of a :term:`Configurator`.
+
+ 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 12 returns a :term:`WSGI` application to the caller of the function
+ 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 ``views.py`` module).
+
+ Line 10 returns a :term:`WSGI` application to the caller of the function
(Pyramid's pserve).
.. index::
@@ -768,10 +745,22 @@ and which returns a :term:`response`.
:language: python
:linenos:
-This bit of code was registered as the view callable within ``__init__.py``
-(via ``add_view``). ``add_view`` said that the default URL for instances
-that are of the class :class:`myproject.resources.Root` should run this
-:func:`myproject.views.my_view` function.
+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 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`
@@ -781,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.
@@ -798,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``
@@ -838,11 +797,11 @@ template. It includes CSS and images.
``templates/mytemplate.pt``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The single :term:`Chameleon` template that exists in the project. Its contents
-are too long to show here, but it displays a default page when rendered. It
-is referenced by the call to ``add_view`` as the ``renderer`` attribute in
-the ``__init__`` file. See :ref:`views_which_use_a_renderer` for more
-information about renderers.
+The single :term:`Chameleon` template that exists in the project. Its
+contents are too long to show here, but it displays a default page when
+rendered. It is referenced by the call to ``@view_config`` as the
+``renderer`` of the ``my_view`` view callable in the ``views.py`` file. See
+:ref:`views_which_use_a_renderer` for more information about renderers.
Templates are accessed and used by view configurations and sometimes by view
functions themselves. See :ref:`templates_used_directly` and
@@ -907,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,16 +881,39 @@ configuration as would be loaded if you were running your Pyramid application
via ``pserve``. This can be a useful debugging tool. See
:ref:`interactive_shell` for more details.
+.. _alternate_wsgi_server:
+
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/router.rst b/docs/narr/router.rst
index d08261b17..b78362066 100644
--- a/docs/narr/router.rst
+++ b/docs/narr/router.rst
@@ -9,74 +9,67 @@
Request Processing
==================
-Once a :app:`Pyramid` application is up and running, it is ready to
-accept requests and return responses.
+Once a :app:`Pyramid` application is up and running, it is ready to accept
+requests and return responses. What happens from the time a :term:`WSGI`
+request enters a :app:`Pyramid` application through to the point that
+:app:`Pyramid` hands off a response back to WSGI for upstream processing?
-What happens from the time a :term:`WSGI` request enters a
-:app:`Pyramid` application through to the point that
-:app:`Pyramid` hands off a response back to WSGI for upstream
-processing?
+#. A user initiates a request from his browser to the hostname and port
+ number of the WSGI server used by the :app:`Pyramid` application.
-#. A user initiates a request from his browser to the hostname and
- port number of the WSGI server used by the :app:`Pyramid`
- application.
-
-#. The WSGI server used by the :app:`Pyramid` application passes
- the WSGI environment to the ``__call__`` method of the
- :app:`Pyramid` :term:`router` object.
+#. The WSGI server used by the :app:`Pyramid` application passes the WSGI
+ environment to the ``__call__`` method of the :app:`Pyramid`
+ :term:`router` object.
#. A :term:`request` object is created based on the WSGI environment.
-#. The :term:`application registry` and the :term:`request` object
- created in the last step are pushed on to the :term:`thread local`
- stack that :app:`Pyramid` uses to allow the functions named
+#. The :term:`application registry` and the :term:`request` object created in
+ the last step are pushed on to the :term:`thread local` stack that
+ :app:`Pyramid` uses to allow the functions named
:func:`~pyramid.threadlocal.get_current_request` and
:func:`~pyramid.threadlocal.get_current_registry` to work.
#. A :class:`~pyramid.events.NewRequest` :term:`event` is sent to any
subscribers.
-#. If any :term:`route` has been defined within application
- configuration, the :app:`Pyramid` :term:`router` calls a
- :term:`URL dispatch` "route mapper." The job of the mapper is to
- examine the request to determine whether any user-defined
- :term:`route` matches the current WSGI environment. The
- :term:`router` passes the request as an argument to the mapper.
-
-#. If any route matches, the request is mutated; a ``matchdict`` and
- ``matched_route`` attributes are added to the request object; the
- former contains a dictionary representing the matched dynamic
- elements of the request's ``PATH_INFO`` value, the latter contains
- the :class:`~pyramid.interfaces.IRoute` object representing the
- route which matched. The root object associated with the route
- found is also generated: if the :term:`route configuration` which
- matched has an associated a ``factory`` argument, this factory is
- used to generate the root object, otherwise a default :term:`root
- factory` is used.
-
-#. If a route match was *not* found, and a ``root_factory`` argument
- was passed to the :term:`Configurator` constructor, that callable
- is used to generate the root object. If the ``root_factory``
- argument passed to the Configurator constructor was ``None``, a
- default root factory is used to generate a root object.
-
-#. The :app:`Pyramid` router calls a "traverser" function with the
- root object and the request. The traverser function attempts to
- traverse the root object (using any existing ``__getitem__`` on the
- root object and subobjects) to find a :term:`context`. If the root
- object has no ``__getitem__`` method, the root itself is assumed to
- be the context. The exact traversal algorithm is described in
- :ref:`traversal_chapter`. The traverser function returns a
- dictionary, which contains a :term:`context` and a :term:`view
- name` as well as other ancillary information.
-
-#. The request is decorated with various names returned from the
- traverser (such as ``context``, ``view_name``, and so forth), so
- they can be accessed via e.g. ``request.context`` within
- :term:`view` code.
-
-#. A :class:`~pyramid.events.ContextFound` :term:`event` is
- sent to any subscribers.
+#. If any :term:`route` has been defined within application configuration,
+ the :app:`Pyramid` :term:`router` calls a :term:`URL dispatch` "route
+ mapper." The job of the mapper is to examine the request to determine
+ whether any user-defined :term:`route` matches the current WSGI
+ environment. The :term:`router` passes the request as an argument to the
+ mapper.
+
+#. If any route matches, the route mapper adds attributes to the request:
+ ``matchdict`` and ``matched_route`` attributes are added to the request
+ object. The former contains a dictionary representing the matched dynamic
+ elements of the request's ``PATH_INFO`` value, the latter contains the
+ :class:`~pyramid.interfaces.IRoute` object representing the route which
+ matched. The root object associated with the route found is also
+ generated: if the :term:`route configuration` which matched has an
+ associated a ``factory`` argument, this factory is used to generate the
+ root object, otherwise a default :term:`root factory` is used.
+
+#. If a route match was *not* found, and a ``root_factory`` argument was
+ passed to the :term:`Configurator` constructor, that callable is used to
+ generate the root object. If the ``root_factory`` argument passed to the
+ Configurator constructor was ``None``, a default root factory is used to
+ generate a root object.
+
+#. The :app:`Pyramid` router calls a "traverser" function with the root
+ object and the request. The traverser function attempts to traverse the
+ root object (using any existing ``__getitem__`` on the root object and
+ subobjects) to find a :term:`context`. If the root object has no
+ ``__getitem__`` method, the root itself is assumed to be the context. The
+ exact traversal algorithm is described in :ref:`traversal_chapter`. The
+ traverser function returns a dictionary, which contains a :term:`context`
+ and a :term:`view name` as well as other ancillary information.
+
+#. The request is decorated with various names returned from the traverser
+ (such as ``context``, ``view_name``, and so forth), so they can be
+ accessed via e.g. ``request.context`` within :term:`view` code.
+
+#. A :class:`~pyramid.events.ContextFound` :term:`event` is sent to any
+ subscribers.
#. :app:`Pyramid` looks up a :term:`view` callable using the context, the
request, and the view name. If a view callable doesn't exist for this
@@ -86,20 +79,17 @@ processing?
:class:`~pyramid.httpexceptions.HTTPNotFound` exception, which is meant to
be caught by a surrounding :term:`exception view`.
-#. If a view callable was found, :app:`Pyramid` attempts to call
- the view function.
-
-#. If an :term:`authorization policy` is in use, and the view was protected
- by a :term:`permission`, :app:`Pyramid` passes the context, the request,
- and the view_name to a function which determines whether the view being
- asked for can be executed by the requesting user, based on credential
- information in the request and security information attached to the
- context. If it returns ``True``, :app:`Pyramid` calls the view callable
- to obtain a response. If it returns ``False``, it raises a
- :class:`~pyramid.httpexceptions.HTTPForbidden` exception, which is meant
- to be called by a surrounding :term:`exception view`.
-
-#. If any exception was raised within a :term:`root factory`, by
+#. If a view callable was found, :app:`Pyramid` attempts to call it. If an
+ :term:`authorization policy` is in use, and the view configuration is
+ protected by a :term:`permission`, :app:`Pyramid` determines whether the
+ view callable being asked for can be executed by the requesting user based
+ on credential information in the request and security information attached
+ to the context. If the view execution is allowed, :app:`Pyramid` calls
+ the view callable to obtain a response. If view execution is forbidden,
+ :app:`Pyramid` raises a :class:`~pyramid.httpexceptions.HTTPForbidden`
+ exception.
+
+#. If any exception is raised within a :term:`root factory`, by
:term:`traversal`, by a :term:`view callable` or by :app:`Pyramid` itself
(such as when it raises :class:`~pyramid.httpexceptions.HTTPNotFound` or
:class:`~pyramid.httpexceptions.HTTPForbidden`), the router catches the
@@ -128,9 +118,8 @@ processing?
.. image:: router.png
-This is a very high-level overview that leaves out various details.
-For more detail about subsystems invoked by the :app:`Pyramid` router
-such as traversal, URL dispatch, views, and event processing, see
-:ref:`urldispatch_chapter`, :ref:`views_chapter`, and
-:ref:`events_chapter`.
+This is a very high-level overview that leaves out various details. For more
+detail about subsystems invoked by the :app:`Pyramid` router such as
+traversal, URL dispatch, views, and event processing, see
+:ref:`urldispatch_chapter`, :ref:`views_chapter`, and :ref:`events_chapter`.
diff --git a/docs/narr/startup.rst b/docs/narr/startup.rst
index f4ebef154..a7fc5d33c 100644
--- a/docs/narr/startup.rst
+++ b/docs/narr/startup.rst
@@ -24,11 +24,11 @@ The Startup Process
-------------------
The easiest and best-documented way to start and serve a :app:`Pyramid`
-application is to use the ``pserve`` command against a
-:term:`PasteDeploy` ``.ini`` file. This uses the ``.ini`` file to infer
-settings and starts a server listening on a port. For the purposes of this
-discussion, we'll assume that you are using this command to run your
-:app:`Pyramid` application.
+application is to use the ``pserve`` command against a :term:`PasteDeploy`
+``.ini`` file. This uses the ``.ini`` file to infer settings and starts a
+server listening on a port. For the purposes of this discussion, we'll
+assume that you are using this command to run your :app:`Pyramid`
+application.
Here's a high-level time-ordered overview of what happens when you press
``return`` after running ``pserve development.ini``.
@@ -56,11 +56,12 @@ Here's a high-level time-ordered overview of what happens when you press
#. The framework finds all :mod:`logging` related configuration in the
``.ini`` file and uses it to configure the Python standard library logging
- system for this application.
+ system for this application. See :ref:`logging_config` for more
+ information.
-#. The application's *constructor* (named by the entry point reference or
+#. The application's *constructor* named by the entry point reference or
dotted Python name on the ``use=`` line of the section representing your
- :app:`Pyramid` application) is passed the key/value parameters mentioned
+ :app:`Pyramid` application is passed the key/value parameters mentioned
within the section in which it's defined. The constructor is meant to
return a :term:`router` instance, which is a :term:`WSGI` application.
@@ -76,12 +77,14 @@ Here's a high-level time-ordered overview of what happens when you press
Note that the constructor function accepts a ``global_config`` argument,
which is a dictionary of key/value pairs mentioned in the ``[DEFAULT]``
- section of an ``.ini`` file. It also accepts a ``**settings`` argument,
- which collects another set of arbitrary key/value pairs. The arbitrary
- key/value pairs received by this function in ``**settings`` will be
- composed of all the key/value pairs that are present in the ``[app:main]``
- section (except for the ``use=`` setting) when this function is called by
- when you run ``pserve``.
+ section of an ``.ini`` file (if `[DEFAULT]
+ <http://docs.pylonsproject.org/projects/pyramid/dev/narr/paste.html#defaults-section-of-a-pastedeploy-ini-file>`__
+ is present). It also accepts a ``**settings`` argument, which collects
+ another set of arbitrary key/value pairs. The arbitrary key/value pairs
+ received by this function in ``**settings`` will be composed of all the
+ key/value pairs that are present in the ``[app:main]`` section (except for
+ the ``use=`` setting) when this function is called by when you run
+ ``pserve``.
Our generated ``development.ini`` file looks like so:
@@ -95,7 +98,8 @@ Here's a high-level time-ordered overview of what happens when you press
will receive the key/value pairs ``{'pyramid.reload_templates':'true',
'pyramid.debug_authorization':'false', 'pyramid.debug_notfound':'false',
'pyramid.debug_routematch':'false', 'pyramid.debug_templates':'true',
- 'pyramid.default_locale_name':'en'}``.
+ 'pyramid.default_locale_name':'en'}``. See :ref:`environment_chapter` for
+ the meanings of these keys.
#. The ``main`` function first constructs a
:class:`~pyramid.config.Configurator` instance, passing a root resource
@@ -103,10 +107,6 @@ Here's a high-level time-ordered overview of what happens when you press
``settings`` dictionary captured via the ``**settings`` kwarg as its
``settings`` argument.
- The root resource factory is invoked on every request to retrieve the
- application's root resource. It is not called during startup, only when a
- request is handled.
-
The ``settings`` dictionary contains all the options in the ``[app:main]``
section of our .ini file except the ``use`` option (which is internal to
PasteDeploy) such as ``pyramid.reload_templates``,
diff --git a/docs/narr/tb_introspector.png b/docs/narr/tb_introspector.png
new file mode 100644
index 000000000..4ae406a86
--- /dev/null
+++ b/docs/narr/tb_introspector.png
Binary files differ
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index fb9dd56c2..11318d9eb 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -403,14 +403,6 @@ The language definition documentation for Chameleon ZPT-style
templates is available from `the Chameleon website
<http://chameleon.repoze.org/>`_.
-.. warning::
-
- :term:`Chameleon` only works on :term:`CPython` platforms and
- :term:`Google App Engine`. On :term:`Jython` and other non-CPython
- platforms, you should use Mako (see :ref:`mako_templates`) or
- ``pyramid_jinja2`` instead. See
- :ref:`available_template_system_bindings`.
-
Given a :term:`Chameleon` ZPT template named ``foo.pt`` in a directory
in your application named ``templates``, you can render the template as
a :term:`renderer` like so:
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 05e851fde..7ee432fa7 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -52,7 +52,7 @@ The suggested mechanism for unit and integration testing of a :app:`Pyramid`
application is the Python :mod:`unittest` module. Although this module is
named :mod:`unittest`, it is actually capable of driving both unit and
integration tests. A good :mod:`unittest` tutorial is available within `Dive
-Into Python <http://diveintopython.org/unit_testing/index.html>`_ by Mark
+Into Python <http://diveintopython.nfshost.com/unit_testing/index.html>`_ by Mark
Pilgrim.
:app:`Pyramid` provides a number of facilities that make unit, integration,
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 9ceb20f21..35613ea1b 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -65,7 +65,7 @@ example:
config.add_view(myview, route_name='myroute')
When a :term:`view callable` added to the configuration by way of
-:meth:`~pyramid.config.Configurator.add_view` bcomes associated with a route
+:meth:`~pyramid.config.Configurator.add_view` becomes associated with a route
via its ``route_name`` predicate, that view callable will always be found and
invoked when the associated route pattern matches during a request.
@@ -101,7 +101,7 @@ that references ``myroute`` as a ``route_name`` parameter:
def myview(request):
return Response('OK')
-THe above combination of ``add_route`` and ``scan`` is completely equivalent
+The above combination of ``add_route`` and ``scan`` is completely equivalent
to using the previous combination of ``add_route`` and ``add_view``.
.. index::
diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst
index af5d7f242..03000629c 100644
--- a/docs/narr/viewconfig.rst
+++ b/docs/narr/viewconfig.rst
@@ -621,6 +621,7 @@ against the ``amethod`` method could be spelled equivalently as the below:
def amethod(self):
return Response('hello')
+
.. index::
single: add_view
@@ -658,6 +659,186 @@ configurations, you don't need to issue a :term:`scan` in order for the view
configuration to take effect.
.. index::
+ single: view_defaults class decorator
+
+.. _view_defaults:
+
+``@view_defaults`` Class Decorator
+----------------------------------
+
+.. note::
+
+ This feature is new in Pyramid 1.3.
+
+If you use a class as a view, you can use the
+:class:`pyramid.view.view_defaults` class decorator on the class to provide
+defaults to the view configuration information used by every ``@view_config``
+decorator that decorates a method of that class.
+
+For instance, if you've got a class that has methods that represent "REST
+actions", all which are mapped to the same route, but different request
+methods, instead of this:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
+
+ @view_config(route_name='rest', request_method='GET')
+ def get(self):
+ return Response('get')
+
+ @view_config(route_name='rest', request_method='POST')
+ def post(self):
+ return Response('post')
+
+ @view_config(route_name='rest', request_method='DELETE')
+ def delete(self):
+ return Response('delete')
+
+You can do this:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_defaults
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_defaults(route_name='rest')
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
+
+ @view_config(request_method='GET')
+ def get(self):
+ return Response('get')
+
+ @view_config(request_method='POST')
+ def post(self):
+ return Response('post')
+
+ @view_config(request_method='DELETE')
+ def delete(self):
+ return Response('delete')
+
+In the above example, we were able to take the ``route_name='rest'`` argument
+out of the call to each individual ``@view_config`` statement, because we
+used a ``@view_defaults`` class decorator to provide the argument as a
+default to each view method it possessed.
+
+Arguments passed to ``@view_config`` will override any default passed to
+``@view_defaults``.
+
+The ``view_defaults`` class decorator can also provide defaults to the
+:meth:`pyramid.config.Configurator.add_view` directive when a decorated class
+is passed to that directive as its ``view`` argument. For example, instead
+of this:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.config import Configurator
+
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def get(self):
+ return Response('get')
+
+ def post(self):
+ return Response('post')
+
+ def delete(self):
+ return Response('delete')
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('rest', '/rest')
+ config.add_view(
+ RESTView, route_name='rest', attr='get', request_method='GET')
+ config.add_view(
+ RESTView, route_name='rest', attr='post', request_method='POST')
+ config.add_view(
+ RESTView, route_name='rest', attr='delete', request_method='DELETE')
+
+To reduce the amount of repetion in the ``config.add_view`` statements, we
+can move the ``route_name='rest'`` argument to a ``@view_default`` class
+decorator on the RESTView class:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+ from pyramid.config import Configurator
+
+ @view_defaults(route_name='rest')
+ class RESTView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def get(self):
+ return Response('get')
+
+ def post(self):
+ return Response('post')
+
+ def delete(self):
+ return Response('delete')
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('rest', '/rest')
+ config.add_view(RESTView, attr='get', request_method='GET')
+ config.add_view(RESTView, attr='post', request_method='POST')
+ config.add_view(RESTView, attr='delete', request_method='DELETE')
+
+:class:`pyramid.view.view_defaults` accepts the same set of arguments that
+:class:`pyramid.view.view_config` does, and they have the same meaning. Each
+argument passed to ``view_defaults`` provides a default for the view
+configurations of methods of the class it's decorating.
+
+Normal Python inheritance rules apply to defaults added via
+``view_defaults``. For example:
+
+.. code-block:: python
+ :linenos:
+
+ @view_defaults(route_name='rest')
+ class Foo(object):
+ pass
+
+ class Bar(Foo):
+ pass
+
+The ``Bar`` class above will inherit its view defaults from the arguments
+passed to the ``view_defaults`` decorator of the ``Foo`` class. To prevent
+this from happening, use a ``view_defaults`` decorator without any arguments
+on the subclass:
+
+.. code-block:: python
+ :linenos:
+
+ @view_defaults(route_name='rest')
+ class Foo(object):
+ pass
+
+ @view_defaults()
+ class Bar(Foo):
+ pass
+
+The ``view_defaults`` decorator only works as a class decorator; using it
+against a function or a method will produce nonsensical results.
+
+.. index::
single: view security
pair: security; view