summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile8
-rw-r--r--docs/api.rst1
-rw-r--r--docs/api/authentication.rst16
-rw-r--r--docs/api/decorator.rst9
-rw-r--r--docs/api/request.rst56
-rw-r--r--docs/api/session.rst2
-rw-r--r--docs/api/testing.rst2
-rw-r--r--docs/changes.rst2
-rw-r--r--docs/conf.py4
-rw-r--r--docs/designdefense.rst14
-rw-r--r--docs/glossary.rst51
-rw-r--r--docs/index.rst3
-rw-r--r--docs/latexindex.rst3
-rw-r--r--docs/narr/MyProject/myproject/static/pylons.css435
-rw-r--r--docs/narr/advconfig.rst7
-rw-r--r--docs/narr/install.rst213
-rw-r--r--docs/narr/introduction.rst2
-rw-r--r--docs/narr/introspector.rst4
-rw-r--r--docs/narr/project.rst41
-rw-r--r--docs/narr/renderers.rst2
-rw-r--r--docs/narr/sessions.rst13
-rw-r--r--docs/narr/subrequest.rst271
-rw-r--r--docs/narr/templates.rst36
-rw-r--r--docs/narr/testing.rst24
-rw-r--r--docs/narr/upgrading.rst234
-rw-r--r--docs/narr/viewconfig.rst68
-rw-r--r--docs/narr/views.rst10
-rwxr-xr-xdocs/remake2
-rw-r--r--docs/tutorials/modwsgi/index.rst22
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/views.py10
-rw-r--r--docs/tutorials/wiki2/authorization.rst8
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst28
-rw-r--r--docs/tutorials/wiki2/definingviews.rst2
-rw-r--r--docs/tutorials/wiki2/design.rst3
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/__init__.py6
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/views.py16
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py6
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/__init__.py6
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/__init__.py6
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/views.py16
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/__init__.py6
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/pylons.css435
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/views.py16
-rw-r--r--docs/whatsnew-1.4.rst310
55 files changed, 5447 insertions, 917 deletions
diff --git a/docs/Makefile b/docs/Makefile
index e4a325022..c98fdc65e 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -25,7 +25,7 @@ help:
clean:
-rm -rf _build/*
-html: _themes
+html: themes
mkdir -p _build/html _build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
@echo
@@ -47,7 +47,7 @@ pickle:
web: pickle
-htmlhelp: _themes
+htmlhelp: themes
mkdir -p _build/htmlhelp _build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
@echo
@@ -84,5 +84,5 @@ epub:
@echo
@echo "Build finished. The epub file is in _build/epub."
-_themes:
- git submodule update --init
+themes:
+ cd ..; git submodule update --init --recursive; cd docs;
diff --git a/docs/api.rst b/docs/api.rst
index e33fd6a74..9e540b49b 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -12,6 +12,7 @@ documentation is organized alphabetically by module name.
api/authentication
api/compat
api/config
+ api/decorator
api/events
api/exceptions
api/httpexceptions
diff --git a/docs/api/authentication.rst b/docs/api/authentication.rst
index ed96e9c98..e6ee5658b 100644
--- a/docs/api/authentication.rst
+++ b/docs/api/authentication.rst
@@ -11,12 +11,24 @@ Authentication Policies
.. autoclass:: SHA512AuthTktAuthenticationPolicy
.. autoclass:: AuthTktAuthenticationPolicy
-
- .. autoclass:: RepozeWho1AuthenticationPolicy
+ :members:
+ :inherited-members:
.. autoclass:: RemoteUserAuthenticationPolicy
+ :members:
+ :inherited-members:
.. autoclass:: SessionAuthenticationPolicy
+ :members:
+ :inherited-members:
+
+ .. autoclass:: BasicAuthAuthenticationPolicy
+ :members:
+ :inherited-members:
+
+ .. autoclass:: RepozeWho1AuthenticationPolicy
+ :members:
+ :inherited-members:
Helper Classes
~~~~~~~~~~~~~~
diff --git a/docs/api/decorator.rst b/docs/api/decorator.rst
new file mode 100644
index 000000000..35d9131df
--- /dev/null
+++ b/docs/api/decorator.rst
@@ -0,0 +1,9 @@
+.. _decorator_module:
+
+:mod:`pyramid.decorator`
+--------------------------
+
+.. automodule:: pyramid.decorator
+
+.. autofunction:: reify
+
diff --git a/docs/api/request.rst b/docs/api/request.rst
index 1112ea069..3a1439874 100644
--- a/docs/api/request.rst
+++ b/docs/api/request.rst
@@ -161,6 +161,62 @@
request, the value of this attribute will be ``None``. See
:ref:`matched_route`.
+ .. method:: invoke_subrequest(request, use_tweens=False)
+
+ .. warning::
+
+ This API was added in Pyramid 1.4a1.
+
+ Obtain a response object from the Pyramid application based on
+ information in the ``request`` object provided. The ``request`` object
+ must be an object that implements the Pyramid request interface (such
+ as a :class:`pyramid.request.Request` instance). If ``use_tweens`` is
+ ``True``, the request will be sent to the :term:`tween` in the tween
+ stack closest to the request ingress. If ``use_tweens`` is ``False``,
+ the request will be sent to the main router handler, and no tweens will
+ be invoked.
+
+ This function also:
+
+ - manages the threadlocal stack (so that
+ :func:`~pyramid.threadlocal.get_current_request` and
+ :func:`~pyramid.threadlocal.get_current_registry` work during a
+ request)
+
+ - Adds a ``registry`` attribute (the current Pyramid registry) and a
+ ``invoke_subrequest`` attribute (a callable) to the request object it's
+ handed.
+
+ - sets request extensions (such as those added via
+ :meth:`~pyramid.config.Configurator.add_request_method` or
+ :meth:`~pyramid.config.Configurator.set_request_property`) on the
+ request it's passed.
+
+ - causes a :class:`~pyramid.event.NewRequest` event to be sent at the
+ beginning of request processing.
+
+ - causes a :class:`~pyramid.event.ContextFound` event to be sent
+ when a context resource is found.
+
+ - Ensures that the user implied by the request passed has the necessary
+ authorization to invoke view callable before calling it.
+
+ - causes a :class:`~pyramid.event.NewResponse` event to be sent when
+ the Pyramid application returns a response.
+
+ - Calls any :term:`response callback` functions defined within the
+ request's lifetime if a response is obtained from the Pyramid
+ application.
+
+ - Calls any :term:`finished callback` functions defined within the
+ request's lifetime.
+
+ ``invoke_subrequest`` isn't *actually* a method of the Request object;
+ it's a callable added when the Pyramid router is invoked, or when a
+ subrequest is invoked. This means that it's not available for use on a
+ request provided by e.g. the ``pshell`` environment. For more
+ information, see :ref:`subrequest_chapter`.
+
.. automethod:: add_response_callback
.. automethod:: add_finished_callback
diff --git a/docs/api/session.rst b/docs/api/session.rst
index 44b4bd860..31bc196ad 100644
--- a/docs/api/session.rst
+++ b/docs/api/session.rst
@@ -11,4 +11,6 @@
.. autofunction:: signed_deserialize
+ .. autofunction:: check_csrf_token
+
diff --git a/docs/api/testing.rst b/docs/api/testing.rst
index f388dc263..1366a1795 100644
--- a/docs/api/testing.rst
+++ b/docs/api/testing.rst
@@ -9,6 +9,8 @@
.. autofunction:: tearDown
+ .. autofunction:: testConfig(registry=None, request=None, hook_zca=True, autocommit=True, settings=None)
+
.. autofunction:: cleanUp
.. autoclass:: DummyResource
diff --git a/docs/changes.rst b/docs/changes.rst
index 6294123ed..fdeaf1e99 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -1,3 +1,5 @@
+.. _changelog:
+
:app:`Pyramid` Change History
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/conf.py b/docs/conf.py
index 80ee0d2e5..9bda4c798 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -81,7 +81,7 @@ copyright = '%s, Agendaless Consulting' % datetime.datetime.now().year
# other places throughout the built documents.
#
# The short X.Y version.
-version = '1.4dev'
+version = '1.4a3'
# The full version, including alpha/beta/rc tags.
release = version
@@ -160,7 +160,7 @@ html_theme_path = ['_themes']
html_theme = 'pyramid'
html_theme_options = dict(
github_url='https://github.com/Pylons/pyramid',
- in_progress='true',
+# in_progress='true',
)
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index d896022e6..b468ddac6 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -390,20 +390,6 @@ completely optional. No ZCML is required at all to use :app:`Pyramid`, nor
any other sort of frameworky declarative frontend to application
configuration.
-.. _model_traversal_confusion:
-
-Pyramid Uses "Model" To Represent A Node In The Graph of Objects Traversed
---------------------------------------------------------------------------
-
-The ``repoze.bfg`` documentation used to refer to the graph being traversed
-when :term:`traversal` is used as a "model graph". A terminology overlap
-confused people who wrote applications that always use ORM packages such as
-SQLAlchemy, which has a different notion of the definition of a "model". As
-a result, in Pyramid 1.0a7, the tree of objects traversed is now renamed to
-:term:`resource tree` and its components are now named :term:`resource`
-objects. Associated APIs have been changed. This hopefully alleviates the
-terminology confusion caused by overriding the term "model".
-
Pyramid Does Traversal, And I Don't Like Traversal
--------------------------------------------------
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 34cf1b078..adcf36f7c 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -41,14 +41,20 @@ Glossary
setuptools
`Setuptools <http://peak.telecommunity.com/DevCenter/setuptools>`_
builds on Python's ``distutils`` to provide easier building,
- distribution, and installation of libraries and applications.
+ distribution, and installation of libraries and applications. As of
+ this writing, setuptools runs under Python 2, but not under Python 3.
+ You can use :term:`distribute` under Python 3 instead.
+
+ distribute
+ `Distribute <http://packages.python.org/distribute/>`_ is a fork of
+ :term:`setuptools` which runs on both Python 2 and Python 3.
pkg_resources
- A module which ships with :term:`setuptools` that provides an API for
- addressing "asset files" within a Python :term:`package`. Asset files
- are static files, template files, etc; basically anything
- non-Python-source that lives in a Python package can be considered a
- asset file. See also `PkgResources
+ A module which ships with :term:`setuptools` and :term:`distribute` that
+ provides an API for addressing "asset files" within a Python
+ :term:`package`. Asset files are static files, template files, etc;
+ basically anything non-Python-source that lives in a Python package can
+ be considered a asset file. See also `PkgResources
<http://peak.telecommunity.com/DevCenter/PkgResources>`_
asset
@@ -84,7 +90,7 @@ Glossary
(Setuptools/distutils terminology). A file representing an
installable library or application. Distributions are usually
files that have the suffix of ``.egg``, ``.tar.gz``, or ``.zip``.
- Distributions are the target of Setuptools commands such as
+ Distributions are the target of Setuptools-related commands such as
``easy_install``.
entry point
@@ -475,10 +481,24 @@ Glossary
:app:`Pyramid` to form a workflow system.
virtual root
- A resource object representing the "virtual" root of a request; this
- is typically the physical root object (the object returned by the
- application root factory) unless :ref:`vhosting_chapter` is in
- use.
+ A resource object representing the "virtual" root of a request; this is
+ typically the :term:`physical root` object unless :ref:`vhosting_chapter`
+ is in use.
+
+ physical root
+ The object returned by the application :term:`root factory`. Unlike the
+ the :term:`virtual root` of a request, it is not impacted by
+ :ref:`vhosting_chapter`: it will always be the actual object returned by
+ the root factory, never a subobject.
+
+ physical path
+ The path required by a traversal which resolve a :term:`resource` starting
+ from the :term:`physical root`. For example, the physical path of the
+ ``abc`` subobject of the physical root object is ``/abc``. Physical paths
+ can also be specified as tuples where the first element is the empty
+ string (representing the root), and every other element is a Unicode
+ object, e.g. ``('', 'abc')``. Physical paths are also sometimes called
+ "traversal paths".
lineage
An ordered sequence of objects based on a ":term:`location` -aware"
@@ -812,9 +832,12 @@ Glossary
application.
session factory
- A callable, which, when called with a single argument named
- ``request`` (a :term:`request` object), returns a
- :term:`session` object.
+ A callable, which, when called with a single argument named ``request``
+ (a :term:`request` object), returns a :term:`session` object. See
+ :ref:`using_the_default_session_factory`,
+ :ref:`using_alternate_session_factories` and
+ :meth:`pyramid.config.Configurator.set_session_factory` for more
+ information.
Mako
`Mako <http://www.makotemplates.org/>`_ is a template language language
diff --git a/docs/index.rst b/docs/index.rst
index c84314274..faf8258c1 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -37,6 +37,7 @@ What's New
.. toctree::
:maxdepth: 1
+ whatsnew-1.4
whatsnew-1.3
whatsnew-1.2
whatsnew-1.1
@@ -82,12 +83,14 @@ Narrative documentation in chapter form explaining how to use
narr/traversal
narr/security
narr/hybrid
+ narr/subrequest
narr/hooks
narr/introspector
narr/extending
narr/advconfig
narr/extconfig
narr/scaffolding
+ narr/upgrading
narr/threadlocals
narr/zca
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 99ec2f54d..6bb875f73 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -54,6 +54,7 @@ Narrative Documentation
narr/traversal
narr/security
narr/hybrid
+ narr/subrequest
narr/hooks
narr/introspector
narr/extending
@@ -85,8 +86,6 @@ API Reference
api/authorization
api/authentication
- api/chameleon_text
- api/chameleon_zpt
api/config
api/events
api/exceptions
diff --git a/docs/narr/MyProject/myproject/static/pylons.css b/docs/narr/MyProject/myproject/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/narr/MyProject/myproject/static/pylons.css
+++ b/docs/narr/MyProject/myproject/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index 165cf7474..ad22a82c9 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -414,3 +414,10 @@ 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.
+More Information
+----------------
+
+For more information, see the article entitled `"A Whirlwind Rour of Advanced
+Configuration Tactics"
+<http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/whirlwind_tour.html>`_
+in the Pyramid Cookbook.
diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index 172cfd6d3..e8482a289 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -14,13 +14,13 @@ run :app:`Pyramid`.
.. sidebar:: Python Versions
- 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.
+ As of this writing, :app:`Pyramid` has been tested under Python 2.6.8,
+ Python 2.7.3, Python 3.2.3, and Python 3.3b1. :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 :term:`PyPy` (1.6+).
+known to run on :term:`PyPy` (1.9+).
:app:`Pyramid` installation does not require the compilation of any
C code, so you need only a Python interpreter that meets the
@@ -45,15 +45,15 @@ system's package manager is slightly different, but the "flavor" of
them is usually the same.
For example, on an Ubuntu Linux system, to use the system package
-manager to install a Python 2.6 interpreter, use the following
+manager to install a Python 2.7 interpreter, use the following
command:
.. code-block:: text
- $ sudo apt-get install python2.6-dev
+ $ sudo apt-get install python2.7-dev
Once these steps are performed, the Python interpreter will usually be
-invokable via ``python2.6`` from a shell prompt.
+invokable via ``python2.7`` from a shell prompt.
.. index::
pair: install; Python (from source, UNIX)
@@ -80,7 +80,7 @@ On Mac OS X, installing `XCode
<http://developer.apple.com/tools/xcode/>`_ has much the same effect.
Once you've got development tools installed on your system, you can
-install a Python 2.6 interpreter from *source*, on the same system,
+install a Python 2.7 interpreter from *source*, on the same system,
using the following commands:
.. code-block:: text
@@ -90,15 +90,15 @@ using the following commands:
[chrism@vitaminf ~]$ mkdir opt
[chrism@vitaminf ~]$ cd tmp
[chrism@vitaminf tmp]$ wget \
- http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tgz
- [chrism@vitaminf tmp]$ tar xvzf Python-2.6.4.tgz
- [chrism@vitaminf tmp]$ cd Python-2.6.4
- [chrism@vitaminf Python-2.6.4]$ ./configure \
- --prefix=$HOME/opt/Python-2.6.4
- [chrism@vitaminf Python-2.6.4]$ make; make install
+ http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz
+ [chrism@vitaminf tmp]$ tar xvzf Python-2.7.3.tgz
+ [chrism@vitaminf tmp]$ cd Python-2.7.3
+ [chrism@vitaminf Python-2.7.3]$ ./configure \
+ --prefix=$HOME/opt/Python-2.7.3
+ [chrism@vitaminf Python-2.7.3]$ make; make install
Once these steps are performed, the Python interpreter will be
-invokable via ``$HOME/opt/Python-2.6.4/bin/python`` from a shell
+invokable via ``$HOME/opt/Python-2.7.3/bin/python`` from a shell
prompt.
.. index::
@@ -108,7 +108,7 @@ If You Don't Yet Have A Python Interpreter (Windows)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If your Windows system doesn't have a Python interpreter, you'll need
-to install it by downloading a Python 2.6-series interpreter
+to install it by downloading a Python 2.7-series interpreter
executable from `python.org's download section
<http://python.org/download/>`_ (the files labeled "Windows
Installer"). Once you've downloaded it, double click on the
@@ -119,7 +119,7 @@ extensions <http://sourceforge.net/projects/pywin32/files/>`_.
.. warning::
After you install Python on Windows, you may need to add the
- ``C:\Python26`` directory to your environment's ``Path`` in order
+ ``C:\Python27`` directory to your environment's ``Path`` in order
to make it possible to invoke Python from a command prompt by
typing ``python``. To do so, right click ``My Computer``, select
``Properties`` --> ``Advanced Tab`` --> ``Environment Variables``
@@ -141,39 +141,62 @@ done by using the :term:`virtualenv` package. Using a virtualenv will
also prevent :app:`Pyramid` from globally installing versions of
packages that are not compatible with your system Python.
-To set up a virtualenv in which to install :app:`Pyramid`, first
-ensure that :term:`setuptools` is installed. Invoke ``import
-setuptools`` within the Python interpreter you'd like to run
-:app:`Pyramid` under:
+To set up a virtualenv in which to install :app:`Pyramid`, first ensure that
+:term:`setuptools` or :term:`distribute` is installed. To do so, invoke
+``import setuptools`` within the Python interpreter you'd like to run
+:app:`Pyramid` under.
+
+Here's the output you'll expect if setuptools or distribute is already
+installed:
.. code-block:: text
- [chrism@vitaminf pyramid]$ python
- Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32)
- [GCC 4.4.3] on linux2
+ [chrism@thinko docs]$ python2.7
+ Python 2.7.3 (default, Aug 1 2012, 05:14:39)
+ [GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import setuptools
+ >>>
-If running ``import setuptools`` does not raise an ``ImportError``, it
-means that setuptools is already installed into your Python
-interpreter. If ``import setuptools`` fails, you will need to install
-setuptools manually. Note that above we're using a Python 2.6-series
-interpreter on Mac OS X; your output may differ if you're using a
-later Python version or a different platform.
-
-If you are using a "system" Python (one installed by your OS
-distributor or a 3rd-party packager such as Fink or MacPorts), you can
-usually install the setuptools package by using your system's package
-manager. If you cannot do this, or if you're using a self-installed
-version of Python, you will need to install setuptools "by hand".
-Installing setuptools "by hand" is always a reasonable thing to do,
-even if your package manager already has a pre-chewed version of
-setuptools for installation.
-
-To install setuptools by hand, first download `ez_setup.py
-<http://peak.telecommunity.com/dist/ez_setup.py>`_ then invoke it
-using the Python interpreter into which you want to install
-setuptools.
+Here's the output you can expect if setuptools or distribute is not already
+installed:
+
+.. code-block:: text
+
+ [chrism@thinko docs]$ python2.7
+ Python 2.7.3 (default, Aug 1 2012, 05:14:39)
+ [GCC 4.6.3] on linux2
+ Type "help", "copyright", "credits" or "license" for more information.
+ >>> import setutptools
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ ImportError: No module named setutptools
+ >>>
+
+If ``import setuptools`` raises an :exc:`ImportError` as it does above, you
+will need to install setuptools or distribute manually. Note that above
+we're using a Python 2.7-series interpreter on Mac OS X; your output may
+differ if you're using a later Python version or a different platform.
+
+If you are using a "system" Python (one installed by your OS distributor or a
+3rd-party packager such as Fink or MacPorts), you can usually install the
+setuptools or distribute package by using your system's package manager. If
+you cannot do this, or if you're using a self-installed version of Python,
+you will need to install setuptools or distribute "by hand". Installing
+setuptools or distribute "by hand" is always a reasonable thing to do, even
+if your package manager already has a pre-chewed version of setuptools for
+installation.
+
+If you're using Python 2, you'll want to install ``setuptools``. If you're
+using Python 3, you'll want to install ``distribute``. Below we tell you how
+to do both.
+
+Installing Setuptools On Python 2
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To install setuptools by hand under Python 2, first download `ez_setup.py
+<http://peak.telecommunity.com/dist/ez_setup.py>`_ then invoke it using the
+Python interpreter into which you want to install setuptools.
.. code-block:: text
@@ -188,16 +211,37 @@ the script. To remediate this, you may need to do:
$ sudo python ez_setup.py
+Installing Distribute On Python 3
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``setuptools`` doesn't work under Python 3. Instead, you can use
+``distribute``, which is a fork of setuptools that does work on Python 3. To
+install it, first download `distribute_setup.py
+<http://python-distribute.org/distribute_setup.py>`_ then invoke it using the
+Python interpreter into which you want to install setuptools.
+
+.. code-block:: text
+
+ $ python3 distribute_setup.py
+
+Once this command is invoked, distribute should be installed on your system.
+If the command fails due to permission errors, you may need to be the
+administrative user on your system to successfully invoke the script. To
+remediate this, you may need to do:
+
+.. code-block:: text
+
+ $ sudo python3 distribute_setup.py
+
.. index::
pair: install; virtualenv
Installing the ``virtualenv`` Package
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Once you've got setuptools installed, you should install the
-:term:`virtualenv` package. To install the :term:`virtualenv` package
-into your setuptools-enabled Python interpreter, use the
-``easy_install`` command.
+Once you've got setuptools or distribute installed, you should install the
+:term:`virtualenv` package. To install the :term:`virtualenv` package into
+your setuptools-enabled Python interpreter, use the ``easy_install`` command.
.. code-block:: text
@@ -269,35 +313,90 @@ complete, as it downloads and installs a number of dependencies.
Installing :app:`Pyramid` on a Windows System
-------------------------------------------------
-#. Install, or find `Python 2.6
- <http://python.org/download/releases/2.6.4/>`_ for your system.
+You can use Pyramid on Windows under Python 2 or under Python 3. Directions
+for both versions are included below.
+
+Windows Using Python 2
+~~~~~~~~~~~~~~~~~~~~~~
+
+#. Install, or find `Python 2.7
+ <http://www.python.org/download/releases/2.7.3/>`_ for your system.
#. Install the `Python for Windows extensions
<http://sourceforge.net/projects/pywin32/files/>`_. Make sure to
- pick the right download for Python 2.6 and install it using the
+ pick the right download for Python 2.7 and install it using the
same Python installation from the previous step.
#. Install latest :term:`setuptools` distribution into the Python you
obtained/installed/found in the step above: download `ez_setup.py
<http://peak.telecommunity.com/dist/ez_setup.py>`_ and run it using
- the ``python`` interpreter of your Python 2.6 installation using a
+ the ``python`` interpreter of your Python 2.7 installation using a
command prompt:
.. code-block:: text
- c:\> c:\Python26\python ez_setup.py
+ c:\> c:\Python27\python ez_setup.py
+
+#. Use that Python's `bin/easy_install` to install `virtualenv`:
+
+ .. code-block:: text
+
+ c:\> c:\Python27\Scripts\easy_install virtualenv
+
+#. Use that Python's virtualenv to make a workspace:
+
+ .. code-block:: text
+
+ c:\> c:\Python27\Scripts\virtualenv --no-site-packages env
+
+#. Switch to the ``env`` directory:
+
+ .. code-block:: text
+
+ c:\> cd env
+
+#. (Optional) Consider using ``Scripts\activate.bat`` to make your shell
+ environment wired to use the virtualenv.
+
+#. Use ``easy_install`` to get :app:`Pyramid` and its direct dependencies
+ installed:
+
+ .. code-block:: text
+
+ c:\env> Scripts\easy_install pyramid
+
+Windows Using Python 3
+~~~~~~~~~~~~~~~~~~~~~~
+
+#. Install, or find `Python 3.2
+ <http://www.python.org/download/releases/3.2.3/>`_ for your system.
+
+#. Install the `Python for Windows extensions
+ <http://sourceforge.net/projects/pywin32/files/>`_. Make sure to
+ pick the right download for Python 3.2 and install it using the
+ same Python installation from the previous step.
+
+#. Install latest :term:`distribute` distribution into the Python you
+ obtained/installed/found in the step above: download `distribute_setup.py
+ <http://python-distribute.org/distribute_setup.py>`_ and run it using the
+ ``python`` interpreter of your Python 3.2 installation using a command
+ prompt:
+
+ .. code-block:: text
+
+ c:\> c:\Python32\python distribute_setup.py
#. Use that Python's `bin/easy_install` to install `virtualenv`:
.. code-block:: text
- c:\> c:\Python26\Scripts\easy_install virtualenv
+ c:\> c:\Python32\Scripts\easy_install virtualenv
#. Use that Python's virtualenv to make a workspace:
.. code-block:: text
- c:\> c:\Python26\Scripts\virtualenv --no-site-packages env
+ c:\> c:\Python32\Scripts\virtualenv --no-site-packages env
#. Switch to the ``env`` directory:
@@ -308,8 +407,8 @@ Installing :app:`Pyramid` on a Windows System
#. (Optional) Consider using ``Scripts\activate.bat`` to make your shell
environment wired to use the virtualenv.
-#. Use ``easy_install`` pointed at the "current" index to get
- :app:`Pyramid` and its direct dependencies installed:
+#. Use ``easy_install`` to get :app:`Pyramid` and its direct dependencies
+ installed:
.. code-block:: text
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index 7c0f9223f..b35c61720 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -315,7 +315,7 @@ Rendered views can return dictionaries
If you use a :term:`renderer`, you don't have to return a special kind of
"webby" ``Response`` object from a view. Instead, you can return a
-dictionary instead, and Pyramid will take care of converting that dictionary
+dictionary, and Pyramid will take care of converting that dictionary
to a Response using a template on your behalf. This makes the view easier to
test, because you don't have to parse HTML in your tests; just make an
assertion instead that the view returns "the right stuff" in the dictionary
diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst
index 6bfaf11c0..b88f3f0c8 100644
--- a/docs/narr/introspector.rst
+++ b/docs/narr/introspector.rst
@@ -393,6 +393,10 @@ introspectables in categories not described here.
The ``match_param`` argument passed to ``add_view``.
+ ``csrf_token``
+
+ The ``csrf_token`` argument passed to ``add_view``.
+
``callable``
The (resolved) ``view`` argument passed to ``add_view``. Represents the
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 1e2c225d2..b08948e43 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -286,11 +286,39 @@ Here's sample output from a run of ``pserve`` on UNIX:
$ ../bin/pserve development.ini
Starting server in PID 16601.
- serving on 0.0.0.0:6543 view at http://127.0.0.1:6543
+ serving on http://0.0.0.0:6543
-By default, :app:`Pyramid` applications generated from a scaffold
-will listen on TCP port 6543. You can shut down a server started this way by
-pressing ``Ctrl-C``.
+When you use ``pserve`` to start the application implied by the default
+rendering of a scaffold, it will respond to requests on *all* IP addresses
+possessed by your system, not just requests to ``localhost``. This is what
+the ``0.0.0.0`` in ``serving on http://0.0.0.0:6543`` means. The server will
+respond to requests made to ``127.0.0.1`` and on any external IP address.
+For example, your system might be configured to have an external IP address
+``192.168.1.50``. If that's the case, if you use a browser running on the
+same system as Pyramid, it will be able to access the application via
+``http://127.0.0.1:6543/`` as well as via
+``http://129.168.1.50:6543/``. However, *other people* on other computers on
+the same network will also be able to visit your Pyramid application in their
+browser by visiting ``http://192.168.1.50:6543/``.
+
+If you want to restrict access such that only a browser running on the same
+machine as Pyramid will be able to access your Pyramid application, edit the
+``development.ini`` file, and replace the ``host`` value in the
+``[server:main]`` section. Change it from ``0.0.0.0`` to ``127.0.0.1``. For
+example::
+
+ [server:main]
+ use = egg:waitress#main
+ host = 127.0.0.1
+ port = 6543
+
+You can change the port on which the server runs on by changing the same
+portion of the ``development.ini`` file. For example, you can change the
+``port = 6543`` line in the ``development.ini`` file's ``[server:main]``
+section to ``port = 8080`` to run the server on port 8080 instead of
+port 6543.
+
+You can shut down a server started this way by pressing ``Ctrl-C``.
The default server used to run your Pyramid application when a project is
created from a scaffold is named :term:`Waitress`. This server is what
@@ -309,11 +337,6 @@ under the default server, it will almost certainly work under any other
server in production if you eventually choose to use a different one. Don't
worry about it right now.
-You can change the port on which the server runs on by changing the
-``development.ini`` file. For example, you can change the ``port = 6543``
-line in the ``development.ini`` file's ``[server:main]`` section to ``port =
-8080`` to run the server on port 8080 instead of port 6543.
-
For more detailed information about the startup process, see
:ref:`startup_chapter`. For more information about environment variables and
configuration file settings that influence startup and runtime behavior, see
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 63287e2cd..1158d2225 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -329,7 +329,7 @@ time "by hand". Configure a JSONP renderer using the
Once this renderer is registered via
:meth:`~pyramid.config.Configurator.add_renderer` as above, you can use
``jsonp`` as the ``renderer=`` parameter to ``@view_config`` or
-:meth:`pyramid.config.Configurator.add_view``:
+:meth:`pyramid.config.Configurator.add_view`:
.. code-block:: python
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst
index 1aa1b6341..f7da7838e 100644
--- a/docs/narr/sessions.rst
+++ b/docs/narr/sessions.rst
@@ -63,10 +63,15 @@ application by using the ``session_factory`` argument to the
this implementation is, by default, *unencrypted*. You should not use it
when you keep sensitive information in the session object, as the
information can be easily read by both users of your application and third
- parties who have access to your users' network traffic. Use a different
- session factory implementation (preferably one which keeps session data on
- the server) for anything but the most basic of applications where "session
- security doesn't matter".
+ parties who have access to your users' network traffic. And if you use this
+ sessioning implementation, and you inadvertently create a cross-site
+ scripting vulnerability in your application, because the session data is
+ stored unencrypted in a cookie, it will also be easier for evildoers to
+ obtain the current user's cross-site scripting token. In short, use a
+ different session factory implementation (preferably one which keeps session
+ data on the server) for anything but the most basic of applications where
+ "session security doesn't matter", and you are sure your application has no
+ cross-site scripting vulnerabilities.
.. index::
single: session object
diff --git a/docs/narr/subrequest.rst b/docs/narr/subrequest.rst
new file mode 100644
index 000000000..89551ab35
--- /dev/null
+++ b/docs/narr/subrequest.rst
@@ -0,0 +1,271 @@
+.. index::
+ single: subrequest
+
+.. _subrequest_chapter:
+
+Invoking a Subrequest
+=====================
+
+.. warning::
+
+ This feature was added in Pyramid 1.4a1.
+
+:app:`Pyramid` allows you to invoke a subrequest at any point during the
+processing of a request. Invoking a subrequest allows you to obtain a
+:term:`response` object from a view callable within your :app:`Pyramid`
+application while you're executing a different view callable within the same
+application.
+
+Here's an example application which uses a subrequest:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ request.response.body = 'This came from view_two'
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two')
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+When ``/view_one`` is visted in a browser, the text printed in the browser
+pane will be ``This came from view_two``. The ``view_one`` view used the
+:meth:`pyramid.request.Request.invoke_subrequest` API to obtain a response
+from another view (``view_two``) within the same application when it
+executed. It did so by constructing a new request that had a URL that it
+knew would match the ``view_two`` view registration, and passed that new
+request along to :meth:`pyramid.request.Request.invoke_subrequest`. The
+``view_two`` view callable was invoked, and it returned a response. The
+``view_one`` view callable then simply returned the response it obtained from
+the ``view_two`` view callable.
+
+Note that it doesn't matter if the view callable invoked via a subrequest
+actually returns a *literal* Response object. Any view callable that uses a
+renderer or which returns an object that can be interpreted by a response
+adapter when found and invoked via
+:meth:`pyramid.request.Request.invoke_subrequest` will return a Response
+object:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ return 'This came from view_two'
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+Even though the ``view_two`` view callable returned a string, it was invoked
+in such a way that the ``string`` renderer associated with the view
+registration that was found turned it into a "real" response object for
+consumption by ``view_one``.
+
+Being able to unconditionally obtain a response object by invoking a view
+callable indirectly is the main advantage to using
+:meth:`pyramid.request.Request.invoke_subrequest` instead of simply importing
+a view callable and executing it directly. Note that there's not much
+advantage to invoking a view using a subrequest if you *can* invoke a view
+callable directly. Subrequests are slower and are less convenient if you
+actually do want just the literal information returned by a function that
+happens to be a view callable.
+
+Note that, by default, if a view callable invoked by a subrequest raises an
+exception, the exception will be raised to the caller of
+:meth:`~pyramid.request.Request.invoke_subrequest` even if you have a
+:term:`exception view` configured:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq)
+ return response
+
+ def view_two(request):
+ raise ValueError('foo')
+
+ def excview(request):
+ request.response.body = b'An exception was raised'
+ request.response.status_int = 500
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ config.add_view(excview, context=Exception)
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+When we run the above code and visit ``/view_one`` in a browser, the
+``excview`` :term:`exception view` will *not* be executed. Instead, the call
+to :meth:`~pyramid.request.Request.invoke_subrequest` will cause a
+:exc:`ValueError` exception to be raised and a response will never be
+generated. We can change this behavior; how to do so is described below in
+our discussion of the ``use_tweens`` argument.
+
+The :meth:`pyramid.request.Request.invoke_subrequest` API accepts two
+arguments: a positional argument ``request`` that must be provided, and and
+``use_tweens`` keyword argument that is optional; it defaults to ``False``.
+
+The ``request`` object passed to the API must be an object that implements
+the Pyramid request interface (such as a :class:`pyramid.request.Request`
+instance). If ``use_tweens`` is ``True``, the request will be sent to the
+:term:`tween` in the tween stack closest to the request ingress. If
+``use_tweens`` is ``False``, the request will be sent to the main router
+handler, and no tweens will be invoked.
+
+In the example above, the call to
+:meth:`~pyramid.request.Request.invoke_subrequest` will always raise an
+exception. This is because it's using the default value for ``use_tweens``,
+which is ``False``. You can pass ``use_tweens=True`` instead to ensure that
+it will convert an exception to a Response if an :term:`exception view` is
+configured instead of raising the exception. This because exception views
+are called by the exception view :term:`tween` as described in
+:ref:`exception_views` when any view raises an exception.
+
+We can cause the subrequest to be run through the tween stack by passing
+``use_tweens=True`` to the call to
+:meth:`~pyramid.request.Request.invoke_subrequest`, like this:
+
+.. code-block:: python
+
+ from wsgiref.simple_server import make_server
+ from pyramid.config import Configurator
+ from pyramid.request import Request
+
+ def view_one(request):
+ subreq = Request.blank('/view_two')
+ response = request.invoke_subrequest(subreq, use_tweens=True)
+ return response
+
+ def view_two(request):
+ raise ValueError('foo')
+
+ def excview(request):
+ request.response.body = b'An exception was raised'
+ request.response.status_int = 500
+ return request.response
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.add_route('one', '/view_one')
+ config.add_route('two', '/view_two')
+ config.add_view(view_one, route_name='one')
+ config.add_view(view_two, route_name='two', renderer='string')
+ config.add_view(excview, context=Exception)
+ app = config.make_wsgi_app()
+ server = make_server('0.0.0.0', 8080, app)
+ server.serve_forever()
+
+In the above case, the call to ``request.invoke_subrequest(subreq)`` will not
+raise an exception. Instead, it will retrieve a "500" response from the
+attempted invocation of ``view_two``, because the tween which invokes an
+exception view to generate a response is run, and therefore ``excview`` is
+executed.
+
+This is one of the major differences between specifying the
+``use_tweens=True`` and ``use_tweens=False`` arguments to
+:meth:`~pyramid.request.Request.invoke_subrequest`. ``use_tweens=True`` may
+also imply invoking transaction commit/abort for the logic executed in the
+subrequest if you've got ``pyramid_tm`` in the tween list, injecting debug
+HTML if you've got ``pyramid_debugtoolbar`` in the tween list, and other
+tween-related side effects as defined by your particular tween list.
+
+The :meth:`~pyramid.request.Request.invoke_subrequest` function also
+unconditionally:
+
+- manages the threadlocal stack so that
+ :func:`~pyramid.threadlocal.get_current_request` and
+ :func:`~pyramid.threadlocal.get_current_registry` work during a request
+ (they will return the subrequest instead of the original request)
+
+- Adds a ``registry`` attribute and a ``invoke_subrequest`` attribute (a
+ callable) to the request object it's handed.
+
+- sets request extensions (such as those added via
+ :meth:`~pyramid.config.Configurator.add_request_method` or
+ :meth:`~pyramid.config.Configurator.set_request_property`) on the subrequest
+ object passed as ``request``
+
+- causes a :class:`~pyramid.event.NewRequest` event to be sent at the
+ beginning of request processing.
+
+- causes a :class:`~pyramid.event.ContextFound` event to be sent when a
+ context resource is found.
+
+- Ensures that the user implied by the request passed has the necessary
+ authorization to invoke view callable before calling it.
+
+- causes a :class:`~pyramid.event.NewResponse` event to be sent when the
+ Pyramid application returns a response.
+
+- Calls any :term:`response callback` functions defined within the subrequest's
+ lifetime if a response is obtained from the Pyramid application.
+
+- Calls any :term:`finished callback` functions defined within the subrequest's
+ lifetime.
+
+The invocation of a subrequest has more or less exactly the same effect as
+the invocation of a request received by the Pyramid router from a web client
+when ``use_tweens=True``. When ``use_tweens=False``, the tweens are skipped
+but all the other steps take place.
+
+It's a poor idea to use the original ``request`` object as an argument to
+:meth:`~pyramid.request.Request.invoke_subrequest`. You should construct a
+new request instead as demonstrated in the above example, using
+:meth:`pyramid.request.Request.blank`. Once you've constructed a request
+object, you'll need to massage the it to match the view callable you'd like
+to be executed during the subrequest. This can be done by adjusting the
+subrequest's URL, its headers, its request method, and other attributes. The
+documentation for :class:`pyramid.request.Request` exposes the methods you
+should call and attributes you should set on the request you create to
+massage it into something that will actually match the view you'd like to
+call via a subrequest.
+
+We've demonstrated use of a subrequest from within a view callable, but you
+can use the :meth:`~pyramid.request.Request.invoke_subrequest` API from
+within a tween or an event handler as well. It's usually a poor idea to
+invoke :meth:`~pyramid.request.Request.invoke_subrequest` from within a
+tween, because tweens already by definition have access to a function that
+will cause a subrequest (they are passed a ``handle`` function), but you can
+do it. It's fine to invoke
+:meth:`~pyramid.request.Request.invoke_subrequest` from within an event
+handler, however.
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 656cf4773..ba72ebfbf 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -46,20 +46,6 @@ within the body of a view callable like so:
{'foo':1, 'bar':2},
request=request)
-.. warning::
-
- Earlier iterations of this documentation
- (pre-version-1.3) encouraged the application developer to use
- ZPT-specific APIs such as
- :func:`pyramid.chameleon_zpt.render_template_to_response` and
- :func:`pyramid.chameleon_zpt.render_template` to render templates
- directly. This style of rendering still works, but at least for
- purposes of this documentation, those functions are deprecated.
- Application developers are encouraged instead to use the functions
- available in the :mod:`pyramid.renderers` module to perform
- rendering tasks. This set of functions works to render templates
- for all renderer extensions registered with :app:`Pyramid`.
-
The ``sample_view`` :term:`view callable` function above returns a
:term:`response` object which contains the body of the
``templates/foo.pt`` template. In this case, the ``templates``
@@ -79,12 +65,12 @@ prefix on Windows.
.. warning::
Only :term:`Chameleon` templates support defining a renderer for a
- template relative to the location of the module where the view
- callable is defined. Mako templates, and other templating system
- bindings work differently. In particular, Mako templates use a
- "lookup path" as defined by the ``mako.directories`` configuration
- file instead of treating relative paths as relative to the current
- view module. See :ref:`mako_templates`.
+ template relative to the location of the module where the view callable is
+ defined. Mako templates, and other templating system bindings work
+ differently. In particular, Mako templates use a "lookup path" as defined
+ by the ``mako.directories`` configuration file instead of treating
+ relative paths as relative to the current view module. See
+ :ref:`mako_templates`.
The path can alternately be a :term:`asset specification` in the form
``some.dotted.package_name:relative/path``. This makes it possible to
@@ -542,7 +528,7 @@ Sommetime you'd like to render a macro inside of a Chameleon ZPT template
instead of the full Chameleon ZPT template. To render the content of a
``define-macro`` field inside a Chameleon ZPT template, given a Chameleon
template file named ``foo.pt`` and a macro named ``bar`` defined within it
-(e.g. ``<div metal:define-macro="bar">...</div>``, you can configure the
+(e.g. ``<div metal:define-macro="bar">...</div>``), you can configure the
template as a :term:`renderer` like so:
.. code-block:: python
@@ -554,8 +540,8 @@ template as a :term:`renderer` like so:
def my_view(request):
return {'project':'my project'}
-The above will render the ``bar`` macro from within the ``foo.pt`` template
-instead of the entire template.
+The above will render only the ``bar`` macro defined within the ``foo.pt``
+template instead of the entire template.
.. note::
@@ -600,10 +586,6 @@ When the template is rendered, it will show:
Hello, world!
-If you'd rather use templates directly within a view callable (without
-the indirection of using a renderer), see :ref:`chameleon_text_module`
-for the API description.
-
See also :ref:`built_in_renderers` for more general information about
renderers, including Chameleon text renderers.
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 50e9d5604..20017064b 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -157,6 +157,30 @@ We use a "dummy" request implementation supplied by
:class:`pyramid.testing.DummyRequest` because it's easier to construct
than a "real" :app:`Pyramid` request object.
+Test setup using a context manager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An alternative style of setting up a test configuration is to use the
+`with` statement and :func:`pyramid.testing.testConfig` to create a
+context manager. The context manager will call
+:func:`pyramid.testing.setUp` before the code under test and
+:func:`pyramid.testing.tearDown` afterwards.
+
+This style is useful for small self-contained tests. For example:
+
+.. code-block:: python
+ :linenos:
+
+ import unittest
+
+ class MyTest(unittest.TestCase):
+
+ def test_my_function(self):
+ from pyramid import testing
+ with testing.testConfig() as config:
+ config.add_route('bar', '/bar/{id}')
+ my_function_which_needs_route_bar()
+
What?
~~~~~
diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst
new file mode 100644
index 000000000..839f59c35
--- /dev/null
+++ b/docs/narr/upgrading.rst
@@ -0,0 +1,234 @@
+.. _upgrading_chapter:
+
+Upgrading Pyramid
+=================
+
+When a new version of Pyramid is released, it will sometimes deprecate a
+feature or remove a feature that was deprecated in an older release. When
+features are removed from Pyramid, applications that depend on those features
+will begin to break. This chapter explains how to ensure your Pyramid
+applications keep working when you upgrade the Pyramid version you're using.
+
+.. sidebar:: About Release Numbering
+
+ Conventionally, application version numbering in Python is described as
+ ``major.minor.micro``. If your Pyramid version is "1.2.3", it means
+ you're running a version of Pyramid with the major version "1", the minor
+ version "2" and the micro version "3". A "major" release is one that
+ increments the first-dot number; 2.X.X might follow 1.X.X. A "minor"
+ release is one that increments the second-dot number; 1.3.X might follow
+ 1.2.X. A "micro" release is one that increments the third-dot number;
+ 1.2.3 might follow 1.2.2. In general, micro releases are "bugfix-only",
+ and contain no new features, minor releases contain new features but are
+ largely backwards compatible with older versions, and a major release
+ indicates a large set of backwards incompatibilities.
+
+The Pyramid core team is conservative when it comes to removing features. We
+don't remove features unnecessarily, but we're human, and we make mistakes
+which cause some features to be evolutionary dead ends. Though we are
+willing to support dead-end features for some amount of time, some eventually
+have to be removed when the cost of supporting them outweighs the benefit of
+keeping them around, because each feature in Pyramid represents a certain
+documentation and maintenance burden.
+
+Deprecation and Removal Policy
+------------------------------
+
+When a feature is scheduled for removal from Pyramid or any of its official
+add-ons, the core development team takes these steps:
+
+- Using the feature will begin to generate a `DeprecationWarning`, indicating
+ the version in which the feature became deprecated.
+
+- A note is added to the documentation indicating that the feature is
+ deprecated.
+
+- A note is added to the :ref:`changelog` about the deprecation.
+
+When a deprecated feature is eventually removed:
+
+- The feature is removed.
+
+- A note is added to the :ref:`changelog` about the removal.
+
+Features are never removed in *micro* releases. They are only removed in
+minor and major releases. Deprecated features are kept around for at least
+*three* minor releases from the time the feature became deprecated.
+Therefore, if a feature is added in Pyramid 1.0, but it's deprecated in
+Pyramid 1.1, it will be kept around through all 1.1.X releases, all 1.2.X
+releases and all 1.3.X releases. It will finally be removed in the first
+1.4.X release.
+
+Sometimes features are "docs-deprecated" instead of formally deprecated.
+This means that the feature will be kept around indefinitely, but it will be
+removed from the documentation or a note will be added to the documentation
+telling folks to use some other newer feature. This happens when the cost of
+keeping an old feature around is very minimal and the support and
+documentation burden is very low. For example, we might rename a function
+that is an API without changing the arguments it accepts. In this case,
+we'll often rename the function, and change the docs to point at the new
+function name, but leave around a backwards compatibility alias to the old
+function name so older code doesn't break.
+
+"Docs deprecated" features tend to work "forever", meaning that they won't be
+removed, and they'll never generate a deprecation warning. However, such
+changes are noted in the :ref:`changelog`, so it's possible to know that you
+should change older spellings to newer ones to ensure that people reading
+your code can find the APIs you're using in the Pyramid docs.
+
+Consulting the Change History
+-----------------------------
+
+Your first line of defense against application failures caused by upgrading
+to a newer Pyramid release is always to read the :ref:`changelog`. to find
+the deprecations and removals for each release between the release you're
+currently running and the one you wish to upgrade to. The change history
+notes every deprecation within a ``Deprecation`` section and every removal
+within a ``Backwards Incompatibilies`` section for each release.
+
+The change history often contains instructions for changing your code to
+avoid deprecation warnings and how to change docs-deprecated spellings to
+newer ones. You can follow along with each deprecation explanation in the
+change history, simply doing a grep or other code search to your application,
+using the change log examples to remediate each potential problem.
+
+.. _testing_under_new_release:
+
+Testing Your Application Under a New Pyramid Release
+----------------------------------------------------
+
+Once you've upgraded your application to a new Pyramid release and you've
+remediated as much as possible by using the change history notes, you'll want
+to run your application's tests (see :ref:`running_tests`) in such a way that
+you can see DeprecationWarnings printed to the console when the tests run.
+
+.. code-block:: bash
+
+ $ python -Wd setup.py test -q
+
+The ``-Wd`` argument is an argument that tells Python to print deprecation
+warnings to the console. Note that the ``-Wd`` flag is only required for
+Python 2.7 and better: Python versions 2.6 and older print deprecation
+warnings to the console by default. See `the Python -W flag documentation
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
+information.
+
+As your tests run, deprecation warnings will be printed to the console
+explaining the deprecation and providing instructions about how to prevent
+the deprecation warning from being issued. For example:
+
+.. code-block:: text
+
+ $ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ /home/chrism/projects/pyramid/env27/myproj/myproj/views.py:3:
+ DeprecationWarning: static: The "pyramid.view.static" class is deprecated
+ as of Pyramid 1.1; use the "pyramid.static.static_view" class instead with
+ the "use_subpath" argument set to True.
+ from pyramid.view import static
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
+
+In the above case, it's line #3 in the ``myproj.views`` module (``from
+pyramid.view import static``) that is causing the problem:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ from pyramid.view import static
+ myview = static('static', 'static')
+
+The deprecation warning tells me how to fix it, so I can change the code to
+do things the newer way:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view. import view_config
+
+ from pyramid.static import static_view
+ myview = static_view('static', 'static', use_subpath=True)
+
+When I run the tests again, the deprecation warning is no longer printed to
+my console:
+
+.. code-block:: text
+
+ $ python -Wd setup.py test -q
+ # .. elided ...
+ running build_ext
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 0.014s
+
+ OK
+
+
+My Application Doesn't Have Any Tests or Has Few Tests
+------------------------------------------------------
+
+If your application has no tests, or has only moderate test coverage, running
+tests won't tell you very much, because the Pyramid codepaths that generate
+deprecation warnings won't be executed.
+
+In this circumstance, you can start your application interactively under a
+server run with the ``PYTHONWARNINGS`` environment variable set to
+``default``. On UNIX, you can do that via:
+
+.. code-block:: bash
+
+ $ PYTHONWARNINGS=default bin/pserve development.ini
+
+On Windows, you need to issue two commands:
+
+.. code-block:: bash
+
+ C:\> set PYTHONWARNINGS=default
+ C:\> Scripts/pserve.exe development.ini
+
+At this point, it's ensured that deprecation warnings will be printed to the
+console whenever a codepath is hit that generates one. You can then click
+around in your application interactively to try to generate them, and
+remediate as explained in :ref:`testing_under_new_release`.
+
+See `the PYTHONWARNINGS environment variable documentation
+<http://docs.python.org/using/cmdline.html#envvar-PYTHONWARNINGS>`_ or `the
+Python -W flag documentation
+<http://docs.python.org/using/cmdline.html#cmdoption-W>`_ for more
+information.
+
+Upgrading to the Very Latest Pyramid Release
+--------------------------------------------
+
+When you upgrade your application to the very most recent Pyramid release,
+it's advisable to upgrade step-wise through each most recent minor release,
+beginning with the one that you know your application currently runs under,
+and ending on the most recent release. For example, if your application is
+running in production on Pyramid 1.2.1, and the most recent Pyramid 1.3
+release is Pyramid 1.3.3, and the most recent Pyramid release is 1.4.4, it's
+advisable to do this:
+
+- Upgrade your environment to the most recent 1.2 release. For example, the
+ most recent 1.2 release might be 1.2.3, so upgrade to it. Then run your
+ application's tests under 1.2.3 as described in
+ :ref:`testing_under_new_release`. Note any deprecation warnings and
+ remediate.
+
+- Upgrade to the most recent 1.3 release, 1.3.3. Run your application's
+ tests, note any deprecation warnings and remediate.
+
+- Upgrade to 1.4.4. Run your application's tests, note any deprecation
+ warnings and remediate.
+
+If you skip testing your application under each minor release (for example if
+you upgrade directly from 1.2.1 to 1.4.4), you might miss a deprecation
+warning and waste more time trying to figure out an error caused by a feature
+removal than it would take to upgrade stepwise through each minor release.
+
+
diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst
index 23b4fde68..6373a8d26 100644
--- a/docs/narr/viewconfig.rst
+++ b/docs/narr/viewconfig.rst
@@ -290,12 +290,13 @@ configured view.
of the ``REQUEST_METHOD`` of the :term:`WSGI` environment.
``request_param``
- This value can be any string. A view declaration with this argument
- ensures that the view will only be called when the :term:`request` has a
- key in the ``request.params`` dictionary (an HTTP ``GET`` or ``POST``
- variable) that has a name which matches the supplied value.
+ This value can be any string or a sequence of strings. A view declaration
+ with this argument ensures that the view will only be called when the
+ :term:`request` has a key in the ``request.params`` dictionary (an HTTP
+ ``GET`` or ``POST`` variable) that has a name which matches the a
+ supplied value.
- If the value supplied has a ``=`` sign in it,
+ If any value supplied has a ``=`` sign in it,
e.g. ``request_param="foo=123"``, then the key (``foo``) must both exist
in the ``request.params`` dictionary, *and* the value must match the right
hand side of the expression (``123``) for the view to "match" the current
@@ -394,6 +395,54 @@ configured view.
consideration when deciding whether or not to invoke the associated view
callable.
+``check_csrf``
+ If specified, this value should be one of ``None``, ``True``, ``False``, or
+ a string representing the 'check name'. If the value is ``True`` or a
+ string, CSRF checking will be performed. If the value is ``False`` or
+ ``None``, CSRF checking will not be performed.
+
+ If the value provided is a string, that string will be used as the 'check
+ name'. If the value provided is ``True``, ``csrf_token`` will be used as
+ the check name.
+
+ If CSRF checking is performed, the checked value will be the value of
+ ``request.params[check_name]``. This value will be compared against the
+ value of ``request.session.get_csrf_token()``, and the check will pass if
+ these two values are the same. If the check passes, the associated view
+ will be permitted to execute. If the check fails, the associated view
+ will not be permitted to execute.
+
+ Note that using this feature requires a :term:`session factory` to have
+ been configured.
+
+ .. versionadded:: 1.4a2
+
+``physical_path``
+ If specified, this value should be a string or a tuple representing the
+ :term:`physical path` of the context found via traversal for this predicate
+ to match as true. For example: ``physical_path='/'`` or
+ ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``. This is
+ not a path prefix match or a regex, it's a whole-path match. It's useful
+ when you want to always potentially show a view when some object is traversed
+ to, but you can't be sure about what kind of object it will be, so you can't
+ use the ``context`` predicate. The individual path elements inbetween slash
+ characters or in tuple elements should be the Unicode representation of the
+ name of the resource and should not be encoded in any way.
+
+ .. versionadded:: 1.4a3
+
+``effective_principals``
+
+ If specified, this value should be a :term:`principal` identifier or a
+ sequence of principal identifiers. If the
+ :func:`pyramid.security.effective_principals` method indicates that every
+ principal named in the argument list is present in the current request, this
+ predicate will return True; otherwise it will return False. For example:
+ ``effective_principals=pyramid.security.Authenticated`` or
+ ``effective_principals=('fred', 'group:admins')``.
+
+ .. versionadded:: 1.4a4
+
``custom_predicates``
If ``custom_predicates`` is specified, it must be a sequence of references
to custom predicate callables. Use custom predicates when no set of
@@ -407,6 +456,15 @@ configured view.
If ``custom_predicates`` is not specified, no custom predicates are
used.
+``predicates``
+ Pass a key/value pair here to use a third-party predicate registered via
+ :meth:`pyramid.config.Configurator.add_view_predicate`. More than one
+ key/value pair can be used at the same time. See
+ :ref:`view_and_route_predicates` for more information about third-party
+ predicates.
+
+ .. versionadded:: 1.4a1
+
.. index::
single: view_config decorator
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index 9e41464a6..07d018127 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -338,6 +338,16 @@ exception views which have a name will be ignored.
Exception views can be configured with any view registration mechanism:
``@view_config`` decorator or imperative ``add_view`` styles.
+.. note::
+
+ Pyramid's :term:`exception view` handling logic is implemented as a tween
+ factory function: :func:`pyramid.tweens.excview_tween_factory`. If
+ Pyramid exception view handling is desired, and tween factories are
+ specified via the ``pyramid.tweens`` configuration setting, the
+ :func:`pyramid.tweens.excview_tween_factory` function must be added to the
+ ``pyramid.tweens`` configuration setting list explicitly. If it is not
+ present, Pyramid will not perform exception view handling.
+
.. index::
single: view http redirect
single: http redirect (from a view)
diff --git a/docs/remake b/docs/remake
index b236f2976..eb818289f 100755
--- a/docs/remake
+++ b/docs/remake
@@ -1 +1 @@
-make clean html SPHINXBUILD=../env26/bin/sphinx-build
+make clean html SPHINXBUILD=../env27/bin/sphinx-build
diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst
index d11167344..a22f12610 100644
--- a/docs/tutorials/modwsgi/index.rst
+++ b/docs/tutorials/modwsgi/index.rst
@@ -7,12 +7,11 @@ Running a :app:`Pyramid` Application under ``mod_wsgi``
It allows :term:`WSGI` programs to be served using the Apache web
server.
-This guide will outline broad steps that can be used to get a
-:app:`Pyramid` application running under Apache via ``mod_wsgi``.
-This particular tutorial was developed under Apple's Mac OS X platform
-(Snow Leopard, on a 32-bit Mac), but the instructions should be
-largely the same for all systems, delta specific path information for
-commands and files.
+This guide will outline broad steps that can be used to get a :app:`Pyramid`
+application running under Apache via ``mod_wsgi``. This particular tutorial
+was developed under Apple's Mac OS X platform (Snow Leopard, on a 32-bit
+Mac), but the instructions should be largely the same for all systems, delta
+specific path information for commands and files.
.. note:: Unfortunately these instructions almost certainly won't work for
deploying a :app:`Pyramid` application on a Windows system using
@@ -90,12 +89,11 @@ commands and files.
`logging` module to allow logging within your application.
See :ref:`logging_config`.
-#. Make the ``pyramid.wsgi`` script executable.
-
- .. code-block:: text
-
- $ cd ~/modwsgi/env
- $ chmod 755 pyramid.wsgi
+ There is no need to make the ``pyramid.wsgi`` script executable.
+ However, you'll need to make sure that *two* users have access to change
+ into the ``~/modwsgi/env`` directory: your current user (mine is
+ ``chrism`` and the user that Apache will run as often named ``apache`` or
+ ``httpd``). Make sure both of these users can "cd" into that directory.
#. Edit your Apache configuration and add some stuff. I happened to
create a file named ``/etc/apache2/other/modwsgi.conf`` on my own
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css b/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py
index 21f12b31d..50485d279 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py
@@ -51,17 +51,17 @@ def view_page(context, request):
renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url,
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css b/docs/tutorials/wiki/src/models/tutorial/static/pylons.css
index 7e6ec739d..4b1c017cd 100644
--- a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/models/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.top-snall,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki/src/tests/tutorial/static/pylons.css b/docs/tutorials/wiki/src/tests/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/tests/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki/src/tests/tutorial/views.py b/docs/tutorials/wiki/src/tests/tutorial/views.py
index 21f12b31d..50485d279 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/views.py
@@ -51,17 +51,17 @@ def view_page(context, request):
renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url,
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/pylons.css b/docs/tutorials/wiki/src/views/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki/src/views/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/views/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py
index 016f5b6bb..b0c15297f 100644
--- a/docs/tutorials/wiki/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki/src/views/tutorial/views.py
@@ -35,17 +35,17 @@ def view_page(context, request):
@view_config(name='add_page', context='.models.Wiki',
renderer='templates/edit.pt')
def add_page(context, request):
- name = request.subpath[0]
+ pagename = request.subpath[0]
if 'form.submitted' in request.params:
body = request.params['body']
page = Page(body)
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
- context[name] = page
+ context[pagename] = page
return HTTPFound(location = request.resource_url(page))
- save_url = request.resource_url(context, 'add_page', name)
+ save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
- page.__name__ = name
+ page.__name__ = pagename
page.__parent__ = context
return dict(page = page, save_url = save_url)
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index d7bd24a53..6b2d44410 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -112,7 +112,7 @@ parameter to our :term:`Configurator` constructor, that points to
the class we created above:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 19-20
+ :lines: 23-24
:linenos:
:emphasize-lines: 2
:language: python
@@ -144,7 +144,7 @@ add these import statements:
Now add those policies to the configuration:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 16-22
+ :lines: 20-26
:linenos:
:emphasize-lines: 1-3,6-7
:language: python
@@ -206,7 +206,7 @@ Go back to ``tutorial/tutorial/__init__.py`` and add these two
routes:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 25-26
+ :lines: 29-30
:linenos:
:language: python
@@ -333,7 +333,7 @@ when we're done:
.. literalinclude:: src/authorization/tutorial/__init__.py
:linenos:
- :emphasize-lines: 2-3,7,16-18,20-22,25-26
+ :emphasize-lines: 2-3,7,23-24,20-26,29-30
:language: python
(Only the highlighted lines need to be added.)
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index b3184c4fc..dbd130c36 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -51,21 +51,33 @@ The main function first creates a SQLAlchemy database engine using
(something like ``sqlite://``):
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 9
+ :lines: 12
:linenos:
:language: py
-``main`` then initializes our SQL database using SQLAlchemy, passing it the
+``main`` then initializes our SQLAlchemy session object, passing it the
engine:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 10
+ :lines: 13
+ :language: py
+
+``main`` subsequently initializes our SQLAlchemy declarative Base object,
+assigning the engine we created to the ``bind`` attribute of it's
+``metadata`` object. This allows table definitions done imperatively
+(instead of declaratively, via a class statement) to work. We won't use any
+such tables in our application, but if you add one later, long after you've
+forgotten about this tutorial, you won't be left scratching your head when it
+doesn't work.
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 14
:language: py
The next step of ``main`` is to construct a :term:`Configurator` object:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 11
+ :lines: 15
:language: py
``settings`` is passed to the Configurator as a keyword argument with the
@@ -78,7 +90,7 @@ deployment-related values such as ``pyramid.reload_templates``,
two arguments: ``static`` (the name), and ``static`` (the path):
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 12
+ :lines: 16
:language: py
This registers a static resource view which will match any URL that starts
@@ -96,7 +108,7 @@ via the :meth:`pyramid.config.Configurator.add_route` method that will be
used when the URL is ``/``:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 13
+ :lines: 17
:language: py
Since this route has a ``pattern`` equalling ``/`` it is the route that will
@@ -109,7 +121,7 @@ view configuration will be registered, which will allow one of our
application URLs to be mapped to some code.
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 14
+ :lines: 18
:language: py
Finally, ``main`` is finished configuring things, so it uses the
@@ -117,7 +129,7 @@ Finally, ``main`` is finished configuring things, so it uses the
:term:`WSGI` application:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 15
+ :lines: 19
:language: py
View Declarations via ``views.py``
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index 24ac4338d..a54996e3c 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -342,7 +342,7 @@ something like:
.. literalinclude:: src/views/tutorial/__init__.py
:linenos:
:language: python
- :emphasize-lines: 13-16
+ :emphasize-lines: 17-20
(The highlighted lines are the ones that need to be added or edited.)
diff --git a/docs/tutorials/wiki2/design.rst b/docs/tutorials/wiki2/design.rst
index deaf32ef6..6e41e00aa 100644
--- a/docs/tutorials/wiki2/design.rst
+++ b/docs/tutorials/wiki2/design.rst
@@ -115,7 +115,8 @@ listed in the following table:
| | redirect to | | | |
| | /PageName | | | |
+----------------------+-----------------------+-------------+------------+------------+
-| /login | Display login form. | login | login.pt | |
+| /login | Display login form, | login | login.pt | |
+| | Forbidden [3]_ | | | |
| | | | | |
| | If the form was | | | |
| | submitted, | | | |
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
index 7e290a1e1..8922a3cc0 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
@@ -6,13 +6,17 @@ from sqlalchemy import engine_from_config
from tutorial.security import groupfinder
-from .models import DBSession
+from .models import (
+ DBSession,
+ Base,
+ )
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
+ Base.metadata.bind = engine
authn_policy = AuthTktAuthenticationPolicy(
'sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views.py b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
index c7670b049..0d085b0e2 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
@@ -60,14 +60,14 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt',
permission='edit')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url,
logged_in=authenticated_userid(request))
@@ -75,16 +75,16 @@ def add_page(request):
@view_config(route_name='edit_page', renderer='templates/edit.pt',
permission='edit')
def edit_page(request):
- name = request.matchdict['pagename']
- page = DBSession.query(Page).filter_by(name=name).one()
+ pagename = request.matchdict['pagename']
+ page = DBSession.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
logged_in=authenticated_userid(request),
)
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
index 253341563..e39f619ed 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
@@ -1,13 +1,17 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from .models import DBSession
+from .models import (
+ DBSession,
+ Base,
+ )
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
+ Base.metadata.bind = engine
config = Configurator(settings=settings)
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
index 253341563..e39f619ed 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
@@ -1,13 +1,17 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from .models import DBSession
+from .models import (
+ DBSession,
+ Base,
+ )
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
+ Base.metadata.bind = engine
config = Configurator(settings=settings)
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
index 7e290a1e1..8922a3cc0 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
@@ -6,13 +6,17 @@ from sqlalchemy import engine_from_config
from tutorial.security import groupfinder
-from .models import DBSession
+from .models import (
+ DBSession,
+ Base,
+ )
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
+ Base.metadata.bind = engine
authn_policy = AuthTktAuthenticationPolicy(
'sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/tests/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views.py b/docs/tutorials/wiki2/src/tests/tutorial/views.py
index f2a33af1e..42ac0eb7f 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/views.py
@@ -61,15 +61,15 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt',
permission='edit')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
session = DBSession()
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
session.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url,
logged_in=authenticated_userid(request))
@@ -77,17 +77,17 @@ def add_page(request):
@view_config(route_name='edit_page', renderer='templates/edit.pt',
permission='edit')
def edit_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
session = DBSession()
- page = session.query(Page).filter_by(name=name).one()
+ page = session.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
session.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
logged_in=authenticated_userid(request),
)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
index b30d593cf..810e92f75 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
@@ -1,13 +1,17 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from .models import DBSession
+from .models import (
+ DBSession,
+ Base,
+ )
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
+ Base.metadata.bind = engine
config = Configurator(settings=settings)
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css
index c54499ddd..4b1c017cd 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css
@@ -1,65 +1,372 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-:focus{outline:0;}
-ins{text-decoration:none;}
-del{text-decoration:line-through;}
-table{border-collapse:collapse;border-spacing:0;}
-sub{vertical-align:sub;font-size:smaller;line-height:normal;}
-sup{vertical-align:super;font-size:smaller;line-height:normal;}
-ul,menu,dir{display:block;list-style-type:disc;margin:1em 0;padding-left:40px;}
-ol{display:block;list-style-type:decimal-leading-zero;margin:1em 0;padding-left:40px;}
-li{display:list-item;}
-ul ul,ul ol,ul dir,ul menu,ul dl,ol ul,ol ol,ol dir,ol menu,ol dl,dir ul,dir ol,dir dir,dir menu,dir dl,menu ul,menu ol,menu dir,menu menu,menu dl,dl ul,dl ol,dl dir,dl menu,dl dl{margin-top:0;margin-bottom:0;}
-ol ul,ul ul,menu ul,dir ul,ol menu,ul menu,menu menu,dir menu,ol dir,ul dir,menu dir,dir dir{list-style-type:circle;}
-ol ol ul,ol ul ul,ol menu ul,ol dir ul,ol ol menu,ol ul menu,ol menu menu,ol dir menu,ol ol dir,ol ul dir,ol menu dir,ol dir dir,ul ol ul,ul ul ul,ul menu ul,ul dir ul,ul ol menu,ul ul menu,ul menu menu,ul dir menu,ul ol dir,ul ul dir,ul menu dir,ul dir dir,menu ol ul,menu ul ul,menu menu ul,menu dir ul,menu ol menu,menu ul menu,menu menu menu,menu dir menu,menu ol dir,menu ul dir,menu menu dir,menu dir dir,dir ol ul,dir ul ul,dir menu ul,dir dir ul,dir ol menu,dir ul menu,dir menu menu,dir dir menu,dir ol dir,dir ul dir,dir menu dir,dir dir dir{list-style-type:square;}
-.hidden{display:none;}
-p{line-height:1.5em;}
-h1{font-size:1.75em;line-height:1.7em;font-family:helvetica,verdana;}
-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 "NobileRegular","Lucida Grande",Lucida,Verdana,sans-serif;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-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,#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,.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;}
-.bottom{padding-top:50px;}
-#left{width:350px;float:left;padding-right:25px;}
-#right{width:350px;float:right;padding-left:25px;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-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],input[type=password]{width:205px;}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%; /* 16px */
+ vertical-align: baseline;
+ background: transparent;
+}
+
+body
+{
+ line-height: 1;
+}
+
+ol, ul
+{
+ list-style: none;
+}
+
+blockquote, q
+{
+ quotes: none;
+}
+
+blockquote:before, blockquote:after, q:before, q:after
+{
+ content: '';
+ content: none;
+}
+
+:focus
+{
+ outline: 0;
+}
+
+ins
+{
+ text-decoration: none;
+}
+
+del
+{
+ text-decoration: line-through;
+}
+
+table
+{
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+sub
+{
+ vertical-align: sub;
+ font-size: smaller;
+ line-height: normal;
+}
+
+sup
+{
+ vertical-align: super;
+ font-size: smaller;
+ line-height: normal;
+}
+
+ul, menu, dir
+{
+ display: block;
+ list-style-type: disc;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+ol
+{
+ display: block;
+ list-style-type: decimal-leading-zero;
+ margin: 1em 0;
+ padding-left: 40px;
+}
+
+li
+{
+ display: list-item;
+}
+
+ul ul, ul ol, ul dir, ul menu, ul dl, ol ul, ol ol, ol dir, ol menu, ol dl, dir ul, dir ol, dir dir, dir menu, dir dl, menu ul, menu ol, menu dir, menu menu, menu dl, dl ul, dl ol, dl dir, dl menu, dl dl
+{
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ul, ul ul, menu ul, dir ul, ol menu, ul menu, menu menu, dir menu, ol dir, ul dir, menu dir, dir dir
+{
+ list-style-type: circle;
+}
+
+ol ol ul, ol ul ul, ol menu ul, ol dir ul, ol ol menu, ol ul menu, ol menu menu, ol dir menu, ol ol dir, ol ul dir, ol menu dir, ol dir dir, ul ol ul, ul ul ul, ul menu ul, ul dir ul, ul ol menu, ul ul menu, ul menu menu, ul dir menu, ul ol dir, ul ul dir, ul menu dir, ul dir dir, menu ol ul, menu ul ul, menu menu ul, menu dir ul, menu ol menu, menu ul menu, menu menu menu, menu dir menu, menu ol dir, menu ul dir, menu menu dir, menu dir dir, dir ol ul, dir ul ul, dir menu ul, dir dir ul, dir ol menu, dir ul menu, dir menu menu, dir dir menu, dir ol dir, dir ul dir, dir menu dir, dir dir dir
+{
+ list-style-type: square;
+}
+
+.hidden
+{
+ display: none;
+}
+
+p
+{
+ line-height: 1.5em;
+}
+
+h1
+{
+ font-size: 1.75em;
+ line-height: 1.7em;
+ font-family: helvetica, verdana;
+}
+
+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: #fff;
+ 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, body h2, body h3, body h4, body h5, body h6
+{
+ font-family: NeutonRegular, "Lucida Grande", Lucida, Verdana, sans-serif;
+ font-weight: 400;
+ color: #373839;
+ font-style: normal;
+}
+
+#wrap
+{
+ min-height: 100%;
+}
+
+#header, #footer
+{
+ width: 100%;
+ color: #fff;
+ height: 40px;
+ position: absolute;
+ text-align: center;
+ line-height: 40px;
+ overflow: hidden;
+ font-size: 12px;
+ vertical-align: middle;
+}
+
+#header
+{
+ background: #000;
+ top: 0;
+ font-size: 14px;
+}
+
+#footer
+{
+ bottom: 0;
+ background: #000 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, #top-small, #bottom
+{
+ width: 100%;
+}
+
+#top
+{
+ color: #000;
+ height: 230px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#top-small
+{
+ color: #000;
+ height: 60px;
+ background: #fff url(headerbg.png) repeat-x 0 top;
+ position: relative;
+}
+
+#bottom
+{
+ color: #222;
+ background-color: #fff;
+}
+
+.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 #fff;
+ border-bottom: 2px solid #b2b2b2;
+}
+
+.app-welcome
+{
+ margin-top: 25px;
+}
+
+.app-name
+{
+ color: #000;
+ font-weight: 700;
+}
+
+.bottom
+{
+ padding-top: 50px;
+}
+
+#left
+{
+ width: 350px;
+ float: left;
+ padding-right: 25px;
+}
+
+#right
+{
+ width: 350px;
+ float: right;
+ padding-left: 25px;
+}
+
+.align-left
+{
+ text-align: left;
+}
+
+.align-right
+{
+ text-align: right;
+}
+
+.align-center
+{
+ text-align: center;
+}
+
+ul.links
+{
+ margin: 0;
+ padding: 0;
+}
+
+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], input[type=password]
+{
+ width: 205px;
+}
+
+input[type=submit]
+{
+ background-color: #ddd;
+ font-weight: 700;
+}
+
/*Opera Fix*/
-body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before
+{
+ content: "";
+ height: 100%;
+ float: left;
+ width: 0;
+ margin-top: -32767px;
+}
diff --git a/docs/tutorials/wiki2/src/views/tutorial/views.py b/docs/tutorials/wiki2/src/views/tutorial/views.py
index c2a94a96b..5a9c75a61 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/views.py
@@ -44,27 +44,27 @@ def view_page(request):
@view_config(route_name='add_page', renderer='templates/edit.pt')
def add_page(request):
- name = request.matchdict['pagename']
+ pagename = request.matchdict['pagename']
if 'form.submitted' in request.params:
body = request.params['body']
- page = Page(name, body)
+ page = Page(pagename, body)
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
- save_url = request.route_url('add_page', pagename=name)
+ pagename=pagename))
+ save_url = request.route_url('add_page', pagename=pagename)
page = Page('', '')
return dict(page=page, save_url=save_url)
@view_config(route_name='edit_page', renderer='templates/edit.pt')
def edit_page(request):
- name = request.matchdict['pagename']
- page = DBSession.query(Page).filter_by(name=name).one()
+ pagename = request.matchdict['pagename']
+ page = DBSession.query(Page).filter_by(name=pagename).one()
if 'form.submitted' in request.params:
page.data = request.params['body']
DBSession.add(page)
return HTTPFound(location = request.route_url('view_page',
- pagename=name))
+ pagename=pagename))
return dict(
page=page,
- save_url = request.route_url('edit_page', pagename=name),
+ save_url = request.route_url('edit_page', pagename=pagename),
)
diff --git a/docs/whatsnew-1.4.rst b/docs/whatsnew-1.4.rst
new file mode 100644
index 000000000..59e1f7a96
--- /dev/null
+++ b/docs/whatsnew-1.4.rst
@@ -0,0 +1,310 @@
+What's New In Pyramid 1.4
+=========================
+
+This article explains the new features in :app:`Pyramid` version 1.4 as
+compared to its predecessor, :app:`Pyramid` 1.3. It also documents backwards
+incompatibilities between the two versions and deprecations added to
+:app:`Pyramid` 1.4, as well as software dependency changes and notable
+documentation additions.
+
+Major Feature Additions
+-----------------------
+
+The major feature additions in Pyramid 1.4 follow.
+
+Third-Party Predicates
+~~~~~~~~~~~~~~~~~~~~~~~
+
+- Third-party custom view, route, and subscriber predicates can now be added
+ for use by view authors via
+ :meth:`pyramid.config.Configurator.add_view_predicate`,
+ :meth:`pyramid.config.Configurator.add_route_predicate` and
+ :meth:`pyramid.config.Configurator.add_subscriber_predicate`. So, for
+ example, doing this::
+
+ config.add_view_predicate('abc', my.package.ABCPredicate)
+
+ Might allow a view author to do this in an application that configured that
+ predicate::
+
+ @view_config(abc=1)
+
+ Similar features exist for :meth:`pyramid.config.Configurator.add_route`,
+ and :meth:`pyramid.config.Configurator.add_subscriber`. See
+ :ref:`registering_thirdparty_predicates` for more information.
+
+Easy Custom JSON Serialization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Views can now return custom objects which will be serialized to JSON by a
+ JSON renderer by defining a ``__json__`` method on the object's class. This
+ method should return values natively serializable by ``json.dumps`` (such
+ as ints, lists, dictionaries, strings, and so forth). See
+ :ref:`json_serializing_custom_objects` for more information. The JSON
+ renderer now also allows for the definition of custom type adapters to
+ convert unknown objects to JSON serializations, in case you can't add a
+ ``__json__`` method to returned objects.
+
+Partial Mako and Chameleon Template Renderings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- The Mako renderer now supports using a def name in an asset spec. When the
+ def name is present in the asset spec, the system will render the template
+ named def within the template instead of rendering the entire template. An
+ example asset spec which names a def is
+ ``package:path/to/template#defname.mako``. This will render the def named
+ ``defname`` inside the ``template.mako`` template instead of rendering the
+ entire template. The old way of returning a tuple in the form
+ ``('defname', {})`` from the view is supported for backward compatibility.
+
+- The Chameleon ZPT renderer now supports using a macro name in an asset
+ spec. When the macro name is present in the asset spec, the system will
+ render the macro listed as a ``define-macro`` and return the result instead
+ of rendering the entire template. An example asset spec:
+ ``package:path/to/template#macroname.pt``. This will render the macro
+ defined as ``macroname`` within the ``template.pt`` template instead of the
+ entire template.
+
+Subrequest Support
+~~~~~~~~~~~~~~~~~~
+
+- Developers may invoke a subrequest by using the
+ :meth:`pyramid.request.Request.invoke_subrequest` API. This allows a
+ developer to obtain a response from one view callable by issuing a subrequest
+ from within a different view callable. See :ref:`subrequest_chapter` for
+ more information.
+
+Minor Feature Additions
+-----------------------
+
+- :meth:`pyramid.config.Configurator.add_directive` now accepts arbitrary
+ callables like partials or objects implementing ``__call__`` which don't
+ have ``__name__`` and ``__doc__`` attributes. See
+ https://github.com/Pylons/pyramid/issues/621 and
+ https://github.com/Pylons/pyramid/pull/647.
+
+- As of this release, the ``request_method`` view/route predicate, when used,
+ will also imply that ``HEAD`` is implied when you use ``GET``. For
+ example, using ``@view_config(request_method='GET')`` is equivalent to
+ using ``@view_config(request_method=('GET', 'HEAD'))``. Using
+ ``@view_config(request_method=('GET', 'POST')`` is equivalent to using
+ ``@view_config(request_method=('GET', 'HEAD', 'POST')``. This is because
+ HEAD is a variant of GET that omits the body, and WebOb has special support
+ to return an empty body when a HEAD is used.
+
+- :meth:`pyramid.config.Configurator.add_request_method` has been introduced
+ to support extending request objects with arbitrary callables. This method
+ expands on the now documentation-deprecated
+ :meth:`pyramid.config.Configurator.set_request_property` by supporting
+ methods as well as properties. This method also causes less code to be
+ executed at request construction time than
+ :meth:`~pyramid.config.Configurator.set_request_property`.
+
+- The static view machinery now raises rather than returns
+ :class:`pyramid.httpexceptions.HTTPNotFound` and
+ :class:`pyramid.httpexceptions.HTTPMovedPermanently` exceptions, so these can
+ be caught by the notfound view (and other exception views).
+
+- When there is a predicate mismatch exception (seen when no view matches for
+ a given request due to predicates not working), the exception now contains
+ a textual description of the predicate which didn't match.
+
+- An :meth:`pyramid.config.Configurator.add_permission` directive method was
+ added to the Configurator. This directive registers a free-standing
+ permission introspectable into the Pyramid introspection system.
+ Frameworks built atop Pyramid can thus use the ``permissions``
+ introspectable category data to build a comprehensive list of permissions
+ supported by a running system. Before this method was added, permissions
+ were already registered in this introspectable category as a side effect of
+ naming them in an :meth:`pyramid.config.Configurator.add_view` call, this
+ method just makes it possible to arrange for a permission to be put into
+ the ``permissions`` introspectable category without naming it along with an
+ associated view. Here's an example of usage of ``add_permission``::
+
+ config = Configurator()
+ config.add_permission('view')
+
+- The :func:`pyramid.session.UnencryptedCookieSessionFactoryConfig` function
+ now accepts ``signed_serialize`` and ``signed_deserialize`` hooks which may
+ be used to influence how the sessions are marshalled (by default this is
+ done with HMAC+pickle).
+
+- :class:`pyramid.testing.DummyRequest` now supports methods supplied by the
+ ``pyramid.util.InstancePropertyMixin`` class such as ``set_property``.
+
+- Request properties and methods added via
+ :meth:`pyramid.config.Configurator.add_request_method` or
+ :meth:`pyramid.config.Configurator.set_request_property` are now available to
+ tweens.
+
+- Request properties and methods added via
+ :meth:`pyramid.config.Configurator.add_request_method` or
+ :meth:`pyramid.config.Configurator.set_request_property` are now available
+ in the request object returned from :func:`pyramid.paster.bootstrap`.
+
+- ``request.context`` of environment request during
+ :func:`pyramid.paster.bootstrap` is now the root object if a context isn't
+ already set on a provided request.
+
+- :class:`pyramid.decorator.reify` is now an API, and was added to
+ the API documentation.
+
+- Added the :func:`pyramid.testing.testConfig` context manager, which can be
+ used to generate a configurator in a test, e.g. ``with
+ testing.testConfig(...):``.
+
+- A new :func:`pyramid.session.check_csrf_token` convenience API function was
+ added.
+
+- A ``check_csrf`` view predicate was added. For example, you can now do
+ ``config.add_view(someview, check_csrf=True)``. When the predicate is
+ checked, if the ``csrf_token`` value in ``request.params`` matches the csrf
+ token in the request's session, the view will be permitted to execute.
+ Otherwise, it will not be permitted to execute.
+
+- Add ``Base.metadata.bind = engine`` to ``alchemy`` scaffold, so that tables
+ defined imperatively will work.
+
+- Comments with references to documentation sections placed in scaffold
+ ``.ini`` files.
+
+- Allow multiple values to be specified to the ``request_param`` view/route
+ predicate as a sequence. Previously only a single string value was allowed.
+ See https://github.com/Pylons/pyramid/pull/705
+
+- Added an HTTP Basic authentication policy
+ at :class:`pyramid.authentication.BasicAuthAuthenticationPolicy`.
+
+- The :meth:`pyramid.config.Configurator.testing_securitypolicy` method now
+ returns the policy object it creates.
+
+- The DummySecurityPolicy created by
+ :meth:`pyramid.config.testing_securitypolicy` now sets a ``forgotten`` value
+ on the policy (the value ``True``) when its ``forget`` method is called.
+
+
+- The DummySecurityPolicy created by
+ :meth:`pyramid.config.testing_securitypolicy` now sets a
+ ``remembered`` value on the policy, which is the value of the ``principal``
+ argument it's called with when its ``remember`` method is called.
+
+- New ``physical_path`` view predicate. If specified, this value should be a
+ string or a tuple representing the physical traversal path of the context
+ found via traversal for this predicate to match as true. For example:
+ ``physical_path='/'`` or ``physical_path='/a/b/c'`` or ``physical_path=('',
+ 'a', 'b', 'c')``. It's useful when you want to always potentially show a
+ view when some object is traversed to, but you can't be sure about what kind
+ of object it will be, so you can't use the ``context`` predicate.
+
+Backwards Incompatibilities
+---------------------------
+
+- The Pyramid router no longer adds the values ``bfg.routes.route`` or
+ ``bfg.routes.matchdict`` to the request's WSGI environment dictionary.
+ These values were docs-deprecated in ``repoze.bfg`` 1.0 (effectively seven
+ minor releases ago). If your code depended on these values, use
+ ``request.matched_route`` and ``request.matchdict`` instead.
+
+- It is no longer possible to pass an environ dictionary directly to
+ ``pyramid.traversal.ResourceTreeTraverser.__call__`` (aka
+ ``ModelGraphTraverser.__call__``). Instead, you must pass a request
+ object. Passing an environment instead of a request has generated a
+ deprecation warning since Pyramid 1.1.
+
+- Pyramid will no longer work properly if you use the
+ ``webob.request.LegacyRequest`` as a request factory. Instances of the
+ LegacyRequest class have a ``request.path_info`` which return a string.
+ This Pyramid release assumes that ``request.path_info`` will
+ unconditionally be Unicode.
+
+- The functions from ``pyramid.chameleon_zpt`` and ``pyramid.chameleon_text``
+ named ``get_renderer``, ``get_template``, ``render_template``, and
+ ``render_template_to_response`` have been removed. These have issued a
+ deprecation warning upon import since Pyramid 1.0. Use
+ :func:`pyramid.renderers.get_renderer`,
+ ``pyramid.renderers.get_renderer().implementation()``,
+ :func:`pyramid.renderers.render` or
+ :func:`pyramid.renderers.render_to_response` respectively instead of these
+ functions.
+
+- The ``pyramid.configuration`` module was removed. It had been deprecated
+ since Pyramid 1.0 and printed a deprecation warning upon its use. Use
+ :mod:`pyramid.config` instead.
+
+- The ``pyramid.paster.PyramidTemplate`` API was removed. It had been
+ deprecated since Pyramid 1.1 and issued a warning on import. If your code
+ depended on this, adjust your code to import
+ :class:`pyramid.scaffolds.PyramidTemplate` instead.
+
+- The ``pyramid.settings.get_settings()`` API was removed. It had been
+ printing a deprecation warning since Pyramid 1.0. If your code depended on
+ this API, use ``pyramid.threadlocal.get_current_registry().settings``
+ instead or use the ``settings`` attribute of the registry available from
+ the request (``request.registry.settings``).
+
+- These APIs from the ``pyramid.testing`` module were removed. They have
+ been printing deprecation warnings since Pyramid 1.0:
+
+ * ``registerDummySecurityPolicy``, use
+ :meth:`pyramid.config.Configurator.testing_securitypolicy` instead.
+
+ * ``registerResources`` (aka ``registerModels``), use
+ :meth:`pyramid.config.Configurator.testing_resources` instead.
+
+ * ``registerEventListener``, use
+ :meth:`pyramid.config.Configurator.testing_add_subscriber` instead.
+
+ * ``registerTemplateRenderer`` (aka ``registerDummyRenderer``), use
+ :meth:`pyramid.config.Configurator.testing_add_template` instead.
+
+ * ``registerView``, use :meth:`pyramid.config.Configurator.add_view` instead.
+
+ * ``registerUtility``, use
+ :meth:`pyramid.config.Configurator.registry.registerUtility` instead.
+
+ * ``registerAdapter``, use
+ :meth:`pyramid.config.Configurator.registry.registerAdapter` instead.
+
+ * ``registerSubscriber``, use
+ :meth:`pyramid.config.Configurator.add_subscriber` instead.
+
+ * ``registerRoute``, use
+ :meth:`pyramid.config.Configurator.add_route` instead.
+
+ * ``registerSettings``, use
+ :meth:`pyramid.config.Configurator.add_settings` instead.
+
+- In Pyramid 1.3 and previous, the ``__call__`` method of a Response object
+ returned by a view was invoked before any finished callbacks were executed.
+ As of this release, the ``__call__`` method of a Response object is invoked
+ *after* finished callbacks are executed. This is in support of the
+ :meth:`pyramid.request.Request.invoke_subrequest` feature.
+
+Deprecations
+------------
+
+- The :meth:`pyramid.config.Configurator.set_request_property` directive has
+ been documentation-deprecated. The method remains usable but the more
+ featureful :meth:`pyramid.config.Configurator.add_request_method` should be
+ used in its place (it has all of the same capabilities but can also extend
+ the request object with methods).
+
+Documentation Enhancements
+--------------------------
+
+- Added an :ref:`upgrading_chapter` chapter to the narrative documentation.
+ It describes how to cope with deprecations and removals of Pyramid APIs and
+ how to show Pyramid-generated deprecation warnings while running tests and
+ while running a server.
+
+- Added a :ref:`subrequest_chapter` chapter to the narrative documentation.
+
+- Many cleanups and improvements to narrative and API docs.
+
+Dependency Changes
+------------------
+
+- Pyramid now requires WebOb 1.2b3+ (the prior Pyramid release only relied on
+ 1.2dev+). This is to ensure that we obtain a version of WebOb that returns
+ ``request.path_info`` as text.
+