summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile2
-rw-r--r--docs/api.rst1
-rw-r--r--docs/api/authentication.rst10
-rw-r--r--docs/api/config.rst6
-rw-r--r--docs/api/interfaces.rst4
-rw-r--r--docs/api/router.rst8
-rw-r--r--docs/api/security.rst2
-rw-r--r--docs/api/url.rst2
-rw-r--r--docs/authorintro.rst25
-rw-r--r--docs/conf.py17
-rw-r--r--docs/conventions.rst2
-rw-r--r--docs/copyright.rst21
-rw-r--r--docs/designdefense.rst373
-rw-r--r--docs/glossary.rst114
-rw-r--r--docs/index.rst18
-rw-r--r--docs/latexindex.rst39
-rw-r--r--docs/narr/MyProject/myproject/templates/mytemplate.pt172
-rw-r--r--docs/narr/MyProject/myproject/tests.py6
-rw-r--r--docs/narr/advconfig.rst34
-rw-r--r--docs/narr/assets.rst6
-rw-r--r--docs/narr/configuration.rst8
-rw-r--r--docs/narr/csrf.rst63
-rw-r--r--docs/narr/declarative.rst1436
-rw-r--r--docs/narr/environment.rst17
-rw-r--r--docs/narr/events.rst65
-rw-r--r--docs/narr/extending.rst16
-rw-r--r--docs/narr/firstapp.rst6
-rw-r--r--docs/narr/flash.rst107
-rw-r--r--docs/narr/forms.rst126
-rw-r--r--docs/narr/hooks.rst125
-rw-r--r--docs/narr/i18n.rst15
-rw-r--r--docs/narr/install.rst2
-rw-r--r--docs/narr/introduction.rst4
-rw-r--r--docs/narr/muchadoabouttraversal.rst311
-rw-r--r--docs/narr/project.rst61
-rw-r--r--docs/narr/renderers.rst72
-rw-r--r--docs/narr/resourcelocation.rst103
-rw-r--r--docs/narr/resources.rst46
-rw-r--r--docs/narr/router.rst4
-rw-r--r--docs/narr/security.rst37
-rw-r--r--docs/narr/sessions.rst190
-rw-r--r--docs/narr/templates.rst6
-rw-r--r--docs/narr/testing.rst154
-rw-r--r--docs/narr/threadlocals.rst4
-rw-r--r--docs/narr/traversal.rst201
-rw-r--r--docs/narr/urldispatch.rst55
-rw-r--r--docs/narr/viewconfig.rst737
-rw-r--r--docs/narr/views.rst1162
-rw-r--r--docs/narr/zca.rst47
-rw-r--r--docs/tutorials/bfg/index.rst4
-rw-r--r--docs/tutorials/cmf/actions.rst28
-rw-r--r--docs/tutorials/cmf/catalog.rst73
-rw-r--r--docs/tutorials/cmf/content.rst67
-rw-r--r--docs/tutorials/cmf/index.rst38
-rw-r--r--docs/tutorials/cmf/missing.rst22
-rw-r--r--docs/tutorials/cmf/skins.rst23
-rw-r--r--docs/tutorials/cmf/workflow.rst14
-rw-r--r--docs/tutorials/modwsgi/index.rst12
-rw-r--r--docs/tutorials/wiki/authorization.rst9
-rw-r--r--docs/tutorials/wiki/basiclayout.rst1
-rw-r--r--docs/tutorials/wiki/definingmodels.rst2
-rw-r--r--docs/tutorials/wiki/definingviews.rst22
-rw-r--r--docs/tutorials/wiki/distributing.rst2
-rw-r--r--docs/tutorials/wiki/installation.rst74
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/style.css109
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt85
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt79
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt108
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt89
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/views.py2
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt48
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/tests.py6
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/views.py3
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt108
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/tests.py6
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/style.css109
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/templates/edit.pt79
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt108
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/templates/view.pt83
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/views.py2
-rw-r--r--docs/tutorials/wiki2/authorization.rst361
-rw-r--r--docs/tutorials/wiki2/definingviews.rst29
-rw-r--r--docs/tutorials/wiki2/distributing.rst2
-rw-r--r--docs/tutorials/wiki2/installation.rst32
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/style.css109
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.pt86
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/templates/login.pt79
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.pt48
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/templates/view.pt85
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/tests.py22
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/models.py3
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt48
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py6
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/models.py3
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt48
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/tests.py6
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/__init__.py2
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/footerbg.pngbin0 -> 333 bytes
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/headerbg.pngbin0 -> 203 bytes
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/ie6.css8
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/middlebg.pngbin0 -> 2797 bytes
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/pylons.css50
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/pyramid-small.pngbin0 -> 7044 bytes
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/pyramid.pngbin0 -> 33055 bytes
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/style.css109
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/static/transparent.gifbin0 -> 49 bytes
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/templates/edit.pt79
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt48
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/templates/view.pt78
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/tests.py20
-rw-r--r--docs/zcml.rst33
-rw-r--r--docs/zcml/aclauthorizationpolicy.rst35
-rw-r--r--docs/zcml/adapter.rst47
-rw-r--r--docs/zcml/asset.rst65
-rw-r--r--docs/zcml/authtktauthenticationpolicy.rst102
-rw-r--r--docs/zcml/configure.rst95
-rw-r--r--docs/zcml/default_permission.rst57
-rw-r--r--docs/zcml/forbidden.rst78
-rw-r--r--docs/zcml/handler.rst158
-rw-r--r--docs/zcml/include.rst71
-rw-r--r--docs/zcml/localenegotiator.rst39
-rw-r--r--docs/zcml/notfound.rst78
-rw-r--r--docs/zcml/remoteuserauthenticationpolicy.rst51
-rw-r--r--docs/zcml/renderer.rst51
-rw-r--r--docs/zcml/repozewho1authenticationpolicy.rst53
-rw-r--r--docs/zcml/route.rst223
-rw-r--r--docs/zcml/scan.rst34
-rw-r--r--docs/zcml/static.rst89
-rw-r--r--docs/zcml/subscriber.rst45
-rw-r--r--docs/zcml/translationdir.rst64
-rw-r--r--docs/zcml/utility.rst46
-rw-r--r--docs/zcml/view.rst252
196 files changed, 3876 insertions, 7114 deletions
diff --git a/docs/Makefile b/docs/Makefile
index 3d706d17e..1d032cf45 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
diff --git a/docs/api.rst b/docs/api.rst
index b650c8ded..be7942502 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -24,7 +24,6 @@ documentation is organized alphabetically by module name.
api/renderers
api/request
api/response
- api/router
api/scripting
api/security
api/session
diff --git a/docs/api/authentication.rst b/docs/api/authentication.rst
index 54db77417..a6d4c1e18 100644
--- a/docs/api/authentication.rst
+++ b/docs/api/authentication.rst
@@ -3,6 +3,9 @@
:mod:`pyramid.authentication`
--------------------------------
+Authentication Policies
+~~~~~~~~~~~~~~~~~~~~~~~
+
.. automodule:: pyramid.authentication
.. autoclass:: AuthTktAuthenticationPolicy
@@ -11,3 +14,10 @@
.. autoclass:: RemoteUserAuthenticationPolicy
+Helper Classes
+~~~~~~~~~~~~~~
+
+ .. autoclass:: AuthTktCookieHelper
+
+
+
diff --git a/docs/api/config.rst b/docs/api/config.rst
index 3f37e739c..05bcb8146 100644
--- a/docs/api/config.rst
+++ b/docs/api/config.rst
@@ -48,14 +48,10 @@
.. automethod:: add_translation_dirs
- .. automethod:: add_handler
-
.. automethod:: add_view
.. automethod:: derive_view
- .. automethod:: load_zcml(spec)
-
.. automethod:: make_wsgi_app()
.. automethod:: override_asset(to_override, override_with)
@@ -76,6 +72,8 @@
.. automethod:: set_renderer_globals_factory
+ .. automethod:: add_directive
+
.. automethod:: testing_securitypolicy
.. automethod:: testing_resources
diff --git a/docs/api/interfaces.rst b/docs/api/interfaces.rst
index b3c14e5f7..3ce926230 100644
--- a/docs/api/interfaces.rst
+++ b/docs/api/interfaces.rst
@@ -35,3 +35,7 @@ Other Interfaces
.. autointerface:: ITemplateRenderer
+ .. autointerface:: IViewMapperFactory
+
+ .. autointerface:: IViewMapper
+
diff --git a/docs/api/router.rst b/docs/api/router.rst
deleted file mode 100644
index e5ffe97ce..000000000
--- a/docs/api/router.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-.. _router_module:
-
-:mod:`pyramid.router`
----------------------
-
-.. automodule:: pyramid.router
-
-.. autofunction:: pyramid.router.make_app(root_factory, package=None, filename='configure.zcml', settings=None)
diff --git a/docs/api/security.rst b/docs/api/security.rst
index 4acf5fe4d..de249355d 100644
--- a/docs/api/security.rst
+++ b/docs/api/security.rst
@@ -10,6 +10,8 @@ Authentication API Functions
.. autofunction:: authenticated_userid
+.. autofunction:: unauthenticated_userid
+
.. autofunction:: effective_principals
.. autofunction:: forget
diff --git a/docs/api/url.rst b/docs/api/url.rst
index 1aa3082b7..01be76283 100644
--- a/docs/api/url.rst
+++ b/docs/api/url.rst
@@ -9,6 +9,8 @@
.. autofunction:: route_url
+ .. autofunction:: current_route_url
+
.. autofunction:: route_path
.. autofunction:: static_url
diff --git a/docs/authorintro.rst b/docs/authorintro.rst
index f5ac402b0..bbcde68e6 100644
--- a/docs/authorintro.rst
+++ b/docs/authorintro.rst
@@ -54,7 +54,7 @@ technologies.
Book Content
============
-This book is divided into four major parts:
+This book is divided into three major parts:
:ref:`narrative_documentation`
@@ -79,12 +79,6 @@ This book is divided into four major parts:
:app:`Pyramid`. The API documentation is organized
alphabetically by module name.
-:ref:`zcml_reference`
-
- Comprehensive reference material for every :term:`ZCML directive`
- provided by :app:`Pyramid`. The ZCML directive documentation is
- organized alphabetically by directive name.
-
.. index::
single: repoze.zope2
single: Zope 3
@@ -163,6 +157,10 @@ others' technology.
single: Holth, Daniel
single: Hathaway, Shane
single: Akkerman, Wichert
+ single: Laflamme, Blaise
+ single: Bangert, Ben
+ single: Duncan, Casey
+ single: Orr, Mike
Thanks
======
@@ -173,12 +171,13 @@ typewriter (a Royal), and my mother, who bought me my first computer
Thanks to the following people for providing expertise, resources, and
software. Without the help of these folks, neither this book nor the
-software which it details would exist: Paul Everitt, Tres Seaver,
-Andrew Sawyers, Malthe Borch, Carlos de la Guardia, Chris Rossi, Shane
-Hathaway, Daniel Holth, Wichert Akkerman, Georg Brandl, Simon Oram and
-Nat Hardwick of Electrosoup, Ian Bicking of the Open Planning Project,
-Jim Fulton of Zope Corporation, Tom Moroz of the Open Society
-Institute, and Todd Koym of Environmental Health Sciences.
+software which it details would exist: Paul Everitt, Tres Seaver, Andrew
+Sawyers, Malthe Borch, Carlos de la Guardia, Chris Rossi, Shane Hathaway,
+Daniel Holth, Wichert Akkerman, Georg Brandl, Blaise Laflamme, Ben Bangert,
+Casey Duncan, Mike Orr, Simon Oram and Nat Hardwick of Electrosoup, Ian
+Bicking of the Open Planning Project, Jim Fulton of Zope Corporation, Tom
+Moroz of the Open Society Institute, and Todd Koym of Environmental Health
+Sciences.
Thanks to Guido van Rossum and Tim Peters for Python.
diff --git a/docs/conf.py b/docs/conf.py
index 8c238cecd..dce4ef879 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -13,6 +13,7 @@
import sys, os
import datetime
+import inspect
import warnings
warnings.simplefilter('ignore', DeprecationWarning)
@@ -76,7 +77,7 @@ copyright = '%s, Agendaless Consulting' % datetime.datetime.now().year
# other places throughout the built documents.
#
# The short X.Y version.
-version = '1.0a8'
+version = '1.0a10'
# The full version, including alpha/beta/rc tags.
release = version
@@ -407,6 +408,18 @@ def setup(app):
app.add_directive('frontmatter', frontmatter, 1, (0, 0, 0))
app.add_directive('mainmatter', mainmatter, 1, (0, 0, 0))
app.add_directive('backmatter', backmatter, 1, (0, 0, 0))
+ app.connect('autodoc-process-signature', resig)
+
+def resig(app, what, name, obj, options, signature, return_annotation):
+ """ Allow for preservation of ``@action_method`` decorated methods
+ in configurator """
+ docobj = getattr(obj, '__docobj__', None)
+ if docobj is not None:
+ argspec = inspect.getargspec(docobj)
+ if argspec[0] and argspec[0][0] in ('cls', 'self'):
+ del argspec[0][0]
+ signature = inspect.formatargspec(*argspec)
+ return signature, return_annotation
# turn off all line numbers in latex formatting
@@ -426,7 +439,7 @@ def setup(app):
epub_title = 'The Pyramid Web Application Development Framework, Version 1.0'
epub_author = 'Chris McDonough'
epub_publisher = 'Agendaless Consulting'
-epub_copyright = '2008-2010'
+epub_copyright = '2008-2011'
# The language of the text. It defaults to the language option
# or en if the language is not set.
diff --git a/docs/conventions.rst b/docs/conventions.rst
index 71c40e104..9e8510e4d 100644
--- a/docs/conventions.rst
+++ b/docs/conventions.rst
@@ -35,7 +35,7 @@ References to glossary terms are presented using the following style:
URLs are presented using the following style:
- `Pylons <http://pylonshq.com>`_
+ `Pylons <http://pylonsproject.org>`_
References to sections and chapters are presented using the following
style:
diff --git a/docs/copyright.rst b/docs/copyright.rst
index fa564a785..c8fc01609 100644
--- a/docs/copyright.rst
+++ b/docs/copyright.rst
@@ -7,7 +7,7 @@ by Chris McDonough
.. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN
-Copyright |copy| 2008-2010, Agendaless Consulting.
+Copyright |copy| 2008-2011, Agendaless Consulting.
.. ISBN-10: 0615345379
@@ -48,17 +48,30 @@ with respect to the use of the information contained herein.
Attributions
------------
+Editor:
+ Casey Duncan
+
Contributors:
- Ben Bangert, Blaise Laflamme, Carlos de la Guardia, Paul Everitt,
- Marius Gedminas
+
+ Ben Bangert, Blaise Laflamme, Rob Miller, Mike Orr, Carlos de la Guardia,
+ Paul Everitt, Tres Seaver, John Shipman, Marius Gedminas, Chris Rossi,
+ Joachim Krebs, Xavier Spriet, Reed O'Brien, William Chambers, Charlie
+ Choiniere, Jamaludin Ahmad.
.. Cover Designer:
.. Nat Hardwick of `Electrosoup <http://www.electrosoup.co.uk>`_.
Used with permission:
+
The :ref:`webob_chapter` chapter is adapted, with permission, from
documentation originally written by Ian Bicking.
+ The :ref:`much_ado_about_traversal_chapter` chapter is adapted,
+ with permission, from an article written by Rob Miller.
+
+ The :ref:`wiki2_flow_of_authentication` section was contributed by John
+ Shipman.
+
.. Print Production
.. ----------------
@@ -79,7 +92,7 @@ HTML Version and Source Code
----------------------------
An HTML version of this book is freely available via
-http://docs.pylonshq.com
+http://docs.pylonsproject.org
The source code for the examples used in this book are available
within the :app:`Pyramid` software distribution, always available
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index 53b95b9d0..a7cc31d81 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -21,19 +21,20 @@ an acronym for "there is more than one way to do it").
it includes more than one way to resolve a URL to a :term:`view callable`:
via :term:`url dispatch` or :term:`traversal`. Multiple methods of
configuration exist: :term:`imperative configuration`, :term:`configuration
-decoration`, and :term:`ZCML`. It works with multiple different kinds of
-persistence and templating systems. And so on. However, the existence of
-most of these overlapping ways to do things are not without reason and
-purpose: we have a number of audiences to serve, and we believe that TIMTOWTI
-at the web framework level actually *prevents* a much more insidious and
-harmful set of duplication at higher levels in the Python web community.
+decoration`, and :term:`ZCML` (optionally via :term:`pyramid_zcml`). It works
+with multiple different kinds of persistence and templating systems. And so
+on. However, the existence of most of these overlapping ways to do things
+are not without reason and purpose: we have a number of audiences to serve,
+and we believe that TIMTOWTI at the web framework level actually *prevents* a
+much more insidious and harmful set of duplication at higher levels in the
+Python web community.
:app:`Pyramid` began its life as :mod:`repoze.bfg`, written by a team of
people with many years of prior :ref:`Zope` experience. The idea of
-:term:`traversal`, the usage of :term:`ZCML` and the way :term:`view lookup`
-works was stolen entirely from Zope. The authorization subsystem provided by
-:app:`Pyramid` is a derivative of Zope's. The idea that an application can
-be *extended* without forking is also a Zope derivative.
+:term:`traversal` and the way :term:`view lookup` works was stolen entirely
+from Zope. The authorization subsystem provided by :app:`Pyramid` is a
+derivative of Zope's. The idea that an application can be *extended* without
+forking is also a Zope derivative.
Implementations of these features were *required* to allow the :app:`Pyramid`
authors to build the bread-and-butter CMS-type systems for customers in the
@@ -164,12 +165,11 @@ variable. Using an API that consults a thread local makes understanding how
it works non-local.
You've now bought in to the fact that there's a registry that is just
-"hanging around". But how does the registry get populated? Why,
-:term:`ZCML` of course. Sometimes. Or via imperative code. In this
-particular case, however, the registration of ``ISettings`` is made by the
-framework itself "under the hood": it's not present in any ZCML nor was it
-performed imperatively. This is extremely hard to comprehend. Problem
-number six.
+"hanging around". But how does the registry get populated? Why, via code
+that calls directives like ``config.add_view``. In this particular case,
+however, the registration of ``ISettings`` is made by the framework itself
+"under the hood": it's not present in any user configuration. This is
+extremely hard to comprehend. Problem number six.
Clearly there's some amount of cognitive load here that needs to be borne by
a reader of code that extends the :app:`Pyramid` framework due to its use of
@@ -323,17 +323,18 @@ the ZCA registry:
- Composability. A ZCA component registry can be populated imperatively, or
there's an existing mechanism to populate a registry via the use of a
- configuration file (ZCML). We didn't need to write a frontend from scratch
- to make use of configuration-file-driven registry population.
+ configuration file (ZCML, via :term:`pyramid_zcml`). We didn't need to
+ write a frontend from scratch to make use of configuration-file-driven
+ registry population.
- Pluggability. Use of the ZCA registry allows for framework extensibility
via a well-defined and widely understood plugin architecture. As long as
framework developers and extenders understand the ZCA registry, it's
possible to extend :app:`Pyramid` almost arbitrarily. For example, it's
- relatively easy to build a ZCML directive that registers several views "all
- at once", allowing app developers to use that ZCML directive as a "macro"
- in code that they write. This is somewhat of a differentiating feature
- from other (non-Zope) frameworks.
+ relatively easy to build a directive that registers several views "all at
+ once", allowing app developers to use that directive as a "macro" in code
+ that they write. This is somewhat of a differentiating feature from other
+ (non-Zope) frameworks.
- Testability. Judicious use of the ZCA registry in framework code makes
testing that code slightly easier. Instead of using monkeypatching or
@@ -346,9 +347,8 @@ the ZCA registry:
for just these purposes. The ZCA registry contains optional C code for
this purpose which demonstrably has no (or very few) bugs.
-- Ecosystem. Many existing Zope packages can be used in
- :app:`Pyramid` with few (or no) changes due to our use of the ZCA
- registry and :term:`ZCML`.
+- Ecosystem. Many existing Zope packages can be used in :app:`Pyramid` with
+ few (or no) changes due to our use of the ZCA registry.
Conclusion
++++++++++
@@ -366,13 +366,12 @@ this is you, it's extremely hard to have a lot of sympathy for you. You'll
either need to get familiar with how we're using the ZCA registry or you'll
need to use only the documented APIs; that's why we document them as APIs.
-If you *extend* or *develop* :app:`Pyramid` (create new ZCML directives, use
-some of the more obscure "ZCML hooks" as described in :ref:`hooks_chapter`,
-or work on the :app:`Pyramid` core code), you will be faced with needing to
-understand at least some ZCA concepts. In some places it's used unabashedly,
-and will be forever. We know it's quirky, but it's also useful and
-fundamentally understandable if you take the time to do some reading about
-it.
+If you *extend* or *develop* :app:`Pyramid` (create new directives, use some
+of the more obscure "hooks" as described in :ref:`hooks_chapter`, or work on
+the :app:`Pyramid` core code), you will be faced with needing to understand
+at least some ZCA concepts. In some places it's used unabashedly, and will
+be forever. We know it's quirky, but it's also useful and fundamentally
+understandable if you take the time to do some reading about it.
Pyramid Uses Interfaces Too Liberally
-------------------------------------
@@ -453,74 +452,11 @@ Pyramid "Encourages Use of ZCML"
:term:`Zope Component Architecture` registry that :app:`Pyramid` uses for
application configuration. Often people claim that Pyramid "needs ZCML".
-Quick answer: it doesn't. At least not anymore. In :mod:`repoze.bfg` (the
-predecessor to Pyramid) versions 1.0 and and 1.1, an application needed to
-possess a ZCML file for it to begin executing successfully. However,
-:mod:`repoze.bfg` 1.2 and greater (including :app:`Pyramid` 1.0) includes a
-completely imperative mode for all configuration. You will be able to make
-"single file" apps in this mode, which should help people who need to see
-everything done completely imperatively. For example, the very most basic
-:app:`Pyramid` "helloworld" program has become something like:
-
-.. code-block:: python
- :linenos:
-
- from webob import Response
- from paste.httpserver import serve
- from pyramid.config import Configurator
-
- def hello_world(request):
- return Response('Hello world!')
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- app = config.make_wsgi_app()
- serve(app)
-
-In this mode, no ZCML is required at all, nor any other sort of frameworky
-frontend to application configuration. Hopefully this mode will allow people
-who are used to doing everything imperatively feel more comfortable.
-
-Pyramid Uses ZCML; ZCML is XML and I Don't Like XML
----------------------------------------------------
-
-:term:`ZCML` is a configuration language in the XML syntax. Due to the
-"imperative configuration" feature (new in :mod:`repoze.bfg` 1.2), you don't
-need to use ZCML at all. But if you really do want to perform declarative
-configuration, perhaps because you want to build an extensible application,
-you may need to use and understand it.
-
-:term:`ZCML` contains elements that are mostly singleton tags that are
-called *declarations*. For an example:
-
-.. code-block:: xml
- :linenos:
-
- <route
- view=".views.my_view"
- path="/"
- name="root"
- />
-
-This declaration associates a :term:`view` with a route pattern.
-
-All :app:`Pyramid` declarations are singleton tags, unlike many other XML
-configuration systems. No XML *values* in ZCML are meaningful; it's always
-just XML tags and attributes. So in the very common case it's not really
-very much different than an otherwise "flat" configuration format like
-``.ini``, except a developer can *create* a directive that requires nesting
-(none of these exist in :app:`Pyramid` itself), and multiple "sections" can
-exist with the same "name" (e.g. two ``<route>`` declarations) must be able
-to exist simultaneously.
-
-You might think some other configuration file format would be better. But
-all configuration formats suck in one way or another. I personally don't
-think any of our lives would be markedly better if the declarative
-configuration format used by :app:`Pyramid` were YAML, JSON, or INI. It's
-all just plumbing that you mostly cut and paste once you've progressed 30
-minutes into your first project. Folks who tend to agitate for another
-configuration file format are folks that haven't yet spent that 30 minutes.
+It doesn't. In :app:`Pyramid` 1.0, ZCML doesn't ship as part of the core;
+instead it ships in the :term:`pyramid_zcml` add-on package, which is
+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:
@@ -541,14 +477,18 @@ Pyramid Does Traversal, And I Don't Like Traversal
In :app:`Pyramid`, :term:`traversal` is the act of resolving a URL path to a
:term:`resource` object in a resource tree. Some people are uncomfortable
-with this notion, and believe it is wrong.
-
-This is understandable. The people who believe it is wrong almost invariably
-have all of their data in a relational database. Relational databases aren't
+with this notion, and believe it is wrong. Thankfully, if you use
+:app:`Pyramid`, and you don't want to model your application in terms of a
+resource tree, you needn't use it at all. Instead, use :term:`URL dispatch`
+to map URL paths to views.
+
+The idea that some folks believe traversal is unilaterally "wrong" is
+understandable. The people who believe it is wrong almost invariably have
+all of their data in a relational database. Relational databases aren't
naturally hierarchical, so "traversing" one like a tree is not possible.
-Folks who deem traversal unilaterally "wrong" are neglecting to take into
-account that many persistence mechanisms *are* hierarchical. Examples
+However, folks who deem traversal unilaterally wrong are neglecting to take
+into account that many persistence mechanisms *are* hierarchical. Examples
include a filesystem, an LDAP database, a :term:`ZODB` (or another type of
graph) database, an XML document, and the Python module namespace. It is
often convenient to model the frontend to a hierarchical data store as a
@@ -566,28 +506,32 @@ resource tree is an excellent way to model this, even if the backend is a
relational database. In this situation, the resource tree a just a site
structure.
-But the point is ultimately moot. If you use :app:`Pyramid`, and you don't
-want to model your application in terms of a resource tree, you needn't use
-it at all. Instead, use :term:`URL dispatch` to map URL paths to views.
+Traversal also offers better composability of applications than URL dispatch,
+because it doesn't rely on a fixed ordering of URL matching. You can compose
+a set of disparate functionality (and add to it later) around a mapping of
+view to resource more predictably than trying to get "the right" ordering of
+URL pattern matching.
+
+But the point is ultimately moot. If you don't want to use traversal, you
+needn't. Use URL dispatch instead.
Pyramid Does URL Dispatch, And I Don't Like URL Dispatch
--------------------------------------------------------
-In :app:`Pyramid`, :term:`url dispatch` is the act of resolving a
-URL path to a :term:`view` callable by performing pattern matching
-against some set of ordered route definitions. The route definitions
-are examined in order: the first pattern which matches is used to
-associate the URL with a view callable.
-
-Some people are uncomfortable with this notion, and believe it is
-wrong. These are usually people who are steeped deeply in
-:term:`Zope`. Zope does not provide any mechanism except
-:term:`traversal` to map code to URLs. This is mainly because Zope
-effectively requires use of :term:`ZODB`, which is a hierarchical
-object store. Zope also supports relational databases, but typically
-the code that calls into the database lives somewhere in the ZODB
-object graph (or at least is a :term:`view` related to a node in the
-object graph), and traversal is required to reach this code.
+In :app:`Pyramid`, :term:`url dispatch` is the act of resolving a URL path to
+a :term:`view` callable by performing pattern matching against some set of
+ordered route definitions. The route definitions are examined in order: the
+first pattern which matches is used to associate the URL with a view
+callable.
+
+Some people are uncomfortable with this notion, and believe it is wrong.
+These are usually people who are steeped deeply in :term:`Zope`. Zope does
+not provide any mechanism except :term:`traversal` to map code to URLs. This
+is mainly because Zope effectively requires use of :term:`ZODB`, which is a
+hierarchical object store. Zope also supports relational databases, but
+typically the code that calls into the database lives somewhere in the ZODB
+object graph (or at least is a :term:`view` related to a node in the object
+graph), and traversal is required to reach this code.
I'll argue that URL dispatch is ultimately useful, even if you want to use
traversal as well. You can actually *combine* URL dispatch and traversal in
@@ -604,20 +548,19 @@ present them with the default object view. There are other tricks you can
pull in these hybrid configurations if you're clever (and maybe masochistic)
too.
-Also, if you are a URL dispatch hater, if you should ever be asked to
-write an application that must use some legacy relational database
-structure, you might find that using URL dispatch comes in handy for
-one-off associations between views and URL paths. Sometimes it's just
-pointless to add a node to the object graph that effectively
-represents the entry point for some bit of code. You can just use a
-route and be done with it. If a route matches, a view associated with
-the route will be called; if no route matches, :app:`Pyramid` falls
-back to using traversal.
-
-But the point is ultimately moot. If you use :app:`Pyramid`, and
-you really don't want to use URL dispatch, you needn't use it at all.
-Instead, use :term:`traversal` exclusively to map URL paths to views,
-just like you do in :term:`Zope`.
+Also, if you are a URL dispatch hater, if you should ever be asked to write
+an application that must use some legacy relational database structure, you
+might find that using URL dispatch comes in handy for one-off associations
+between views and URL paths. Sometimes it's just pointless to add a node to
+the object graph that effectively represents the entry point for some bit of
+code. You can just use a route and be done with it. If a route matches, a
+view associated with the route will be called; if no route matches,
+:app:`Pyramid` falls back to using traversal.
+
+But the point is ultimately moot. If you use :app:`Pyramid`, and you really
+don't want to use URL dispatch, you needn't use it at all. Instead, use
+:term:`traversal` exclusively to map URL paths to views, just like you do in
+:term:`Zope`.
Pyramid Views Do Not Accept Arbitrary Keyword Arguments
-------------------------------------------------------
@@ -649,40 +592,24 @@ arguments to any method of a resource object found via traversal:
def aview(self, a, b, c=None):
return '%s %s %c' % (a, b, c)
-When this method is called as the result of being the published
-callable, the Zope request object's GET and POST namespaces are
-searched for keys which match the names of the positional and keyword
-arguments in the request, and the method is called (if possible) with
-its argument list filled with values mentioned therein. TurboGears
-and Pylons 1.X operate similarly.
-
-:app:`Pyramid` has neither of these features. :mod:`pyramid`
-view callables always accept only ``context`` and ``request`` (or just
-``request``), and no other arguments. The rationale: this argument
-specification matching done aggressively can be costly, and
-:app:`Pyramid` has performance as one of its main goals, so we've
-decided to make people obtain information by interrogating the request
-object for it in the view body instead of providing magic to do
-unpacking into the view argument list. The feature itself also just
-seems a bit like a gimmick. Getting the arguments you want explicitly
-from the request via getitem is not really very hard; it's certainly
-never a bottleneck for the author when he writes web apps.
-
-It is possible to replicate the Zope-like behavior in a view callable
-decorator, however, should you badly want something like it back. No
-such decorator currently exists. If you'd like to create one, Google
-for "zope mapply" and adapt the function you'll find to a decorator
-that pulls the argument mapping information out of the
-``request.params`` dictionary.
-
-A similar feature could be implemented to provide the Django-like
-behavior as a decorator by wrapping the view with a decorator that
-looks in ``request.matchdict``.
-
-It's possible at some point that :app:`Pyramid` will grow some form
-of argument matching feature (it would be simple to make it an
-always-on optional feature that has no cost unless you actually use
-it) for, but currently it has none.
+When this method is called as the result of being the published callable, the
+Zope request object's GET and POST namespaces are searched for keys which
+match the names of the positional and keyword arguments in the request, and
+the method is called (if possible) with its argument list filled with values
+mentioned therein. TurboGears and Pylons 1.X operate similarly.
+
+Out of the box, :app:`Pyramid` is configured to have none of these features.
+By default, :mod:`pyramid` view callables always accept only ``reqest`` and
+no other arguments. The rationale: this argument specification matching done
+aggressively can be costly, and :app:`Pyramid` has performance as one of its
+main goals, so we've decided to make people, by default, obtain information
+by interrogating the request object within the view callable body instead of
+providing magic to do unpacking into the view argument list.
+
+However, as of :app:`Pyramid` 1.0a9, user code can influence the way view
+callables are expected to be called, making it possible to compose a system
+out of view callables which are called with arbitrary arguments. See
+:ref:`using_a_view_mapper`.
Pyramid Provides Too Few "Rails"
--------------------------------
@@ -700,32 +627,54 @@ built using :app:`Pyramid` as a base. See also :ref:`apps_are_extensible`.
Pyramid Provides Too Many "Rails"
---------------------------------
-:app:`Pyramid` provides some features that other web frameworks do
-not. Most notably it has machinery which resolves a URL first to a
-:term:`context` before calling a view (which has the capability to
-accept the context in its argument list), and a declarative
-authorization system that makes use of this feature. Most other web
-frameworks besides :term:`Zope`, from which the pattern was stolen,
-have no equivalent core feature.
-
-We consider this an important feature for a particular class of
-applications (CMS-style applications, which the authors are often
-commissioned to write) that usually use :term:`traversal` against a
-persistent object graph. The object graph contains security
-declarations as :term:`ACL` objects.
-
-Having context-sensitive declarative security for individual objects
-in the object graph is simply required for this class of application.
-Other frameworks save for Zope just do not have this feature. This is
-one of the primary reasons that :app:`Pyramid` was actually
-written.
-
-If you don't like this, it doesn't mean you can't use
-:app:`Pyramid`. Just ignore this feature and avoid configuring an
-authorization or authentication policy and using ACLs. You can build
-"Pylons-1.X-style" applications using :app:`Pyramid` that use their own
-security model via decorators or plain-old-imperative logic in view
-code.
+:app:`Pyramid` provides some features that other web frameworks do not.
+These are features meant for use cases that might not make sense to you if
+you're building a simple "bespoke" web application:
+
+- An optional way to map URLs to code using :term:`traversal` which implies a
+ walk of a :term:`resource tree`.
+
+- The ability to aggregate Pyramid application configuration from multiple
+ sources using :meth:`pyramid.config.Configurator.include`.
+
+- View and subscriber registrations made using :term:`interface` objects
+ instead of class objects (e.g. :ref:`using_resource_interfaces`).
+
+- A declarative :term:`authorization` system.
+
+- Multiple separate I18N :term:`translation string` factories, each of which
+ can name its own "domain".
+
+These features are important to the authors of :app:`Pyramid`. The
+:app:`Pyramid` authors are often commissioned to build CMS-style
+applications. Such applications are often "frameworky" because they have
+more than one deployment. Each deployment requires a slightly different
+composition of sub-applications, and the framework and sub-applications often
+need to be *extensible*. Because the application has more than one
+deployment, pluggability and extensibility is important, as maintaining
+multiple forks of the application, one per deployment, is extremely
+undesirable. Because it's easier to extend a system that uses
+:term:`traversal` "from the outside" than it is to do the same in a system
+that uses :term:`URL dispatch`, each deployment uses a :term:`resource tree`
+composed of a persistent tree of domain model objects, and uses
+:term:`traversal` to map :term:`view callable` code to resources in the tree.
+The resource tree contains very granular security declarations, as resources
+are owned and accessible by different sets of users. Interfaces are used to
+make unit testing and implementation substitutability easier.
+
+In a bespoke web application, usually there's a single canonical deployment,
+and therefore no possibility of multiple code forks. Extensibility is not
+required; the code is just changed in-place. Security requirements are often
+less granular. Using the features listed above will often be overkill for
+such an application.
+
+If you don't like these features, it doesn't mean you can't or shouldn't use
+:app:`Pyramid`. They are all optional, and a lot of time has been spent
+making sure you don't need to know about them up-front. You can build
+"Pylons-1.X-style" applications using :app:`Pyramid` that are purely bespoke
+by ignoring the features above. You may find these features handy later
+after building a "bespoke" web application that suddenly becomes popular and
+requires extensibility because it must be deployed in multiple locations.
Pyramid Is Too Big
------------------
@@ -895,9 +844,9 @@ Pyramid Applications are Extensible; I Don't Believe In Application Extensibilit
Any :app:`Pyramid` application written obeying certain constraints is
*extensible*. This feature is discussed in the :app:`Pyramid` documentation
-chapters named :ref:`extending_chapter` and :ref:`advconf_narr`. It is made
-possible by the use of the :term:`Zope Component Architecture` and within
-:app:`Pyramid`.
+chapters named :ref:`extending_chapter` and :ref:`advconfig_narr`. It is
+made possible by the use of the :term:`Zope Component Architecture` and
+within :app:`Pyramid`.
"Extensible", in this context, means:
@@ -993,11 +942,11 @@ the :term:`Zope Component Architecture`, you can optionally use it to expose
other more domain-specific configuration plugpoints while developing an
application. The plugpoints you expose needn't be as coarse as the ones
provided automatically by :app:`Pyramid` itself. For example, you might
-compose your own :term:`ZCML` directive that configures a set of views for a
-prebaked purpose (e.g. ``restview`` or somesuch) , allowing other people to
-refer to that directive when they make declarations in the ``configure.zcml``
-of their customization package. There is a cost for this: the developer of
-an application that defines custom plugpoints for its deployers will need to
+compose your own directive that configures a set of views for a prebaked
+purpose (e.g. ``restview`` or somesuch) , allowing other people to refer to
+that directive when they make declarations in the ``includeme`` of their
+customization package. There is a cost for this: the developer of an
+application that defines custom plugpoints for its deployers will need to
understand the ZCA or he will need to develop his own similar extensibility
system.
@@ -1018,7 +967,7 @@ Challenge
:app:`Pyramid` performs automatic authorization checks only at :term:`view`
execution time. Zope 3 wraps context objects with a `security proxy
-<http://wiki.zope.org/zope3/WhatAreSecurityProxies>`, which causes Zope 3 to
+<http://wiki.zope.org/zope3/WhatAreSecurityProxies>`_, which causes Zope 3 to
do also security checks during attribute access. I like this, because it
means:
@@ -1459,7 +1408,7 @@ global*:
# this is executed if the request method was GET or the
# credentials were invalid
-The `Pylons 1.X <http://pylonshq.com>`_ web framework uses a similar
+The `Pylons 1.X <http://pylonsproject.org>`_ web framework uses a similar
strategy. It calls these things "Stacked Object Proxies", so, for purposes
of this discussion, I'll do so as well.
@@ -1604,10 +1553,10 @@ If you can understand this hello world program, you can use Pyramid:
app = config.make_wsgi_app()
serve(app)
-Pyramid has ~ 650 of documentation (printed), covering topics from the very
-basic to the most advanced. *Nothing* is left undocumented, quite literally.
-It also has an *awesome*, very helpful community. Visit the #repoze and/or
-#pylons IRC channels on freenode.net and see.
+Pyramid has ~ 650 pages of documentation (printed), covering topics from the
+very basic to the most advanced. *Nothing* is left undocumented, quite
+literally. It also has an *awesome*, very helpful community. Visit the
+#repoze and/or #pylons IRC channels on freenode.net and see.
Hate Zope
+++++++++
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 49d273197..3c6f5cb1a 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -89,9 +89,9 @@ Glossary
dotted Python name
A reference to a Python object by name using a string, in the form
``path.to.modulename:attributename``. Often used in Paste and
- setuptools configurations. A variant is used in dotted names
- within :term:`ZCML` attributes that name objects (such as the ZCML
- "view" directive's "view" attribute): the colon (``:``) is not
+ setuptools configurations. A variant is used in dotted names within
+ configurator method arguments that name objects (such as the "add_view"
+ method's "view" and "context" attributes): the colon (``:``) is not
used; in its place is a dot.
view
@@ -112,14 +112,14 @@ Glossary
about :app:`Pyramid` view callables.
view configuration
- View configuration is the act of associating a :term:`view
- callable` with configuration information. This configuration
- information helps map a given :term:`request` to a particular view
- callable and it can influence the response of a view callable.
- :app:`Pyramid` views can be configured via :term:`imperative
- configuration`, :term:`ZCML` or by a special ``@view_config``
- decorator coupled with a :term:`scan`. See :ref:`views_chapter`
- for more information about view configuration.
+ View configuration is the act of associating a :term:`view callable`
+ with configuration information. This configuration information helps
+ map a given :term:`request` to a particular view callable and it can
+ influence the response of a view callable. :app:`Pyramid` views can be
+ configured via :term:`imperative configuration`, or by a special
+ ``@view_config`` decorator coupled with a :term:`scan`. See
+ :ref:`view_config_chapter` for more information about view
+ configuration.
view name
The "URL name" of a view, e.g ``index.html``. If a view is
@@ -285,7 +285,7 @@ Glossary
WSGI
`Web Server Gateway Interface <http://wsgi.org/>`_. This is a
Python standard for connecting web applications to web servers,
- similar to the concept of Java Servlets. ``pyramid`` requires
+ similar to the concept of Java Servlets. :app:`Pyramid` requires
that your application be served as a WSGI application.
middleware
@@ -377,29 +377,10 @@ Glossary
ultimately a :term:`view`). See also :term:`url dispatch`.
route configuration
- Route configuration is the act of using :term:`imperative
- configuration` or a :term:`ZCML` ``<route>`` statement to
- associate request parameters with a particular :term:`route` using
- pattern matching and :term:`route predicate` statements. See
- :ref:`urldispatch_chapter` for more information about route
- configuration.
-
- ZCML
- `Zope Configuration Markup Language
- <http://www.muthukadan.net/docs/zca.html#zcml>`_, an XML dialect
- used by Zope and :app:`Pyramid` for configuration tasks. ZCML
- is capable of performing different types of :term:`configuration
- declaration`, but its primary purpose in :app:`Pyramid` is to
- perform :term:`view configuration` and :term:`route configuration`
- within the ``configure.zcml`` file in a :app:`Pyramid`
- application. You can use ZCML as an alternative to
- :term:`imperative configuration`.
-
- ZCML directive
- A ZCML "tag" such as ``<view>`` or ``<route>``.
-
- ZCML declaration
- The concrete use of a :term:`ZCML directive` within a ZCML file.
+ Route configuration is the act of associating request parameters with a
+ particular :term:`route` using pattern matching and :term:`route
+ predicate` statements. See :ref:`urldispatch_chapter` for more
+ information about route configuration.
Zope Component Architecture
The `Zope Component Architecture
@@ -457,9 +438,9 @@ Glossary
subscriber
A callable which receives an :term:`event`. A callable becomes a
- subscriber via :term:`imperative configuration` or the
- ``<subscriber>`` ZCML directive. See :ref:`events_chapter` for
- more information.
+ subscriber via :term:`imperative configuration` or via
+ :term:`configuration decoration`. See :ref:`events_chapter` for more
+ information.
request type
An attribute of a :term:`request` that allows for specialization
@@ -577,15 +558,13 @@ Glossary
also `PEP 318 <http://www.python.org/dev/peps/pep-0318/>`_.
configuration declaration
- An individual method call made to an instance of a
- :app:`Pyramid` :term:`Configurator` object which performs an
- arbitrary action, such as registering a :term:`view configuration`
- (via the ``view`` method of the configurator) or :term:`route
- configuration` (via the ``route`` method of the configurator). A
- set of configuration declarations is also usually implied via the
- use of a :term:`ZCML declaration` within an application, or a set
- of configuration declarations might be performed by a :term:`scan`
- of code in a package.
+ An individual method call made to an instance of a :app:`Pyramid`
+ :term:`Configurator` object which performs an arbitrary action, such as
+ registering a :term:`view configuration` (via the ``add_view`` method of
+ the configurator) or :term:`route configuration` (via the ``add_route``
+ method of the configurator). A set of configuration declarations is
+ also implied by the :term:`configuration decoration` detected by a
+ :term:`scan` of code in a package.
configuration decoration
Metadata implying one or more :term:`configuration declaration`
@@ -609,8 +588,8 @@ Glossary
declaration` required by your application.
declarative configuration
- The configuration mode in which you use :term:`ZCML` to make
- a set of :term:`configuration declaration` statements.
+ The configuration mode in which you use :term:`ZCML` to make a set of
+ :term:`configuration declaration` statements. See :term:`pyramid_zcml`.
Not Found view
An :term:`exception view` invoked by :app:`Pyramid` when the
@@ -834,7 +813,7 @@ Glossary
:meth:`pyramid.config.Configurator.add_route` and
:meth:`pyramid.config.Configurator.add_view` to make it more
convenient to register a collection of views as a single class when
- using :term:`url dispatch`. See also :ref:`handlers_chapter`.
+ using :term:`url dispatch`. See also :ref:`views_chapter`.
Deployment settings
Deployment settings are settings passed to the :term:`Configurator` as a
@@ -850,6 +829,39 @@ Glossary
WSGI middleware which can display debuggable traceback information in
the browser when an exception is raised by a Pyramid application. See
http://pypi.python.org/pypi/WebError .
-
+ view mapper
+ A view mapper is a class which implements the
+ :class:`pyramid.interfaces.IViewMapperFactory` interface, which performs
+ view argument and return value mapping. This is a plug point for
+ extension builders, not normally used by "civilians".
+
+ matchdict
+ The dictionary attached to the :term:`request` object as
+ ``request.matchdict`` when a :term:`URL dispatch` route has been matched.
+ Its keys are names as identified within the route pattern; its values are
+ the values matched by each pattern name.
+
+ pyramid_zcml
+ An add-on package to :app:`Pyramid` which allows applications to be
+ configured via ZCML. It is available on :term:`PyPI`. If you use
+ ``pyramid_zcml``, you can use ZCML as an alternative to
+ :term:`imperative configuration`.
+
+ ZCML
+ `Zope Configuration Markup Language
+ <http://www.muthukadan.net/docs/zca.html#zcml>`_, an XML dialect
+ used by Zope and :term:`pyramid_zcml` for configuration tasks.
+
+ ZCML directive
+ A ZCML "tag" such as ``<view>`` or ``<route>``.
+
+ ZCML declaration
+ The concrete use of a :term:`ZCML directive` within a ZCML file.
+
+ pyramid_handlers
+ An add-on package which allows :app:`Pyramid` users to create classes
+ that are analogues of Pylons 1 "controllers". See
+ `http://docs.pylonsproject.org/projects/pyramid_handlers/dev/
+ <http://docs.pylonsproject.org/projects/pyramid_handlers/dev/>`_.
diff --git a/docs/index.rst b/docs/index.rst
index 23ffb3b1b..030b4dc1c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -6,7 +6,7 @@ The Pyramid Web Application Development Framework
:app:`Pyramid` is a small, fast, down-to-earth Python web application
development framework. It is developed as part of the `Pylons Project
-<http://docs.pylonshq.com/>`_. It is licensed under a `BSD-like license
+<http://docs.pylonsproject.org/>`_. It is licensed under a `BSD-like license
<http://repoze.org/license.html>`_.
.. note::
@@ -38,18 +38,17 @@ Narrative documentation in chapter form explaining how to use
narr/firstapp
narr/project
narr/startup
- narr/resourcelocation
narr/urldispatch
+ narr/muchadoabouttraversal
narr/traversal
narr/views
narr/renderers
narr/templates
+ narr/viewconfig
narr/resources
narr/assets
narr/webob
narr/sessions
- narr/flash
- narr/csrf
narr/security
narr/hybrid
narr/i18n
@@ -59,11 +58,11 @@ Narrative documentation in chapter form explaining how to use
narr/testing
narr/hooks
narr/advconfig
- narr/declarative
narr/extending
narr/router
narr/threadlocals
narr/zca
+ narr/forms
Tutorials
=========
@@ -78,7 +77,6 @@ applications to various platforms.
tutorials/wiki/index.rst
tutorials/wiki2/index.rst
tutorials/bfg/index.rst
- tutorials/cmf/index.rst
tutorials/gae/index.rst
tutorials/modwsgi/index.rst
tutorials/zeo/index.rst
@@ -87,14 +85,12 @@ applications to various platforms.
Reference Material
==================
-Reference material includes API documentation and documentation of
-every :app:`Pyramid` :term:`ZCML directive`.
+Reference material includes documentation for every :app:`Pyramid` API.
.. toctree::
:maxdepth: 2
api
- zcml
Detailed Change History
=======================
@@ -176,7 +172,7 @@ commenting, and file uploads. See the `KARL site
Support and Development
=======================
-The `Pylons Project web site <http://docs.pylonshq.com/>`_ is the main online
+The `Pylons Project web site <http://pylonsproject.org/>`_ is the main online
source of :app:`Pyramid` support and development information.
To report bugs, use the `issue tracker
@@ -197,7 +193,7 @@ To check out the trunk via ``git``, use this command:
To find out how to become a contributor to :app:`Pyramid`, please see the
`contributor's section of the documentation
-<http://docs.pylonshq.com/index.html#contributing>`_.
+<http://docs.pylonsproject.org/index.html#contributing>`_.
Index and Glossary
==================
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 058835937..2426ec4b0 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -31,18 +31,17 @@ Narrative Documentation
narr/configuration
narr/firstapp
narr/project
- narr/resourcelocation
narr/urldispatch
+ narr/muchadoabouttraversal
narr/traversal
narr/views
narr/renderers
narr/templates
+ narr/viewconfig
narr/resources
narr/assets
narr/webob
narr/sessions
- narr/flash
- narr/csrf
narr/security
narr/hybrid
narr/i18n
@@ -52,12 +51,11 @@ Narrative Documentation
narr/testing
narr/hooks
narr/advconfig
- narr/declarative
narr/extending
- narr/router
narr/startup
narr/threadlocals
narr/zca
+ narr/forms
.. _tutorials:
@@ -99,7 +97,6 @@ API Reference
api/renderers
api/request
api/response
- api/router
api/scripting
api/security
api/settings
@@ -110,36 +107,6 @@ API Reference
api/view
api/wsgi
-.. _zcml_reference:
-
-ZCML Directive Reference
-@@@@@@@@@@@@@@@@@@@@@@@@
-
-.. toctree::
- :maxdepth: 1
-
- zcml/aclauthorizationpolicy
- zcml/adapter
- zcml/authtktauthenticationpolicy
- zcml/asset
- zcml/configure
- zcml/default_permission
- zcml/forbidden
- zcml/handler
- zcml/include
- zcml/localenegotiator
- zcml/notfound
- zcml/remoteuserauthenticationpolicy
- zcml/renderer
- zcml/repozewho1authenticationpolicy
- zcml/route
- zcml/scan
- zcml/static
- zcml/subscriber
- zcml/translationdir
- zcml/utility
- zcml/view
-
.. backmatter::
Glossary and Index
diff --git a/docs/narr/MyProject/myproject/templates/mytemplate.pt b/docs/narr/MyProject/myproject/templates/mytemplate.pt
index 02fc00eeb..0bfea9d53 100644
--- a/docs/narr/MyProject/myproject/templates/mytemplate.pt
+++ b/docs/narr/MyProject/myproject/templates/mytemplate.pt
@@ -1,76 +1,106 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal">
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <title>The Pyramid Web Application Development Framework</title>
- <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
- <meta name="keywords" content="python web application" />
- <meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link href="http://fonts.googleapis.com/css?family=Neuton&amp;subset=latin" rel="stylesheet" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
- <!--[if lte IE 6]>
- <link rel="stylesheet" href="${request.application_url}/static/ie6.css" type="text/css" media="screen" charset="utf-8" />
- <![endif]-->
+ <title>The Pyramid Web Application Development Framework</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('myproject:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('myproject:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet"
+ href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('myproject:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
<body>
- <div id="wrap">
- <div id="top">
- <div class="top align-center">
- <div><img src="${request.application_url}/static/pyramid.png" width="750" height="169" alt="pyramid"/></div>
- </div>
- </div>
- <div id="middle">
- <div class="middle align-center">
- <p class="app-welcome">
- Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
- the Pyramid web application development framework.
- </p>
- </div>
- </div>
- <div id="bottom">
- <div class="bottom">
- <div id="left" class="align-right">
- <h2>Search documentation</h2>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
- <input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Go" />
- </form>
- </div>
- <div id="right" class="align-left">
- <h2>Pyramid links</h2>
- <ul class="links">
- <li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
- </li>
- <li>
- <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
- </li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- <div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
- </div>
+ <div id="wrap">
+ <div id="top">
+ <div class="top align-center">
+ <div>
+ <img src="${request.static_url('myproject:static/pyramid.png')}"
+ width="750" height="169" alt="pyramid"/>
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
+ <p class="app-welcome">
+ Welcome to <span class="app-name">${project}</span>,
+ an application generated by<br/>
+ the Pyramid web application development framework.
+ </p>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div id="left" class="align-right">
+ <h2>Search documentation</h2>
+ <form method="get"
+ action="http://docs.pylonsproject.org/pyramid/dev/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
+ </div>
+ <div id="right" class="align-left">
+ <h2>Pyramid links</h2>
+ <ul class="links">
+ <li>
+ <a href="http://pylonsproject.org">
+ Pylons Website
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">
+ Narrative Documentation
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">
+ API Documentation
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">
+ Tutorials
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">
+ Change History
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">
+ Sample Applications
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">
+ Support and Development
+ </a>
+ </li>
+ <li>
+ <a href="irc://irc.freenode.net#pyramid">
+ IRC Channel
+ </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ </div>
</body>
</html> \ No newline at end of file
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py
index b14fb37af..5fa710278 100644
--- a/docs/narr/MyProject/myproject/tests.py
+++ b/docs/narr/MyProject/myproject/tests.py
@@ -1,15 +1,13 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
class ViewTests(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_my_view(self):
from myproject.views import my_view
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index f8b3ee191..30f76e456 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -115,11 +115,8 @@ allowing the circumstance to go unreported, by default Pyramid raises a
running.
Conflict detection happens for any kind of configuration: imperative
-configuration, :term:`ZCML` configuration, or configuration that results from
-the execution of a :term:`scan`.
-
-.. note:: If you use, ZCML, its conflict detection algorithm is described in
- :ref:`zcml_conflict_detection`.
+configuration or configuration that results from the execution of a
+:term:`scan`.
Manually Resolving Conflicts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -274,7 +271,7 @@ If your code uses the :meth:`pyramid.config.Configurator.include` method to
include external configuration, some conflicts are automatically resolved.
Configuration statements that are made as the result of an "include" will be
overridden by configuration statements that happen within the caller of
-the "include" method. See also
+the "include" method.
Automatic conflict resolution supports this goal: if a user wants to reuse a
Pyramid application, and they want to customize the configuration of this
@@ -301,9 +298,6 @@ These are the methods of the configurator which provide conflict detection:
Some other methods of the configurator also indirectly provide conflict
detection, because they're implemented in terms of conflict-aware methods:
-- :meth:`~pyramid.config.Configurator.add_handler`, a frontend for
- ``add_route`` and ``add_view``.
-
- :meth:`~pyramid.config.Configurator.add_route` does a second type of
conflict detection when a ``view`` parameter is passed (it calls
``add_view``).
@@ -338,6 +332,23 @@ Instead, use :meth:`pyramid.config.Configuration.include`:
Using ``include`` rather than calling the function directly will allow
:ref:`automatic_conflict_resolution` to work.
+:meth:`pyramid.config.Configuration.include` can also accept a :term:`module`
+as an argument:
+
+.. code-block:: python
+ :linenos:
+
+ import myapp
+
+ config.include(myapp)
+
+For this to work properly, the ``myapp`` module must contain a callable with
+the special name ``includeme``, which should perform configuration (like the
+``add_routes`` callable we showed above as an example).
+
+:meth:`pyramid.config.Configuration.include` can also accept a :term:`dotted
+Python name` to a function or a module.
+
.. note: See :ref:`the_include_tag` for a declarative alternative to
:meth:`pyramid.config.Configurator.include`.
@@ -387,9 +398,8 @@ used, two-phase configuration is disabled, and configuration statements must
be ordered in dependency order.
Some configuration methods, such as
-:meth:`pyramid.config.Configurator.add_route` and
-:meth:`pyramid.config.Configurator.add_handler` have internal ordering
-constraints: they routes they imply require relative ordering. Such ordering
+:meth:`pyramid.config.Configurator.add_route` have internal ordering
+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.
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index f147426ce..b1c1c419c 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -98,7 +98,7 @@ directory on a filesystem to an application user's browser. Use the
mechanism makes a directory of static files available at a name relative to
the application root URL, e.g. ``/static`` or as an external URL.
-.. note:: `~pyramid.config.Configurator.add_static_view` cannot serve a
+.. note:: :meth:`~pyramid.config.Configurator.add_static_view` cannot serve a
single file, nor can it serve a directory of static files directly
relative to the root URL of a :app:`Pyramid` application. For these
features, see :ref:`advanced_static`.
@@ -282,7 +282,7 @@ create such a circumstance, we suggest using the
in the application ``.ini`` file named ``media_location``. Then set the
value of ``media_location`` to either a prefix or a URL depending on whether
the application is being run in development or in production (use a different
-`.ini`` file for production than you do for development). This is just a
+``.ini`` file for production than you do for development). This is just a
suggestion for a pattern; any setting name other than ``media_location``
could be used.
@@ -345,7 +345,7 @@ application's startup code.
.. code-block:: python
:linenos:
- # .. every other add_route and/or add_handler declaration should come
+ # .. every other add_route declaration should come
# before this one, as it will, by default, catch all requests
config.add_route('catchall_static', '/*subpath', 'myapp.static.static_view')
diff --git a/docs/narr/configuration.rst b/docs/narr/configuration.rst
index 394603946..05bc4d6cc 100644
--- a/docs/narr/configuration.rst
+++ b/docs/narr/configuration.rst
@@ -151,9 +151,7 @@ Declarative Configuration
A third mode of configuration can be employed when you create a
:app:`Pyramid` application named *declarative configuration*. This mode uses
an XML language known as :term:`ZCML` to represent configuration statements
-rather than Python. ZCML is often used when application extensibility is
-important. Most of the examples in the narrative portion of this
-documentation concentrate on imperative configuration rather than ZCML, but
-almost everything that can be configured imperatively can also be configured
-via ZCML. See :ref:`declarative_chapter` for more information about ZCML.
+rather than Python. ZCML is not built-in to Pyramid, but almost everything
+that can be configured imperatively can also be configured via ZCML if you
+install the :term:`pyramid_zcml` package.
diff --git a/docs/narr/csrf.rst b/docs/narr/csrf.rst
deleted file mode 100644
index 7586b0ed7..000000000
--- a/docs/narr/csrf.rst
+++ /dev/null
@@ -1,63 +0,0 @@
-.. _csrf_chapter:
-
-Preventing Cross-Site Request Forgery Attacks
-=============================================
-
-`Cross-site request forgery
-<http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a
-phenomenon whereby a user with an identity on your website might click on a
-URL or button on another website which unwittingly redirects the user to your
-application to perform some command that requires elevated privileges.
-
-You can avoid most of these attacks by making sure that a the correct *CSRF
-token* has been set in an :app:`Pyramid` session object before performing any
-actions in code which requires elevated privileges and is invoked via a form
-post. To use CSRF token support, you must enable a :term:`session factory`
-as described in :ref:`using_the_default_session_factory` or
-:ref:`using_alternate_session_factories`.
-
-Using the ``session.new_csrf_token`` Method
--------------------------------------------
-
-To add a CSRF token to the session, use the ``session.new_csrf_token`` method.
-
-.. code-block:: python
- :linenos:
-
- token = request.session.new_csrf_token()
-
-The ``.new_csrf_token`` method accepts no arguments. It returns a *token*
-string, which will be opaque and randomized. This token will also be set
-into the session, awaiting pickup by the ``session.get_csrf_token`` method.
-You can subsequently use the returned token as the value of a hidden field in
-a form that posts to a method that requires elevated privileges. The handler
-for the form post should use ``session.get_csrf_token`` (explained below) to
-obtain the current CSRF token related to the user from the session, and
-compare it to the value of the hidden form field.
-
-Using the ``session.get_csrf_token`` Method
--------------------------------------------
-
-To get the current CSRF token from the session, use the
-``session.get_csrf_token`` method.
-
-.. code-block:: python
- :linenos:
-
- token = request.session.get_csrf_token()
-
-The ``get_csrf_token`` method accepts no arguments. It returns the "current"
-*token* string (as per the last call to ``session.new_csrf_token``). You can
-then use it to compare against the token provided within form post hidden
-value data. For example, if your form rendering included the CSRF token
-obtained via ``session.new_csrf_token`` as a hidden input field named
-``csrf_token``:
-
-.. code-block:: python
- :linenos:
-
- token = request.session.get_csrf_token()
- if token != request.POST['csrf_token']:
- raise ValueError('CSRF token did not match')
-
-
diff --git a/docs/narr/declarative.rst b/docs/narr/declarative.rst
deleted file mode 100644
index f36e55b29..000000000
--- a/docs/narr/declarative.rst
+++ /dev/null
@@ -1,1436 +0,0 @@
-.. _declarative_chapter:
-
-Declarative Configuration
-=========================
-
-The mode of configuration detailed in the majority of examples within this
-this book is "imperative" configuration. This is the configuration mode in
-which a developer cedes the least amount of control to the framework; it's
-"imperative" because you express the configuration directly in Python code,
-and you have the full power of Python at your disposal as you issue
-configuration statements. However, another mode of configuration exists
-within :app:`Pyramid` named :term:`ZCML` which often provides better
-opportunity for extensibility.
-
-A complete listing of ZCML directives is available within
-:ref:`zcml_directives`. This chapter provides an overview of how you might
-get started with ZCML and highlights some common tasks performed when you use
-ZCML.
-
-.. index::
- single: declarative configuration
-
-.. _declarative_configuration:
-
-ZCML Configuration
-------------------
-
-A :app:`Pyramid` application can be configured "declaratively", if so
-desired. Declarative configuration relies on *declarations* made external to
-the code in a configuration file format named :term:`ZCML` (Zope
-Configuration Markup Language), an XML dialect.
-
-A :app:`Pyramid` application configured declaratively requires not
-one, but two files: a Python file and a :term:`ZCML` file.
-
-In a file named ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- from paste.httpserver import serve
- from pyramid.response import Response
- from pyramid.config import Configurator
-
- def hello_world(request):
- return Response('Hello world!')
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-In a file named ``configure.zcml`` in the same directory as the
-previously created ``helloworld.py``:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- </configure>
-
-This pair of files forms an application functionally equivalent to the
-application we created earlier in :ref:`imperative_configuration`.
-Let's examine the differences between that code listing and the code
-above.
-
-In :ref:`imperative_configuration`, we had the following lines within
-the ``if __name__ == '__main__'`` section of ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-In our "declarative" code, we've removed the call to ``add_view`` and
-replaced it with a call to the
-:meth:`pyramid.config.Configurator.load_zcml` method so that
-it now reads as:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-Everything else is much the same.
-
-The ``config.load_zcml('configure.zcml')`` line tells the configurator
-to load configuration declarations from the file named
-``configure.zcml`` which sits next to ``helloworld.py`` on the
-filesystem. Let's take a look at that ``configure.zcml`` file again:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- </configure>
-
-Note that this file contains some XML, and that the XML contains a
-``<view>`` :term:`configuration declaration` tag that references a
-:term:`dotted Python name`. This dotted name refers to the
-``hello_world`` function that lives in our ``helloworld`` Python
-module.
-
-This ``<view>`` declaration tag performs the same function as the
-``add_view`` method that was employed within
-:ref:`imperative_configuration`. In fact, the ``<view>`` tag is
-effectively a "macro" which calls the
-:meth:`pyramid.config.Configurator.add_view` method on your
-behalf.
-
-The ``<view>`` tag is an example of a :app:`Pyramid` declaration
-tag. Other such tags include ``<route>`` and ``<scan>``. Each of
-these tags is effectively a "macro" which calls methods of a
-:class:`pyramid.config.Configurator` object on your behalf.
-
-Essentially, using a :term:`ZCML` file and loading it from the
-filesystem allows us to put our configuration statements within this
-XML file rather as declarations, rather than representing them as
-method calls to a :term:`Configurator` object. Otherwise, declarative
-and imperative configuration are functionally equivalent.
-
-Using declarative configuration has a number of benefits, the primary
-benefit being that applications configured declaratively can be
-*overridden* and *extended* by third parties without requiring the
-third party to change application code. If you want to build a
-framework or an extensible application, using declarative
-configuration is a good idea.
-
-Declarative configuration has an obvious downside: you can't use
-plain-old-Python syntax you probably already know and understand to
-configure your application; instead you need to use :term:`ZCML`.
-
-.. index::
- single: ZCML conflict detection
-
-.. _zcml_conflict_detection:
-
-ZCML Conflict Detection
-~~~~~~~~~~~~~~~~~~~~~~~
-
-A minor additional feature of ZCML is *conflict detection*. If you
-define two declaration tags within the same ZCML file which logically
-"collide", an exception will be raised, and the application will not
-start. For example, the following ZCML file has two conflicting
-``<view>`` tags:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- view="helloworld.hello_world"
- />
-
- </configure>
-
-If you try to use this ZCML file as the source of ZCML for an
-application, an error will be raised when you attempt to start the
-application. This error will contain information about which tags
-might have conflicted.
-
-.. index::
- single: helloworld (declarative)
-
-.. _helloworld_declarative:
-
-Hello World, Goodbye World (Declarative)
-----------------------------------------
-
-Another almost entirely equivalent mode of application configuration
-exists named *declarative* configuration. :app:`Pyramid` can be
-configured for the same "hello world" application "declaratively", if
-so desired.
-
-To do so, first, create a file named ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.config import Configurator
- from pyramid.response import Response
- from paste.httpserver import serve
-
- def hello_world(request):
- return Response('Hello world!')
-
- def goodbye_world(request):
- return Response('Goodbye world!')
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-Then create a file named ``configure.zcml`` in the same directory as
-the previously created ``helloworld.py``:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
- </configure>
-
-This pair of files forms an application functionally equivalent to the
-application we created earlier in :ref:`helloworld_imperative`. We can run
-it the same way.
-
-.. code-block:: text
-
- $ python helloworld.py
- serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
-
-Let's examine the differences between the code in that section and the code
-above. In :ref:`helloworld_imperative_appconfig`, we had the following lines
-within the ``if __name__ == '__main__'`` section of ``helloworld.py``:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- config.add_view(goodbye_world, name='goodbye')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-In our "declarative" code, we've added a call to the
-:meth:`pyramid.config.Configurator.load_zcml` method with
-the value ``configure.zcml``, and we've removed the lines which read
-``config.add_view(hello_world)`` and ``config.add_view(goodbye_world,
-name='goodbye')``, so that it now reads as:
-
-.. code-block:: python
- :linenos:
-
- if __name__ == '__main__':
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-Everything else is much the same.
-
-The ``config.load_zcml('configure.zcml')`` line tells the configurator
-to load configuration declarations from the ``configure.zcml`` file
-which sits next to ``helloworld.py``. Let's take a look at the
-``configure.zcml`` file now:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
- </configure>
-
-We already understand what the view code does, because the application
-is functionally equivalent to the application described in
-:ref:`helloworld_imperative`, but use of :term:`ZCML` is new. Let's
-break that down tag-by-tag.
-
-The ``<configure>`` Tag
-~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``configure.zcml`` ZCML file contains this bit of XML:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- other directives -->
-
- </configure>
-
-Because :term:`ZCML` is XML, and because XML requires a single root
-tag for each document, every ZCML file used by :app:`Pyramid` must
-contain a ``configure`` container directive, which acts as the root
-XML tag. It is a "container" directive because its only job is to
-contain other directives.
-
-See also :ref:`configure_directive` and :ref:`word_on_xml_namespaces`.
-
-.. _the_include_tag:
-
-The ``<include>`` Tag
-~~~~~~~~~~~~~~~~~~~~~
-
-The ``configure.zcml`` ZCML file contains this bit of XML within the
-``<configure>`` root tag:
-
-.. code-block:: xml
- :linenos:
-
- <include package="pyramid.includes" />
-
-This self-closing tag instructs :app:`Pyramid` to load a ZCML file
-from the Python package with the :term:`dotted Python name`
-``pyramid.includes``, as specified by its ``package`` attribute.
-This particular ``<include>`` declaration is required because it
-actually allows subsequent declaration tags (such as ``<view>``, which
-we'll see shortly) to be recognized. The ``<include>`` tag
-effectively just includes another ZCML file, causing its declarations
-to be executed. In this case, we want to load the declarations from
-the file named ``configure.zcml`` within the
-:mod:`pyramid.includes` Python package. We know we want to load
-the ``configure.zcml`` from this package because ``configure.zcml`` is
-the default value for another attribute of the ``<include>`` tag named
-``file``. We could have spelled the include tag more verbosely, but
-equivalently as:
-
-.. code-block:: xml
- :linenos:
-
- <include package="pyramid.includes"
- file="configure.zcml"/>
-
-The ``<include>`` tag that includes the ZCML statements implied by the
-``configure.zcml`` file from the Python package named
-:mod:`pyramid.includes` is basically required to come before any
-other named declaration in an application's ``configure.zcml``. If it
-is not included, subsequent declaration tags will fail to be
-recognized, and the configuration system will generate an error at
-startup. However, the ``<include package="pyramid.includes"/>``
-tag needs to exist only in a "top-level" ZCML file, it needn't also
-exist in ZCML files *included by* a top-level ZCML file.
-
-See also :ref:`include_directive`.
-
-The ``<view>`` Tag
-~~~~~~~~~~~~~~~~~~
-
-The ``configure.zcml`` ZCML file contains these bits of XML *after* the
-``<include>`` tag, but *within* the ``<configure>`` root tag:
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
-These ``<view>`` declaration tags direct :app:`Pyramid` to create
-two :term:`view configuration` registrations. The first ``<view>``
-tag has an attribute (the attribute is also named ``view``), which
-points at a :term:`dotted Python name`, referencing the
-``hello_world`` function defined within the ``helloworld`` package.
-The second ``<view>`` tag has a ``view`` attribute which points at a
-:term:`dotted Python name`, referencing the ``goodbye_world`` function
-defined within the ``helloworld`` package. The second ``<view>`` tag
-also has an attribute called ``name`` with a value of ``goodbye``.
-
-These effect of the ``<view>`` tag declarations we've put into our
-``configure.zcml`` is functionally equivalent to the effect of lines
-we've already seen in an imperatively-configured application. We're
-just spelling things differently, using XML instead of Python.
-
-In our previously defined application, in which we added view
-configurations imperatively, we saw this code:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- config.add_view(hello_world)
- config.add_view(goodbye_world, name='goodbye')
-
-Each ``<view>`` declaration tag encountered in a ZCML file effectively
-invokes the :meth:`pyramid.config.Configurator.add_view`
-method on the behalf of the developer. Various attributes can be
-specified on the ``<view>`` tag which influence the :term:`view
-configuration` it creates.
-
-Since the relative ordering of calls to
-:meth:`pyramid.config.Configurator.add_view` doesn't matter
-(see the sidebar entitled *View Dispatch and Ordering* within
-:ref:`adding_configuration`), the relative order of ``<view>`` tags in
-ZCML doesn't matter either. The following ZCML orderings are
-completely equivalent:
-
-.. topic:: Hello Before Goodbye
-
- .. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.hello_world"
- />
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
-.. topic:: Goodbye Before Hello
-
- .. code-block:: xml
- :linenos:
-
- <view
- name="goodbye"
- view="helloworld.goodbye_world"
- />
-
- <view
- view="helloworld.hello_world"
- />
-
-We've now configured a :app:`Pyramid` helloworld application
-declaratively. More information about this mode of configuration is
-available in :ref:`declarative_configuration` and within
-:ref:`zcml_reference`.
-
-.. index::
- single: ZCML granularity
-
-ZCML Granularity
-~~~~~~~~~~~~~~~~
-
-It's extremely helpful to third party application "extenders" (aka
-"integrators") if the :term:`ZCML` that composes the configuration for an
-application is broken up into separate files which do very specific things.
-These more specific ZCML files can be reintegrated within the application's
-main ``configure.zcml`` via ``<include file="otherfile.zcml"/>``
-declarations. When ZCML files contain sets of specific declarations, an
-integrator can avoid including any ZCML he does not want by including only
-ZCML files which contain the declarations he needs. He is not forced to
-"accept everything" or "use nothing".
-
-For example, it's often useful to put all ``<route>`` declarations in a
-separate ZCML file, as ``<route>`` statements have a relative ordering that
-is extremely important to the application: if an extender wants to add a
-route to the "middle" of the routing table, he will always need to disuse all
-the routes and cut and paste the routing configuration into his own
-application. It's useful for the extender to be able to disuse just a
-*single* ZCML file in this case, accepting the remainder of the configuration
-from other :term:`ZCML` files in the original application.
-
-Granularizing ZCML is not strictly required. An extender can always disuse
-*all* your ZCML, choosing instead to copy and paste it into his own package,
-if necessary. However, doing so is considerate, and allows for the best
-reusability. Sometimes it's possible to include only certain ZCML files from
-an application that contain only the registrations you really need, omitting
-others. But sometimes it's not. For brute force purposes, when you're
-getting ``view`` or ``route`` registrations that you don't actually want in
-your overridden application, it's always appropriate to just *not include*
-any ZCML file from the overridden application. Instead, just cut and paste
-the entire contents of the ``configure.zcml`` (and any ZCML file included by
-the overridden application's ``configure.zcml``) into your own package and
-omit the ``<include package=""/>`` ZCML declaration in the overriding
-package's ``configure.zcml``.
-
-.. _zcml_scanning:
-
-Scanning via ZCML
------------------
-
-:term:`ZCML` can invoke a :term:`scan` via its ``<scan>`` directive. If a
-ZCML file is processed that contains a scan directive, the package the ZCML
-file points to is scanned.
-
-.. code-block:: python
- :linenos:
-
- # helloworld.py
-
- from paste.httpserver import serve
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config()
- def hello(request):
- return Response('Hello')
-
- if __name__ == '__main__':
- from pyramid.config import Configurator
- config = Configurator()
- config.load_zcml('configure.zcml')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://namespaces.repoze.org">
-
- <!-- configure.zcml -->
-
- <include package="pyramid.includes"/>
- <scan package="."/>
-
- </configure>
-
-See also :ref:`scan_directive`.
-
-Which Mode Should I Use?
-------------------------
-
-A combination of imperative configuration, declarative configuration
-via ZCML and scanning can be used to configure any application. They
-are not mutually exclusive.
-
-The :app:`Pyramid` authors often recommend using mostly declarative
-configuration, because it's the more traditional form of configuration
-used in :app:`Pyramid` applications, it can be overridden and
-extended by third party deployers, and there are more examples for it
-"in the wild".
-
-However, imperative mode configuration can be simpler to understand,
-and the framework is not "opinionated" about the choice. This book
-presents examples in both styles, mostly interchangeably. You can
-choose the mode that best fits your brain as necessary.
-
-.. index::
- single: ZCML view configuration
-
-.. _mapping_views_using_zcml_section:
-
-View Configuration Via ZCML
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You may associate a view with a URL by adding :ref:`view_directive`
-declarations via :term:`ZCML` in a ``configure.zcml`` file. An
-example of a view declaration in ZCML is as follows:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".resources.Hello"
- view=".views.hello_world"
- name="hello.html"
- />
-
-The above maps the ``.views.hello_world`` view callable function to
-the following set of :term:`resource location` results:
-
-- A :term:`context` object which is an instance (or subclass) of the
- Python class represented by ``.resources.Hello``
-
-- A :term:`view name` equalling ``hello.html``.
-
-.. note:: Values prefixed with a period (``.``) for the ``context``
- and ``view`` attributes of a ``view`` declaration (such as those
- above) mean "relative to the Python package directory in which this
- :term:`ZCML` file is stored". So if the above ``view`` declaration
- was made inside a ``configure.zcml`` file that lived in the
- ``hello`` package, you could replace the relative ``.resources.Hello``
- with the absolute ``hello.resources.Hello``; likewise you could
- replace the relative ``.views.hello_world`` with the absolute
- ``hello.views.hello_world``. Either the relative or absolute form
- is functionally equivalent. It's often useful to use the relative
- form, in case your package's name changes. It's also shorter to
- type.
-
-You can also declare a *default view callable* for a :term:`resource` type:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".resources.Hello"
- view=".views.hello_world"
- />
-
-A *default view callable* simply has no ``name`` attribute. For the above
-registration, when a :term:`context` is found that is of the type
-``.resources.Hello`` and there is no :term:`view name` associated with the
-result of :term:`resource location`, the *default view callable* will be
-used. In this case, it's the view at ``.views.hello_world``.
-
-A default view callable can alternately be defined by using the empty
-string as its ``name`` attribute:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".resources.Hello"
- view=".views.hello_world"
- name=""
- />
-
-You may also declare that a view callable is good for any context type
-by using the special ``*`` character as the value of the ``context``
-attribute:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context="*"
- view=".views.hello_world"
- name="hello.html"
- />
-
-This indicates that when :app:`Pyramid` identifies that the
-:term:`view name` is ``hello.html`` and the context is of any type,
-the ``.views.hello_world`` view callable will be invoked.
-
-A ZCML ``view`` declaration's ``view`` attribute can also name a
-class. In this case, the rules described in :ref:`class_as_view`
-apply for the class which is named.
-
-See :ref:`view_directive` for complete ZCML directive documentation.
-
-.. index::
- single: ZCML directive; route
-
-.. _zcml_route_configuration:
-
-Configuring a Route via ZCML
-----------------------------
-
-Instead of using the imperative :meth:`pyramid.config.Configurator.add_route`
-method to add a new route, you can alternately use :term:`ZCML`.
-:ref:`route_directive` statements in a :term:`ZCML` file. For example, the
-following :term:`ZCML declaration` causes a route to be added to the
-application.
-
-.. code-block:: xml
- :linenos:
-
- <route
- name="myroute"
- pattern="/prefix/{one}/{two}"
- view=".views.myview"
- />
-
-.. note::
-
- Values prefixed with a period (``.``) within the values of ZCML
- attributes such as the ``view`` attribute of a ``route`` mean
- "relative to the Python package directory in which this
- :term:`ZCML` file is stored". So if the above ``route``
- declaration was made inside a ``configure.zcml`` file that lived in
- the ``hello`` package, you could replace the relative
- ``.views.myview`` with the absolute ``hello.views.myview`` Either
- the relative or absolute form is functionally equivalent. It's
- often useful to use the relative form, in case your package's name
- changes. It's also shorter to type.
-
-The order that routes are evaluated when declarative configuration is used
-is the order that they appear relative to each other in the ZCML file.
-
-See :ref:`route_directive` for full ``route`` ZCML directive
-documentation.
-
-.. _zcml_handler_configuration:
-
-Configuring a Handler via ZCML
-------------------------------
-
-Instead of using the imperative
-:meth:`pyramid.config.Configurator.add_handler` method to add a new
-route, you can alternately use :term:`ZCML`. :ref:`handler_directive`
-statements in a :term:`ZCML` file used by your application is a sign that
-you're using :term:`URL dispatch`. For example, the following :term:`ZCML
-declaration` causes a route to be added to the application.
-
-.. code-block:: xml
- :linenos:
-
- <handler
- route_name="myroute"
- pattern="/prefix/{action}"
- handler=".handlers.MyHandler"
- />
-
-.. note::
-
- Values prefixed with a period (``.``) within the values of ZCML attributes
- such as the ``handler`` attribute of a ``handler`` directive mean
- "relative to the Python package directory in which this :term:`ZCML` file
- is stored". So if the above ``handler`` declaration was made inside a
- ``configure.zcml`` file that lived in the ``hello`` package, you could
- replace the relative ``.views.MyHandler`` with the absolute
- ``hello.views.MyHandler`` Either the relative or absolute form is
- functionally equivalent. It's often useful to use the relative form, in
- case your package's name changes. It's also shorter to type.
-
-The order that the routes attached to handlers are evaluated when declarative
-configuration is used is the order that they appear relative to each other in
-the ZCML file.
-
-See :ref:`handler_directive` for full ``handler`` ZCML directive
-documentation.
-
-.. index::
- triple: view; zcml; static resource
-
-.. _zcml_static_assets_section:
-
-Serving Static Assets Using ZCML
---------------------------------
-
-Use of the ``static`` ZCML directive makes static assets available at a name
-relative to the application root URL, e.g. ``/static``.
-
-Note that the ``path`` provided to the ``static`` ZCML directive may be a
-fully qualified :term:`asset specification`, a package-relative path, or
-an *absolute path*. The ``path`` with the value ``a/b/c/static`` of a
-``static`` directive in a ZCML file that resides in the "mypackage" package
-will resolve to a package-qualified assets such as
-``some_package:a/b/c/static``.
-
-Here's an example of a ``static`` ZCML directive that will serve files
-up under the ``/static`` URL from the ``/var/www/static`` directory of
-the computer which runs the :app:`Pyramid` application using an
-absolute path.
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="/var/www/static"
- />
-
-Here's an example of a ``static`` directive that will serve files up
-under the ``/static`` URL from the ``a/b/c/static`` directory of the
-Python package named ``some_package`` using a fully qualified
-:term:`asset specification`.
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="some_package:a/b/c/static"
- />
-
-Here's an example of a ``static`` directive that will serve files up
-under the ``/static`` URL from the ``static`` directory of the Python
-package in which the ``configure.zcml`` file lives using a
-package-relative path.
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="static"
- />
-
-Whether you use for ``path`` a fully qualified asset specification,
-an absolute path, or a package-relative path, When you place your
-static files on the filesystem in the directory represented as the
-``path`` of the directive, you will then be able to view the static
-files in this directory via a browser at URLs prefixed with the
-directive's ``name``. For instance if the ``static`` directive's
-``name`` is ``static`` and the static directive's ``path`` is
-``/path/to/static``, ``http://localhost:6543/static/foo.js`` will
-return the file ``/path/to/static/dir/foo.js``. The static directory
-may contain subdirectories recursively, and any subdirectories may
-hold files; these will be resolved by the static view as you would
-expect.
-
-While the ``path`` argument can be a number of different things, the
-``name`` argument of the ``static`` ZCML directive can also be one of
-a number of things: a *view name* or a *URL*. The above examples have
-shown usage of the ``name`` argument as a view name. When ``name`` is
-a *URL* (or any string with a slash (``/``) in it), static assets
-can be served from an external webserver. In this mode, the ``name``
-is used as the URL prefix when generating a URL using
-:func:`pyramid.url.static_url`.
-
-For example, the ``static`` ZCML directive may be fed a ``name``
-argument which is ``http://example.com/images``:
-
-.. code-block:: xml
- :linenos:
-
- <static
- name="http://example.com/images"
- path="mypackage:images"
- />
-
-Because the ``static`` ZCML directive is provided with a ``name`` argument
-that is the URL prefix ``http://example.com/images``, subsequent calls to
-:func:`pyramid.url.static_url` with paths that start with the ``path``
-argument passed to :meth:`pyramid.url.static_url` will generate a URL
-something like ``http://example.com/logo.png``. The external webserver
-listening on ``example.com`` must be itself configured to respond properly to
-such a request. The :func:`pyramid.url.static_url` API is discussed in more
-detail later in this chapter.
-
-The :meth:`pyramid.config.Configurator.add_static_view` method offers
-an imperative equivalent to the ``static`` ZCML directive. Use of the
-``add_static_view`` imperative configuration method is completely equivalent
-to using ZCML for the same purpose. See :ref:`static_assets_section` for
-more information.
-
-.. index::
- pair: ZCML directive; asset
-
-.. _asset_zcml_directive:
-
-The ``asset`` ZCML Directive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Instead of using :meth:`pyramid.config.Configurator.override_asset` during
-:term:`imperative configuration`, an equivalent ZCML directive can be used.
-The ZCML ``asset`` tag is a frontend to using
-:meth:`pyramid.config.Configurator.override_asset`.
-
-An individual :app:`Pyramid` ``asset`` ZCML statement can override a
-single asset. For example:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package:templates/mytemplate.pt"
- override_with="another.package:othertemplates/anothertemplate.pt"
- />
-
-The string value passed to both ``to_override`` and ``override_with``
-attached to an ``asset`` directive is called an "asset specification". The
-colon separator in a specification separates the *package name* from the
-*asset name*. The colon and the following asset name are optional. If they
-are not specified, the override attempts to resolve every lookup into a
-package from the directory of another package. For example:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package"
- override_with="another.package"
- />
-
-Individual subdirectories within a package can also be overridden:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package:templates/"
- override_with="another.package:othertemplates/"
- />
-
-If you wish to override an asset directory with another directory, you *must*
-make sure to attach the slash to the end of both the ``to_override``
-specification and the ``override_with`` specification. If you fail to attach
-a slash to the end of an asset specification that points to a directory, you
-will get unexpected results.
-
-The package name in an asset specification may start with a dot, meaning that
-the package is relative to the package in which the ZCML file resides. For
-example:
-
-.. code-block:: xml
- :linenos:
-
- <asset
- to_override=".subpackage:templates/"
- override_with="another.package:templates/"
- />
-
-See also :ref:`asset_directive`.
-
-.. _zcml_authorization_policy:
-
-Enabling an Authorization Policy Via ZCML
------------------------------------------
-
-If you'd rather use :term:`ZCML` to specify an authorization policy
-than imperative configuration, modify the ZCML file loaded by your
-application (usually named ``configure.zcml``) to enable an
-authorization policy.
-
-For example, to enable a policy which compares the value of an "auth ticket"
-cookie passed in the request's environment which contains a reference to a
-single :term:`principal` against the principals present in any :term:`ACL`
-found in the resource tree when attempting to call some :term:`view`, modify
-your ``configure.zcml`` to look something like this:
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- views and other directives before this... -->
-
- <authtktauthenticationpolicy
- secret="iamsosecret"/>
-
- <aclauthorizationpolicy/>
-
- </configure>
-
-"Under the hood", these statements cause an instance of the class
-:class:`pyramid.authentication.AuthTktAuthenticationPolicy` to be
-injected as the :term:`authentication policy` used by this application
-and an instance of the class
-:class:`pyramid.authorization.ACLAuthorizationPolicy` to be
-injected as the :term:`authorization policy` used by this application.
-
-:app:`Pyramid` ships with a number of authorization and
-authentication policy ZCML directives that should prove useful. See
-:ref:`authentication_policies_directives_section` and
-:ref:`authorization_policies_directives_section` for more information.
-
-.. index::
- pair: ZCML directive; authentication policy
-
-.. _authentication_policies_directives_section:
-
-Built-In Authentication Policy ZCML Directives
-----------------------------------------------
-
-Instead of configuring an authentication policy and authorization
-policy imperatively, :app:`Pyramid` ships with a few "pre-chewed"
-authentication policy ZCML directives that you can make use of within
-your application.
-
-``authtktauthenticationpolicy``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When this directive is used, authentication information is obtained
-from an "auth ticket" cookie value, assumed to be set by a custom
-login form.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <authtktauthenticationpolicy
- secret="goshiamsosecret"
- callback=".somemodule.somefunc"
- cookie_name="mycookiename"
- secure="false"
- include_ip="false"
- timeout="86400"
- reissue_time="600"
- max_age="31536000"
- path="/"
- http_only="false"
- />
-
-See :ref:`authtktauthenticationpolicy_directive` for details about
-this directive.
-
-``remoteuserauthenticationpolicy``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When this directive is used, authentication information is obtained
-from a ``REMOTE_USER`` key in the WSGI environment, assumed to
-be set by a WSGI server or an upstream middleware component.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <remoteuserauthenticationpolicy
- environ_key="REMOTE_USER"
- callback=".somemodule.somefunc"
- />
-
-See :ref:`remoteuserauthenticationpolicy_directive` for detailed
-information.
-
-``repozewho1authenticationpolicy``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When this directive is used, authentication information is obtained
-from a ``repoze.who.identity`` key in the WSGI environment, assumed to
-be set by :term:`repoze.who` middleware.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <repozewho1authenticationpolicy
- identifier_name="auth_tkt"
- callback=".somemodule.somefunc"
- />
-
-See :ref:`repozewho1authenticationpolicy_directive` for detailed
-information.
-
-.. index::
- pair: ZCML directive; authorization policy
-
-.. _authorization_policies_directives_section:
-
-Built-In Authorization Policy ZCML Directives
----------------------------------------------
-
-``aclauthorizationpolicy``
-
-When this directive is used, authorization information is obtained
-from :term:`ACL` objects attached to resources.
-
-An example of its usage, with all attributes fully expanded:
-
-.. code-block:: xml
- :linenos:
-
- <aclauthorizationpolicy/>
-
-In other words, it has no configuration attributes; its existence in a
-``configure.zcml`` file enables it.
-
-See :ref:`aclauthorizationpolicy_directive` for detailed information.
-
-.. _zcml_adding_and_overriding_renderers:
-
-Adding and Overriding Renderers via ZCML
-----------------------------------------
-
-New templating systems and serializers can be associated with :app:`Pyramid`
-renderer names. To this end, configuration declarations can be made which
-override an existing :term:`renderer factory` and which add a new renderer
-factory.
-
-Adding or overriding a renderer via ZCML is accomplished via the
-:ref:`renderer_directive` ZCML directive.
-
-For example, to add a renderer which renders views which have a
-``renderer`` attribute that is a path that ends in ``.jinja2``:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".jinja2"
- factory="my.package.MyJinja2Renderer"
- />
-
-The ``factory`` attribute is a :term:`dotted Python name` that must
-point to an implementation of a :term:`renderer factory`.
-
-The ``name`` attribute is the renderer name.
-
-Registering a Renderer Factory
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-See :ref:`adding_a_renderer` for more information for the definition of a
-:term:`renderer factory`. Here's an example of the registration of a simple
-:term:`renderer factory` via ZCML:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name="amf"
- factory="my.package.MyAMFRenderer"
- />
-
-Adding the above ZCML to your application will allow you to use the
-``my.package.MyAMFRenderer`` renderer factory implementation in view
-configurations by subseqently referring to it as ``amf`` in the ``renderer``
-attribute of a :term:`view configuration`:
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="mypackage.views.my_view"
- renderer="amf"
- />
-
-Here's an example of the registration of a more complicated renderer
-factory, which expects to be passed a filesystem path:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".jinja2"
- factory="my.package.MyJinja2Renderer"
- />
-
-Adding the above ZCML to your application will allow you to use the
-``my.package.MyJinja2Renderer`` renderer factory implementation in
-view configurations by referring to any ``renderer`` which *ends in*
-``.jinja`` in the ``renderer`` attribute of a :term:`view
-configuration`:
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="mypackage.views.my_view"
- renderer="templates/mytemplate.jinja2"
- />
-
-When a :term:`view configuration` which has a ``name`` attribute that does
-contain a dot, such as ``templates/mytemplate.jinja2`` above is encountered at
-startup time, the value of the name attribute is split on its final dot. The
-second element of the split is typically the filename extension. This
-extension is used to look up a renderer factory for the configured view. Then
-the value of ``renderer`` is passed to the factory to create a renderer for the
-view. In this case, the view configuration will create an instance of a
-``Jinja2Renderer`` for each view configuration which includes anything ending
-with ``.jinja2`` as its ``renderer`` value. The ``name`` passed to the
-``Jinja2Renderer`` constructor will be whatever the user passed as
-``renderer=`` to the view configuration.
-
-See also :ref:`renderer_directive` and
-:meth:`pyramid.config.Configurator.add_renderer`.
-
-Overriding an Existing Renderer
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can associate more than one filename extension with the same
-existing renderer implementation as necessary if you need to use a
-different file extension for the same kinds of templates. For
-example, to associate the ``.zpt`` extension with the Chameleon ZPT
-renderer factory, use:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".zpt"
- factory="pyramid.chameleon_zpt.renderer_factory"
- />
-
-After you do this, :app:`Pyramid` will treat templates ending in
-both the ``.pt`` and ``.zpt`` filename extensions as Chameleon ZPT
-templates.
-
-To override the default mapping in which files with a ``.pt``
-extension are rendered via a Chameleon ZPT page template renderer, use
-a variation on the following in your application's ZCML:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".pt"
- factory="my.package.pt_renderer"
- />
-
-After you do this, the :term:`renderer factory` in
-``my.package.pt_renderer`` will be used to render templates which end
-in ``.pt``, replacing the default Chameleon ZPT renderer.
-
-To override the default mapping in which files with a ``.txt``
-extension are rendered via a Chameleon text template renderer, use a
-variation on the following in your application's ZCML:
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- name=".txt"
- factory="my.package.text_renderer"
- />
-
-After you do this, the :term:`renderer factory` in
-``my.package.text_renderer`` will be used to render templates which
-end in ``.txt``, replacing the default Chameleon text renderer.
-
-To associate a *default* renderer with *all* view configurations (even
-ones which do not possess a ``renderer`` attribute), use a variation
-on the following (ie. omit the ``name`` attribute to the renderer
-tag):
-
-.. code-block:: xml
- :linenos:
-
- <renderer
- factory="pyramid.renderers.json_renderer_factory"
- />
-
-See also :ref:`renderer_directive` and
-:meth:`pyramid.config.Configurator.add_renderer`.
-
-.. _zcml_adding_a_translation_directory:
-
-Adding a Translation Directory via ZCML
----------------------------------------
-
-You can add a translation directory via ZCML by using the
-:ref:`translationdir_directive` ZCML directive:
-
-.. code-block:: xml
- :linenos:
-
- <translationdir dir="my.application:locale/"/>
-
-A message catalog in a translation directory added via
-:ref:`translationdir_directive` will be merged into translations from
-a message catalog added earlier if both translation directories
-contain translations for the same locale and :term:`translation
-domain`.
-
-See also :ref:`translationdir_directive` and
-:ref:`adding_a_translation_directory`.
-
-.. _zcml_adding_a_locale_negotiator:
-
-Adding a Custom Locale Negotiator via ZCML
-------------------------------------------
-
-You can add a custom locale negotiator via ZCML by using the
-:ref:`localenegotiator_directive` ZCML directive:
-
-.. code-block:: xml
- :linenos:
-
- <localenegotiator
- negotiator="my_application.my_module.my_locale_negotiator"
- />
-
-See also :ref:`custom_locale_negotiator` and
-:ref:`localenegotiator_directive`.
-
-.. index::
- pair: subscriber; ZCML directive
-
-.. _zcml_event_listener:
-
-Configuring an Event Listener via ZCML
---------------------------------------
-
-You can configure an :term:`subscriber` by modifying your application's
-``configure.zcml``. Here's an example of a bit of XML you can add to the
-``configure.zcml`` file which registers the above ``mysubscriber`` function,
-which we assume lives in a ``subscribers.py`` module within your application:
-
-.. code-block:: xml
- :linenos:
-
- <subscriber
- for="pyramid.events.NewRequest"
- handler=".subscribers.mysubscriber"
- />
-
-See also :ref:`subscriber_directive` and :ref:`events_chapter`.
-
-.. index::
- single: not found view
-
-.. _notfound_zcml:
-
-Configuring a Not Found View via ZCML
--------------------------------------
-
-If your application uses :term:`ZCML`, you can replace the Not Found view by
-placing something like the following ZCML in your ``configure.zcml`` file.
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.NotFound"
- />
-
-Replace ``helloworld.views.notfound_view`` with the Python dotted name to the
-notfound view you want to use.
-
-See :ref:`changing_the_notfound_view` for more information.
-
-.. index::
- single: forbidden view
-
-.. _forbidden_zcml:
-
-Configuring a Forbidden View via ZCML
--------------------------------------
-
-If your application uses :term:`ZCML`, you can replace the Forbidden view by
-placing something like the following ZCML in your ``configure.zcml`` file.
-
-.. code-block:: xml
- :linenos:
-
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.Forbidden"
- />
-
-Replace ``helloworld.views.forbidden_view`` with the Python dotted name to
-the forbidden view you want to use.
-
-See :ref:`changing_the_forbidden_view` for more information.
-
-.. _changing_traverser_zcml:
-
-Configuring an Alternate Traverser via ZCML
--------------------------------------------
-
-Use an ``adapter`` stanza in your application's ``configure.zcml`` to
-change the default traverser:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="*"
- />
-
-Or to register a traverser for a specific resource type:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="myapp.resources.MyRoot"
- />
-
-See :ref:`changing_the_traverser` for more information.
-
-.. index::
- single: url generator
-
-.. _changing_resource_url_zcml:
-
-Changing ``resource_url`` URL Generation via ZCML
--------------------------------------------------
-
-You can change how :func:`pyramid.url.resource_url` generates a URL for a
-specific type of resource by adding an adapter statement to your
-``configure.zcml``.
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.URLGenerator"
- provides="pyramid.interfaces.IContextURL"
- for="myapp.resources.MyRoot *"
- />
-
-See :ref:`changing_resource_url` for more information.
-
-.. _changing_request_factory_zcml:
-
-Changing the Request Factory via ZCML
--------------------------------------
-
-A ``MyRequest`` class can be registered via ZCML as a request factory through
-the use of the ZCML ``utility`` directive. In the below, we assume it lives
-in a package named ``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.MyRequest"
- provides="pyramid.interfaces.IRequestFactory"
- />
-
-See :ref:`changing_request_factory` for more information.
-
-.. _adding_renderer_globals_zcml:
-
-Changing the Renderer Globals Factory via ZCML
-----------------------------------------------
-
-A renderer globals factory can be registered via ZCML as a through the use of
-the ZCML ``utility`` directive. In the below, we assume a
-``renderers_globals_factory`` function lives in a package named
-``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.renderer_globals_factory"
- provides="pyramid.interfaces.IRendererGlobalsFactory"
- />
-
-See :ref:`adding_renderer_globals` for more information.
-
diff --git a/docs/narr/environment.rst b/docs/narr/environment.rst
index 7caa1dcc6..7b7946aae 100644
--- a/docs/narr/environment.rst
+++ b/docs/narr/environment.rst
@@ -38,10 +38,11 @@ application-specific configuration settings.
Reloading Templates
-------------------
-When this value is true, reload templates without a restart, so you can see
-changes to templates take effect immediately during development. This flag
-is meaningful to Chameleon and Mako templates, as well as most third-party
-template rendering extensions.
+When this value is true, templates are automatically reloaded whenever
+they are modified without restarting the application, so you can see
+changes to templates take effect immediately during development. This
+flag is meaningful to Chameleon and Mako templates, as well as most
+third-party template rendering extensions.
+---------------------------------+-----------------------------+
| Environment Variable Name | Config File Setting Name |
@@ -335,6 +336,14 @@ with ``reload_``). on in one fell swoop, you can use
affect settings that do not start with ``reload_*`` such as
``debug_notfound``.
+.. note::
+ Specifying configuration settings via environment variables is generally
+ most useful during development, where you may wish to augment or
+ override the more permanent settings in the configuration file.
+ This is useful because many of the reload and debug settings may
+ have performance or security (i.e., disclosure) implications
+ that make them undesirable in a production environment.
+
.. index::
single: reload_templates
single: reload_assets
diff --git a/docs/narr/events.rst b/docs/narr/events.rst
index 06b30883f..224eeca16 100644
--- a/docs/narr/events.rst
+++ b/docs/narr/events.rst
@@ -38,52 +38,51 @@ you'll need to use the
need to use the :func:`pyramid.events.subscriber` decorator to decorate a
function found via a :term:`scan`.
-.. topic:: Configuring an Event Listener Imperatively
+Configuring an Event Listener Imperatively
+------------------------------------------
- You can imperatively configure a subscriber function to be called
- for some event type via the
- :meth:`pyramid.config.Configurator.add_subscriber`
- method (see also :term:`Configurator`):
+You can imperatively configure a subscriber function to be called
+for some event type via the
+:meth:`pyramid.config.Configurator.add_subscriber`
+method (see also :term:`Configurator`):
- .. code-block:: python
- :linenos:
-
- from pyramid.events import NewRequest
+.. code-block:: python
+ :linenos:
- from subscribers import mysubscriber
+ from pyramid.events import NewRequest
- # "config" below is assumed to be an instance of a
- # pyramid.config.Configurator object
+ from subscribers import mysubscriber
- config.add_subscriber(mysubscriber, NewRequest)
+ # "config" below is assumed to be an instance of a
+ # pyramid.config.Configurator object
- The first argument to
- :meth:`pyramid.config.Configurator.add_subscriber` is the
- subscriber function (or a :term:`dotted Python name` which refers
- to a subscriber callable); the second argument is the event type.
+ config.add_subscriber(mysubscriber, NewRequest)
-.. topic:: Configuring an Event Listener Using a Decorator
+The first argument to
+:meth:`pyramid.config.Configurator.add_subscriber` is the
+subscriber function (or a :term:`dotted Python name` which refers
+to a subscriber callable); the second argument is the event type.
- You can configure a subscriber function to be called for some event
- type via the :func:`pyramid.events.subscriber` function.
+Configuring an Event Listener Using a Decorator
+-----------------------------------------------
- .. code-block:: python
- :linenos:
+You can configure a subscriber function to be called for some event
+type via the :func:`pyramid.events.subscriber` function.
- from pyramid.events import NewRequest
- from pyramid.events import subscriber
+.. code-block:: python
+ :linenos:
- @subscriber(NewRequest)
- def mysubscriber(event):
- event.request.foo = 1
+ from pyramid.events import NewRequest
+ from pyramid.events import subscriber
- When the :func:`pyramid.subscriber` decorator is used a
- :term:`scan` must be performed against the package containing the
- decorated function for the decorator to have any effect. See
- :func:`pyramid.subscriber` for more information.
+ @subscriber(NewRequest)
+ def mysubscriber(event):
+ event.request.foo = 1
-.. note:: You can also configure an event listener via ZCML. See
- :ref:`zcml_event_listener`.
+When the :func:`pyramid.subscriber` decorator is used a
+:term:`scan` must be performed against the package containing the
+decorated function for the decorator to have any effect. See
+:func:`pyramid.subscriber` for more information.
Either of the above registration examples implies that every time the
:app:`Pyramid` framework emits an event object that supplies an
diff --git a/docs/narr/extending.rst b/docs/narr/extending.rst
index 524dcb2ac..c709e1f8f 100644
--- a/docs/narr/extending.rst
+++ b/docs/narr/extending.rst
@@ -108,7 +108,7 @@ extensible and overrideable. :term:`ZCML` declarations that belong to an
application can be overridden and extended by integrators as necessary in a
similar fashion. If you use only :term:`ZCML` to configure your application,
it will automatically be maximally extensible without any manual effort. See
-:ref:`declarative_chapter` for information about using ZCML.
+:term:`pyramid_zcml` for information about using ZCML.
Fundamental Plugpoints
~~~~~~~~~~~~~~~~~~~~~~
@@ -121,9 +121,9 @@ ZCML ``<route>`` directive). Views are declarations made using the
directive). Assets are files that are accessed by :app:`Pyramid` using the
:term:`pkg_resources` API such as static files and templates via a
:term:`asset specification`. Other directives and configurator methods also
-deal in routes, views, and assets. For example,
-:meth:`pyramid.config.Configurator.add_handler` adds a single route, and some
-number of views.
+deal in routes, views, and assets. For example, ``add_handler`` directive of
+the ``pyramid_handlers`` package adds a single route, and some number of
+views.
.. index::
single: extending an existing application
@@ -196,7 +196,7 @@ like this:
:ref:`creating_a_project` for more information.
- In the new package, create Python files containing views and other
- overridden elements, such as templates and static resources as necessary.
+ overridden elements, such as templates and static assets as necessary.
- Install the new package into the same Python environment as the original
application (e.g. ``python setup.py develop`` or ``python setup.py
@@ -278,7 +278,7 @@ into the override package's file and changing them as necessary. Then
disinclude any ``add_route`` statements from the original application.
.. index::
- pair: overriding; resources
+ pair: overriding; assets
.. _overriding_resources:
@@ -286,10 +286,10 @@ Overriding Assets
~~~~~~~~~~~~~~~~~
Assets are files on the filesystem that are accessible within a Python
-*package*. An entire chapter is devoted to resources: :ref:`assets_chapter`.
+*package*. An entire chapter is devoted to assets: :ref:`assets_chapter`.
Within this chapter is a section named :ref:`overriding_assets_section`.
This section of that chapter describes in detail how to override package
-resources with other resources by using the
+assets with other assets by using the
:meth:`pyramid.config.Configurator.override_asset` method. Add such
``override_asset`` calls to your override package's ``__init__.py`` to
perform overrides.
diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst
index cb1e54b19..34e6981a4 100644
--- a/docs/narr/firstapp.rst
+++ b/docs/narr/firstapp.rst
@@ -10,7 +10,7 @@ more detail how it works.
.. note::
If you're a "theory-first" kind of person, you might choose to read
- :ref:`resourcelocation_chapter` and :ref:`views_chapter` before diving into
+ :ref:`urldispatch_chapter` and :ref:`views_chapter` before diving into
the code that follows, but it's not necessary if -- like many programmers
-- you're willing to "go with the flow".
@@ -323,8 +323,8 @@ For more information about the API of a :term:`Configurator` object,
see :class:`pyramid.config.Configurator` .
For more information about :term:`view configuration`, see
-:ref:`views_chapter`.
+:ref:`view_config_chapter`.
An example of using *declarative* configuration (:term:`ZCML`) instead of
imperative configuration to create a similar "hello world" is available
-within :ref:`declarative_configuration`.
+within the documentation for :term:`pyramid_zcml`.
diff --git a/docs/narr/flash.rst b/docs/narr/flash.rst
deleted file mode 100644
index d41c2cdaf..000000000
--- a/docs/narr/flash.rst
+++ /dev/null
@@ -1,107 +0,0 @@
-.. _flash_chapter:
-
-Flash Messages
-==============
-
-"Flash messages" are simply a queue of message strings stored in the
-:term:`session`. To use flash messaging, you must enable a :term:`session
-factory` as described in :ref:`using_the_default_session_factory` or
-:ref:`using_alternate_session_factories`.
-
-Flash messaging has two main uses: to display a status message only once to
-the user after performing an internal redirect, and to allow generic code to
-log messages for single-time display without having direct access to an HTML
-template. The user interface consists of a number of methods of the
-:term:`session` object.
-
-Using the ``session.flash`` Method
-----------------------------------
-
-To add a message to a flash message queue, use a session object's ``flash``
-method:
-
-.. code-block:: python
- :linenos:
-
- request.session.flash('mymessage')
-
-The ``.flash`` method appends a message to a flash queue, creating the queue
-if necessary.
-
-``.flash`` accepts three arguments:
-
-.. method:: flash(message, queue='', allow_duplicate=True)
-
-The ``message`` argument is required. It represents a message you wish to
-later display to a user. It is usually a string but the ``message`` you
-provide is not modified in any way.
-
-The ``queue`` argument allows you to choose a queue to which to append the
-message you provide. This can be used to push different kinds of messages
-into flash storage for later display in different places on a page. You cam
-pass any name for your queue, but it must be a string. The default value is
-the empty string, which chooses the default queue. Each queue is independent,
-and can be popped by ``pop_flash`` or examined via ``peek_flash`` separately.
-``queue`` defaults to the empty string. The empty string represents the
-default flash message queue.
-
-.. code-block:: python
-
- request.session.flash(msg, 'myappsqueue')
-
-The ``allow_duplicate`` argument, which defaults to ``True``. If this is
-``False``, if you attempt to add a message to a queue which is already
-present in the queue, it will not be added.
-
-Using the ``session.pop_flash`` Method
---------------------------------------
-
-Once one or more messages has been added to a flash queue by the
-``session.flash`` API, the ``session.pop_flash`` API can be used to pop that
-queue and return it for use.
-
-To pop a particular queue of messages from the flash object, use the session
-object's ``pop_flash`` method.
-
-.. code-block:: python
- :linenos:
-
- >>> request.session.flash('info message')
- >>> request.session.pop_flash()
- ['info message']
-
-Calling ``session.pop_flash()`` again like above without a corresponding call
-to ``session.flash`` will return an empty list, because the queue has already
-been popped.
-
-.. code-block:: python
- :linenos:
-
- >>> request.session.flash('info message')
- >>> request.session.pop_flash()
- ['info message']
- >>> request.session.pop_flash()
- []
-
-The object returned from ``pop_flash`` is a list.
-
-Using the ``session.pop_flash`` Method
---------------------------------------
-
-Once one or more messages has been added to a flash queue by the
-``session.flash`` API, the ``session.peek_flash`` API can be used to "peek"
-at that queue. Unlike ``session.pop_flash``, the queue is not popped from
-flash storage.
-
-.. code-block:: python
- :linenos:
-
- >>> request.session.flash('info message')
- >>> request.session.peek_flash()
- ['info message']
- >>> request.session.peek_flash()
- ['info message']
- >>> request.session.pop_flash()
- ['info message']
- >>> request.session.peek_flash()
- []
diff --git a/docs/narr/forms.rst b/docs/narr/forms.rst
new file mode 100644
index 000000000..080f02159
--- /dev/null
+++ b/docs/narr/forms.rst
@@ -0,0 +1,126 @@
+.. _forms_chapter:
+
+.. index::
+ single: unicode, views, and forms
+ single: forms, views, and unicode
+ single: views, forms, and unicode
+
+Form Handling
+=============
+
+Handling Form Submissions in View Callables (Unicode and Character Set Issues)
+------------------------------------------------------------------------------
+
+Most web applications need to accept form submissions from web browsers and
+various other clients. In :app:`Pyramid`, form submission handling logic is
+always part of a :term:`view`. For a general overview of how to handle form
+submission data using the :term:`WebOb` API, see :ref:`webob_chapter` and
+`"Query and POST variables" within the WebOb documentation
+<http://pythonpaste.org/webob/reference.html#query-post-variables>`_.
+:app:`Pyramid` defers to WebOb for its request and response implementations,
+and handling form submission data is a property of the request
+implementation. Understanding WebOb's request API is the key to
+understanding how to process form submission data.
+
+There are some defaults that you need to be aware of when trying to handle
+form submission data in a :app:`Pyramid` view. Having high-order (i.e.,
+non-ASCII) characters in data contained within form submissions is
+exceedingly common, and the UTF-8 encoding is the most common encoding used
+on the web for character data. Since Unicode values are much saner than
+working with and storing bytestrings, :app:`Pyramid` configures the
+:term:`WebOb` request machinery to attempt to decode form submission values
+into Unicode from UTF-8 implicitly. This implicit decoding happens when view
+code obtains form field values via the ``request.params``, ``request.GET``,
+or ``request.POST`` APIs (see :ref:`request_module` for details about these
+APIs).
+
+.. note::
+
+ Many people find the difference between Unicode and UTF-8 confusing.
+ Unicode is a standard for representing text that supports most of the
+ world's writing systems. However, there are many ways that Unicode data
+ can be encoded into bytes for transit and storage. UTF-8 is a specific
+ encoding for Unicode, that is backwards-compatible with ASCII. This makes
+ UTF-8 very convenient for encoding data where a large subset of that data
+ is ASCII characters, which is largely true on the web. UTF-8 is also the
+ standard character encoding for URLs.
+
+As an example, let's assume that the following form page is served up to a
+browser client, and its ``action`` points at some :app:`Pyramid` view code:
+
+.. code-block:: xml
+ :linenos:
+
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ </head>
+ <form method="POST" action="myview">
+ <div>
+ <input type="text" name="firstname"/>
+ </div>
+ <div>
+ <input type="text" name="lastname"/>
+ </div>
+ <input type="submit" value="Submit"/>
+ </form>
+ </html>
+
+The ``myview`` view code in the :app:`Pyramid` application *must* expect that
+the values returned by ``request.params`` will be of type ``unicode``, as
+opposed to type ``str``. The following will work to accept a form post from
+the above form:
+
+.. code-block:: python
+ :linenos:
+
+ def myview(request):
+ firstname = request.params['firstname']
+ lastname = request.params['lastname']
+
+But the following ``myview`` view code *may not* work, as it tries to decode
+already-decoded (``unicode``) values obtained from ``request.params``:
+
+.. code-block:: python
+ :linenos:
+
+ def myview(request):
+ # the .decode('utf-8') will break below if there are any high-order
+ # characters in the firstname or lastname
+ firstname = request.params['firstname'].decode('utf-8')
+ lastname = request.params['lastname'].decode('utf-8')
+
+For implicit decoding to work reliably, you should ensure that every form you
+render that posts to a :app:`Pyramid` view explicitly defines a charset
+encoding of UTF-8. This can be done via a response that has a
+``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form above,
+with a ``meta http-equiv`` tag that implies that the charset is UTF-8 within
+the HTML ``head`` of the page containing the form. This must be done
+explicitly because all known browser clients assume that they should encode
+form data in the same character set implied by ``Content-Type`` value of the
+response containing the form when subsequently submitting that form. There is
+no other generally accepted way to tell browser clients which charset to use
+to encode form data. If you do not specify an encoding explicitly, the
+browser client will choose to encode form data in its default character set
+before submitting it, which may not be UTF-8 as the server expects. If a
+request containing form data encoded in a non-UTF8 charset is handled by your
+view code, eventually the request code accessed within your view will throw
+an error when it can't decode some high-order character encoded in another
+character set within form data, e.g., when ``request.params['somename']`` is
+accessed.
+
+If you are using the :class:`pyramid.response.Response` class to generate a
+response, or if you use the ``render_template_*`` templating APIs, the UTF-8
+charset is set automatically as the default via the ``Content-Type`` header.
+If you return a ``Content-Type`` header without an explicit charset, a
+request will add a ``;charset=utf-8`` trailer to the ``Content-Type`` header
+value for you, for response content types that are textual
+(e.g. ``text/html``, ``application/xml``, etc) as it is rendered. If you are
+using your own response object, you will need to ensure you do this yourself.
+
+.. note:: Only the *values* of request params obtained via
+ ``request.params``, ``request.GET`` or ``request.POST`` are decoded
+ to Unicode objects implicitly in the :app:`Pyramid` default
+ configuration. The keys are still (byte) strings.
+
+
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 2917b5254..b3b41046f 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -70,9 +70,6 @@ Here's some sample code that implements a minimal NotFound view callable:
:exc:`pyramid.exceptions.NotFound` exception instance. If available, the
resource context will still be available as ``request.context``.
-For information about how to configure a not found view via :term:`ZCML`, see
-:ref:`notfound_zcml`.
-
.. index::
single: forbidden view
@@ -83,7 +80,7 @@ Changing the Forbidden View
When :app:`Pyramid` can't authorize execution of a view based on the
:term:`authorization policy` in use, it invokes a :term:`forbidden view`.
-The default forbidden response has a 401 status code and is very plain, but
+The default forbidden response has a 403 status code and is very plain, but
the view which generates it can be overridden as necessary.
The :term:`forbidden view` callable is a view callable like any other. The
@@ -132,15 +129,6 @@ Here's some sample code that implements a minimal forbidden view:
``debug_authorization`` environment setting is true than it is when
it is false.
-.. warning:: the default forbidden view sends a response with a ``401
- Unauthorized`` status code for backwards compatibility reasons.
- You can influence the status code of Forbidden responses by using
- an alternate forbidden view. For example, it would make sense to
- return a response with a ``403 Forbidden`` status code.
-
-For information about how to configure a forbidden view via :term:`ZCML`, see
-:ref:`forbidden_zcml`.
-
.. index::
single: request factory
@@ -185,8 +173,6 @@ already constructed a :term:`configurator` it can also be registered via the
config = Configurator()
config.set_request_factory(MyRequest)
-To use ZCML for the same purpose, see :ref:`changing_request_factory_zcml`.
-
.. index::
single: renderer globals
@@ -242,9 +228,6 @@ already constructed a :term:`configurator` it can also be registered via the
Another mechanism which allows event subscribers to add renderer global values
exists in :ref:`beforerender_event`.
-If you'd rather ZCML to register a renderer globals factory, see
-:ref:`adding_renderer_globals_zcml`.
-
.. index::
single: before render event
@@ -365,10 +348,11 @@ parameter: ``request``. For example:
transaction.commit()
request.add_finished_callback(commit_callback)
-Finished callbacks are called in the order they're added ( first- to
-most-recently- added). Finished callbacks (unlike a :term:`response
-callback`) are *always* called, even if an exception happens in application
-code that prevents a response from being generated.
+Finished callbacks are called in the order they're added
+(first-to-most-recently-added). Finished callbacks (unlike a
+:term:`response callback`) are *always* called, even if an exception
+happens in application code that prevents a response from being
+generated.
The set of finished callbacks associated with a request are called *very
late* in the processing of that request; they are essentially the very last
@@ -474,9 +458,6 @@ when the application :term:`root factory` returned an instance of the
``myapp.resources.MyRoot`` object. Otherwise it would use the default
:app:`Pyramid` traverser to do traversal.
-For information about how to configure an alternate traverser via
-:term:`ZCML`, see :ref:`changing_traverser_zcml`.
-
.. index::
single: url generator
@@ -541,6 +522,98 @@ The default context URL generator is available for perusal as the class
:term:`Pylons` GitHub Pyramid repository.
.. index::
+ single: view mapper
+
+.. _using_a_view_mapper:
+
+Using a View Mapper
+-------------------
+
+The default calling conventions for view callables are documented in the
+:ref:`views_chapter` chapter. You can change the way users define view
+callbles by employing a :term:`view mapper`.
+
+A view mapper is an object that accepts a set of keyword arguments and which
+returns a callable. The returned callable is called with the :term:`view
+callable` object. The returned callable should itself return another
+callable which can be called with the "internal calling protocol" ``(context,
+request)``.
+
+You can use a view mapper in a number of ways:
+
+- by setting a ``__view_mapper__`` attribute (which is the view mapper
+ object) on the view callable itself
+
+- by passing the mapper object to
+ :meth:`pyramid.config.Configurator.add_view` (or its declarative/decorator
+ equivalents) as the ``mapper`` argument.
+
+- by registering a *default* view mapper.
+
+Here's an example of a view mapper that emulates (somewhat) a Pylons
+"controller". The mapper is initialized with some keyword arguments. Its
+``__call__`` method accepts the view object (which will be a class). It uses
+the ``attr`` keyword argument it is passed to determine which attribute
+should be used as an action method. The wrapper method it returns accepts
+``(context, request)`` and returns the result of calling the action method
+with keyword arguments implied by the :term:`matchdict` after popping the
+``action`` out of it. This somewhat emulates the Pylons style of calling
+action methods with routing parameters pulled out of the route matching dict
+as keyword arguments.
+
+.. code-block:: python
+ :linenos:
+
+ # framework
+
+ class PylonsControllerViewMapper(object):
+ def __init__(self, **kw):
+ self.kw = kw
+
+ def __call__(self, view):
+ attr = self.kw['attr']
+ def wrapper(context, request):
+ matchdict = request.matchdict.copy()
+ matchdict.pop('action', None)
+ inst = view()
+ meth = getattr(inst, attr)
+ return meth(**matchdict)
+ return wrapper
+
+ class BaseController(object):
+ __view_mapper__ = PylonsControllerViewMapper
+
+A user might make use of these framework components like so:
+
+.. code-block:: python
+ :linenos:
+
+ # user application
+
+ from webob import Response
+ from pyramid.config import Configurator
+ import pyramid_handlers
+ from paste.httpserver import serve
+
+ class MyController(BaseController):
+ def index(self, id):
+ return Response(id)
+
+ if __name__ == '__main__':
+ config = Configurator()
+ config.include(pyramid_handlers)
+ config.add_handler('one', '/{id}', MyController, action='index')
+ config.add_handler('two', '/{action}/{id}', MyController)
+ serve(config.make_wsgi_app())
+
+The :meth:`pyramid.config.Configurator.set_default_mapper` method can be used
+to set a *default* view mapper (overriding the superdefault view mapper used
+by Pyramid itself).
+
+A *single* view registration can use a view mapper by passing the mapper as
+the ``mapper`` argument to :meth:`pyramid.config.Configuration.add_view`.
+
+.. index::
single: configuration decorator
.. _registering_configuration_decorators:
@@ -581,7 +654,7 @@ follows:
self.path = path
def register(self, scanner, name, wrapped):
- registry = get_current_registry()
+ registry = scanner.config.registry
registry.getUtility(IMyUtility).register(
self.path, wrapped
)
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
index c2a5b8ce7..83973a17e 100644
--- a/docs/narr/i18n.rst
+++ b/docs/narr/i18n.rst
@@ -867,11 +867,11 @@ which itself includes an ``LC_MESSAGES`` directory. Each
Each ``.mo`` file represents a :term:`message catalog`, which is used
to provide translations to your application.
-Adding a :term:`translation directory` registers all of its
-constituent :term:`message catalog` files (all of the ``.mo`` files
-found within all ``LC_MESSAGES`` directories within each locale
-directory in the translation directory) within your :app:`Pyramid`
-application to be available to use for translation services.
+Adding a :term:`translation directory` registers all of its constituent
+:term:`message catalog` files within your :app:`Pyramid` application to
+be available to use for translation services. This includes all of the
+``.mo`` files found within all ``LC_MESSAGES`` directories within each
+locale directory in the translation directory.
You can add a translation directory imperatively by using the
:meth:`pyramid.config.Configurator.add_translation_dirs` during
@@ -890,9 +890,6 @@ will be merged into translations from a message catalog added earlier
if both translation directories contain translations for the same
locale and :term:`translation domain`.
-.. note:: You can also add a translation directory via ZCML. See
- :ref:`zcml_adding_a_translation_directory`
-
Setting the Locale
~~~~~~~~~~~~~~~~~~
@@ -1019,5 +1016,3 @@ For example:
config = Configurator()
config.set_locale_negotiator(my_locale_negotiator)
-.. note:: You can also add a custom locale negotiator via ZCML. See
- :ref:`zcml_adding_a_locale_negotiator`
diff --git a/docs/narr/install.rst b/docs/narr/install.rst
index e32d0c6c3..c5ec14aa1 100644
--- a/docs/narr/install.rst
+++ b/docs/narr/install.rst
@@ -295,7 +295,7 @@ Installing :app:`Pyramid` on a Windows System
c:\> cd env
-#. (Optional) Consider using ``bin\activate.bat`` to make your shell
+#. (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
diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst
index 3ade3726c..2da75df39 100644
--- a/docs/narr/introduction.rst
+++ b/docs/narr/introduction.rst
@@ -63,7 +63,7 @@ A Sense of Fun
Minimalism
:app:`Pyramid` provides only the very basics: *URL to code
- mapping*, *templating*, *security*, and *resources*. There is not
+ mapping*, *templating*, *security*, and *assets*. There is not
much more to the framework than these pieces: you are expected to
provide the rest.
@@ -104,7 +104,7 @@ What Is The Pylons Project?
:app:`Pyramid` is a member of the collection of software published under the
Pylons Project. Pylons software is written by a loose-knit community of
-contributors. The `Pylons Project website <http://docs.pylonshq.com>`_
+contributors. The `Pylons Project website <http://docs.pylonsproject.org>`_
includes details about how :app:`Pyramid` relates to the Pylons Project.
.. index::
diff --git a/docs/narr/muchadoabouttraversal.rst b/docs/narr/muchadoabouttraversal.rst
new file mode 100644
index 000000000..c57e58cd0
--- /dev/null
+++ b/docs/narr/muchadoabouttraversal.rst
@@ -0,0 +1,311 @@
+.. _much_ado_about_traversal_chapter:
+
+========================
+Much Ado About Traversal
+========================
+
+.. note:: This chapter was adapted, with permission, from a blog post by `Rob
+ Miller <http://blog.nonsequitarian.org/>`_, originally published at
+ `http://blog.nonsequitarian.org/2010/much-ado-about-traversal/
+ <http://blog.nonsequitarian.org/2010/much-ado-about-traversal/>`_.
+
+Traversal is an alternative to :term:`URL dispatch` which allows
+:app:`Pyramid` applications to map URLs to code.
+
+.. note::
+
+ Ex-Zope users whom are already familiar with traversal and view lookup
+ conceptually may want to skip directly to the :ref:`traversal_chapter`
+ chapter, which discusses technical details. This chapter is mostly aimed
+ at people who have previous :term:`Pylons` experience or experience in
+ another framework which does not provide traversal, and need an
+ introduction to the "why" of traversal.
+
+Some folks who have been using Pylons and its Routes-based URL matching for a
+long time are being exposed for the first time, via :app:`Pyramid`, to new
+ideas such as ":term:`traversal`" and ":term:`view lookup`" as a way to route
+incoming HTTP requests to callable code. Some of the same folks believe that
+traversal is hard to understand. Others question its usefulness; URL
+matching has worked for them so far, why should they even consider dealing
+with another approach, one which doesn't fit their brain and which doesn't
+provide any immediately obvious value?
+
+You can be assured that if you don't want to understand traversal, you don't
+have to. You can happily build :app:`Pyramid` applications with only
+:term:`URL dispatch`. However, there are some straightforward, real-world
+use cases that are much more easily served by a traversal-based approach than
+by a pattern-matching mechanism. Even if you haven't yet hit one of these
+use cases yourself, understanding these new ideas is worth the effort for any
+web developer so you know when you might want to use them. :term:`Traversal`
+is actually a straightforward metaphor easily comprehended by anyone who's
+ever used a run-of-the-mill file system with folders and files.
+
+URL Dispatch
+------------
+
+Let's step back and consider the problem we're trying to solve. An
+HTTP request for a particular path has been routed to our web
+application. The requested path will possibly invoke a specific
+:term:`view callable` function defined somewhere in our app. We're
+trying to determine *which* callable function, if any, should be
+invoked for a given requested URL.
+
+Many systems, including Pyramid, offer a simple solution. They offer the
+concept of "URL matching". URL matching approaches this problem by parsing
+the URL path and comparing the results to a set of registered "patterns",
+defined by a set of regular expressions, or some other URL path templating
+syntax. Each pattern is mapped to a callable function somewhere; if the
+request path matches a specific pattern, the associated function is called.
+If the request path matches more than one pattern, some conflict resolution
+scheme is used, usually a simple order precedence so that the first match
+will take priority over any subsequent matches. If a request path doesn't
+match any of the defined patterns, a "404 Not Found" response is returned.
+
+In Pyramid, we offer an implementation of URL matching which we call
+:term:`URL dispatch`. Using :app:`Pyramid` syntax, we might have a match
+pattern such as ``/{userid}/photos/{photoid}``, mapped to a ``photo_view()``
+function defined somewhere in our code. Then a request for a path such as
+``/joeschmoe/photos/photo1`` would be a match, and the ``photo_view()``
+function would be invoked to handle the request. Similarly,
+``/{userid}/blog/{year}/{month}/{postid}`` might map to a
+``blog_post_view()`` function, so ``/joeschmoe/blog/2010/12/urlmatching``
+would trigger the function, which presumably would know how to find and
+render the ``urlmatching`` blog post.
+
+Historical Refresher
+--------------------
+
+Now that we've refreshed our understanding of :term:`URL dispatch`, we'll dig
+in to the idea of traversal. Before we do, though, let's take a trip down
+memory lane. If you've been doing web work for a while, you may remember a
+time when we didn't have fancy web frameworks like :term:`Pylons` and
+:app:`Pyramid`. Instead, we had general purpose HTTP servers that primarily
+served files off of a file system. The "root" of a given site mapped to a
+particular folder somewhere on the file system. Each segment of the request
+URL path represented a subdirectory. The final path segment would be either
+a directory or a file, and once the server found the right file it would
+package it up in an HTTP response and send it back to the client. So serving
+up a request for ``/joeschmoe/photos/photo1`` literally meant that there was
+a ``joeschmoe`` folder somewhere, which contained a ``photos`` folder, which
+in turn contained a ``photo1`` file. If at any point along the way we find
+that there is not a folder or file matching the requested path, we return a
+404 response.
+
+As the web grew more dynamic, however, a little bit of extra complexity was
+added. Technologies such as CGI and HTTP server modules were developed.
+Files were still looked up on the file system, but if the file ended with
+(for example) ``.cgi`` or ``.php``, or if it lived in a special folder,
+instead of simply sending the file to the client the server would read the
+file, execute it using an interpreter of some sort, and then send the output
+from this process to the client as the final result. The server
+configuration specified which files would trigger some dynamic code, with the
+default case being to just serve the static file.
+
+Traversal (aka Resource Location)
+---------------------------------
+
+.. index::
+ single: traversal overview
+
+Believe it or not, if you understand how serving files from a file system
+works,you understand traversal. And if you understand that a server might do
+something different based on what type of file a given request specifies,
+then you understand view lookup.
+
+The major difference between file system lookup and traversal is that a file
+system lookup steps through nested directories and files in a file system
+tree, while traversal steps through nested dictionary-type objects in a
+:term:`resource tree`. Let's take a detailed look at one of our example
+paths, so we can see what I mean:
+
+The path ``/joeschmoe/photos/photo1``, has four segments: ``/``,
+``joeschmoe``, ``photos`` and ``photo1``. With file system lookup we might
+have a root folder (``/``) containing a nested folder (``joeschmoe``), which
+contains another nested folder (``photos``), which finally contains a JPG
+file (``photo1``). With traversal, we instead have a dictionary-like root
+object. Asking for the ``joeschmoe`` key gives us another dictionary-like
+object. Asking this in turn for the ``photos`` key gives us yet another
+mapping object, which finally (hopefully) contains the resource that we're
+looking for within its values, referenced by the ``photo1`` key.
+
+In pure Python terms, then, the traversal or "resource location"
+portion of satisfying the ``/joeschmoe/photos/photo1`` request
+will look something like this pseudocode::
+
+ get_root()['joeschmoe']['photos']['photo1']
+
+``get_root()`` is some function that returns a root traversal
+:term:`resource`. If all of the specified keys exist, then the returned
+object will be the resource that is being requested, analogous to the JPG
+file that was retrieved in the file system example. If a :exc:`KeyError` is
+generated anywhere along the way, :app:`Pyramid` will return 404. (This
+isn't precisely true, as you'll see when we learn about view lookup below,
+but the basic idea holds.)
+
+What Is a "Resource"?
+---------------------
+
+"Files on a file system I understand", you might say. "But what are these
+nested dictionary things? Where do these objects, these 'resources', live?
+What *are* they?"
+
+Since :app:`Pyramid` is not a highly opinionated framework, it makes no
+restriction on how a :term:`resource` is implemented; a developer can
+implement them as he wishes. One common pattern used is to persist all of
+the resources, including the root, in a database as a graph. The root object
+is a dictionary-like object. Dictionary-like objects in Python supply a
+``__getitem__`` method which is called when key lookup is done. Under the
+hood, when ``adict`` is a dictionary-like object, Python translates
+``adict['a']`` to ``adict.__getitem__('a')``. Try doing this in a Python
+interpreter prompt if you don't believe us:
+
+.. code-block:: text
+ :linenos:
+
+ Python 2.4.6 (#2, Apr 29 2010, 00:31:48)
+ [GCC 4.4.3] on linux2
+ Type "help", "copyright", "credits" or "license" for more information.
+ >>> adict = {}
+ >>> adict['a'] = 1
+ >>> adict['a']
+ 1
+ >>> adict.__getitem__('a')
+ 1
+
+
+The dictionary-like root object stores the ids of all of its subresources as
+keys, and provides a ``__getitem__`` implementation that fetches them. So
+``get_root()`` fetches the unique root object, while
+``get_root()['joeschmoe']`` returns a different object, also stored in the
+database, which in turn has its own subresources and ``__getitem__``
+implementation, etc. These resources might be persisted in a relational
+database, one of the many "NoSQL" solutions that are becoming popular these
+days, or anywhere else, it doesn't matter. As long as the returned objects
+provide the dictionary-like API (i.e. as long as they have an appropriately
+implemented ``__getitem__`` method) then traversal will work.
+
+In fact, you don't need a "database" at all. You could use plain
+dictionaries, with your site's URL structure hard-coded directly in
+the Python source. Or you could trivially implement a set of objects
+with ``__getitem__`` methods that search for files in specific
+directories, and thus precisely recreate the traditional mechanism of
+having the URL path mapped directly to a folder structure on the file
+system. Traversal is in fact a superset of file system lookup.
+
+.. note:: See the chapter entitled :ref:`resources_chapter` for a more
+ technical overview of resources.
+
+View Lookup
+-----------
+
+At this point we're nearly there. We've covered traversal, which is the
+process by which a specific resource is retrieved according to a specific URL
+path. But what is "view lookup"?
+
+The need for view lookup is simple: there is more than one possible action
+that you might want to take after finding a :term:`resource`. With our photo
+example, for instance, you might want to view the photo in a page, but you
+might also want to provide a way for the user to edit the photo and any
+associated metadata. We'll call the former the ``view`` view, and the latter
+will be the ``edit`` view. (Original, I know.) :app:`Pyramid` has a
+centralized view :term:`application registry` where named views can be
+associated with specific resource types. So in our example, we'll assume
+that we've registered ``view`` and ``edit`` views for photo objects, and that
+we've specified the ``view`` view as the default, so that
+``/joeschmoe/photos/photo1/view`` and ``/joeschmoe/photos/photo1`` are
+equivalent. The edit view would sensibly be provided by a request for
+``/joeschmoe/photos/photo1/edit``.
+
+Hopefully it's clear that the first portion of the edit view's URL path is
+going to resolve to the same resource as the non-edit version, specifically
+the resource returned by ``get_root()['joeschmoe']['photos']['photo1']``.
+But traveral ends there; the ``photo1`` resource doesn't have an ``edit``
+key. In fact, it might not even be a dictionary-like object, in which case
+``photo1['edit']`` would be meaningless. When the :app:`Pyramid` resource
+location has been resolved to a *leaf* resource, but the entire request path
+has not yet been expended, the *very next* path segment is treated as a
+:term:`view name`. The registry is then checked to see if a view of the
+given name has been specified for a resource of the given type. If so, the
+view callable is invoked, with the resource passed in as the related
+``context`` object (also available as ``request.context``). If a view
+callable could not be found, :app:`Pyramid` will return a "404 Not Found"
+response.
+
+You might conceptualize a request for ``/joeschmoe/photos/photo1/edit`` as
+ultimately converted into the following piece of Pythonic pseudocode::
+
+ context = get_root()['joeschmoe']['photos']['photo1']
+ view_callable = get_view(context, 'edit')
+ request.context = context
+ view_callable(request)
+
+The ``get_root`` and ``get_view`` functions don't really exist. Internally,
+:app:`Pyramid` does something more complicated. But the example above
+is a reasonable approximation of the view lookup algorithm in pseudocode.
+
+Use Cases
+---------
+
+Why should we care about traversal? URL matching is easier to explain, and
+it's good enough, right?
+
+In some cases, yes, but certainly not in all cases. So far we've had very
+structured URLs, where our paths have had a specific, small number of pieces,
+like this::
+
+ /{userid}/{typename}/{objectid}[/{view_name}]
+
+In all of the examples thus far, we've hard coded the typename value,
+assuming that we'd know at development time what names were going to be used
+("photos", "blog", etc.). But what if we don't know what these names will
+be? Or, worse yet, what if we don't know *anything* about the structure of
+the URLs inside a user's folder? We could be writing a CMS where we want the
+end user to be able to arbitrarily add content and other folders inside his
+folder. He might decide to nest folders dozens of layers deep. How will you
+construct matching patterns that could account for every possible combination
+of paths that might develop?
+
+It might be possible, but it certainly won't be easy. The matching
+patterns are going to become complex quickly as you try to handle all
+of the edge cases.
+
+With traversal, however, it's straightforward. 20 layers of nesting would be
+no problem. :app:`Pyramid` will happily call ``__getitem__`` as many times
+as it needs to, until it runs out of path segments or until a resource raises
+a :exc:`KeyError`. Each resource only needs to know how to fetch its
+immediate children, the traversal algorithm takes care of the rest. Also,
+since the structure of the resource tree can live in the database and not in
+the code, it's simple to let users modify the tree at runtime to set up their
+own personalized "directory" structures.
+
+Another use case in which traversal shines is when there is a need to support
+a context-dependent security policy. One example might be a document
+management infrastructure for a large corporation, where members of different
+departments have varying access levels to the various other departments'
+files. Reasonably, even specific files might need to be made available to
+specific individuals. Traversal does well here if your resources actually
+represent the data objects related to your documents, because the idea of a
+resource authorization is baked right into the code resolution and calling
+process. Resource objects can store ACLs, which can be inherited and/or
+overridden by the subresources.
+
+If each resource can thus generate a context-based ACL, then whenever view
+code is attempting to perform a sensitive action, it can check against that
+ACL to see whether the current user should be allowed to perform the action.
+In this way you achieve so called "instance based" or "row level" security
+which is considerably harder to model using a traditional tabular approach.
+:app:`Pyramid` actively supports such a scheme, and in fact if you register
+your views with guard permissions and use an authorization policy,
+:app:`Pyramid` can check against a resource's ACL when deciding whether or
+not the view itself is available to the current user.
+
+In summary, there are entire classes of problems that are more easily served
+by traversal and view lookup than by :term:`URL dispatch`. If your problems
+don't require it, great: stick with :term:`URL dispatch`. But if you're
+using :app:`Pyramid` and you ever find that you *do* need to support one of
+these use cases, you'll be glad you have traversal in your toolkit.
+
+.. note::
+ It is even possible to mix and match :term:`traversal` with
+ :term:`URL dispatch` in the same :app:`Pyramid` application. See the
+ :ref:`hybrid_chapter` chapter for details.
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 55a2711f3..f0ee91164 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -8,13 +8,13 @@ As we saw in :ref:`firstapp_chapter`, it's possible to create a
convenient to use a *template* to generate a basic :app:`Pyramid`
:term:`project`.
-A project is a directory that contains at least one :term:`package`. You'll
-use a template to create a project, and you'll create your application logic
-within a package that lives inside the project. Even if your application is
-extremely simple, it is useful to place code that drives the application
-within a package, because a package is more easily extended with new code.
-An application that lives inside a package can also be distributed more
-easily than one which does not live within a package.
+A project is a directory that contains at least one Python :term:`package`.
+You'll use a template to create a project, and you'll create your application
+logic within a package that lives inside the project. Even if your
+application is extremely simple, it is useful to place code that drives the
+application within a package, because a package is more easily extended with
+new code. An application that lives inside a package can also be distributed
+more easily than one which does not live within a package.
:app:`Pyramid` comes with a variety of templates that you can use to generate
a project. Each template makes different configuration assumptions about
@@ -26,13 +26,9 @@ and so therefore they are often referred to as "paster templates".
.. index::
single: paster templates
single: pyramid_starter paster template
- single: pyramid_starter_zcml paster template
single: pyramid_zodb paster template
single: pyramid_alchemy paster template
single: pyramid_routesalchemy paster template
- single: pylons_minimal paster template
- single: pylons_basic paster template
- single: pylons_sqla paster template
.. _additional_paster_templates:
@@ -48,8 +44,6 @@ each other on a number of axes:
- the mechanism they use to map URLs to code (:term:`traversal` or :term:`URL
dispatch`).
-- the type of configuration used (:term:`ZCML` vs. imperative configuration).
-
- whether or not the ``pyramid_beaker`` library is relied upon as the
sessioning implementation (as opposed to no sessioning or default
sessioning).
@@ -59,10 +53,6 @@ The included templates are these:
``pyramid_starter``
URL mapping via :term:`traversal` and no persistence mechanism.
-``pyramid_starter_zcml``
- URL mapping via :term:`traversal` and no persistence mechanism, using
- :term:`ZCML` (declarative configuration).
-
``pyramid_zodb``
URL mapping via :term:`traversal` and persistence via :term:`ZODB`.
@@ -74,20 +64,6 @@ The included templates are these:
URL mapping via :term:`traversal` and persistence via
:term:`SQLAlchemy`
-``pylons_minimal``
- URL mapping via :term:`URL dispatch` and Pylons-style view handlers,
- minimal setup, uses ``pyramid_beaker`` as a sessioning implementation.
-
-``pylons_basic``
- URL mapping via :term:`URL dispatch` and Pylons-style view handlers, and
- some extra functionality, uses ``pyramid_beaker`` as a sessioning
- implementation.
-
-``pylons_sqla``
- URL mapping via :term:`URL dispatch` and Pylons-style view handlers, some
- extra functionality, and SQLAlchemy set up, uses ``pyramid_beaker`` as a
- sessioning implementation.
-
.. index::
single: creating a project
single: project
@@ -180,7 +156,7 @@ Installing your Newly Created Project for Development
To install a newly created project for development, you should ``cd`` to the
newly created project directory and use the Python interpreter from the
:term:`virtualenv` you created during :ref:`installing_chapter` to invoke the
-command ``python setup.py develop.py``
+command ``python setup.py develop``
The file named ``setup.py`` will be in the root of the paster-generated
project directory. The ``python`` you're invoking should be the one that
@@ -601,7 +577,7 @@ or influencing runtime behavior of a :app:`Pyramid` application. See
default 'application' (although it's actually a pipeline of middleware and an
application) run by ``paster serve`` when it is invoked against this
configuration file. The name ``main`` is a convention used by PasteDeploy
-signifying that it the default application.
+signifying that it is the default application.
The ``[server:main]`` section of the configuration file configures a WSGI
server which listens on TCP port 6543. It is configured to listen on all
@@ -705,7 +681,8 @@ who want to use your application.
be included in the tarball. If you don't use Subversion, and instead use
a different version control system, you may need to install a setuptools
add-on such as ``setuptools-git`` or ``setuptools-hg`` for this behavior
- to work properly.
+ to work properly. Alternatively, you can specify the non-Python-source
+ files by hand in a ``manifest template``, called ``MANIFEST.in`` by default.
``setup.cfg``
~~~~~~~~~~~~~
@@ -876,9 +853,6 @@ represent the root.
This directory contains static assets which support the ``mytemplate.pt``
template. It includes CSS and images.
-.. index::
- single: tests.py
-
``templates/mytemplate.pt``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -892,6 +866,9 @@ Templates are accessed and used by view configurations and sometimes by view
functions themselves. See :ref:`templates_used_directly` and
:ref:`templates_used_as_renderers`.
+.. index::
+ single: tests.py
+
``tests.py``
~~~~~~~~~~~~
@@ -910,6 +887,8 @@ example.
See :ref:`testing_chapter` for more information about writing :app:`Pyramid`
unit tests.
+.. _modifying_package_structure:
+
Modifying Package Structure
----------------------------
@@ -958,12 +937,14 @@ To this:
.. code-block:: python
:linenos:
- config.add_view('myproject.views.blogs.my_view',
+ config.add_view('myproject.views.blog.my_view',
renderer='myproject:templates/mytemplate.pt')
You can then continue to add files to the ``views`` directory, and refer to
-views or handler classes/functions within those files via the dotted name
-passed as the first argument to ``add_view``. For example:
+view classes or functions within those files via the dotted name passed as
+the first argument to ``add_view``. For example, if you added a file named
+``anothermodule.py`` to the ``views`` subdirectory, and added a view callable
+named ``my_view`` to it:
.. code-block:: python
:linenos:
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 3804fcf42..a80c5a9c2 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -3,18 +3,10 @@
Renderers
=========
-In the :ref:`views_chapter` chapter, we said that a view callable must
-return a :term:`Response` object. We lied. A :term:`renderer` is a service
-that attempts to convert a non-Response return value of a function, class, or
-instance that acts as a :term:`view callable` to a :term:`Response` object.
-
-Overview
---------
-
-A view needn't *always* return a Response object. If a view happens to
-return something which does not implement the Pyramid Response interface,
-:app:`Pyramid` will attempt to use a :term:`renderer` to construct a
-response. For example:
+A view needn't *always* return a :term:`Response` object. If a view
+happens to return something which does not implement the Pyramid
+Response interface, :app:`Pyramid` will attempt to use a
+:term:`renderer` to construct a response. For example:
.. code-block:: python
:linenos:
@@ -22,6 +14,7 @@ response. For example:
from pyramid.response import Response
from pyramid.view import view_config
+ @view_config(renderer='json')
def hello_world(request):
return {'content':'Hello!'}
@@ -396,21 +389,17 @@ documentation in :ref:`request_module`.
.. _adding_and_overriding_renderers:
-Adding and Overriding Renderers
--------------------------------
+Adding and Changing Renderers
+-----------------------------
New templating systems and serializers can be associated with :app:`Pyramid`
renderer names. To this end, configuration declarations can be made which
-override an existing :term:`renderer factory`, and which add a new renderer
+change an existing :term:`renderer factory`, and which add a new renderer
factory.
Renderers can be registered imperatively using the
:meth:`pyramid.config.Configurator.add_renderer` API.
-.. note:: The tasks described in this section can also be performed via
- :term:`declarative configuration`. See
- :ref:`zcml_adding_and_overriding_renderers`.
-
For example, to add a renderer which renders views which have a
``renderer`` attribute that is a path that ends in ``.jinja2``:
@@ -553,7 +542,7 @@ set as ``renderer=`` in the view configuration.
See also :ref:`renderer_directive` and
:meth:`pyramid.config.Configurator.add_renderer`.
-Overriding an Existing Renderer
+Changing an Existing Renderer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can associate more than one filename extension with the same existing
@@ -570,7 +559,7 @@ extension for the same kinds of templates. For example, to associate the
After you do this, :app:`Pyramid` will treat templates ending in both the
``.pt`` and ``.zpt`` filename extensions as Chameleon ZPT templates.
-To override the default mapping in which files with a ``.pt`` extension are
+To change the default mapping in which files with a ``.pt`` extension are
rendered via a Chameleon ZPT page template renderer, use a variation on the
following in your application's startup code:
@@ -592,3 +581,44 @@ the ``name`` attribute to the renderer tag:
config.add_renderer(None, 'mypackage.json_renderer_factory')
+Overriding A Renderer At Runtime
+--------------------------------
+
+.. warning:: This is an advanced feature, not typically used by "civilians".
+
+In some circumstances, it is necessary to instruct the system to ignore the
+static renderer declaration provided by the developer in view configuration,
+replacing the renderer with another *after a request starts*. For example,
+an "omnipresent" XML-RPC implementation that detects that the request is from
+an XML-RPC client might override a view configuration statement made by the
+user instructing the view to use a template renderer with one that uses an
+XML-RPC renderer. This renderer would produce an XML-RPC representation of
+the data returned by an arbitrary view callable.
+
+To use this feature, create a :class:`pyramid.events.NewRequest`
+:term:`subscriber` which sniffs at the request data and which conditionally
+sets an ``override_renderer`` attribute on the request itself, which is the
+*name* of a registered renderer. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.event import subscriber
+ from pyramid.event import NewRequest
+
+ @subscriber(NewRequest)
+ def set_xmlrpc_params(event):
+ request = event.request
+ if (request.content_type == 'text/xml'
+ and request.method == 'POST'
+ and not 'soapaction' in request.headers
+ and not 'x-pyramid-avoid-xmlrpc' in request.headers):
+ params, method = parse_xmlrpc_request(request)
+ request.xmlrpc_params, request.xmlrpc_method = params, method
+ request.is_xmlrpc = True
+ request.override_renderer = 'xmlrpc'
+ return True
+
+The result of such a subscriber will be to replace any existing static
+renderer configured by the developer with a (notional, nonexistent) XML-RPC
+renderer if the request appears to come from an XML-RPC client.
diff --git a/docs/narr/resourcelocation.rst b/docs/narr/resourcelocation.rst
deleted file mode 100644
index 8ddc890ed..000000000
--- a/docs/narr/resourcelocation.rst
+++ /dev/null
@@ -1,103 +0,0 @@
-.. index::
- single: resource location
-
-.. _resourcelocation_chapter:
-
-Resource Location and View Lookup
----------------------------------
-
-:app:`Pyramid` uses two separate but cooperating subsystems to find and
-invoke :term:`view callable` code written by the application developer:
-:term:`resource location` and :term:`view lookup`.
-
-- First, a :app:`Pyramid` :term:`resource location` subsystem is given a
- :term:`request`; it is responsible for finding a :term:`resource` object
- based on information present in the request. When a resource is found via
- resource location, it becomes known as the :term:`context`.
-
-- Next, using the context resource found by :term:`resource location` and the
- :term:`request`, :term:`view lookup` is then responsible for finding and
- invoking a :term:`view callable`. A view callable is a specific bit of
- code written and registered by the application developer which receives the
- :term:`request` and which returns a :term:`response`.
-
-These two subsystems are used by :app:`Pyramid` serially: first, a
-:term:`resource location` subsystem does its job. Then the result of
-resource location is passed to the :term:`view lookup` subsystem. The view
-lookup system finds a :term:`view callable` written by an application
-developer, and invokes it. A view callable returns a :term:`response`. The
-response is returned to the requesting user.
-
-There are two separate :term:`resource location` subsystems in
-:app:`Pyramid`: :term:`traversal` and :term:`URL dispatch`. They can be used
-separately or they can be combined. Three chapters which follow describe
-:term:`resource location`: :ref:`traversal_chapter`,
-:ref:`urldispatch_chapter` and :ref:`hybrid_chapter`.
-
-There is only one :term:`view lookup` subsystem present in :app:`Pyramid`.
-Where appropriate, we will describe how view lookup interacts with context
-finding. One chapter which follows describes :term:`view lookup`:
-:ref:`views_chapter`.
-
-Should I Use Traversal or URL Dispatch for Resource Location?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When you use :app:`Pyramid`, you have a choice about how you'd like to
-resolve URLs to code: you can use either :term:`traversal` or :term:`URL
-dispatch`. The choice to use traversal vs. URL dispatch is largely
-"religious". Since :app:`Pyramid` provides support for both approaches, you
-can use either exclusively or combine them as you see fit.
-
-:term:`URL dispatch` is very straightforward. When you limit your
-application to using URL dispatch, you know every URL that your application
-might generate or respond to, all the URL matching elements are listed in a
-single place, and you needn't think about :term:`resource location` or
-:term:`view lookup` at all.
-
-URL dispatch can easily handle URLs such as
-``http://example.com/members/Chris``, where it's assumed that each item
-"below" ``members`` in the URL represents a single member in some system.
-You just match everything "below" ``members`` to a particular :term:`view
-callable`, e.g. ``/members/{memberid}``.
-
-However, URL dispatch is not very convenient if you'd like your URLs to
-represent an arbitrary-depth hierarchy. For example, if you need to infer
-the difference between sets of URLs such as these, where the ``document`` in
-the first URL represents a PDF document, and ``/stuff/page`` in the second
-represents an OpenOffice document in a "stuff" folder.
-
-.. code-block:: text
-
- http://example.com/members/Chris/document
- http://example.com/members/Chris/stuff/page
-
-It takes more pattern matching assertions to be able to make hierarchies work
-in URL-dispatch based systems, and some assertions just aren't possible.
-URL-dispatch based systems just don't deal very well with URLs that represent
-arbitrary-depth hierarchies.
-
-:term:`URL dispatch` tends to collapse the two steps of :term:`resource
-location` and :term:`view lookup` into a single step. Thus, a URL can map
-*directly* to a view callable. This makes URL dispatch easier to understand
-than traversal, because traversal makes you understand how :term:`resource
-location` works. But explicitly locating a resource provides extra
-flexibility. For example, it makes it possible to protect your application
-with declarative context-sensitive instance-level :term:`authorization`.
-
-Unlike URL dispatch, :term:`traversal` works well for URLs that represent
-arbitrary-depth hierarchies. Since the path segments that compose a URL are
-addressed separately, it becomes very easy to form URLs that represent
-arbitrary depth hierarchies in a system that uses traversal. When you're
-willing to treat your application resources as a tree that can be traversed,
-it also becomes easy to provide "instance-level security": you just attach an
-:term:`ACL` security declaration to each resource in the tree. This is not
-nearly as easy to do when using URL dispatch.
-
-Traversal probably just doesn't make any sense when you possess completely
-"square" data stored in a relational database because it requires the
-construction and maintenance of a resource tree and requires that the
-developer think about mapping URLs to code in terms of traversing that tree.
-
-We'll examine both :term:`URL dispatch` and :term:`traversal` in the next two
-chapters.
-
diff --git a/docs/narr/resources.rst b/docs/narr/resources.rst
index ac88afdfd..c97b4c676 100644
--- a/docs/narr/resources.rst
+++ b/docs/narr/resources.rst
@@ -1,21 +1,23 @@
+.. _resources_chapter:
+
Resources
=========
-A :term:`resource` is an object that represents a "place" in a tree related
-to your application. Every :app:`Pyramid` application has at least one
-resource object: the :term:`root` resource (even if you don't define one
-manually, a default root resource is created for you). The root resource is
-the root of a :term:`resource tree`. A resource tree is a set of nested
-dictionary-like objects which you can use to represent your website's
-structure.
+A :term:`resource` is an object that represents a "place" in a tree
+related to your application. Every :app:`Pyramid` application has at
+least one resource object: the :term:`root` resource. Even if you don't
+define a root resource manually, a default one is created for you. The
+root resource is the root of a :term:`resource tree`. A resource tree
+is a set of nested dictionary-like objects which you can use to
+represent your website's structure.
In an application which uses :term:`traversal` to map URLs to code, the
-resource tree structure is used heavily to map a URL to a :term:`view
-callable`. :app:`Pyramid` will walk "up" the resource tree by traversing
-through the nested dictionary structure of the tree when :term:`traversal` is
-used in order to find a :term:`context` resource. Once a context resource is
-found, the context resource and data in the request will be used to find a
-:term:`view callable`.
+resource tree structure is used heavily to map each URL to a :term:`view
+callable`. When :term:`traversal` is used, :app:`Pyramid` will walk
+through the resource tree by traversing through its nested dictionary
+structure in order to find a :term:`context` resource. Once a context
+resource is found, the context resource and data in the request will be
+used to find a :term:`view callable`.
In an application which uses :term:`URL dispatch`, the resource tree is only
used indirectly, and is often "invisible" to the developer. In URL dispatch
@@ -26,7 +28,7 @@ much less important in applications that use URL dispatch than applications
that use traversal.
In "Zope-like" :app:`Pyramid` applications, resource objects also often store
-data persistently and offer methods related to mutating that persistent data.
+data persistently, and offer methods related to mutating that persistent data.
In these kinds of applications, resources not only represent the site
structure of your website, but they become the :term:`domain model` of the
application.
@@ -72,8 +74,8 @@ tree:
the container's ``__getitem__`` should return the sub-resource.
- Leaf resources, which do not contain other resources, must not implement a
- ``__getitem__``, or if they do, their ``__getitem__`` method must raise a
- :exc:`KeyError`.
+ ``__getitem__``, or if they do, their ``__getitem__`` method must always
+ raise a :exc:`KeyError`.
See :ref:`traversal_chapter` for more information about how traversal
works against resource instances.
@@ -184,7 +186,7 @@ you will reach the filesystem root directory.
objects "by hand". Instead, as necessary, during traversal :app:`Pyramid`
will wrap each resource (even the root resource) in a ``LocationProxy``
which will dynamically assign a ``__name__`` and a ``__parent__`` to the
- traversed resrouce (based on the last traversed resource and the name
+ traversed resource (based on the last traversed resource and the name
supplied to ``__getitem__``). The root resource will have a ``__name__``
attribute of ``None`` and a ``__parent__`` attribute of ``None``.
@@ -239,7 +241,7 @@ A slash is appended to all resource URLs when
:func:`~pyramid.url.resource_url` is used to generate them in this simple
manner, because resources are "places" in the hierarchy, and URLs are meant
to be clicked on to be visited. Relative URLs that you include on HTML pages
-rendered as the result of the default view of a resource are typically more
+rendered as the result of the default view of a resource are more
apt to be relative to these resources than relative to their parent.
You can also pass extra elements to :func:`~pyramid.url.resource_url`:
@@ -404,7 +406,7 @@ Obtaining the Lineage of a Resource
-----------------------------------
:func:`pyramid.location.lineage` returns a generator representing the
-:term:`lineage` of the :term:`location` aware:term:`resource` object.
+:term:`lineage` of the :term:`location` aware :term:`resource` object.
The :func:`~pyramid.location.lineage` function returns the resource it is
passed, then each parent of the resource, in order. For example, if the
@@ -533,7 +535,7 @@ declares that the blog entry implements an :term:`interface`.
implements(IBlogEntry)
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
@@ -568,7 +570,7 @@ To do so, use the :func:`zope.interface.directlyProvides` function:
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
@@ -596,7 +598,7 @@ the :func:`zope.interface.alsoProvides` function:
class BlogEntry(object):
def __init__(self, title, body, author):
self.title = title
- self.body = body
+ self.body = body
self.author = author
self.created = datetime.datetime.now()
diff --git a/docs/narr/router.rst b/docs/narr/router.rst
index d3d5bd370..782098bac 100644
--- a/docs/narr/router.rst
+++ b/docs/narr/router.rst
@@ -44,7 +44,7 @@ processing?
#. If any route matches, the request is mutated; a ``matchdict`` and
``matched_route`` attributes are added to the request object; the
- former contains a dictionary representign the matched dynamic
+ former contains a dictionary representing the matched dynamic
elements of the request's ``PATH_INFO`` value, the latter contains
the :class:`pyramid.interfaces.IRoute` object representing the
route which matched. The root object associated with the route
@@ -133,6 +133,6 @@ processing?
This is a very high-level overview that leaves out various details.
For more detail about subsystems invoked by the :app:`Pyramid` router
such as traversal, URL dispatch, views, and event processing, see
-:ref:`resourcelocation_chapter`, :ref:`views_chapter`, and
+:ref:`urldispatch_chapter`, :ref:`views_chapter`, and
:ref:`events_chapter`.
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index c5262faa2..e395b15f1 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -6,20 +6,20 @@
Security
========
-:app:`Pyramid` provides an optional declarative authorization system that
-prevents a :term:`view` from being invoked when the user represented by
-credentials in the :term:`request` does not have an appropriate level of
-access when a particular resource is the :term:`context`. Here's how it
-works at a high level:
+:app:`Pyramid` provides an optional declarative authorization system
+that can prevent a :term:`view` from being invoked based on an
+:term:`authorization policy`. Before a view is invoked, the
+authorization system can use the credentials in the :term:`request`
+along with the :term:`context` resource to determine if access will be
+allowed. Here's how it works at a high level:
-- A :term:`request` is generated when a user visits our application.
+- A :term:`request` is generated when a user visits the application.
- Based on the request, a :term:`context` resource is located through
:term:`resource location`. A context is located differently depending on
whether the application uses :term:`traversal` or :term:`URL dispatch`, but
a context is ultimately found in either case. See
- :ref:`resourcelocation_chapter` for more information about resource
- location.
+ the :ref:`urldispatch_chapter` chapter for more information.
- A :term:`view callable` is located by :term:`view lookup` using the
context as well as other attributes of the request.
@@ -41,6 +41,15 @@ works at a high level:
- If the authorization policy denies access, the view callable is not
invoked; instead the :term:`forbidden view` is invoked.
+Security in :app:`Pyramid`, unlike many systems, cleanly and explicitly
+separates authentication and authorization. Authentication is merely the
+mechanism by which credentials provided in the :term:`request` are
+resolved to one or more :term:`principal` identifiers. These identifiers
+represent the users and groups in effect during the request.
+Authorization then determines access based on the :term:`principal`
+identifiers, the :term:`view callable` being invoked, and the
+:term:`context` resource.
+
Authorization is enabled by modifying your application to include an
:term:`authentication policy` and :term:`authorization policy`.
:app:`Pyramid` comes with a variety of implementations of these
@@ -107,9 +116,6 @@ See also the :mod:`pyramid.authorization` and
:mod:`pyramid.authentication` modules for alternate implementations
of authorization and authentication policies.
-You can also enable a security policy declaratively via ZCML. See
-:ref:`zcml_authorization_policy`.
-
.. index::
single: permissions
single: protecting views
@@ -155,9 +161,6 @@ may be performed via the ``@view_config`` decorator:
""" Add blog entry code goes here """
pass
-Or the same thing can be done using the ``permission`` attribute of the ZCML
-:ref:`view_directive` directive.
-
As a result of any of these various view configuration statements, if an
authorization policy is in place when the view callable is found during
normal application operations, the requesting user will need to possess the
@@ -170,8 +173,8 @@ to invoke the ``blog_entry_add_view`` view. If he does not, the
Setting a Default Permission
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If a permission is not supplied to a view configuration, the
-registered view always be executable by entirely anonymous users: any
+If a permission is not supplied to a view configuration, the registered
+view will always be executable by entirely anonymous users: any
authorization policy in effect is ignored.
In support of making it easier to configure applications which are
@@ -190,8 +193,6 @@ application:
:meth:`pyramid.config.Configurator.set_default_permission`
method.
-- The :ref:`default_permission_directive` ZCML directive.
-
When a default permission is registered:
- if a view configuration names an explicit ``permission``, the default
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst
index de9add3b7..0ed52b563 100644
--- a/docs/narr/sessions.rst
+++ b/docs/narr/sessions.rst
@@ -3,13 +3,18 @@
.. _sessions_chapter:
-Session Objects
-===============
+Sessions
+========
A :term:`session` is a namespace which is valid for some period of
continual activity that can be used to represent a user's interaction
with a web application.
+This chapter describes how to configure sessions, what session
+implementations :app:`Pyramid` provides out of the box, how to store and
+retrieve data from sessions, and two session-specific features: flash
+messages, and cross-site request forgery attack prevention.
+
.. _using_the_default_session_factory:
Using The Default Session Factory
@@ -32,7 +37,7 @@ limitation:
representation of the session is fewer than 4000. This is
suitable only for very small data sets.
-It is, however, digitally signed, and thus its data cannot easily be
+It is digitally signed, however, and thus its data cannot easily be
tampered with.
You can configure this session factory in your :app:`Pyramid`
@@ -113,7 +118,7 @@ documentation.
Some gotchas:
- Keys and values of session data must be *pickleable*. This means,
- typically, that they must be instances of basic types of objects,
+ typically, that they are instances of basic types of objects,
such as strings, lists, dictionaries, tuples, integers, etc. If you
place an object in a session data key or value that is not
pickleable, an error will be raised when the session is serialized.
@@ -162,3 +167,180 @@ both types are available in
:class:`pyramid.interfaces.ISession`. You might use the cookie
implementation in the :mod:`pyramid.session` module as inspiration.
+.. index::
+ single: flash messages
+
+Flash Messages
+--------------
+
+"Flash messages" are simply a queue of message strings stored in the
+:term:`session`. To use flash messaging, you must enable a :term:`session
+factory` as described in :ref:`using_the_default_session_factory` or
+:ref:`using_alternate_session_factories`.
+
+Flash messaging has two main uses: to display a status message only once to
+the user after performing an internal redirect, and to allow generic code to
+log messages for single-time display without having direct access to an HTML
+template. The user interface consists of a number of methods of the
+:term:`session` object.
+
+Using the ``session.flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To add a message to a flash message queue, use a session object's ``flash()``
+method:
+
+.. code-block:: python
+
+ request.session.flash('mymessage')
+
+The ``flash()`` method appends a message to a flash queue, creating the queue
+if necessary.
+
+``flash()`` accepts three arguments:
+
+.. method:: flash(message, queue='', allow_duplicate=True)
+
+The ``message`` argument is required. It represents a message you wish to
+later display to a user. It is usually a string but the ``message`` you
+provide is not modified in any way.
+
+The ``queue`` argument allows you to choose a queue to which to append
+the message you provide. This can be used to push different kinds of
+messages into flash storage for later display in different places on a
+page. You can pass any name for your queue, but it must be a string.
+Each queue is independent, and can be popped by ``pop_flash()`` or
+examined via ``peek_flash()`` separately. ``queue`` defaults to the
+empty string. The empty string represents the default flash message
+queue.
+
+.. code-block:: python
+
+ request.session.flash(msg, 'myappsqueue')
+
+The ``allow_duplicate`` argument defaults to ``True``. If this is
+``False``, and you attempt to add a message value which is already
+present in the queue, it will not be added.
+
+Using the ``session.pop_flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once one or more messages have been added to a flash queue by the
+``session.flash()`` API, the ``session.pop_flash()`` API can be used to
+pop an entire queue and return it for use.
+
+To pop a particular queue of messages from the flash object, use the session
+object's ``pop_flash()`` method. This returns a list of the messages
+that were added to the flash queue, and empties the queue.
+
+.. method:: pop_flash(queue='')
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.pop_flash()
+ ['info message']
+
+Calling ``session.pop_flash()`` again like above without a corresponding call
+to ``session.flash()`` will return an empty list, because the queue has already
+been popped.
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.pop_flash()
+ ['info message']
+ >>> request.session.pop_flash()
+ []
+
+Using the ``session.peek_flash`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once one or more messages has been added to a flash queue by the
+``session.flash()`` API, the ``session.peek_flash()`` API can be used to
+"peek" at that queue. Unlike ``session.pop_flash()``, the queue is not
+popped from flash storage.
+
+.. method:: peek_flash(queue='')
+
+.. code-block:: python
+ :linenos:
+
+ >>> request.session.flash('info message')
+ >>> request.session.peek_flash()
+ ['info message']
+ >>> request.session.peek_flash()
+ ['info message']
+ >>> request.session.pop_flash()
+ ['info message']
+ >>> request.session.peek_flash()
+ []
+
+.. index::
+ single: preventing cross-site request forgery attacks
+ single: cross-site request forgery attacks, prevention
+
+Preventing Cross-Site Request Forgery Attacks
+---------------------------------------------
+
+`Cross-site request forgery
+<http://en.wikipedia.org/wiki/Cross-site_request_forgery>`_ attacks are a
+phenomenon whereby a user with an identity on your website might click on a
+URL or button on another website which unwittingly redirects the user to your
+application to perform some command that requires elevated privileges.
+
+You can avoid most of these attacks by making sure that the correct *CSRF
+token* has been set in an :app:`Pyramid` session object before performing any
+actions in code which requires elevated privileges that is invoked via a form
+post. To use CSRF token support, you must enable a :term:`session factory`
+as described in :ref:`using_the_default_session_factory` or
+:ref:`using_alternate_session_factories`.
+
+Using the ``session.get_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To get the current CSRF token from the session, use the
+``session.get_csrf_token()`` method.
+
+.. code-block:: python
+
+ token = request.session.get_csrf_token()
+
+The ``session.get_csrf_token()`` method accepts no arguments. It returns a
+CSRF *token* string. If ``session.get_csrf_token()`` or
+``session.new_csrf_token()`` was invoked previously for this session, the
+existing token will be returned. If no CSRF token previously existed for
+this session, a new token will be will be set into the session and returned.
+The newly created token will be opaque and randomized.
+
+You can use the returned token as the value of a hidden field in a form that
+posts to a method that requires elevated privileges. The handler for the
+form post should use ``session.get_csrf_token()`` *again* to obtain the
+current CSRF token related to the user from the session, and compare it to
+the value of the hidden form field. For example, if your form rendering
+included the CSRF token obtained via ``session.get_csrf_token()`` as a hidden
+input field named ``csrf_token``:
+
+.. code-block:: python
+ :linenos:
+
+ token = request.session.get_csrf_token()
+ if token != request.POST['csrf_token']:
+ raise ValueError('CSRF token did not match')
+
+Using the ``session.new_csrf_token`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To explicitly add a new CSRF token to the session, use the
+``session.new_csrf_token()`` method. This differs only from
+``session.get_csrf_token()`` inasmuch as it clears any existing CSRF token,
+creates a new CSRF token, sets the token into the session, and returns the
+token.
+
+.. code-block:: python
+
+ token = request.session.new_csrf_token()
+
+
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 437b823e9..b97cc7be6 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -448,7 +448,7 @@ Here's what a simple :term:`Chameleon` ZPT template used under
<body>
<h1 class="title">Welcome to <code>${project}</code>, an
application generated by the <a
- href="http://pylonshq.com/pyramid">pyramid</a> web
+ href="http://docs.pylonsproject.org/projects/pyramid/dev/">pyramid</a> web
application framework.</h1>
</body>
</html>
@@ -628,7 +628,7 @@ application's configuration section, e.g.:
.. code-block:: ini
:linenos:
- [app:main]
+ [app:MyProject]
use = egg:MyProject#app
debug_templates = true
@@ -744,7 +744,7 @@ look like:
<body>
<h1 class="title">Welcome to <code>${project}</code>, an
application generated by the <a
- href="http://pylonshq.com/pyramid">pyramid</a> web
+ href="http://docs.pylonsproject.org/projects/pyramid/dev/">pyramid</a> web
application framework.</h1>
</body>
</html>
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index 007b96c2a..0968ad229 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -78,81 +78,84 @@ See :ref:`threadlocals_chapter` for information about these functions and the
data structures they return.
If your code uses these ``get_current_*`` functions or calls :app:`Pyramid`
-code which uses ``get_current_*`` functions, you will need to construct a
-:term:`Configurator` and call its ``begin`` method within the ``setUp``
-method of your unit test and call the same Configurator's ``end`` method
-within the ``tearDown`` method of your unit test.
-
-We'll also instruct the Configurator we use during testing to *autocommit*.
-Normally when a Configurator is used by an application, it defers performing
-any "real work" until its ``.commit`` method is called (often implicitly by
-the :meth:`pyramid.config.Configurator.make_wsgi_app` method). Passing
-``autocommit=True`` to the Configurator constructor causes the Configurator
-to perform all actions implied by methods called on it immediately, which is
-more convenient for unit-testing purposes than needing to call
-:meth:`pyramid.config.Configurator.commit` in each test.
-
-The use of a Configurator and its ``begin`` and ``end`` methods allows you to
-supply each unit test method in a test case with an environment that has an
-isolated registry and an isolated request for the duration of a single test.
-Here's an example of using this feature:
+code which uses ``get_current_*`` functions, you will need to call
+:func:`pyramid.testing.setUp` in your test setup and you will need to call
+:func:`pyramid.testing.tearDown` in your test teardown.
+:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread
+local` stack, which makes the ``get_current_*`` functions work. It returns a
+:term:`Configurator` object which can be used to perform extra configuration
+required by the code under test. :func:`~pyramid.testing.tearDown` pops the
+thread local stack.
+
+Normally when a Configurator is used directly with the ``main`` block of
+a Pyramid application, it defers performing any "real work" until its
+``.commit`` method is called (often implicitly by the
+:meth:`pyramid.config.Configurator.make_wsgi_app` method). The
+Configurator returned by :func:`~pyramid.testing.setUp` is an
+*autocommitting* Configurator, however, which performs all actions
+implied by methods called on it immediately. This is more convenient
+for unit-testing purposes than needing to call
+:meth:`pyramid.config.Configurator.commit` in each test after adding
+extra configuration statements.
+
+The use of the :func:`~pyramid.testing.setUp` and
+:func:`~pyramid.testing.tearDown` functions allows you to supply each unit
+test method in a test case with an environment that has an isolated registry
+and an isolated request for the duration of a single test. Here's an example
+of using this feature:
.. code-block:: python
:linenos:
import unittest
- from pyramid.config import Configurator
+ from pyramid import testing
class MyTest(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
The above will make sure that
-:func:`pyramid.threadlocal.get_current_registry` will return the
-:term:`application registry` associated with the ``config`` Configurator
-instance when :func:`pyramid.threadlocal.get_current_registry` is called in a
-test case method attached to ``MyTest``. Each test case method attached to
-``MyTest`` will use an isolated registry.
+:func:`pyramid.threadlocal.get_current_registry` called within a test
+case method of ``MyTest`` will return the :term:`application registry`
+associated with the ``config`` Configurator instance. Each test case
+method attached to ``MyTest`` will use an isolated registry.
-The :meth:`pyramid.config.Configurator.begin` method accepts various
-arguments that influence the code run during the test. See the
-:ref:`configuration_module` chapter for information about the API of a
-:term:`Configurator`, including its ``begin`` and ``end`` methods.
+The :func:`~pyramid.testing.setUp` and :func:`~pyramid.testing.tearDown`
+functions accepts various arguments that influence the environment of the
+test. See the :ref:`testing_module` chapter for information about the extra
+arguments supported by these functions.
If you also want to make :func:`pyramid.get_current_request` return something
other than ``None`` during the course of a single test, you can pass a
-:term:`request` object into the :meth:`pyramid.config.Configurator.begin`
-method of the Configurator within the ``setUp`` method of your test:
+:term:`request` object into the :func:`pyramid.testing.setUp` within the
+``setUp`` method of your test:
.. code-block:: python
:linenos:
import unittest
- from pyramid.config import Configurator
from pyramid import testing
class MyTest(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
request = testing.DummyRequest()
- self.config.begin(request=request)
+ self.config = testing.setUp(request=request)
def tearDown(self):
- self.config.end()
-
-If you pass a :term:`request` object into the ``begin`` method of the
-configurator within your test case's ``setUp``, any test method attached to
-the ``MyTest`` test case that directly or indirectly calls
-:func:`pyramid.threadlocal.get_current_request` will receive the request you
-passed into the ``begin`` method. Otherwise, during testing,
-:func:`pyramid.threadlocal.get_current_request` will return ``None``. 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.
+ testing.tearDown()
+
+If you pass a :term:`request` object into :func:`pyramid.testing.setUp`
+within your test case's ``setUp``, any test method attached to the
+``MyTest`` test case that directly or indirectly calls
+:func:`pyramid.threadlocal.get_current_request` will receive the request
+object. Otherwise, during testing,
+:func:`pyramid.threadlocal.get_current_request` will return ``None``.
+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.
What?
~~~~~
@@ -162,18 +165,18 @@ they're used by frameworks. Sorry. So here's a rule of thumb: if you don't
*know* whether you're calling code that uses the
:func:`pyramid.threadlocal.get_current_registry` or
:func:`pyramid.threadlocal.get_current_request` functions, or you don't care
-about any of this, but you still want to write test code, just always create
-an autocommitting Configurator instance and call its ``begin`` method within
-the ``setUp`` of a unit test, then subsequently call its ``end`` method in
-the test's ``tearDown``. This won't really hurt anything if the application
-you're testing does not call any ``get_current*`` function.
+about any of this, but you still want to write test code, just always call
+:func:`pyramid.testing.setUp` in your test's ``setUp`` method and
+:func:`pyramid.testing.tearDown` in your tests' ``tearDown`` method. This
+won't really hurt anything if the application you're testing does not call
+any ``get_current*`` function.
.. index::
single: pyramid.testing
single: Configurator testing API
Using the ``Configurator`` and ``pyramid.testing`` APIs in Unit Tests
-------------------------------------------------------------------------
+---------------------------------------------------------------------
The ``Configurator`` API and the ``pyramid.testing`` module provide a number
of functions which can be used during unit testing. These functions make
@@ -198,13 +201,11 @@ Without invoking any startup code or using the testing API, an attempt to run
this view function in a unit test will result in an error. When a
:app:`Pyramid` application starts normally, it will populate a
:term:`application registry` using :term:`configuration declaration` calls
-made against a :term:`Configurator` (sometimes deferring to the application's
-``configure.zcml`` :term:`ZCML` file via ``load_zcml``). But if this
-application registry is not created and populated (e.g. with an
+made against a :term:`Configurator`. But if this application registry is not
+created and populated (e.g. with an
:meth:`pyramid.config.Configurator.add_view` :term:`configuration
-declaration` or ``view`` declarations in :term:`ZCML`), like when you invoke
-application code via a unit test, :app:`Pyramid` API functions will tend to
-fail.
+declaration`), like when you invoke application code via a unit test,
+:app:`Pyramid` API functions will tend to fail.
The testing API provided by :app:`Pyramid` allows you to simulate various
application registry registrations for use under a unit testing framework
@@ -217,16 +218,14 @@ without needing to invoke the actual application configuration implied by its
:linenos:
import unittest
- from pyramid.config import Configurator
from pyramid import testing
class MyTest(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_view_fn_not_submitted(self):
from my.package import view_fn
@@ -277,8 +276,8 @@ performs a similar template registration and assertion. We assert at the end
of this that the renderer's ``say`` attribute is ``Yo``, as this is what is
expected of the view function in the branch it's testing.
-Note that the test calls the :meth:`pyramid.config.Configurator.begin` method
-in its ``setUp`` method and the ``end`` method of the same in its
+Note that the test calls the :func:`pyramid.testing.setUp` function in its
+``setUp`` method and the :func:`pyramid.testing.tearDown` function in its
``tearDown`` method. If you use any of the
:class:`pyramid.config.Configurator` APIs during testing, be sure to use this
pattern in your test case's ``setUp`` and ``tearDown``; these methods make
@@ -309,12 +308,13 @@ implementations to give the code under test only enough context to run.
some code *and* its integration with the rest of the :app:`Pyramid`
framework.
-In :app:`Pyramid` applications that use :term:`ZCML`, you can create an
-integration test by *loading its ZCML* in the test's setup code. This causes
-the entire :app:`Pyramid` environment to be set up and torn down as if your
-application was running "for real". This is a heavy-hammer way of making
-sure that your tests have enough context to run properly, and it tests your
-code's integration with the rest of :app:`Pyramid`.
+In :app:`Pyramid` applications that are plugins to Pyramid, you can create an
+integration test by including it's ``includeme`` function via
+:meth:`pyramid.config.Configurator.include` in the test's setup code. This
+causes the entire :app:`Pyramid` environment to be set up and torn down as if
+your application was running "for real". This is a heavy-hammer way of
+making sure that your tests have enough context to run properly, and it tests
+your code's integration with the rest of :app:`Pyramid`.
Let's demonstrate this by showing an integration test for a view. The below
test assumes that your application's package name is ``myapp``, and that
@@ -327,23 +327,21 @@ after accessing some values that require a fully set up environment.
import unittest
- from pyramid.config import Configurator
from pyramid import testing
class ViewIntegrationTests(unittest.TestCase):
def setUp(self):
""" This sets up the application registry with the
- registrations your application declares in its configure.zcml
- (including dependent registrations for pyramid itself).
+ registrations your application declares in its ``includeme``
+ function.
"""
import myapp
- self.config = Configurator(package=myapp, autocommit=True)
- self.config.begin()
- self.config.load_zcml('myapp:configure.zcml')
+ self.config = testing.setUp()
+ self.config.include('myapp')
def tearDown(self):
""" Clear out the application registry """
- self.config.end()
+ testing.tearDown()
def test_my_view(self):
from myapp.views import my_view
diff --git a/docs/narr/threadlocals.rst b/docs/narr/threadlocals.rst
index 171eaa1c7..13bfe41cb 100644
--- a/docs/narr/threadlocals.rst
+++ b/docs/narr/threadlocals.rst
@@ -111,8 +111,8 @@ follows:
each as ``request``).
- ``get_current_request`` should never be called in :term:`resource` code.
- If a resource needs access to the request, it should be passed the request
- by a :term:`view callable`.
+ If a resource needs access to the request, it should be passed the request
+ by a :term:`view callable`.
- ``get_current_request`` function should never be called because it's
"easier" or "more elegant" to think about calling it than to pass a
diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst
index 2d7878265..7c6280ba1 100644
--- a/docs/narr/traversal.rst
+++ b/docs/narr/traversal.rst
@@ -3,33 +3,22 @@
Traversal
=========
-:term:`Traversal` provides an alternative to using :term:`URL dispatch` to
-map a URL to a :term:`view callable`. It is the act of locating a
-:term:`context` resource by walking over a :term:`resource tree`, starting
-from a :term:`root` resource, using a :term:`request` object as a source of
-path information. Once a context resource is found, a view callable is
-looked up and invoked.
-
-Using :term:`Traversal` to map a URL to code is optional. It is often less
-easy to understand than URL dispatch, so if you're a rank beginner, it
-probably makes sense to use URL dispatch to map URLs to code instead of
-traversal. In that case, you can skip this chapter.
-
-.. index::
- single: traversal overview
-
-A High-Level Overview of Traversal
-----------------------------------
-
A :term:`traversal` uses the URL (Universal Resource Locator) to find a
-:term:`resource`. This is done by mapping each segment of the path portion
-of the URL into a set of nested dictionary-like objects called the
-:term:`resource tree`. You might think of this as looking up files and
-directories in a file system. Traversal walks down the path until it finds a
-published "directory" or "file". The resource we find as the result of a
-traversal becomes the :term:`context`. A separate :term:`view lookup`
-subsystem is used to then find some view code willing "publish" the context
-resource.
+:term:`resource` located in a :term:`resource tree`, which is a set of
+nested dictionary-like objects. Traversal is done by using each segment
+of the path portion of the URL to navigate through the :term:`resource
+tree`. You might think of this as looking up files and directories in a
+file system. Traversal walks down the path until it finds a published
+resource, analogous to a file system "directory" or "file". The
+resource found as the result of a traversal becomes the
+:term:`context` of the :term:`request`. Then, the :term:`view lookup`
+subsystem is used to find some view code willing "publish" this
+resource by generating a :term:`response`.
+
+Using :term:`Traversal` to map a URL to code is optional. It is often
+less easy to understand than :term:`URL dispatch`, so if you're a rank
+beginner, it probably makes sense to use URL dispatch to map URLs to
+code instead of traversal. In that case, you can skip this chapter.
.. index::
single: traversal details
@@ -37,62 +26,65 @@ resource.
Traversal Details
-----------------
-:term:`Traversal` is dependent on information in a :term:`request` object.
-Every :term:`request` object contains URL path information in the
-``PATH_INFO`` portion of the :term:`WSGI` environment. The ``PATH_INFO``
-portion of the WSGI environment is the portion of a request's URL following
-the hostname and port number, but before any query string elements or
+:term:`Traversal` is dependent on information in a :term:`request`
+object. Every :term:`request` object contains URL path information in
+the ``PATH_INFO`` portion of the :term:`WSGI` environment. The
+``PATH_INFO`` string is the portion of a request's URL following the
+hostname and port number, but before any query string elements or
fragment element. For example the ``PATH_INFO`` portion of the URL
``http://example.com:8080/a/b/c?foo=1`` is ``/a/b/c``.
-Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of path
-segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is converted to
-the sequence ``['a', 'b', 'c']``.
+Traversal treats the ``PATH_INFO`` segment of a URL as a sequence of
+path segments. For example, the ``PATH_INFO`` string ``/a/b/c`` is
+converted to the sequence ``['a', 'b', 'c']``.
-After the path info is converted, a lookup is performed against the resource
-tree for each path segment. Each lookup uses the ``__getitem__`` method of a
-resource in the tree.
+This path sequence is then used to descend through the :term:`resource
+tree`, looking up a resource for each path segment. Each lookup uses the
+``__getitem__`` method of a resource in the tree.
For example, if the path info sequence is ``['a', 'b', 'c']``:
-- :term:`Traversal` pops the first element (``a``) from the path segment
- sequence and attempts to call the root resource's ``__getitem__`` method
- using that value (``a``) as an argument; we'll presume it succeeds.
+- :term:`Traversal` starts by acquiring the :term:`root` resource of the
+ application by calling the :term:`root factory`. The :term:`root factory`
+ can be configured to return whatever object is appropriate as the
+ traversal root of your application.
-- When the root resource's ``__getitem__`` succeeds it will return another
- resource, which we'll call "A". The :term:`context` temporarily becomes
- the "A" resource.
+- Next, the first element (``a``) is popped from the path segment
+ sequence and is used as a key to lookup the corresponding resource
+ in the root. This invokes the root resource's ``__getitem__`` method
+ using that value (``a``) as an argument.
+
+- If the root resource "contains" a resource with key ``a``, its
+ ``__getitem__`` method will return it. The :term:`context` temporarily
+ becomes the "A" resource.
- The next segment (``b``) is popped from the path sequence, and the "A"
resource's ``__getitem__`` is called with that value (``b``) as an
argument; we'll presume it succeeds.
-- When the "A" resource's ``__getitem__`` succeeds it will return another
- resource, which we'll call "B". The :term:`context` temporarily becomes
- the "B" resource.
-
-This process continues until the path segment sequence is exhausted or a path
-element cannot be resolved to a resource. In either case, a :term:`context`
-resource is chosen.
-
-Traversal "stops" when it either reaches a leaf level resource in your
-resource tree or when the path segments implied by the URL "run out". The
-resource that traversal "stops on" becomes the :term:`context`. If at any
-point during traversal any resource in the tree doesn't have a
-``__getitem__`` method, or if the ``__getitem__`` method of a resource raises
-a :exc:`KeyError`, traversal ends immediately, and that resource becomes the
-:term:`context`.
-
-The results of a :term:`traversal` also include a :term:`view name`. The
-:term:`view name` is the *first* URL path segment in the set of ``PATH_INFO``
-segments "left over" in the path segment list popped by the traversal process
-*after* traversal finds a context resource.
-
-The combination of the context resource and the :term:`view name` found via
-traversal is used later in the same request by a separate :app:`Pyramid`
-subsystem -- the :term:`view lookup` subsystem -- to find a :term:`view
-callable` later within the same request. How :app:`Pyramid` performs view
-lookup is explained within the :ref:`views_chapter` chapter.
+- The "A" resource's ``__getitem__`` returns another resource, which
+ we'll call "B". The :term:`context` temporarily becomes the "B"
+ resource.
+
+Traversal continues until the path segment sequence is exhausted or a
+path element cannot be resolved to a resource. In either case, the
+:term:`context` resource is the last object that the traversal
+successfully resolved. If any resource found during traversal lacks a
+``__getitem__`` method, or if its ``__getitem__`` method raises a
+:exc:`KeyError`, traversal ends immediately, and that resource becomes
+the :term:`context`.
+
+The results of a :term:`traversal` also include a :term:`view name`. If
+traversal ends before the path segment sequence is exhausted, the
+:term:`view name` is the *next* remaining path segment element. If the
+:term:`traversal` expends all of the path segments, then the :term:`view
+name` is the empty string (`''`).
+
+The combination of the context resource and the :term:`view name` found
+via traversal is used later in the same request by the :term:`view
+lookup` subsystem to find a :term:`view callable`. How :app:`Pyramid`
+performs view lookup is explained within the :ref:`view_config_chapter`
+chapter.
.. index::
single: object tree
@@ -104,19 +96,20 @@ lookup is explained within the :ref:`views_chapter` chapter.
The Resource Tree
-----------------
-When your application uses :term:`traversal` to resolve URLs to code, the
-application must supply a :term:`resource tree` to :app:`Pyramid`. The
-resource tree is a set of nested dictionary-like objects. The root of the
-tree is represented by a :term:`root` resource. The tree is effectively a
-nested set of dictionary-like objects.
+The resource tree is a set of nested dictionary-like resource objects
+that begins with a :term:`root` resource. In order to use
+:term:`traversal` to resolve URLs to code, your application must supply
+a :term:`resource tree` to :app:`Pyramid`.
-In order to supply a root resource for an application, at system startup
-time, the :app:`Pyramid` :term:`Router` is configured with a callback known
-as a :term:`root factory`. The root factory is supplied by the application
-developer as the ``root_factory`` argument to the application's
-:term:`Configurator`.
+In order to supply a root resource for an application the :app:`Pyramid`
+:term:`Router` is configured with a callback known as a :term:`root
+factory`. The root factory is supplied by the application, at startup
+time, as the ``root_factory`` argument to the :term:`Configurator`.
-Here's an example of a simple root factory:
+The root factory is a Python callable that accepts a :term:`request`
+object, and returns the root object of the :term:`resource tree`. A
+function, or class is typically used as an application's root factory.
+Here's an example of a simple root factory class:
.. code-block:: python
:linenos:
@@ -133,24 +126,23 @@ passing it to an instance of a :term:`Configurator` named ``config``:
config = Configurator(root_factory=Root)
-Using the ``root_factory`` argument to a :class:`pyramid.config.Configurator`
-constructor tells your :app:`Pyramid` application to call this root factory
-to generate a root resource whenever a request enters the application. This
-root factory is also known as the global root factory. A root factory can
-alternately be passed to the ``Configurator`` as a :term:`dotted Python name`
-which refers to a root factory defined in a different module.
-
-A root factory is passed a :term:`request` object and it is expected to
-return an object which represents the root of the resource tree. All
-:term:`traversal` will begin at this root resource. Usually a root factory
-for a traversal-based application will be more complicated than the above
-``Root`` class; in particular it may be associated with a database connection
-or another persistence mechanism.
+The ``root_factory`` argument to the
+:class:`pyramid.config.Configurator` constructor registers this root
+factory to be called to generate a root resource whenever a request
+enters the application. The root factory registered this way is also
+known as the global root factory. A root factory can alternately be
+passed to the ``Configurator`` as a :term:`dotted Python name` which can
+refer to a root factory defined in a different module.
If no :term:`root factory` is passed to the :app:`Pyramid`
-:term:`Configurator` constructor, or the ``root_factory`` is specified as the
-value ``None``, a *default* root factory is used. The default root factory
-always returns a resource that has no child resources.
+:term:`Configurator` constructor, or if the ``root_factory`` value
+specified is ``None``, a *default* root factory is used. The default
+root factory always returns a resource that has no child resources; it
+is effectively empty.
+
+Usually a root factory for a traversal-based application will be more
+complicated than the above ``Root`` class; in particular it may be
+associated with a database connection or another persistence mechanism.
.. sidebar:: Emulating the Default Root Factory
@@ -225,13 +217,14 @@ We'll provide a description of the algorithm, a diagram of how the algorithm
works, and some example traversal scenarios that might help you understand
how the algorithm operates against a specific resource tree.
-We'll also talk a bit about :term:`view lookup`. The :ref:`views_chapter`
-chapter discusses :term:`view lookup` in detail, and it is the canonical
-source for information about views. Technically, :term:`view lookup` is a
-:app:`Pyramid` subsystem that is separated from traversal entirely. However,
-we'll describe the fundamental behavior of view lookup in the examples in the
-next few sections to give you an idea of how traversal and view lookup
-cooperate, because they are almost always used together.
+We'll also talk a bit about :term:`view lookup`. The
+:ref:`view_config_chapter` chapter discusses :term:`view lookup` in
+detail, and it is the canonical source for information about views.
+Technically, :term:`view lookup` is a :app:`Pyramid` subsystem that is
+separated from traversal entirely. However, we'll describe the
+fundamental behavior of view lookup in the examples in the next few
+sections to give you an idea of how traversal and view lookup cooperate,
+because they are almost always used together.
.. index::
single: view name
@@ -469,7 +462,7 @@ References
A tutorial showing how :term:`traversal` can be used within a :app:`Pyramid`
application exists in :ref:`bfg_wiki_tutorial`.
-See the :ref:`views_chapter` chapter for detailed information about
+See the :ref:`view_config_chapter` chapter for detailed information about
:term:`view lookup`.
The :mod:`pyramid.traversal` module contains API functions that deal with
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 4c601340f..a9057003f 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -6,16 +6,28 @@
URL Dispatch
============
-:term:`URL dispatch` provides a simple way to map URLs :term:`view` code
-using a simple pattern matching language. An ordered set of patterns is
-checked one-by-one. If one of the patterns matches the path information
-associated with a request, a particular :term:`view callable` is invoked. If
-no route matches, :app:`Pyramid` falls back to trying to use
-:term:`traversal` to map the current request to a :term:`view callable`.
-
-The presence of calls to the :meth:`pyramid.config.Configurator.add_route`
-method within your application is a sign that you're using :term:`URL
-dispatch`.
+:term:`URL dispatch` provides a simple way to map URLs to :term:`view`
+code using a simple pattern matching language. An ordered set of
+patterns is checked one-by-one. If one of the patterns matches the path
+information associated with a request, a particular :term:`view
+callable` is invoked.
+
+:term:`URL dispatch` is one of two ways to perform :term:`resource
+location` in :app:`Pyramid`; the other way is using :term:`traversal`.
+If no route is matched using :term:`URL dispatch`, :app:`Pyramid` falls
+back to :term:`traversal` to handle the :term:`request`.
+
+It is the responsibility of the :term:`resource location` subsystem
+(i.e., :term:`URL dispatch` or :term:`traversal`) to find the resource
+object that is the :term:`context` of the :term:`request`. Once the
+:term:`context` is determined, :term:`view lookup` is then responsible
+for finding and invoking a :term:`view callable`. A view callable is a
+specific bit of code, defined in your application, that receives the
+:term:`request` and returns a :term:`response` object.
+
+Where appropriate, we will describe how view lookup interacts with
+:term:`resource location`. The :ref:`view_config_chapter` chapter describes
+the details of :term:`view lookup`.
High-Level Operational Overview
-------------------------------
@@ -24,10 +36,9 @@ If route configuration is present in an application, the :app:`Pyramid`
:term:`Router` checks every incoming request against an ordered set of URL
matching patterns present in a *route map*.
-If any route pattern matches the information in the :term:`request` provided
-to :app:`Pyramid`, :app:`Pyramid` will shortcut :term:`traversal`, and will
-invoke :term:`view lookup` using a :term:`context` resource generated by the
-route match.
+If any route pattern matches the information in the :term:`request`,
+:app:`Pyramid` will invoke :term:`view lookup` using a :term:`context`
+resource generated by the route match.
However, if no route pattern matches the information in the :term:`request`
provided to :app:`Pyramid`, it will fail over to using :term:`traversal` to
@@ -72,7 +83,7 @@ example:
.. versionchanged:: 1.0a4
Prior to 1.0a4, routes allow for a marker starting with a ``:``, for
- example ``/prefix/:one/:two``. Starting in 1.0a4, this style is deprecated
+ example ``/prefix/:one/:two``. This style is now deprecated
in favor or ``{}`` usage which allows for additional functionality.
.. index::
@@ -84,7 +95,7 @@ Route Configuration That Names a View Callable
When a route configuration declaration names a ``view`` attribute, the value
of the attribute will reference a :term:`view callable`. This view callable
will be invoked when the route matches. A view callable, as described in
-:ref:`views_chapter`, is developer-supplied code that "does stuff" as the
+:ref:`view_chapter`, is developer-supplied code that "does stuff" as the
result of a request. For more information about how to create view
callables, see :ref:`views_chapter`.
@@ -533,12 +544,12 @@ neither predicates nor view configuration information.
callables. Use custom predicates when no set of predefined predicates does
what you need. Custom predicates can be combined with predefined
predicates as necessary. Each custom predicate callable should accept two
- arguments: ``context`` and ``request`` and should return either ``True`` or
+ arguments: ``info`` and ``request`` and should return either ``True`` or
``False`` after doing arbitrary evaluation of the context resource and/or
the request. If all callables return ``True``, the associated route will
be considered viable for a given request. If any custom predicate returns
- ``False``, route matching continues. Note that the value ``context`` will
- always be ``None`` when passed to a custom route predicate.
+ ``False``, route matching continues. See :ref:`custom_route_predicates`
+ for more information.
**View-Related Arguments**
@@ -854,7 +865,8 @@ The ``mypackage.views`` module referred to above might look like so:
The view has access to the matchdict directly via the request, and can access
variables within it that match keys present as a result of the route pattern.
-See :ref:`views_chapter` for more information about views.
+See :ref:`views_chapter`, and :ref:`view_config_chapter` for more
+information about views.
Example 2
~~~~~~~~~
@@ -1275,6 +1287,3 @@ References
A tutorial showing how :term:`URL dispatch` can be used to create a
:app:`Pyramid` application exists in :ref:`bfg_sql_wiki_tutorial`.
-Route configuration may also be added to the system via :term:`ZCML` (see
-:ref:`zcml_route_configuration`).
-
diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst
new file mode 100644
index 000000000..3f2b1b179
--- /dev/null
+++ b/docs/narr/viewconfig.rst
@@ -0,0 +1,737 @@
+.. _view_config_chapter:
+
+.. _view_configuration:
+
+View Configuration
+==================
+
+.. index::
+ single: view lookup
+
+:term:`View configuration` controls how :term:`view lookup` operates in
+your application. In earlier chapters, you have been exposed to a few
+simple view configuration declarations without much explanation. In this
+chapter we will explore the subject in detail.
+
+.. _view_lookup:
+
+View Lookup and Invocation
+--------------------------
+
+:term:`View lookup` is the :app:`Pyramid` subsystem responsible for finding
+an invoking a :term:`view callable`. The view lookup subsystem is passed a
+:term:`context` and a :term:`request` object.
+
+:term:`View configuration` information stored within in the
+:term:`application registry` is compared against the context and request by
+the view lookup subsystem in order to find the "best" view callable for the
+set of circumstances implied by the context and request.
+
+:term:`View predicate` attributes are an important part of view
+configuration that enables the :term:`View lookup` subsystem to find and
+invoke the appropriate view. Predicate attributes can be thought of
+like "narrowers". In general, the greater number of predicate
+attributes possessed by a view's configuration, the more specific the
+circumstances need to be before the registered view callable will be
+invoked.
+
+Mapping a Resource or URL Pattern to a View Callable
+----------------------------------------------------
+
+A developer makes a :term:`view callable` available for use within a
+:app:`Pyramid` application via :term:`view configuration`. A view
+configuration associates a view callable with a set of statements that
+determine the set of circumstances which must be true for the view callable
+to be invoked.
+
+A view configuration statement is made about information present in the
+:term:`context` resource and the :term:`request`.
+
+View configuration is performed in one of these ways:
+
+- by running a :term:`scan` against application source code which has a
+ :class:`pyramid.view.view_config` decorator attached to a Python object as
+ per :class:`pyramid.view.view_config` and
+ :ref:`mapping_views_using_a_decorator_section`.
+
+- by using the :meth:`pyramid.config.Configurator.add_view` method as per
+ :meth:`pyramid.config.Configurator.add_view` and
+ :ref:`mapping_views_using_imperative_config_section`.
+
+- By specifying a view within a :term:`route configuration`. View
+ configuration via a route configuration is performed by using the
+ :meth:`pyramid.config.Configurator.add_route` method, passing a ``view``
+ argument specifying a view callable.
+
+.. note:: A package named ``pyramid_handlers`` (available from PyPI) provides
+ an analogue of :term:`Pylons` -style "controllers", which are a special
+ kind of view class which provides more automation when your application
+ uses :term:`URL dispatch` solely.
+
+.. _view_configuration_parameters:
+
+View Configuration Parameters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All forms of view configuration accept the same general types of arguments.
+
+Many arguments supplied during view configuration are :term:`view predicate`
+arguments. View predicate arguments used during view configuration are used
+to narrow the set of circumstances in which :term:`view lookup` will find a
+particular view callable.
+
+In general, the fewer number of predicates which are supplied to a
+particular view configuration, the more likely it is that the associated
+view callable will be invoked. The greater the number supplied, the
+less likely. A view with five predicates will always be found and
+evaluated before a view with two, for example. All predicates must
+match for the associated view to be called.
+
+This does not mean however, that :app:`Pyramid` "stops looking" when it
+finds a view registration with predicates that don't match. If one set
+of view predicates does not match, the "next most specific" view (if
+any) is consulted for predicates, and so on, until a view is found, or
+no view can be matched up with the request. The first view with a set
+of predicates all of which match the request environment will be
+invoked.
+
+If no view can be found with predicates which allow it to be matched up with
+the request, :app:`Pyramid` will return an error to the user's browser,
+representing a "not found" (404) page. See :ref:`changing_the_notfound_view`
+for more information about changing the default notfound view.
+
+Some view configuration arguments are non-predicate arguments. These tend to
+modify the response of the view callable or prevent the view callable from
+being invoked due to an authorization policy. The presence of non-predicate
+arguments in a view configuration does not narrow the circumstances in which
+the view callable will be invoked.
+
+Non-Predicate Arguments
++++++++++++++++++++++++
+
+``permission``
+ The name of a :term:`permission` that the user must possess in order to
+ invoke the :term:`view callable`. See :ref:`view_security_section` for
+ more information about view security and permissions.
+
+ If ``permission`` is not supplied, no permission is registered for this
+ view (it's accessible by any caller).
+
+``attr``
+ The view machinery defaults to using the ``__call__`` method of the
+ :term:`view callable` (or the function itself, if the view callable is a
+ function) to obtain a response. The ``attr`` value allows you to vary the
+ method attribute used to obtain the response. For example, if your view
+ was a class, and the class has a method named ``index`` and you wanted to
+ use this method instead of the class' ``__call__`` method to return the
+ response, you'd say ``attr="index"`` in the view configuration for the
+ view. This is most useful when the view definition is a class.
+
+ If ``attr`` is not supplied, ``None`` is used (implying the function itself
+ if the view is a function, or the ``__call__`` callable attribute if the
+ view is a class).
+
+``renderer``
+ Denotes the :term:`renderer` implementation which will be used to construct
+ a :term:`response` from the associated view callable's return value. (see
+ also :ref:`renderers_chapter`).
+
+ This is either a single string term (e.g. ``json``) or a string implying a
+ path or :term:`asset specification` (e.g. ``templates/views.pt``) naming a
+ :term:`renderer` implementation. If the ``renderer`` value does not
+ contain a dot (``.``), the specified string will be used to look up a
+ renderer implementation, and that renderer implementation will be used to
+ construct a response from the view return value. If the ``renderer`` value
+ contains a dot (``.``), the specified term will be treated as a path, and
+ the filename extension of the last element in the path will be used to look
+ up the renderer implementation, which will be passed the full path.
+
+ When the renderer is a path, although a path is usually just a simple
+ relative pathname (e.g. ``templates/foo.pt``, implying that a template
+ named "foo.pt" is in the "templates" directory relative to the directory of
+ the current :term:`package`), a path can be absolute, starting with a slash
+ on UNIX or a drive letter prefix on Windows. The path can alternately be a
+ :term:`asset specification` in the form
+ ``some.dotted.package_name:relative/path``, making it possible to address
+ template assets which live in a separate package.
+
+ The ``renderer`` attribute is optional. If it is not defined, the "null"
+ renderer is assumed (no rendering is performed and the value is passed back
+ to the upstream :app:`Pyramid` machinery unmolested). Note that if the
+ view callable itself returns a :term:`response` (see :ref:`the_response`),
+ the specified renderer implementation is never called.
+
+``wrapper``
+ The :term:`view name` of a different :term:`view configuration` which will
+ receive the response body of this view as the ``request.wrapped_body``
+ attribute of its own :term:`request`, and the :term:`response` returned by
+ this view as the ``request.wrapped_response`` attribute of its own request.
+ Using a wrapper makes it possible to "chain" views together to form a
+ composite response. The response of the outermost wrapper view will be
+ returned to the user. The wrapper view will be found as any view is found:
+ see :ref:`view_lookup`. The "best" wrapper view will be found based on the
+ lookup ordering: "under the hood" this wrapper view is looked up via
+ ``pyramid.view.render_view_to_response(context, request,
+ 'wrapper_viewname')``. The context and request of a wrapper view is the
+ same context and request of the inner view.
+
+ If ``wrapper`` is not supplied, no wrapper view is used.
+
+``decorator``
+ A :term:`dotted Python name` to function (or the function itself) which
+ will be used to decorate the registered :term:`view callable`. The
+ decorator function will be called with the view callable as a single
+ argument. The view callable it is passed will accept ``(context,
+ request)``. The decorator must return a replacement view callable which
+ also accepts ``(context, request)``.
+
+``mapper``
+ A Python object or :term:`dotted Python name` which refers to a :term:`view
+ mapper`, or ``None``. By default it is ``None``, which indicates that the
+ view should use the default view mapper. This plug-point is useful for
+ Pyramid extension developers, but it's not very useful for 'civilians' who
+ are just developing stock Pyramid applications. Pay no attention to the man
+ behind the curtain.
+
+Predicate Arguments
++++++++++++++++++++
+
+These arguments modify view lookup behavior. In general, the more predicate
+arguments that are supplied, the more specific, and narrower the usage of the
+configured view.
+
+``name``
+ The :term:`view name` required to match this view callable. Read
+ :ref:`traversal_chapter` to understand the concept of a view name.
+
+ If ``name`` is not supplied, the empty string is used (implying the default
+ view).
+
+``context``
+ An object representing a Python class that the :term:`context` resource
+ must be an instance of *or* the :term:`interface` that the :term:`context`
+ resource must provide in order for this view to be found and called. This
+ predicate is true when the :term:`context` resource is an instance of the
+ represented class or if the :term:`context` resource provides the
+ represented interface; it is otherwise false.
+
+ If ``context`` is not supplied, the value ``None``, which matches any
+ resource, is used.
+
+``route_name``
+ If ``route_name`` is supplied, the view callable will be invoked only when
+ the named route has matched.
+
+ This value must match the ``name`` of a :term:`route configuration`
+ declaration (see :ref:`urldispatch_chapter`) that must match before this
+ view will be called. Note that the ``route`` configuration referred to by
+ ``route_name`` will usually have a ``*traverse`` token in the value of its
+ ``pattern``, representing a part of the path that will be used by
+ :term:`traversal` against the result of the route's :term:`root factory`.
+
+ If ``route_name`` is not supplied, the view callable will be have a chance
+ of being invoked if no other route was matched. This is when the
+ request/context pair found via :term:`resource location` does not indicate
+ it matched any configured route.
+
+``request_type``
+ This value should be an :term:`interface` that the :term:`request` must
+ provide in order for this view to be found and called.
+
+ If ``request_type`` is not supplied, the value ``None`` is used, implying
+ any request type.
+
+ *This is an advanced feature, not often used by "civilians"*.
+
+``request_method``
+ This value can either be one of the strings ``GET``, ``POST``, ``PUT``,
+ ``DELETE``, or ``HEAD`` representing an HTTP ``REQUEST_METHOD``. A view
+ declaration with this argument ensures that the view will only be called
+ when the request's ``method`` attribute (aka the ``REQUEST_METHOD`` of the
+ WSGI environment) string matches the supplied value.
+
+ If ``request_method`` is not supplied, the view will be invoked regardless
+ 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.
+
+ If the value supplied has a ``=`` sign in it,
+ e.g. ``request_params="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
+ request.
+
+ If ``request_param`` is not supplied, the view will be invoked without
+ consideration of keys and values in the ``request.params`` dictionary.
+
+``containment``
+ This value should be a reference to a Python class or :term:`interface`
+ that a parent object in the context resource's :term:`lineage` must provide
+ in order for this view to be found and called. The resources in your
+ resource tree must be "location-aware" to use this feature.
+
+ If ``containment`` is not supplied, the interfaces and classes in the
+ lineage are not considered when deciding whether or not to invoke the view
+ callable.
+
+ See :ref:`location_aware` for more information about location-awareness.
+
+``xhr``
+ This value should be either ``True`` or ``False``. If this value is
+ specified and is ``True``, the :term:`WSGI` environment must possess an
+ ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has the
+ value ``XMLHttpRequest`` for the associated view callable to be found and
+ called. This is useful for detecting AJAX requests issued from jQuery,
+ Prototype and other Javascript libraries.
+
+ If ``xhr`` is not specified, the ``HTTP_X_REQUESTED_WITH`` HTTP header is
+ not taken into consideration when deciding whether or not to invoke the
+ associated view callable.
+
+``accept``
+ The value of this argument represents a match query for one or more
+ mimetypes in the ``Accept`` HTTP request header. If this value is
+ specified, it must be in one of the following forms: a mimetype match token
+ in the form ``text/plain``, a wildcard mimetype match token in the form
+ ``text/*`` or a match-all wildcard mimetype match token in the form
+ ``*/*``. If any of the forms matches the ``Accept`` header of the request,
+ this predicate will be true.
+
+ If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not
+ taken into consideration when deciding whether or not to invoke the
+ associated view callable.
+
+``header``
+ This value represents an HTTP header name or a header name/value pair.
+
+ If ``header`` is specified, it must be a header name or a
+ ``headername:headervalue`` pair.
+
+ If ``header`` is specified without a value (a bare header name only,
+ e.g. ``If-Modified-Since``), the view will only be invoked if the HTTP
+ header exists with any value in the request.
+
+ If ``header`` is specified, and possesses a name/value pair
+ (e.g. ``User-Agent:Mozilla/.*``), the view will only be invoked if the HTTP
+ header exists *and* the HTTP header matches the value requested. When the
+ ``headervalue`` contains a ``:`` (colon), it will be considered a
+ name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).
+ The value portion should be a regular expression.
+
+ Whether or not the value represents a header name or a header name/value
+ pair, the case of the header name is not significant.
+
+ If ``header`` is not specified, the composition, presence or absence of
+ HTTP headers is not taken into consideration when deciding whether or not
+ to invoke the associated view callable.
+
+``path_info``
+ This value represents a regular expression pattern that will be tested
+ against the ``PATH_INFO`` WSGI environment variable to decide whether or
+ not to call the associated view callable. If the regex matches, this
+ predicate will be ``True``.
+
+ If ``path_info`` is not specified, the WSGI ``PATH_INFO`` is not taken into
+ consideration when deciding whether or not to invoke the associated view
+ callable.
+
+``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
+ predefined predicates do what you need. Custom predicates can be combined
+ with predefined predicates as necessary. Each custom predicate callable
+ should accept two arguments: ``context`` and ``request`` and should return
+ either ``True`` or ``False`` after doing arbitrary evaluation of the
+ context resource and/or the request. If all callables return ``True``, the
+ associated view callable will be considered viable for a given request.
+
+ If ``custom_predicates`` is not specified, no custom predicates are
+ used.
+
+.. index::
+ single: view_config decorator
+
+.. _mapping_views_using_a_decorator_section:
+
+View Configuration Using the ``@view_config`` Decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For better locality of reference, you may use the
+:class:`pyramid.view.view_config` decorator to associate your view functions
+with URLs instead of using :term:`ZCML` or imperative configuration for the
+same purpose.
+
+.. warning::
+
+ Using this feature tends to slows down application startup slightly, as
+ more work is performed at application startup to scan for view
+ declarations.
+
+Usage of the ``view_config`` decorator is a form of :term:`declarative
+configuration`, like ZCML, but in decorator form.
+:class:`pyramid.view.view_config` can be used to associate :term:`view
+configuration` information -- as done via the equivalent imperative code or
+ZCML -- with a function that acts as a :app:`Pyramid` view callable. All
+arguments to the :meth:`pyramid.config.Configurator.add_view` method (save
+for the ``view`` argument) are available in decorator form and mean precisely
+the same thing.
+
+An example of the :class:`pyramid.view.view_config` decorator might reside in
+a :app:`Pyramid` application module ``views.py``:
+
+.. ignore-next-block
+.. code-block:: python
+ :linenos:
+
+ from resources import MyResource
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(name='my_view', request_method='POST', context=MyResource,
+ permission='read')
+ def my_view(request):
+ return Response('OK')
+
+Using this decorator as above replaces the need to add this imperative
+configuration stanza:
+
+.. ignore-next-block
+.. code-block:: python
+ :linenos:
+
+ config.add_view('.views.my_view', name='my_view', request_method='POST',
+ context=MyResource, permission='read')
+
+All arguments to ``view_config`` may be omitted. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config()
+ def my_view(request):
+ """ My view """
+ return Response()
+
+Such a registration as the one directly above implies that the view name will
+be ``my_view``, registered with a ``context`` argument that matches any
+resource type, using no permission, registered against requests with any
+request method, request type, request param, route name, or containment.
+
+The mere existence of a ``@view_config`` decorator doesn't suffice to perform
+view configuration. All that the decorator does is "annotate" the function
+with your configuration declarations, it doesn't process them. To make
+:app:`Pyramid` process your :class:`pyramid.view.view_config` declarations,
+you *must* do use the ``scan`` method of a
+:class:`pyramid.config.Configurator`:
+
+.. code-block:: python
+ :linenos:
+
+ # config is assumed to be an instance of the
+ # pyramid.config.Configurator class
+ config.scan()
+
+Please see :ref:`decorations_and_code_scanning` for detailed information
+about what happens when code is scanned for configuration declarations
+resulting from use of decorators like :class:`pyramid.view.view_config`.
+
+See :ref:`configuration_module` for additional API arguments to the
+:meth:`pyramid.config.Configurator.scan` method. For example, the method
+allows you to supply a ``package`` argument to better control exactly *which*
+code will be scanned.
+
+``@view_config`` Placement
+++++++++++++++++++++++++++
+
+A :class:`pyramid.view.view_config` decorator can be placed in various points
+in your application.
+
+If your view callable is a function, it may be used as a function decorator:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(name='edit')
+ def edit(request):
+ return Response('edited!')
+
+If your view callable is a class, the decorator can also be used as a class
+decorator in Python 2.6 and better (Python 2.5 and below do not support class
+decorators). All the arguments to the decorator are the same when applied
+against a class as when they are applied against a function. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config()
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def __call__(self):
+ return Response('hello')
+
+You can use the :class:`pyramid.view.view_config` decorator as a simple
+callable to manually decorate classes in Python 2.5 and below without the
+decorator syntactic sugar, if you wish:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def __call__(self):
+ return Response('hello')
+
+ my_view = view_config()(MyView)
+
+More than one :class:`pyramid.view.view_config` decorator can be stacked on
+top of any number of others. Each decorator creates a separate view
+registration. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+ from pyramid.response import Response
+
+ @view_config(name='edit')
+ @view_config(name='change')
+ def edit(request):
+ return Response('edited!')
+
+This registers the same view under two different names.
+
+The decorator can also be used against class methods:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ @view_config(name='hello')
+ def amethod(self):
+ return Response('hello')
+
+When the decorator is used against a class method, a view is registered for
+the *class*, so the class constructor must accept an argument list in one of
+two forms: either it must accept a single argument ``request`` or it must
+accept two arguments, ``context, request``.
+
+The method which is decorated must return a :term:`response`.
+
+Using the decorator against a particular method of a class is equivalent to
+using the ``attr`` parameter in a decorator attached to the class itself.
+For example, the above registration implied by the decorator being used
+against the ``amethod`` method could be spelled equivalently as the below:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+ from pyramid.view import view_config
+
+ @view_config(attr='amethod', name='hello')
+ class MyView(object):
+ def __init__(self, request):
+ self.request = request
+
+ def amethod(self):
+ return Response('hello')
+
+.. index::
+ single: add_view
+
+.. _mapping_views_using_imperative_config_section:
+
+View Registration Using :meth:`~pyramid.config.Configurator.add_view`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :meth:`pyramid.config.Configurator.add_view` method within
+:ref:`configuration_module` is used to configure a view imperatively. The
+arguments to this method are very similar to the arguments that you provide
+to the ``@view_config`` decorator. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+
+ def hello_world(request):
+ return Response('hello!')
+
+ # config is assumed to be an instance of the
+ # pyramid.config.Configurator class
+ config.add_view(hello_world, name='hello.html')
+
+The first argument, ``view``, is required. It must either be a Python object
+which is the view itself or a :term:`dotted Python name` to such an object.
+All other arguments are optional. See
+:meth:`pyramid.config.Configurator.add_view` for more information.
+
+.. index::
+ single: resource interfaces
+
+.. _using_resource_interfaces:
+
+Using Resource Interfaces In View Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Instead of registering your views with a ``context`` that names a Python
+resource *class*, you can optionally register a view callable with a
+``context`` which is an :term:`interface`. An interface can be attached
+arbitrarily to any resource object. View lookup treats context interfaces
+specially, and therefore the identity of a resource can be divorced from that
+of the class which implements it. As a result, associating a view with an
+interface can provide more flexibility for sharing a single view between two
+or more different implementations of a resource type. For example, if two
+resource objects of different Python class types share the same interface,
+you can use the same view configuration to specify both of them as a
+``context``.
+
+In order to make use of interfaces in your application during view dispatch,
+you must create an interface and mark up your resource classes or instances
+with interface declarations that refer to this interface.
+
+To attach an interface to a resource *class*, you define the interface and
+use the :func:`zope.interface.implements` function to associate the interface
+with the class.
+
+.. code-block:: python
+ :linenos:
+
+ from zope.interface import Interface
+ from zope.interface import implements
+
+ class IHello(Interface):
+ """ A marker interface """
+
+ class Hello(object):
+ implements(IHello)
+
+To attach an interface to a resource *instance*, you define the interface and
+use the :func:`zope.interface.alsoProvides` function to associate the
+interface with the instance. This function mutates the instance in such a
+way that the interface is attached to it.
+
+.. code-block:: python
+ :linenos:
+
+ from zope.interface import Interface
+ from zope.interface import alsoProvides
+
+ class IHello(Interface):
+ """ A marker interface """
+
+ class Hello(object):
+ pass
+
+ def make_hello():
+ hello = Hello()
+ alsoProvides(hello, IHello)
+ return hello
+
+Regardless of how you associate an interface, with a resource instance, or a
+resource class, the resulting code to associate that interface with a view
+callable is the same. Assuming the above code that defines an ``IHello``
+interface lives in the root of your application, and its module is named
+"resources.py", the interface declaration below will associate the
+``mypackage.views.hello_world`` view with resources that implement, or
+provide, this interface.
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+
+ config.add_view('mypackage.views.hello_world', name='hello.html',
+ context='mypackage.resources.IHello')
+
+Any time a resource that is determined to be the :term:`context` provides
+this interface, and a view named ``hello.html`` is looked up against it as
+per the URL, the ``mypackage.views.hello_world`` view callable will be
+invoked.
+
+Note, in cases where a view is registered against a resource class, and a
+view is also registered against an interface that the resource class
+implements, an ambiguity arises. Views registered for the resource class take
+precedence over any views registered for any interface the resource class
+implements. Thus, if one view configuration names a ``context`` of both the
+class type of a resource, and another view configuration names a ``context``
+of interface implemented by the resource's class, and both view
+configurations are otherwise identical, the view registered for the context's
+class will "win".
+
+For more information about defining resources with interfaces for use within
+view configuration, see :ref:`resources_which_implement_interfaces`.
+
+.. index::
+ single: view security
+ pair: security; view
+
+.. _view_security_section:
+
+Configuring View Security
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If an :term:`authorization policy` is active, any :term:`permission` attached
+to a :term:`view configuration` found during view lookup will be verified.
+This will ensure that the currently authenticated user possesses that
+permission against the :term:`context` resource before the view function is
+actually called. Here's an example of specifying a permission in a view
+configuration using :meth:`pyramid.config.Configurator.add_view`:
+
+.. code-block:: python
+ :linenos:
+
+ # config is an instance of pyramid.config.Configurator
+
+ config.add_view('myproject.views.add_entry', name='add.html',
+ context='myproject.resources.IBlog', permission='add')
+
+When an :term:`authorization policy` is enabled, this view will be protected
+with the ``add`` permission. The view will *not be called* if the user does
+not possess the ``add`` permission relative to the current :term:`context`.
+Instead the :term:`forbidden view` result will be returned to the client as
+per :ref:`protecting_views`.
+
+.. index::
+ single: debugging not found errors
+ single: not found error (debugging)
+
+.. _debug_notfound_section:
+
+:exc:`NotFound` Errors
+~~~~~~~~~~~~~~~~~~~~~~
+
+It's useful to be able to debug :exc:`NotFound` error responses when they
+occur unexpectedly due to an application registry misconfiguration. To debug
+these errors, use the ``PYRAMID_DEBUG_NOTFOUND`` environment variable or the
+``debug_notfound`` configuration file setting. Details of why a view was not
+found will be printed to ``stderr``, and the browser representation of the
+error will include the same information. See :ref:`environment_chapter` for
+more information about how, and where to set these values.
+
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index ad28e48d4..e1eacfeae 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -17,11 +17,12 @@ request made to your application.
that implements a view *callable*, and the process of view
*lookup*.
-The chapter :ref:`resourcelocation_chapter` describes how, using information
-from the :term:`request`, a :term:`context` resource is computed. But the
-context resource itself isn't very useful without an associated :term:`view
-callable`. A view callable returns a response to a user, often using the
-context resource to do so.
+The :ref:`urldispatch_chapter`, and :ref:`traversal_chapter` chapters
+describes how, using information from the :term:`request`, a
+:term:`context` resource is computed. But the context resource itself
+isn't very useful without an associated :term:`view callable`. A view
+callable returns a response to a user, often using the context resource
+to do so.
The job of actually locating and invoking the "best" :term:`view callable` is
the job of the :term:`view lookup` subsystem. The view lookup subsystem
@@ -30,31 +31,34 @@ in the :term:`request` against :term:`view configuration` statements made by
the developer to choose the most appropriate view callable for a specific
set of circumstances.
-This chapter provides documentation detailing the process of creating
-view callables, documentation about performing view configuration, and
-a detailed explanation of view lookup.
+This chapter describes how view callables work. In the
+:ref:`view_config_chapter` chapter, there are details about performing
+view configuration, and a detailed explanation of view lookup.
View Callables
--------------
-No matter how a view callable is eventually found, all view callables
-used by :app:`Pyramid` must be constructed in the same way, and
-must return the same kind of return value.
-
-Most view callables accept a single argument named ``request``. This
-argument represents a :app:`Pyramid` :term:`Request` object. A request
-object encapsulates a WSGI environment as represented to :app:`Pyramid` by
-the upstream :term:`WSGI` server.
-
-In general, a view callable must return a :mod:`Pyramid` :term:`Response`
-object.
-
-.. note:: The above statement, though it sounds definitive, isn't always
- true. See :ref:`renderers_chapter` for information related to using a
- :term:`renderer` to convert a non-Response view callable return value into
- a Response object.
-
-View callables can be functions, instances, or classes.
+View callables are, at the risk of sounding obvious, callable Python
+objects. Specifically, view callables can be functions, classes, or
+instances that implement an ``__call__`` method (making the
+instance callable).
+
+View callables must, at a minimum, accept a single argument named
+``request``. This argument represents a :app:`Pyramid` :term:`Request`
+object. A request object encapsulates a WSGI environment provided to
+:app:`Pyramid` by the upstream :term:`WSGI` server. As you might expect,
+the request object contains everything your application needs to know
+about the specific HTTP request being made.
+
+A view callable's ultimate responsibility is to create a :mod:`Pyramid`
+:term:`Response` object. This can be done by creating the response
+object in the view callable code and returning it directly, as we will
+be doing in this chapter. However, if a view callable does not return a
+response itself, it can be configured to use a :term:`renderer` that
+converts its return value into a :term:`Response` object. Using
+renderers is the common way that templates are used with view callables
+to generate markup. See the :ref:`renderers_chapter` chapter for
+details.
.. index::
single: view calling convention
@@ -63,7 +67,7 @@ View callables can be functions, instances, or classes.
.. _function_as_view:
Defining a View Callable as a Function
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------------
One of the easiest way to define a view callable is to create a function that
accepts a single argument named ``request``, and which returns a
@@ -85,7 +89,7 @@ implemented as a function:
.. _class_as_view:
Defining a View Callable as a Class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------------------
A view callable may also be represented by a Python class instead of a
function. When a view callable is a class, the calling semantics are
@@ -126,8 +130,10 @@ method expected to return a response, you can either:
values, each pointing at a different method of the class if you'd like the
class to represent a collection of related view callables.
-- treat the class as a :term:`view handler` by using it as the ``handler=``
- argument of a call to :meth:`pyramid.config.Configurator.add_handler`.
+.. note:: A package named :term:`pyramid_handlers` (available from PyPI)
+ provides an analogue of :term:`Pylons` -style "controllers", which are a
+ special kind of view class which provides more automation when your
+ application uses :term:`URL dispatch` solely.
.. index::
single: view calling convention
@@ -135,7 +141,7 @@ method expected to return a response, you can either:
.. _request_and_context_view_definitions:
Alternate View Callable Argument/Calling Conventions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------------------------------------------------
Usually, view callables are defined to accept only a single argument:
``request``. However, view callables may alternately be defined as classes,
@@ -210,7 +216,7 @@ access to the context via ``request.context``.
.. _the_response:
View Callable Responses
-~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------
A view callable may always return an object that implements the :app:`Pyramid`
:term:`Response` interface. The easiest way to return something that
@@ -256,7 +262,7 @@ These attributes form the notional "Pyramid Response interface".
.. _http_redirect:
Using a View Callable to Do an HTTP Redirect
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------------------
You can issue an HTTP redirect from within a view by returning a particular
kind of response.
@@ -295,7 +301,7 @@ Unauthorized``.
.. _special_exceptions_in_callables:
Using Special Exceptions In View Callables
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+------------------------------------------
Usually when a Python exception is raised within a view callable,
:app:`Pyramid` allows the exception to propagate all the way out to the
@@ -325,7 +331,7 @@ available to the view which :app:`Pyramid` invokes as
.. _exception_views:
Exception Views
-~~~~~~~~~~~~~~~~
+---------------
The machinery which allows the special :exc:`pyramid.exceptions.NotFound` and
:exc:`pyramid.exceptions.Forbidden` exceptions to be caught by specialized
@@ -404,1089 +410,3 @@ exception views which have a name will be ignored.
Exception views can be configured with any view registration mechanism:
``@view_config`` decorator, ZCML, or imperative ``add_view`` styles.
-.. index::
- single: unicode, views, and forms
- single: forms, views, and unicode
- single: views, forms, and unicode
-
-Handling Form Submissions in View Callables (Unicode and Character Set Issues)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Most web applications need to accept form submissions from web browsers and
-various other clients. In :app:`Pyramid`, form submission handling logic is
-always part of a :term:`view`. For a general overview of how to handle form
-submission data using the :term:`WebOb` API, see :ref:`webob_chapter` and
-`"Query and POST variables" within the WebOb documentation
-<http://pythonpaste.org/webob/reference.html#query-post-variables>`_.
-:app:`Pyramid` defers to WebOb for its request and response implementations,
-and handling form submission data is a property of the request
-implementation. Understanding WebOb's request API is the key to
-understanding how to process form submission data.
-
-There are some defaults that you need to be aware of when trying to handle
-form submission data in a :app:`Pyramid` view. Having high-order (i.e.,
-non-ASCII) characters in data contained within form submissions is
-exceedingly common, and the UTF-8 encoding is the most common encoding used
-on the web for character data. Since Unicode values are much saner than
-working with and storing bytestrings, :app:`Pyramid` configures the
-:term:`WebOb` request machinery to attempt to decode form submission values
-into Unicode from UTF-8 implicitly. This implicit decoding happens when view
-code obtains form field values via the ``request.params``, ``request.GET``,
-or ``request.POST`` APIs (see :ref:`request_module` for details about these
-APIs).
-
-.. note::
-
- Many people find the difference between Unicode and UTF-8 confusing.
- Unicode is a standard for representing text that supports most of the
- world's writing systems. However, there are many ways that Unicode data
- can be encoded into bytes for transit and storage. UTF-8 is a specific
- encoding for Unicode, that is backwards-compatible with ASCII. This makes
- UTF-8 very convenient for encoding data where a large subset of that data
- is ASCII characters, which is largely true on the web. UTF-8 is also the
- standard character encoding for URLs.
-
-As an example, let's assume that the following form page is served up to a
-browser client, and its ``action`` points at some :app:`Pyramid` view code:
-
-.. code-block:: xml
- :linenos:
-
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- </head>
- <form method="POST" action="myview">
- <div>
- <input type="text" name="firstname"/>
- </div>
- <div>
- <input type="text" name="lastname"/>
- </div>
- <input type="submit" value="Submit"/>
- </form>
- </html>
-
-The ``myview`` view code in the :app:`Pyramid` application *must* expect that
-the values returned by ``request.params`` will be of type ``unicode``, as
-opposed to type ``str``. The following will work to accept a form post from
-the above form:
-
-.. code-block:: python
- :linenos:
-
- def myview(request):
- firstname = request.params['firstname']
- lastname = request.params['lastname']
-
-But the following ``myview`` view code *may not* work, as it tries to decode
-already-decoded (``unicode``) values obtained from ``request.params``:
-
-.. code-block:: python
- :linenos:
-
- def myview(request):
- # the .decode('utf-8') will break below if there are any high-order
- # characters in the firstname or lastname
- firstname = request.params['firstname'].decode('utf-8')
- lastname = request.params['lastname'].decode('utf-8')
-
-For implicit decoding to work reliably, you should ensure that every form you
-render that posts to a :app:`Pyramid` view explicitly defines a charset
-encoding of UTF-8. This can be done via a response that has a
-``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form above,
-with a ``meta http-equiv`` tag that implies that the charset is UTF-8 within
-the HTML ``head`` of the page containing the form. This must be done
-explicitly because all known browser clients assume that they should encode
-form data in the same character set implied by ``Content-Type`` value of the
-response containing the form when subsequently submitting that form. There is
-no other generally accepted way to tell browser clients which charset to use
-to encode form data. If you do not specify an encoding explicitly, the
-browser client will choose to encode form data in its default character set
-before submitting it, which may not be UTF-8 as the server expects. If a
-request containing form data encoded in a non-UTF8 charset is handled by your
-view code, eventually the request code accessed within your view will throw
-an error when it can't decode some high-order character encoded in another
-character set within form data, e.g., when ``request.params['somename']`` is
-accessed.
-
-If you are using the :class:`pyramid.response.Response` class to generate a
-response, or if you use the ``render_template_*`` templating APIs, the UTF-8
-charset is set automatically as the default via the ``Content-Type`` header.
-If you return a ``Content-Type`` header without an explicit charset, a
-request will add a ``;charset=utf-8`` trailer to the ``Content-Type`` header
-value for you, for response content types that are textual
-(e.g. ``text/html``, ``application/xml``, etc) as it is rendered. If you are
-using your own response object, you will need to ensure you do this yourself.
-
-.. note:: Only the *values* of request params obtained via
- ``request.params``, ``request.GET`` or ``request.POST`` are decoded
- to Unicode objects implicitly in the :app:`Pyramid` default
- configuration. The keys are still (byte) strings.
-
-.. index::
- single: view configuration
-
-.. _view_configuration:
-
-View Configuration: Mapping a Resource or URL Pattern to a View Callable
-------------------------------------------------------------------------
-
-A developer makes a :term:`view callable` available for use within a
-:app:`Pyramid` application via :term:`view configuration`. A view
-configuration associates a view callable with a set of statements that
-determine the set of circumstances which must be true for the view callable
-to be invoked.
-
-A view configuration statement is made about information present in the
-:term:`context` resource and the :term:`request`.
-
-View configuration is performed in one of these ways:
-
-- by running a :term:`scan` against application source code which has a
- :class:`pyramid.view.view_config` decorator attached to a Python object as
- per :class:`pyramid.view.view_config` and
- :ref:`mapping_views_using_a_decorator_section`.
-
-- by using the :meth:`pyramid.config.Configurator.add_view` method as per
- :meth:`pyramid.config.Configurator.add_view` and
- :ref:`mapping_views_using_imperative_config_section`.
-
-- By specifying a view within a :term:`route configuration`. View
- configuration via a route configuration is performed by using the
- :meth:`pyramid.config.Configurator.add_route` method, passing a ``view``
- argument specifying a view callable.
-
-- by using the :meth:`pyramid.config.Configurator.add_handler` against a
- :term:`view handler` class (useful only for :term:`URL dispatch`
- applications).
-
-.. note:: You can also add view configuration by adding a ``<view>``,
- ``<route>`` or ``<handler>`` declaration to :term:`ZCML` used by your
- application as per :ref:`mapping_views_using_zcml_section`,
- :ref:`view_directive`, :ref:`route_directive` or :ref:`handler_directive`.
-
-.. _view_configuration_parameters:
-
-View Configuration Parameters
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-All forms of view configuration accept the same general types of arguments.
-
-Many arguments supplied during view configuration are :term:`view predicate`
-arguments. View predicate arguments used during view configuration are used
-to narrow the set of circumstances in which :mod:`view lookup` will find a
-particular view callable. In general, the fewer number of predicates which
-are supplied to a particular view configuration, the more likely it is that
-the associated view callable will be invoked. The greater the number
-supplied, the less likely.
-
-Some view configuration arguments are non-predicate arguments. These tend to
-modify the response of the view callable or prevent the view callable from
-being invoked due to an authorization policy. The presence of non-predicate
-arguments in a view configuration does not narrow the circumstances in which
-the view callable will be invoked.
-
-Non-Predicate Arguments
-+++++++++++++++++++++++
-
-``permission``
- The name of a :term:`permission` that the user must possess in order to
- invoke the :term:`view callable`. See :ref:`view_security_section` for
- more information about view security and permissions.
-
- If ``permission`` is not supplied, no permission is registered for this
- view (it's accessible by any caller).
-
-``attr``
- The view machinery defaults to using the ``__call__`` method of the
- :term:`view callable` (or the function itself, if the view callable is a
- function) to obtain a response. The ``attr`` value allows you to vary the
- method attribute used to obtain the response. For example, if your view
- was a class, and the class has a method named ``index`` and you wanted to
- use this method instead of the class' ``__call__`` method to return the
- response, you'd say ``attr="index"`` in the view configuration for the
- view. This is most useful when the view definition is a class.
-
- If ``attr`` is not supplied, ``None`` is used (implying the function itself
- if the view is a function, or the ``__call__`` callable attribute if the
- view is a class).
-
-``renderer``
- Denotes the :term:`renderer` implementation which will be used to construct
- a :term:`response` from the associated view callable's return value. (see
- also :ref:`renderers_chapter`).
-
- This is either a single string term (e.g. ``json``) or a string implying a
- path or :term:`asset specification` (e.g. ``templates/views.pt``) naming a
- :term:`renderer` implementation. If the ``renderer`` value does not
- contain a dot (``.``), the specified string will be used to look up a
- renderer implementation, and that renderer implementation will be used to
- construct a response from the view return value. If the ``renderer`` value
- contains a dot (``.``), the specified term will be treated as a path, and
- the filename extension of the last element in the path will be used to look
- up the renderer implementation, which will be passed the full path.
-
- When the renderer is a path, although a path is usually just a simple
- relative pathname (e.g. ``templates/foo.pt``, implying that a template
- named "foo.pt" is in the "templates" directory relative to the directory of
- the current :term:`package`), a path can be absolute, starting with a slash
- on UNIX or a drive letter prefix on Windows. The path can alternately be a
- :term:`asset specification` in the form
- ``some.dotted.package_name:relative/path``, making it possible to address
- template assets which live in a separate package.
-
- The ``renderer`` attribute is optional. If it is not defined, the "null"
- renderer is assumed (no rendering is performed and the value is passed back
- to the upstream :app:`Pyramid` machinery unmolested). Note that if the
- view callable itself returns a :term:`response` (see :ref:`the_response`),
- the specified renderer implementation is never called.
-
-``wrapper``
- The :term:`view name` of a different :term:`view configuration` which will
- receive the response body of this view as the ``request.wrapped_body``
- attribute of its own :term:`request`, and the :term:`response` returned by
- this view as the ``request.wrapped_response`` attribute of its own request.
- Using a wrapper makes it possible to "chain" views together to form a
- composite response. The response of the outermost wrapper view will be
- returned to the user. The wrapper view will be found as any view is found:
- see :ref:`view_lookup`. The "best" wrapper view will be found based on the
- lookup ordering: "under the hood" this wrapper view is looked up via
- ``pyramid.view.render_view_to_response(context, request,
- 'wrapper_viewname')``. The context and request of a wrapper view is the
- same context and request of the inner view.
-
- If ``wrapper`` is not supplied, no wrapper view is used.
-
-Predicate Arguments
-+++++++++++++++++++
-
-These arguments modify view lookup behavior. In general, the more predicate
-arguments that are supplied, the more specific, and narrower the usage of the
-configured view.
-
-``name``
- The :term:`view name` required to match this view callable. Read
- :ref:`traversal_chapter` to understand the concept of a view name.
-
- If ``name`` is not supplied, the empty string is used (implying the default
- view).
-
-``context``
- An object representing a Python class that the :term:`context` resource
- must be an instance of *or* the :term:`interface` that the :term:`context`
- resource must provide in order for this view to be found and called. This
- predicate is true when the :term:`context` resource is an instance of the
- represented class or if the :term:`context` resource provides the
- represented interface; it is otherwise false.
-
- If ``context`` is not supplied, the value ``None``, which matches any
- resource, is used.
-
-``route_name``
- If ``route_name`` is supplied, the view callable will be invoked only when
- the named route has matched.
-
- This value must match the ``name`` of a :term:`route configuration`
- declaration (see :ref:`urldispatch_chapter`) that must match before this
- view will be called. Note that the ``route`` configuration referred to by
- ``route_name`` will usually have a ``*traverse`` token in the value of its
- ``pattern``, representing a part of the path that will be used by
- :term:`traversal` against the result of the route's :term:`root factory`.
-
- If ``route_name`` is not supplied, the view callable will be have a chance
- of being invoked if no other route was matched. This is when the
- request/context pair found via :term:`resource location` does not indicate
- it matched any configured route.
-
-``request_type``
- This value should be an :term:`interface` that the :term:`request` must
- provide in order for this view to be found and called.
-
- If ``request_type`` is not supplied, the value ``None`` is used, implying
- any request type.
-
- *This is an advanced feature, not often used by "civilians"*.
-
-``request_method``
- This value can either be one of the strings ``GET``, ``POST``, ``PUT``,
- ``DELETE``, or ``HEAD`` representing an HTTP ``REQUEST_METHOD``. A view
- declaration with this argument ensures that the view will only be called
- when the request's ``method`` attribute (aka the ``REQUEST_METHOD`` of the
- WSGI environment) string matches the supplied value.
-
- If ``request_method`` is not supplied, the view will be invoked regardless
- 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.
-
- If the value supplied has a ``=`` sign in it,
- e.g. ``request_params="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
- request.
-
- If ``request_param`` is not supplied, the view will be invoked without
- consideration of keys and values in the ``request.params`` dictionary.
-
-``containment``
- This value should be a reference to a Python class or :term:`interface`
- that a parent object in the context resource's :term:`lineage` must provide
- in order for this view to be found and called. The resources in your
- resource tree must be "location-aware" to use this feature.
-
- If ``containment`` is not supplied, the interfaces and classes in the
- lineage are not considered when deciding whether or not to invoke the view
- callable.
-
- See :ref:`location_aware` for more information about location-awareness.
-
-``xhr``
- This value should be either ``True`` or ``False``. If this value is
- specified and is ``True``, the :term:`WSGI` environment must possess an
- ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has the
- value ``XMLHttpRequest`` for the associated view callable to be found and
- called. This is useful for detecting AJAX requests issued from jQuery,
- Prototype and other Javascript libraries.
-
- If ``xhr`` is not specified, the ``HTTP_X_REQUESTED_WITH`` HTTP header is
- not taken into consideration when deciding whether or not to invoke the
- associated view callable.
-
-``accept``
- The value of this argument represents a match query for one or more
- mimetypes in the ``Accept`` HTTP request header. If this value is
- specified, it must be in one of the following forms: a mimetype match token
- in the form ``text/plain``, a wildcard mimetype match token in the form
- ``text/*`` or a match-all wildcard mimetype match token in the form
- ``*/*``. If any of the forms matches the ``Accept`` header of the request,
- this predicate will be true.
-
- If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not
- taken into consideration when deciding whether or not to invoke the
- associated view callable.
-
-``header``
- This value represents an HTTP header name or a header name/value pair.
-
- If ``header`` is specified, it must be a header name or a
- ``headername:headervalue`` pair.
-
- If ``header`` is specified without a value (a bare header name only,
- e.g. ``If-Modified-Since``), the view will only be invoked if the HTTP
- header exists with any value in the request.
-
- If ``header`` is specified, and possesses a name/value pair
- (e.g. ``User-Agent:Mozilla/.*``), the view will only be invoked if the HTTP
- header exists *and* the HTTP header matches the value requested. When the
- ``headervalue`` contains a ``:`` (colon), it will be considered a
- name/value pair (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).
- The value portion should be a regular expression.
-
- Whether or not the value represents a header name or a header name/value
- pair, the case of the header name is not significant.
-
- If ``header`` is not specified, the composition, presence or absence of
- HTTP headers is not taken into consideration when deciding whether or not
- to invoke the associated view callable.
-
-``path_info``
- This value represents a regular expression pattern that will be tested
- against the ``PATH_INFO`` WSGI environment variable to decide whether or
- not to call the associated view callable. If the regex matches, this
- predicate will be ``True``.
-
- If ``path_info`` is not specified, the WSGI ``PATH_INFO`` is not taken into
- consideration when deciding whether or not to invoke the associated view
- callable.
-
-``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
- predefined predicates do what you need. Custom predicates can be combined
- with predefined predicates as necessary. Each custom predicate callable
- should accept two arguments: ``context`` and ``request`` and should return
- either ``True`` or ``False`` after doing arbitrary evaluation of the
- context resource and/or the request. If all callables return ``True``, the
- associated view callable will be considered viable for a given request.
-
- If ``custom_predicates`` is not specified, no custom predicates are
- used.
-
-.. index::
- single: view_config decorator
-
-.. _mapping_views_using_a_decorator_section:
-
-View Configuration Using the ``@view_config`` Decorator
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-For better locality of reference, you may use the
-:class:`pyramid.view.view_config` decorator to associate your view functions
-with URLs instead of using :term:`ZCML` or imperative configuration for the
-same purpose.
-
-.. warning::
-
- Using this feature tends to slows down application startup slightly, as
- more work is performed at application startup to scan for view
- declarations.
-
-Usage of the ``view_config`` decorator is a form of :term:`declarative
-configuration`, like ZCML, but in decorator form.
-:class:`pyramid.view.view_config` can be used to associate :term:`view
-configuration` information -- as done via the equivalent imperative code or
-ZCML -- with a function that acts as a :app:`Pyramid` view callable. All
-arguments to the :meth:`pyramid.config.Configurator.add_view` method (save
-for the ``view`` argument) are available in decorator form and mean precisely
-the same thing.
-
-An example of the :class:`pyramid.view.view_config` decorator might reside in
-a :app:`Pyramid` application module ``views.py``:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- from resources import MyResource
- from pyramid.view import view_config
- from pyramid.response import Response
-
- @view_config(name='my_view', request_method='POST', context=MyResource,
- permission='read')
- def my_view(request):
- return Response('OK')
-
-Using this decorator as above replaces the need to add this imperative
-configuration stanza:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- config.add_view('.views.my_view', name='my_view', request_method='POST',
- context=MyResource, permission='read')
-
-All arguments to ``view_config`` may be omitted. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config()
- def my_view(request):
- """ My view """
- return Response()
-
-Such a registration as the one directly above implies that the view name will
-be ``my_view``, registered with a ``context`` argument that matches any
-resource type, using no permission, registered against requests with any
-request method, request type, request param, route name, or containment.
-
-The mere existence of a ``@view_config`` decorator doesn't suffice to perform
-view configuration. All that the decorator does is "annotate" the function
-with your configuration declarations, it doesn't process them. To make
-:app:`Pyramid` process your :class:`pyramid.view.view_config` declarations,
-you *must* do use the ``scan`` method of a
-:class:`pyramid.config.Configurator`:
-
-.. code-block:: python
- :linenos:
-
- # config is assumed to be an instance of the
- # pyramid.config.Configurator class
- config.scan()
-
-.. note:: See :ref:`zcml_scanning` for information about how to invoke a scan
- via ZCML (if you're not using imperative configuration).
-
-Please see :ref:`decorations_and_code_scanning` for detailed information
-about what happens when code is scanned for configuration declarations
-resulting from use of decorators like :class:`pyramid.view.view_config`.
-
-See :ref:`configuration_module` for additional API arguments to the
-:meth:`pyramid.config.Configurator.scan` method. For example, the method
-allows you to supply a ``package`` argument to better control exactly *which*
-code will be scanned.
-
-``@view_config`` Placement
-++++++++++++++++++++++++++
-
-A :class:`pyramid.view.view_config` decorator can be placed in various points
-in your application.
-
-If your view callable is a function, it may be used as a function decorator:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import view_config
- from pyramid.response import Response
-
- @view_config(name='edit')
- def edit(request):
- return Response('edited!')
-
-If your view callable is a class, the decorator can also be used as a class
-decorator in Python 2.6 and better (Python 2.5 and below do not support class
-decorators). All the arguments to the decorator are the same when applied
-against a class as when they are applied against a function. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config()
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- def __call__(self):
- return Response('hello')
-
-You can use the :class:`pyramid.view.view_config` decorator as a simple
-callable to manually decorate classes in Python 2.5 and below without the
-decorator syntactic sugar, if you wish:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- def __call__(self):
- return Response('hello')
-
- my_view = view_config()(MyView)
-
-More than one :class:`pyramid.view.view_config` decorator can be stacked on
-top of any number of others. Each decorator creates a separate view
-registration. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import view_config
- from pyramid.response import Response
-
- @view_config(name='edit')
- @view_config(name='change')
- def edit(request):
- return Response('edited!')
-
-This registers the same view under two different names.
-
-The decorator can also be used against class methods:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- @view_config(name='hello')
- def amethod(self):
- return Response('hello')
-
-When the decorator is used against a class method, a view is registered for
-the *class*, so the class constructor must accept an argument list in one of
-two forms: either it must accept a single argument ``request`` or it must
-accept two arguments, ``context, request``.
-
-The method which is decorated must return a :term:`response`.
-
-Using the decorator against a particular method of a class is equivalent to
-using the ``attr`` parameter in a decorator attached to the class itself.
-For example, the above registration implied by the decorator being used
-against the ``amethod`` method could be spelled equivalently as the below:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
- from pyramid.view import view_config
-
- @view_config(attr='amethod', name='hello')
- class MyView(object):
- def __init__(self, request):
- self.request = request
-
- def amethod(self):
- return Response('hello')
-
-.. index::
- single: add_view
-
-.. _mapping_views_using_imperative_config_section:
-
-View Registration Using :meth:`~pyramid.config.Configurator.add_view`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :meth:`pyramid.config.Configurator.add_view` method within
-:ref:`configuration_module` is used to configure a view imperatively. The
-arguments to this method are very similar to the arguments that you provide
-to the ``@view_config`` decorator. For example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
-
- def hello_world(request):
- return Response('hello!')
-
- # config is assumed to be an instance of the
- # pyramid.config.Configurator class
- config.add_view(hello_world, name='hello.html')
-
-The first argument, ``view``, is required. It must either be a Python object
-which is the view itself or a :term:`dotted Python name` to such an object.
-All other arguments are optional. See
-:meth:`pyramid.config.Configurator.add_view` for more information.
-
-.. _using_add_handler:
-
-Handler Registration Using :meth:`~pyramid.config.Configurator.add_handler`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-:app:`Pyramid` provides the special concept of a :term:`view handler`. View
-handlers are view classes that implement a number of methods, each of which
-is a :term:`view callable` as a convenience for :term:`URL dispatch` users.
-
-.. note::
-
- View handlers are *not* useful when using :term:`traversal`, only when using
- :term:`url dispatch`.
-
-Using a view handler instead of a plain function or class :term:`view
-callable` makes it unnecessary to call
-:meth:`pyramid.config.Configurator.add_route` (and/or
-:meth:`pyramid.config.Configurator.add_view`) "by hand" multiple times,
-making it more pleasant to register a collection of views as a single class
-when using :term:`url dispatch`. The view handler machinery also introduces
-the concept of an ``action``, which is used as a :term:`view predicate` to
-control which method of the handler is called. The method name is the
-default *action name* of a handler view callable.
-
-The concept of a view handler is analogous to a "controller" in Pylons 1.0.
-
-The view handler class is initialized by :app:`Pyramid` in the same manner as
-a "plain" view class. Its ``__init__`` is called with a request object (see
-:ref:`class_as_view`). It implements methods, each of which is a :term:`view
-callable`. When a request enters the system which corresponds with an
-*action* related to one of its view callable methods, this method is called,
-and it is expected to return a response.
-
-Here's an example view handler class:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.response import Response
-
- from pyramid.view import action
-
- class Hello(object):
- def __init__(self, request):
- self.request = request
-
- def index(self):
- return Response('Hello world!')
-
- @action(renderer="mytemplate.mak")
- def bye(self):
- return {}
-
-The :class:`pyramid.view.action` decorator is used to fine-tune the view
-parameters for each potential view callable which is a method of the handler.
-
-Handlers are added to application configuration via the
-:meth:`pyramid.config.Configurator.add_handler` API. The
-:meth:`~pyramid.config.Configurator.add_handler` method will scan a
-:term:`view handler` class and automatically set up view configurations for
-its methods that represent "auto-exposed" view callable, or those that were
-decorated explicitly with the :class:`~pyramid.view.action` decorator. This
-decorator is used to setup additional view configuration information for
-individual methods of the class, and can be used repeatedly for a single view
-method to register multiple view configurations for it.
-
-.. code-block:: python
- :linenos:
-
- from myapp.handlers import Hello
- config.add_handler('hello', '/hello/{action}', handler=Hello)
-
-This example will result in a route being added for the pattern
-``/hello/{action}``, and each method of the ``Hello`` class will then be
-examined to see if it should be registered as a potential view callable when
-the ``/hello/{action}`` pattern matches. The value of ``{action}`` in the
-route pattern will be used to determine which view should be called, and each
-view in the class will be setup with a view predicate that requires a
-specific ``action`` name. By default, the action name for a method of a
-handler is the method name.
-
-If the URL was ``/hello/index``, the above example pattern would match, and,
-by default, the ``index`` method of the ``Hello`` class would be called.
-
-Alternatively, the action can be declared specifically for a URL to be
-registered for a *specific* ``action`` name:
-
-.. code-block:: python
- :linenos:
-
- from myapp.handlers import Hello
- config.add_handler('hello_index', '/hello/index',
- handler=Hello, action='index')
-
-This will result one of the methods that are configured for the ``action`` of
-'index' in the ``Hello`` handler class to be called. In this case the name of
-the method is the same as the action name: ``index``. However, this need not
-be the case, as we will see below.
-
-When calling :meth:`~pyramid.config.Configurator.add_handler`, an ``action``
-is required in either the route pattern or as a keyword argument, but
-**cannot appear in both places**. A ``handler`` argument must also be
-supplied, which can be either a :term:`asset specification` or a Python
-reference to the handler class. Additional keyword arguments are passed
-directly through to :meth:`pyramid.config.Configurator.add_route`.
-
-For example:
-
-.. code-block:: python
- :linenos:
-
- config.add_handler('hello', '/hello/{action}',
- handler='mypackage.handlers.MyHandler')
-
-Multiple :meth:`~pyramid.config.Configurator.add_handler` calls can specify
-the same handler, to register specific route names for different
-handler/action combinations. For example:
-
-.. code-block:: python
- :linenos:
-
- config.add_handler('hello_index', '/hello/index',
- handler=Hello, action='index')
- config.add_handler('bye_index', '/hello/bye',
- handler=Hello, action='bye')
-
-.. note::
-
- Handler configuration may also be added to the system via :term:`ZCML` (see
- :ref:`zcml_handler_configuration`).
-
-View Setup in the Handler Class
-+++++++++++++++++++++++++++++++
-
-A handler class can have a single class level attribute called
-``__autoexpose__`` which should be a regular expression or the value
-``None``. It's used to determine which method names will result in additional
-view configurations being registered.
-
-When :meth:`~pyramid.config.Configurator.add_handler` runs, every method in
-the handler class will be searched and a view registered if the method name
-matches the ``__autoexpose__`` regular expression, or if the method was
-decorated with :class:`~pyramid.view.action`.
-
-Every method in the handler class that has a name meeting the
-``__autoexpose__`` regular expression will have a view registered for an
-``action`` name corresponding to the method name. This functionality can be
-disabled by setting the ``__autoexpose__`` attribute to ``None``:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import action
-
- class Hello(object):
- __autoexpose__ = None
-
- def __init__(self, request):
- self.request = request
-
- @action()
- def index(self):
- return Response('Hello world!')
-
- @action(renderer="mytemplate.mak")
- def bye(self):
- return {}
-
-With auto-expose effectively disabled, no views will be registered for a
-method unless it is specifically decorated with
-:class:`~pyramid.view.action`.
-
-Action Decorators in a Handler
-++++++++++++++++++++++++++++++
-
-The :class:`~pyramid.view.action` decorator registers view configuration
-information on the handler method, which is used by
-:meth:`~pyramid.config.Configurator.add_handler` to setup the view
-configuration.
-
-All keyword arguments are recorded, and passed to
-:meth:`~pyramid.config.Configurator.add_view`. Any valid keyword arguments
-for :meth:`~pyramid.config.Configurator.add_view` can thus be used with the
-:class:`~pyramid.view.action` decorator to further restrict when the view
-will be called.
-
-One important difference is that a handler method can respond to an
-``action`` name that is different from the method name by passing in a
-``name`` argument.
-
-Example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import action
-
- class Hello(object):
- def __init__(self, request):
- self.request = request
-
- @action(name='index', renderer='created.mak', request_method='POST')
- def create(self):
- return {}
-
- @action(renderer="view_all.mak", request_method='GET')
- def index(self):
- return {}
-
-This will register two views that require the ``action`` to be ``index``,
-with the additional view predicate requiring a specific request method.
-
-It can be useful to decorate a single method multiple times with
-:class:`~pyramid.view.action`. Each action decorator will register a new view
-for the method. By specifying different names and renderers for each action,
-the same view logic can be exposed and rendered differently on multiple URLs.
-
-Example:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import action
-
- class Hello(object):
- def __init__(self, request):
- self.request = request
-
- @action(name='home', renderer='home.mak')
- @action(name='about', renderer='about.mak')
- def show_template(self):
- # prep some template vars
- return {}
-
- # in the config
- config.add_handler('hello', '/hello/{action}', handler=Hello)
-
-With this configuration, the url ``/hello/home`` will find a view
-configuration that results in calling the ``show_template`` method, then
-rendering the template with ``home.mak``, and the url ``/hello/about`` will
-call the same method and render the ``about.mak`` template.
-
-.. index::
- single: resource interfaces
-
-.. _using_resource_interfaces:
-
-Using Resource Interfaces In View Configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Instead of registering your views with a ``context`` that names a Python
-resource *class*, you can optionally register a view callable with a
-``context`` which is an :term:`interface`. An interface can be attached
-arbitrarily to any resource object. View lookup treats context interfaces
-specially, and therefore the identity of a resource can be divorced from that
-of the class which implements it. As a result, associating a view with an
-interface can provide more flexibility for sharing a single view between two
-or more different implementations of a resource type. For example, if two
-resource objects of different Python class types share the same interface,
-you can use the same view configuration to specify both of them as a
-``context``.
-
-In order to make use of interfaces in your application during view dispatch,
-you must create an interface and mark up your resource classes or instances
-with interface declarations that refer to this interface.
-
-To attach an interface to a resource *class*, you define the interface and
-use the :func:`zope.interface.implements` function to associate the interface
-with the class.
-
-.. code-block:: python
- :linenos:
-
- from zope.interface import Interface
- from zope.interface import implements
-
- class IHello(Interface):
- """ A marker interface """
-
- class Hello(object):
- implements(IHello)
-
-To attach an interface to a resource *instance*, you define the interface and
-use the :func:`zope.interface.alsoProvides` function to associate the
-interface with the instance. This function mutates the instance in such a
-way that the interface is attached to it.
-
-.. code-block:: python
- :linenos:
-
- from zope.interface import Interface
- from zope.interface import alsoProvides
-
- class IHello(Interface):
- """ A marker interface """
-
- class Hello(object):
- pass
-
- def make_hello():
- hello = Hello()
- alsoProvides(hello, IHello)
- return hello
-
-Regardless of how you associate an interface, with a resource instance, or a
-resource class, the resulting code to associate that interface with a view
-callable is the same. Assuming the above code that defines an ``IHello``
-interface lives in the root of your application, and its module is named
-"resources.py", the interface declaration below will associate the
-``mypackage.views.hello_world`` view with resources that implement, or
-provide, this interface.
-
-.. code-block:: python
- :linenos:
-
- # config is an instance of pyramid.config.Configurator
-
- config.add_view('mypackage.views.hello_world', name='hello.html',
- context='mypackage.resources.IHello')
-
-Any time a resource that is determined to be the :term:`context` provides
-this interface, and a view named ``hello.html`` is looked up against it as
-per the URL, the ``mypackage.views.hello_world`` view callable will be
-invoked.
-
-Note, in cases where a view is registered against a resource class, and a
-view is also registered against an interface that the resource class
-implements, an ambiguity arises. Views registered for the resource class take
-precedence over any views registered for any interface the resource class
-implements. Thus, if one view configuration names a ``context`` of both the
-class type of a resource, and another view configuration names a ``context``
-of interface implemented by the resource's class, and both view
-configurations are otherwise identical, the view registered for the context's
-class will "win".
-
-For more information about defining resources with interfaces for use within
-view configuration, see :ref:`resources_which_implement_interfaces`.
-
-.. index::
- single: view security
- pair: security; view
-
-.. _view_security_section:
-
-Configuring View Security
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If an :term:`authorization policy` is active, any :term:`permission` attached
-to a :term:`view configuration` found during view lookup will be verified.
-This will ensure that the currently authenticated user possesses that
-permission against the :term:`context` resource before the view function is
-actually called. Here's an example of specifying a permission in a view
-configuration using :meth:`pyramid.config.Configurator.add_view`:
-
-.. code-block:: python
- :linenos:
-
- # config is an instance of pyramid.config.Configurator
-
- config.add_view('myproject.views.add_entry', name='add.html',
- context='myproject.resources.IBlog', permission='add')
-
-When an :term:`authorization policy` is enabled, this view will be protected
-with the ``add`` permission. The view will *not be called* if the user does
-not possess the ``add`` permission relative to the current :term:`context`.
-Instead the :term:`forbidden view` result will be returned to the client as
-per :ref:`protecting_views`.
-
-.. index::
- single: view lookup
-
-.. _view_lookup:
-
-View Lookup and Invocation
---------------------------
-
-:term:`View lookup` is the :app:`Pyramid` subsystem responsible for finding
-an invoking a :term:`view callable`. The view lookup subsystem is passed a
-:term:`context` and a :term:`request` object.
-
-:term:`View configuration` information stored within in the
-:term:`application registry` is compared against the context and request by
-the view lookup subsystem in order to find the "best" view callable for the
-set of circumstances implied by the context and request.
-
-Predicate attributes of view configuration can be thought of like
-"narrowers". In general, the greater number of predicate attributes
-possessed by a view's configuration, the more specific the circumstances need
-to be before the registered view callable will be invoked.
-
-For any given request, a view with five predicates will always be found and
-evaluated before a view with two, for example. All predicates must match for
-the associated view to be called.
-
-This does not mean however, that :app:`Pyramid` "stops looking" when it finds
-a view registration with predicates that don't match. If one set of view
-predicates does not match, the "next most specific" view (if any) view is
-consulted for predicates, and so on, until a view is found, or no view can be
-matched up with the request. The first view with a set of predicates all of
-which match the request environment will be invoked.
-
-If no view can be found with predicates which allow it to be matched up with
-the request, :app:`Pyramid` will return an error to the user's browser,
-representing a "not found" (404) page. See :ref:`changing_the_notfound_view`
-for more information about changing the default notfound view.
-
-.. index::
- single: debugging not found errors
- single: not found error (debugging)
-
-.. _debug_notfound_section:
-
-:exc:`NotFound` Errors
-~~~~~~~~~~~~~~~~~~~~~~
-
-It's useful to be able to debug :exc:`NotFound` error responses when they
-occur unexpectedly due to an application registry misconfiguration. To debug
-these errors, use the ``PYRAMID_DEBUG_NOTFOUND`` environment variable or the
-``debug_notfound`` configuration file setting. Details of why a view was not
-found will be printed to ``stderr``, and the browser representation of the
-error will include the same information. See :ref:`environment_chapter` for
-more information about how, and where to set these values.
-
-Further Information
--------------------
-
-The chapter entitled :ref:`renderers_chapter` explains how to create
-functions (or instances/classes) which do not return a :term:`Response`
-object, yet which still can be used as view callables.
-
diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst
index f330fd551..78a7b0b75 100644
--- a/docs/narr/zca.rst
+++ b/docs/narr/zca.rst
@@ -57,7 +57,7 @@ Using the ZCA Global API in a :app:`Pyramid` Application
-----------------------------------------------------------
:term:`Zope` uses a single ZCA registry -- the "global" ZCA registry
--- for all Zope applications run in the same Python process,
+-- for all Zope applications that run in the same Python process,
effectively making it impossible to run more than one Zope application
in a single process.
@@ -158,9 +158,7 @@ Consider the following bit of idiomatic :app:`Pyramid` startup code:
def app(global_settings, **settings):
config = Configurator(settings=settings)
- config.begin()
- config.load_zcml('configure.zcml')
- config.end()
+ config.include('some.other.package')
return config.make_wsgi_app()
When the ``app`` function above is run, a :term:`Configurator` is
@@ -198,9 +196,7 @@ setup code. For example:
def app(global_settings, **settings):
config = Configurator(settings=settings)
config.hook_zca()
- config.begin()
- config.load_zcml('configure.zcml')
- config.end()
+ config.include('some.other.application')
return config.make_wsgi_app()
We've added a line to our original startup code, line number 6, which
@@ -250,9 +246,7 @@ registry at startup time instead of constructing a new one:
config = Configurator(registry=globalreg)
config.setup_registry(settings=settings)
config.hook_zca()
- config.begin()
- config.load_zcml('configure.zcml')
- config.end()
+ config.include('some.other.application')
return config.make_wsgi_app()
Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves
@@ -268,36 +262,3 @@ rather than creating a new application-specific registry; since by
default the ZCA global API will use this registry, things will work as
you might expect a Zope app to when you use the global ZCA API.
-.. index::
- single: Zope ZCML directives
- single: getGlobalSiteManager
- single: getSiteManager
-
-Using Broken ZCML Directives
-----------------------------
-
-Some :term:`Zope` and third-party :term:`ZCML` directives use the
-``zope.component.getGlobalSiteManager`` API to get "the registry" when
-they should actually be calling ``zope.component.getSiteManager``.
-
-``zope.component.getSiteManager`` can be overridden by
-:app:`Pyramid` via
-:meth:`pyramid.config.Configurator.hook_zca`, while
-``zope.component.getGlobalSiteManager`` cannot. Directives that use
-``zope.component.getGlobalSiteManager`` are effectively broken; no
-ZCML directive should be using this function to find a registry to
-populate.
-
-You cannot use ZCML directives which use
-``zope.component.getGlobalSiteManager`` within a :app:`Pyramid`
-application without passing the ZCA global registry to the
-:term:`Configurator` constructor at application startup, as per
-:ref:`using_the_zca_global_registry`.
-
-One alternative exists: fix the ZCML directive to use
-``getSiteManager`` rather than ``getGlobalSiteManager``. If a
-directive disuses ``getGlobalSiteManager``, the ``hook_zca`` method of
-using a component registry as documented in :ref:`hook_zca` will begin
-to work, allowing you to make use of the ZCML directive without
-also using the ZCA global registry.
-
diff --git a/docs/tutorials/bfg/index.rst b/docs/tutorials/bfg/index.rst
index 3c0b3bf01..9f9a5238c 100644
--- a/docs/tutorials/bfg/index.rst
+++ b/docs/tutorials/bfg/index.rst
@@ -176,6 +176,10 @@ Here's how to convert a :mod:`repoze.bfg` application to a
<bfg:failingtag attr="foo"/>
</configure>
+ You will also need to add the ``pyramid_zcml`` package to your
+ ``setup.py`` ``install_requires`` list. In Pyramid, ZCML configuration
+ became an optional add-on supported by the ``pyramid_zcml`` package.
+
#. Retest your application using :app:`Pyramid`. This might be as
easy as:
diff --git a/docs/tutorials/cmf/actions.rst b/docs/tutorials/cmf/actions.rst
deleted file mode 100644
index a6e33fa59..000000000
--- a/docs/tutorials/cmf/actions.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. _actions_chapter:
-
-=======
-Actions
-=======
-
-In CMF, the "actions tool" along with "action providers" create an extensible
-mechanism to show links in the CMF management UI that invoke a particular
-behavior or which show a particular template.
-
-:app:`Pyramid` itself has no such concept, and no package provides a direct
-replacement. Actions are such a generic concept that it's simple to
-reimplement action-like navigation in a different way within any given
-application. For example, a module-scope global dictionary which has keys
-that are action names, and values which are tuples of (permission, link).
-Take that concept and expand on it, and you'll have some passable actions
-tool replacement within a single application.
-
-The `pyramid_viewgroup <https://github.com/Pylons/pyramid_viewgroup/>`_
-package provides some functionality for creating "view groups". Each view in
-a viewgroup can provide some snippet of HTML (e.g. a single "tab"), and
-individual views (tabs) within the group which cannot be displayed to the
-user due to the user's lack of permissions will be omitted from the rendered
-output.
-
-The :term:`repoze.lemonade` package provides "list item" support that
-may be used to construct action lists.
-
diff --git a/docs/tutorials/cmf/catalog.rst b/docs/tutorials/cmf/catalog.rst
deleted file mode 100644
index d5e9534ae..000000000
--- a/docs/tutorials/cmf/catalog.rst
+++ /dev/null
@@ -1,73 +0,0 @@
-.. _catalog_chapter:
-
-=======
-Catalog
-=======
-
-The main feature of the CMF catalog is that it filters search results
-from the Zope 2 "catalog" based on the requesting user's ability to
-view a particular cataloged object.
-
-:app:`Pyramid` itself has no cataloging facility, but an addon
-package named :term:`repoze.catalog` offers similar functionality.
-
-Creating an Allowed Index
--------------------------
-
-In CMF, a catalog index named ``getAllowedRolesAndUsers`` along with
-application indexing code allows for filtered search results. It's
-reasonably easy to reproduce this pattern using some custom code.
-
-Creating The ``allowed`` Index
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's some code which creates an ``allowed`` index for use in a
-``repoze.catalog`` catalog::
-
- from pyramid.security import principals_allowed_by_permission
- from repoze.catalog.indexes.keyword import CatalogKeywordIndex
- from repoze.catalog.catalog import Catalog
-
- class Allowed:
- def __init__(self, permission):
- self.permission = permission
-
- def __call__(self, context, default):
- principals = principals_allowed_by_permission(context,
- self.permission)
- return principals
-
- def make_allowed_index(permission='View'):
- index = CatalogKeywordIndex(Allowed(permission))
- return index
-
- index = make_allowed_index()
- catalog = Catalog()
- catalog['allowed'] = index
-
-When you index an item, the allowed index will be populated with all
-the principal ids which have the 'View' permission.
-
-Using the ``allowed`` Index
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's how you might use the ``allowed`` index within a query::
-
- from pyramid.security import effective_principals
- principals = effective_principals(request)
- catalog.searchResults(allowed={'operator':'or', 'query':principals})
-
-The above query will return all document ids that the current user has
-the 'View' permission against. Add other indexes to the query to get
-a useful result.
-
-See the `repoze.catalog package
-<http://svn.repoze.org/repoze.catalog/trunk>`_ for more information.
-
-
-
-
-
-
-
-
diff --git a/docs/tutorials/cmf/content.rst b/docs/tutorials/cmf/content.rst
deleted file mode 100644
index 85e5b5fbc..000000000
--- a/docs/tutorials/cmf/content.rst
+++ /dev/null
@@ -1,67 +0,0 @@
-.. _content_types_chapter:
-
-=============
-Content Types
-=============
-
-In CMF, a content type is defined as a bag of settings (the type
-information, controlled within the "types tool"), as well as factory
-code which generates an instance of that content. It is possible to
-construct and enumerate content types using APIs defined on the types
-tool.
-
-:app:`Pyramid` itself has no such concept, but an addon package named
-:term:`repoze.lemonade` has a barebones replacement.
-
-Factory Type Information
-------------------------
-
-A factory type information object in CMF allows you to associate a
-title, a description, an internationalization domain, an icon, an
-initial view name, a factory, and a number of security settings with a
-type name. Each type information object knows how to manufacture
-content objects that match its type.
-
-:app:`Pyramid` certainly enforces none of these concepts in any
-particular way, but :term:`repoze.lemonade` does.
-
-``repoze.lemonade`` Content
-+++++++++++++++++++++++++++
-
-:term:`repoze.lemonade` provides a reasonably handy directive and set
-of helper functions which allow you to:
-
-#. Associate a interface with a factory function, making it into a
- "content type".
-
-#. Enumerate all interfaces associated with factory functions.
-
-.. note:: Using this pattern is often plain silly, as it's usually
- just as easy to actually import a class implementation and
- create an instance directly using its constructor. But it
- can be useful in cases where you want to address some set of
- constructors uniformly without doing direct imports in the
- code which performs the construction, or if you need to make
- content construction uniform across a diverse set of model
- types, or if you need to enumerate some set of information
- about "content" types. It's left as an exercise to the
- reader to determine under which circumstances using this
- pattern is an appropriate thing to do. Hint: not very
- often, unless you're doing the indirection solely to aid
- content-agnostic unit tests or if you need to get an
- enumerated subset of content type information to aid in UI
- generation. That said, this *is* a tutorial about how to
- get CMF-like features in :app:`Pyramid`, so we'll assume
- the pattern is useful to readers.
-
-See the `repoze.lemonade package
-<http://svn.repoze.org/repoze.lemonade/trunk>`_ for more information,
-particularly its documentation for "content".
-
-
-
-
-
-
-
-
diff --git a/docs/tutorials/cmf/index.rst b/docs/tutorials/cmf/index.rst
deleted file mode 100644
index 26aa336a9..000000000
--- a/docs/tutorials/cmf/index.rst
+++ /dev/null
@@ -1,38 +0,0 @@
-Converting an Existing Zope/CMF Application to :app:`Pyramid`
-================================================================
-
-The Zope `Content Management Framework
-<http://www.zope.org/Products/CMF/>`_ (aka CMF) is a layer on top of
-:term:`Zope` 2 that provides facilities for creating content-driven
-websites. It's reasonably easy to convert a modern Zope/CMF
-application to :app:`Pyramid`.
-
-The main difference between CMF and :app:`Pyramid` is that :app:`Pyramid`
-does not advertise itself as a system into which you can plug arbitrary
-"packages" that extend a system-supplied management user interface. You
-*could* build a CMF-like layer on top of :app:`Pyramid` but none currently
-exists. For those sorts of high-extensibility, highly-regularized-UI
-systems, CMF is still the better choice.
-
-:app:`Pyramid` (and other more lightweight systems) is often a
-better choice when you're building the a user interface from scratch,
-which often happens when the paradigms of some CMF-provided user
-interface don't match the requirements of an application very closely.
-Even so, a good number of developers tend to use CMF even when they do
-start an application for which they need to build a UI from scratch,
-because CMF happens to provide other helpful services, such as types,
-skins, and workflow; this tutorial is for those sorts of developers
-and projects.
-
-.. toctree::
- :maxdepth: 2
-
- content.rst
- catalog.rst
- skins.rst
- actions.rst
- workflow.rst
- missing.rst
-
-
-
diff --git a/docs/tutorials/cmf/missing.rst b/docs/tutorials/cmf/missing.rst
deleted file mode 100644
index 964e0ab04..000000000
--- a/docs/tutorials/cmf/missing.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-Missing Comparisons
-===================
-
-We currently don't have any comparative Pyramid-vs-CMF information
-about the following concepts within this tutorial:
-
-- Templates
-
-- Forms
-
-- Membership
-
-- Discussions
-
-- Syndication
-
-- Dublincore
-
-Please ask on the `Pylons-devel maillist
-<http://groups.google.com/group/pylons-devel>`_ or on the `#pylons IRC
-channel <http://irc.freenode.net#pylons>`_ about these topics.
-
diff --git a/docs/tutorials/cmf/skins.rst b/docs/tutorials/cmf/skins.rst
deleted file mode 100644
index 676a076b3..000000000
--- a/docs/tutorials/cmf/skins.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-.. _skins_chapter:
-
-=====
-Skins
-=====
-
-In CMF, a "skin layer" is defined as a collection of templates and
-code (Python scripts, DTML methods, etc) that can be activated and
-deactivated within a particular setup. A collection of active "skin
-layers" grouped in a particular order forms a "skin". "Add-on" CMF
-products often provide skin layers that are activated within a
-particular skin to provide the site with additional features.
-
-To override static resources using a "search path" much like a set of
-skin layers, :app:`Pyramid` provides the concept of
-:term:`resource` overrides. See :ref:`overriding_resources_section`
-for more information about resource overrides.
-
-While there is no analogue to a skin layer search path for locating
-Python code (as opposed to resources), :term:`view` code combined with
-differing :term:`predicate` arguments can provide a good deal of
-the same sort of behavior.
-
diff --git a/docs/tutorials/cmf/workflow.rst b/docs/tutorials/cmf/workflow.rst
deleted file mode 100644
index cc70d771a..000000000
--- a/docs/tutorials/cmf/workflow.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-.. _workflow_chapter:
-
-========
-Workflow
-========
-
-In CMF, the "workflow tool" allows developers to design state machines
-which imply transition between content states.
-
-:app:`Pyramid` itself has no such concept, but the
-:term:`repoze.workflow` package provides a simple state machine
-implementation that can act as a barebones workflow tool. See its
-documentation for more information.
-
diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst
index 766f05b56..4257f40b3 100644
--- a/docs/tutorials/modwsgi/index.rst
+++ b/docs/tutorials/modwsgi/index.rst
@@ -14,12 +14,12 @@ This particular tutorial was developed under Apple's Mac OS X platform
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 ``mod_wsgi``. If you have experience with :app:`Pyramid`
- and ``mod_wsgi`` on Windows systems, please help us document
- this experience by submitting documentation to the `mailing list
- <http://lists.repoze.org/listinfo/repoze-dev>`_.
+.. note:: Unfortunately these instructions almost certainly won't work for
+ deploying a :app:`Pyramid` application on a Windows system using
+ ``mod_wsgi``. If you have experience with :app:`Pyramid` and ``mod_wsgi``
+ on Windows systems, please help us document this experience by submitting
+ documentation to the `Pylons-devel maillist
+ <http://groups.google.com/group/pylons-devel>`_.
#. The tutorial assumes you have Apache already installed on your
system. If you do not, install Apache 2.X for your platform in
diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst
index 1b66ace96..5e45c070e 100644
--- a/docs/tutorials/wiki/authorization.rst
+++ b/docs/tutorials/wiki/authorization.rst
@@ -136,8 +136,8 @@ Add a ``login.pt`` template to your templates directory. It's
referred to within the login view we just added to ``login.py``.
.. literalinclude:: src/authorization/tutorial/templates/login.pt
- :linenos:
:language: xml
+ :tab-width: 2
Change ``view.pt`` and ``edit.pt``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -146,11 +146,10 @@ We'll also need to change our ``edit.pt`` and ``view.pt`` templates to
display a "Logout" link if someone is logged in. This link will
invoke the logout view.
-To do so we'll add this to both templates within the ``<div
-class="main_content">`` div:
+To do so we'll add this to both templates within the ``<div id="right"
+class="app-welcome align-right">`` div:
.. code-block:: xml
- :linenos:
<span tal:condition="logged_in">
<a href="${request.application_url}/logout">Logout</a>
@@ -283,12 +282,14 @@ Our ``edit.pt`` template will look something like this when we're done:
.. literalinclude:: src/authorization/tutorial/templates/edit.pt
:linenos:
:language: xml
+ :tab-width: 2
Our ``view.pt`` template will look something like this when we're done:
.. literalinclude:: src/authorization/tutorial/templates/view.pt
:linenos:
:language: xml
+ :tab-width: 2
Revisiting the Application
---------------------------
diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst
index f6e1f800a..4017d7af8 100644
--- a/docs/tutorials/wiki/basiclayout.rst
+++ b/docs/tutorials/wiki/basiclayout.rst
@@ -169,7 +169,6 @@ The ``development.ini`` (in the tutorial :term:`project` directory, as
opposed to the tutorial :term:`package` directory) looks like this:
.. literalinclude:: src/views/development.ini
- :linenos:
:language: ini
diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst
index f201f6dc7..5e4b8fb22 100644
--- a/docs/tutorials/wiki/definingmodels.rst
+++ b/docs/tutorials/wiki/definingmodels.rst
@@ -163,7 +163,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut\tutorial> ..\Scripts\python setup.py test -q
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
The expected output is something like this:
diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst
index 5b0e5dca1..7ad5e57cb 100644
--- a/docs/tutorials/wiki/definingviews.rst
+++ b/docs/tutorials/wiki/definingviews.rst
@@ -230,8 +230,8 @@ Once we're done with the ``view.pt`` template, it will look a lot like
the below:
.. literalinclude:: src/views/tutorial/templates/view.pt
- :linenos:
:language: xml
+ :tab-width: 2
.. note:: The names available for our use in a template are always those that
are present in the dictionary returned by the view callable. But our
@@ -257,23 +257,25 @@ Once we're done with the ``edit.pt`` template, it will look a lot like the
below:
.. literalinclude:: src/views/tutorial/templates/edit.pt
- :linenos:
:language: xml
+ :tab-width: 2
Static Assets
-------------
-Our templates name a single static asset named ``style.css``. We need to
-create this and place it in a file named ``style.css`` within our package's
-``static`` directory. This file is a little too long to replicate within the
-body of this guide, however it is available `online
-<http://github.com/Pylons/pyramid/blob/master/docs/tutorials/wiki/src/views/tutorial/static/style.css>`_.
+Our templates name a single static asset named ``pylons.css``. We don't need
+to create this file within our package's ``static`` directory because it was
+provided at the time we created the project. This file is a little too long to
+replicate within the body of this guide, however it is available `online
+<http://github.com/Pylons/pyramid/blob/master/docs/tutorials/wiki/src/views/tutorial/static/pylons.css>`_.
This CSS file will be accessed via
-e.g. ``http://localhost:6543/static/style.css`` by virtue of the call to
+e.g. ``http://localhost:6543/static/pylons.css`` by virtue of the call to
``add_static_view`` directive we've made in the ``__init__`` file. Any
number and type of static assets can be placed in this directory (or
-subdirectories) and are just referred to by URL within templates.
+subdirectories) and are just referred to by URL or by using the convenience
+method ``static_url`` e.g. ``request.static_url('{{package}}:static/foo.css')``
+within templates.
Testing the Views
=================
@@ -308,7 +310,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut\tutorial> ..\Scripts\python setup.py test -q
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
The expected result looks something like:
diff --git a/docs/tutorials/wiki/distributing.rst b/docs/tutorials/wiki/distributing.rst
index ad717e72a..855d54eab 100644
--- a/docs/tutorials/wiki/distributing.rst
+++ b/docs/tutorials/wiki/distributing.rst
@@ -18,7 +18,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut> ..\Scripts\python setup.py sdist
+ c:\pyramidtut> ..\Scripts\python setup.py sdist
.. warning:: If your project files are not checked in to a version
control repository (such as Subversion), the dist tarball will
diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst
index 82265170d..95bc7a03e 100644
--- a/docs/tutorials/wiki/installation.rst
+++ b/docs/tutorials/wiki/installation.rst
@@ -26,28 +26,28 @@ Preparation, UNIX
<http://peak.telecommunity.com/dist/ez_setup.py>`_ and run it using
the ``python`` interpreter of your Python 2.6 installation:
- .. code-block:: bash
+ .. code-block:: text
$ /path/to/my/Python-2.6/bin/python ez_setup.py
#. Use that Python's `bin/easy_install` to install `virtualenv`:
- .. code-block:: bash
+ .. code-block:: text
$ /path/to/my/Python-2.6/bin/easy_install virtualenv
#. Use that Python's virtualenv to make a workspace:
- .. code-block:: bash
+ .. code-block:: text
$ path/to/my/Python-2.6/bin/virtualenv --no-site-packages \
- bigfntut
+ pyramidtut
-#. Switch to the ``bigfntut`` directory:
+#. Switch to the ``pyramidtut`` directory:
- .. code-block:: bash
+ .. code-block:: text
- $ cd bigfntut
+ $ cd pyramidtut
#. (Optional) Consider using ``source bin/activate`` to make your
shell environment wired to use the virtualenv.
@@ -55,14 +55,14 @@ Preparation, UNIX
#. Use ``easy_install`` to get :app:`Pyramid` and its direct
dependencies installed:
- .. code-block:: bash
+ .. code-block:: text
$ bin/easy_install pyramid
#. Use ``easy_install`` to install ``docutils``, ``repoze.tm``,
``repoze.zodbconn``, ``nose`` and ``coverage``:
- .. code-block:: bash
+ .. code-block:: text
$ bin/easy_install docutils repoze.tm repoze.zodbconn \
nose coverage
@@ -79,27 +79,27 @@ Preparation, Windows
the ``python`` interpreter of your Python 2.6 installation using a
command prompt:
- .. code-block:: bat
+ .. code-block:: text
c:\> c:\Python26\python ez_setup.py
#. Use that Python's `bin/easy_install` to install `virtualenv`:
- .. code-block:: bat
+ .. code-block:: text
c:\> c:\Python26\Scripts\easy_install virtualenv
#. Use that Python's virtualenv to make a workspace:
- .. code-block:: bat
+ .. code-block:: text
- c:\> c:\Python26\Scripts\virtualenv --no-site-packages bigfntut
+ c:\> c:\Python26\Scripts\virtualenv --no-site-packages pyramidtut
-#. Switch to the ``bigfntut`` directory:
+#. Switch to the ``pyramidtut`` directory:
- .. code-block:: bat
+ .. code-block:: text
- c:\> cd bigfntut
+ c:\> cd pyramidtut
#. (Optional) Consider using ``bin\activate.bat`` to make your shell
environment wired to use the virtualenv.
@@ -107,16 +107,16 @@ Preparation, Windows
#. Use ``easy_install`` to get :app:`Pyramid` and its direct
dependencies installed:
- .. code-block:: bat
+ .. code-block:: text
- c:\bigfntut> Scripts\easy_install pyramid
+ c:\pyramidtut> Scripts\easy_install pyramid
#. Use ``easy_install`` to install ``docutils``, ``repoze.tm``,
``repoze.zodbconn``, ``nose`` and ``coverage``:
- .. code-block:: bat
+ .. code-block:: text
- c:\bigfntut> Scripts\easy_install docutils repoze.tm \
+ c:\pyramidtut> Scripts\easy_install docutils repoze.tm \
repoze.zodbconn nose coverage
.. _making_a_project:
@@ -129,19 +129,19 @@ variety of templates to generate sample projects. For this tutorial,
we will use the :term:`ZODB` -oriented template named ``pyramid_zodb``.
The below instructions assume your current working directory is the
-"virtualenv" named "bigfntut".
+"virtualenv" named "pyramidtut".
On UNIX:
-.. code-block:: bash
+.. code-block:: text
$ bin/paster create -t pyramid_zodb tutorial
On Windows:
-.. code-block:: bat
+.. code-block:: text
- c:\bigfntut> Scripts\paster create -t pyramid_zodb tutorial
+ c:\pyramidtut> Scripts\paster create -t pyramid_zodb tutorial
.. note:: If you are using Windows, the ``pyramid_zodb`` Paster template
doesn't currently deal gracefully with installation into a location
@@ -160,17 +160,17 @@ directory you created in :ref:`making_a_project`, and run the
On UNIX:
-.. code-block:: bash
+.. code-block:: text
$ cd tutorial
$ ../bin/python setup.py develop
On Windows:
-.. code-block:: bat
+.. code-block:: text
- C:\bigfntut> cd tutorial
- C:\bigfntut\tutorial> ..\Scripts\python setup.py develop
+ C:\pyramidtut> cd tutorial
+ C:\pyramidtut\tutorial> ..\Scripts\python setup.py develop
.. _running_tests:
@@ -182,15 +182,15 @@ the tests for the project.
On UNIX:
-.. code-block:: bash
+.. code-block:: text
$ ../bin/python setup.py test -q
On Windows:
-.. code-block:: bat
+.. code-block:: text
- c:\bigfntut\tutorial> ..\Scripts\python setup.py test -q
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
Starting the Application
========================
@@ -199,15 +199,15 @@ Start the application.
On UNIX:
-.. code-block:: bash
+.. code-block:: text
$ ../bin/paster serve development.ini --reload
On Windows:
-.. code-block:: bat
+.. code-block:: text
- c:\bifgfntut\tutorial> ..\Scripts\paster serve development.ini --reload
+ c:\pyramidtut\tutorial> ..\Scripts\paster serve development.ini --reload
Exposing Test Coverage Information
==================================
@@ -220,15 +220,15 @@ tests.
On UNIX:
-.. code-block:: bash
+.. code-block:: text
$ ../bin/nosetests --cover-package=tutorial --cover-erase --with-coverage
On Windows:
-.. code-block:: bat
+.. code-block:: text
- c:\bigfntut\tutorial> ..\Scripts\nosetests --cover-package=tutorial \
+ c:\pyramidtut\tutorial> ..\Scripts\nosetests --cover-package=tutorial \
--cover-erase --with-coverage
Looks like the code in the ``pyramid_zodb`` template for ZODB projects is
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/footerbg.png b/docs/tutorials/wiki/src/authorization/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/headerbg.png b/docs/tutorials/wiki/src/authorization/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/ie6.css b/docs/tutorials/wiki/src/authorization/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/logo.png b/docs/tutorials/wiki/src/authorization/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki/src/authorization/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/middlebg.png b/docs/tutorials/wiki/src/authorization/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css b/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css
index c153be07f..fd1914d8d 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/pyramid-small.png b/docs/tutorials/wiki/src/authorization/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/pyramid.png b/docs/tutorials/wiki/src/authorization/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/style.css b/docs/tutorials/wiki/src/authorization/tutorial/static/style.css
deleted file mode 100644
index cad87e0d4..000000000
--- a/docs/tutorials/wiki/src/authorization/tutorial/static/style.css
+++ /dev/null
@@ -1,109 +0,0 @@
-html, body {
- color: black;
- background-color: #ddd;
- font: x-small "Lucida Grande", "Lucida Sans Unicode", geneva, sans-serif;
- margin: 0;
- padding: 0;
-}
-
-td, th {padding:3px;border:none;}
-tr th {text-align:left;background-color:#f0f0f0;color:#333;}
-tr.odd td {background-color:#edf3fe;}
-tr.even td {background-color:#fff;}
-
-#header {
- height: 80px;
- width: 777px;
- background: blue URL('../images/header_inner.png') no-repeat;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- margin: 0 auto 0 auto;
-}
-
-a.link, a, a.active {
- color: #369;
-}
-
-
-#main_content {
- color: black;
- font-size: 127%;
- background-color: white;
- width: 757px;
- margin: 0 auto 0 auto;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- padding: 10px;
-}
-
-#sidebar {
- border: 1px solid #aaa;
- background-color: #eee;
- margin: 0.5em;
- padding: 1em;
- float: right;
- width: 200px;
- font-size: 88%;
-}
-
-#sidebar h2 {
- margin-top: 0;
-}
-
-#sidebar ul {
- margin-left: 1.5em;
- padding-left: 0;
-}
-
-h1,h2,h3,h4,h5,h6,#getting_started_steps {
- font-family: "Century Schoolbook L", Georgia, serif;
- font-weight: bold;
-}
-
-h2 {
- font-size: 150%;
-}
-
-#footer {
- border: 1px solid #aaa;
- border-top: 0px none;
- color: #999;
- background-color: white;
- padding: 10px;
- font-size: 80%;
- text-align: center;
- width: 757px;
- margin: 0 auto 1em auto;
-}
-
-.code {
- font-family: monospace;
-}
-
-span.code {
- font-weight: bold;
- background: #eee;
-}
-
-#status_block {
- margin: 0 auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- background: #cec URL('../images/ok.png') left center no-repeat;
- border: 1px solid #9c9;
- width: 450px;
- font-size: 120%;
- font-weight: bolder;
-}
-
-.notice {
- margin: 0.5em auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- width: 450px;
- background: #eef URL('../images/info.png') left center no-repeat;
- border: 1px solid #cce;
-}
-
-.fielderror {
- color: red;
- font-weight: bold;
-}
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/transparent.gif b/docs/tutorials/wiki/src/authorization/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt
index 5f8b22207..b5fa54dec 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt
+++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt
@@ -1,34 +1,61 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)
- Editing: ${page.__name__}</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.__name__} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
- <div style="float:right; width: 10em;"> Viewing
- <span tal:replace="page.__name__">Page Name Goes Here</span> <br/>
- You can return to the <a href="${request.application_url}"
- >FrontPage</a>.
- <span tal:condition="logged_in"><a
- href="${request.application_url}/logout">Logout</a></span>
- </div>
-
- <div>
- <form action="${save_url}" method="post">
- <textarea name="body" tal:content="page.data" rows="10" cols="60"/>
- <input type="submit" name="form.submitted" value="Save"/>
- </form>
- </div>
-</div>
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Editing <b><span tal:replace="page.__name__">Page Name
+ Goes Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right">
+ <span tal:condition="logged_in">
+ <a href="${request.application_url}/logout">Logout</a>
+ </span>
+ </div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <form action="${save_url}" method="post">
+ <textarea name="body" tal:content="page.data" rows="10"
+ cols="60"/><br/>
+ <input type="submit" name="form.submitted" value="Save"/>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt
index c56983d64..554b4ea87 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt
+++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt
@@ -1,32 +1,57 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>Login - Pyramid tutorial wiki (based on TurboGears
+ 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<h1>Log In</h1>
-
-<div tal:replace="message"/>
-
-<div class="main_content">
- <form action="${url}" method="post">
- <input type="hidden" name="came_from" value="${came_from}"/>
- <input type="text" name="login" value="${login}"/>
- <br/>
- <input type="password" name="password" value="${password}"/>
- <br/>
- <input type="submit" name="form.submitted" value="Log In"/>
- </form>
-</div>
-
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ <b>Login</b><br/>
+ <span tal:replace="message"/>
+ </div>
+ <div id="right" class="app-welcome align-right"></div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <form action="${url}" method="post">
+ <input type="hidden" name="came_from" value="${came_from}"/>
+ <input type="text" name="login" value="${login}"/><br/>
+ <input type="password" name="password"
+ value="${password}"/><br/>
+ <input type="submit" name="form.submitted" value="Log In"/>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt
index a5a0dd214..e31a342b2 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt
@@ -5,65 +5,71 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
<body>
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
- <div id="top">
- <div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
- <p class="app-welcome">
- Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
- the Pyramid web application development framework.
- </p>
+ <div id="wrap">
+ <div id="top">
+ <div class="top align-center">
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
</div>
- </div>
- <div id="bottom">
- <div class="bottom">
- <div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
- <input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
- </form>
+ <div id="middle">
+ <div class="middle align-center">
+ <p class="app-welcome">
+ Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
+ the Pyramid web application development framework.
+ </p>
</div>
- <div id="right" class="align-left">
- <h3>Pyramid links</h3>
- <ul class="links">
- <li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
- </li>
- <li>
- <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
- </li>
- </ul>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div id="left" class="align-right">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
+ </div>
+ <div id="right" class="align-left">
+ <h2>Pyramid links</h2>
+ <ul class="links">
+ <li>
+ <a href="http://pylonsproject.org">Pylons Website</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
+ </li>
+ <li>
+ <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
+ </li>
+ </ul>
+ </div>
</div>
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt
index f957176f1..d77d174c1 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt
+++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt
@@ -1,31 +1,64 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>${page.__name__} - Pyramid tutorial wiki
- (based on TurboGears 20-Minute Wiki)
- </title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.__name__} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
-<div style="float:right; width: 10em;"> Viewing
-<span tal:replace="page.__name__">Page Name Goes Here</span> <br/>
-You can return to the <a href="${request.application_url}">FrontPage</a>.
-<span tal:condition="logged_in">
- <a href="${request.application_url}/logout">Logout</a>
-</span>
-</div>
-
-<div tal:replace="structure content">Page text goes here.</div>
-<p><a tal:attributes="href edit_url" href="">Edit this page</a></p>
-</div>
-
-</body></html>
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Viewing <b><span tal:replace="page.__name__">Page Name
+ Goes Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right">
+ <span tal:condition="logged_in">
+ <a href="${request.application_url}/logout">Logout</a>
+ </span>
+ </div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div tal:replace="structure content">
+ Page text goes here.
+ </div>
+ <p>
+ <a tal:attributes="href edit_url" href="">
+ Edit this page
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
+</body>
+</html>
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py
index 183cb2a8d..a83e17de4 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py
@@ -13,7 +13,7 @@ wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
@view_config(context='tutorial.models.Wiki', permission='view')
def view_wiki(context, request):
- return HTTPFound(location = resource_url(context, request, 'FrontPage'))
+ return HTTPFound(location=resource_url(context, request, 'FrontPage'))
@view_config(context='tutorial.models.Page',
renderer='templates/view.pt', permission='view')
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/footerbg.png b/docs/tutorials/wiki/src/basiclayout/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/headerbg.png b/docs/tutorials/wiki/src/basiclayout/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/ie6.css b/docs/tutorials/wiki/src/basiclayout/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/logo.png b/docs/tutorials/wiki/src/basiclayout/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/middlebg.png b/docs/tutorials/wiki/src/basiclayout/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css
index c153be07f..fd1914d8d 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid-small.png b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid.png b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/transparent.gif b/docs/tutorials/wiki/src/basiclayout/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
index 6ad23d44f..2a2340683 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -5,23 +5,22 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
- <!--[if !IE 7]>
- <style type="text/css">
- #wrap {display:table;height:100%}
- </style>
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
</head>
<body>
<div id="wrap">
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
<div id="top">
<div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
<p class="app-welcome">
Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
the Pyramid web application development framework.
@@ -31,38 +30,35 @@
<div id="bottom">
<div class="bottom">
<div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
<input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
+ <input type="submit" id="x" value="Go" />
</form>
</div>
<div id="right" class="align-left">
- <h3>Pyramid links</h3>
+ <h2>Pyramid links</h2>
<ul class="links">
<li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/">The Pylons Project Documentation</a>
+ <a href="http://pylonsproject.org/">Pylons Website</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
</li>
<li>
<a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
@@ -73,7 +69,7 @@
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
index 0a3d507a0..1f3c3bb4d 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
@@ -1,15 +1,13 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
class ViewTests(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_my_view(self):
from tutorial.views import my_view
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
index 555f49e6d..157b9ac8f 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
@@ -1,6 +1,7 @@
from pyramid.view import view_config
from tutorial.models import MyModel
-@view_config(context=MyModel, renderer='tutorial:templates/mytemplate.pt')
+@view_config(context=MyModel,
+ renderer='tutorial:templates/mytemplate.pt')
def my_view(request):
return {'project':'tutorial'}
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/footerbg.png b/docs/tutorials/wiki/src/models/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/headerbg.png b/docs/tutorials/wiki/src/models/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/ie6.css b/docs/tutorials/wiki/src/models/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/logo.png b/docs/tutorials/wiki/src/models/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki/src/models/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/middlebg.png b/docs/tutorials/wiki/src/models/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css b/docs/tutorials/wiki/src/models/tutorial/static/pylons.css
index c153be07f..a9f49cc85 100644
--- a/docs/tutorials/wiki/src/models/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/models/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/pyramid-small.png b/docs/tutorials/wiki/src/models/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/pyramid.png b/docs/tutorials/wiki/src/models/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/models/tutorial/static/transparent.gif b/docs/tutorials/wiki/src/models/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
index a5a0dd214..e31a342b2 100644
--- a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
@@ -5,65 +5,71 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
<body>
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
- <div id="top">
- <div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
- <p class="app-welcome">
- Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
- the Pyramid web application development framework.
- </p>
+ <div id="wrap">
+ <div id="top">
+ <div class="top align-center">
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
</div>
- </div>
- <div id="bottom">
- <div class="bottom">
- <div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
- <input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
- </form>
+ <div id="middle">
+ <div class="middle align-center">
+ <p class="app-welcome">
+ Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
+ the Pyramid web application development framework.
+ </p>
</div>
- <div id="right" class="align-left">
- <h3>Pyramid links</h3>
- <ul class="links">
- <li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
- </li>
- <li>
- <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
- </li>
- </ul>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div id="left" class="align-right">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
+ </div>
+ <div id="right" class="align-left">
+ <h2>Pyramid links</h2>
+ <ul class="links">
+ <li>
+ <a href="http://pylonsproject.org">Pylons Website</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
+ </li>
+ <li>
+ <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
+ </li>
+ </ul>
+ </div>
</div>
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki/src/models/tutorial/tests.py b/docs/tutorials/wiki/src/models/tutorial/tests.py
index 839964538..51c97a95d 100644
--- a/docs/tutorials/wiki/src/models/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/models/tutorial/tests.py
@@ -1,6 +1,5 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
class PageModelTests(unittest.TestCase):
@@ -50,11 +49,10 @@ class AppmakerTests(unittest.TestCase):
class ViewTests(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_my_view(self):
from tutorial.views import my_view
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/footerbg.png b/docs/tutorials/wiki/src/views/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/headerbg.png b/docs/tutorials/wiki/src/views/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/ie6.css b/docs/tutorials/wiki/src/views/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/logo.png b/docs/tutorials/wiki/src/views/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki/src/views/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/middlebg.png b/docs/tutorials/wiki/src/views/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/pylons.css b/docs/tutorials/wiki/src/views/tutorial/static/pylons.css
index c153be07f..fd1914d8d 100644
--- a/docs/tutorials/wiki/src/views/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki/src/views/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/pyramid-small.png b/docs/tutorials/wiki/src/views/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/pyramid.png b/docs/tutorials/wiki/src/views/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/style.css b/docs/tutorials/wiki/src/views/tutorial/static/style.css
deleted file mode 100644
index cad87e0d4..000000000
--- a/docs/tutorials/wiki/src/views/tutorial/static/style.css
+++ /dev/null
@@ -1,109 +0,0 @@
-html, body {
- color: black;
- background-color: #ddd;
- font: x-small "Lucida Grande", "Lucida Sans Unicode", geneva, sans-serif;
- margin: 0;
- padding: 0;
-}
-
-td, th {padding:3px;border:none;}
-tr th {text-align:left;background-color:#f0f0f0;color:#333;}
-tr.odd td {background-color:#edf3fe;}
-tr.even td {background-color:#fff;}
-
-#header {
- height: 80px;
- width: 777px;
- background: blue URL('../images/header_inner.png') no-repeat;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- margin: 0 auto 0 auto;
-}
-
-a.link, a, a.active {
- color: #369;
-}
-
-
-#main_content {
- color: black;
- font-size: 127%;
- background-color: white;
- width: 757px;
- margin: 0 auto 0 auto;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- padding: 10px;
-}
-
-#sidebar {
- border: 1px solid #aaa;
- background-color: #eee;
- margin: 0.5em;
- padding: 1em;
- float: right;
- width: 200px;
- font-size: 88%;
-}
-
-#sidebar h2 {
- margin-top: 0;
-}
-
-#sidebar ul {
- margin-left: 1.5em;
- padding-left: 0;
-}
-
-h1,h2,h3,h4,h5,h6,#getting_started_steps {
- font-family: "Century Schoolbook L", Georgia, serif;
- font-weight: bold;
-}
-
-h2 {
- font-size: 150%;
-}
-
-#footer {
- border: 1px solid #aaa;
- border-top: 0px none;
- color: #999;
- background-color: white;
- padding: 10px;
- font-size: 80%;
- text-align: center;
- width: 757px;
- margin: 0 auto 1em auto;
-}
-
-.code {
- font-family: monospace;
-}
-
-span.code {
- font-weight: bold;
- background: #eee;
-}
-
-#status_block {
- margin: 0 auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- background: #cec URL('../images/ok.png') left center no-repeat;
- border: 1px solid #9c9;
- width: 450px;
- font-size: 120%;
- font-weight: bolder;
-}
-
-.notice {
- margin: 0.5em auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- width: 450px;
- background: #eef URL('../images/info.png') left center no-repeat;
- border: 1px solid #cce;
-}
-
-.fielderror {
- color: red;
- font-weight: bold;
-}
diff --git a/docs/tutorials/wiki/src/views/tutorial/static/transparent.gif b/docs/tutorials/wiki/src/views/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt
index 1d40f526d..c6c589c1a 100644
--- a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt
+++ b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt
@@ -1,32 +1,57 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)
- Editing: ${page.__name__}</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.__name__} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
- <div style="float:right; width: 10em;"> Viewing
- <span tal:replace="page.__name__">Page Name Goes Here</span> <br/>
- You can return to the <a href="${request.application_url}"
- >FrontPage</a>.
- </div>
-
- <div>
- <form action="${save_url}" method="post">
- <textarea name="body" tal:content="page.data" rows="10" cols="60"/>
- <input type="submit" name="form.submitted" value="Save"/>
- </form>
- </div>
-</div>
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Editing <b><span tal:replace="page.__name__">Page Name Goes
+ Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right"></div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <form action="${save_url}" method="post">
+ <textarea name="body" tal:content="page.data" rows="10"
+ cols="60"/><br/>
+ <input type="submit" name="form.submitted" value="Save"/>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt
index a5a0dd214..e31a342b2 100644
--- a/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt
@@ -5,65 +5,71 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
<body>
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
- <div id="top">
- <div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
- <p class="app-welcome">
- Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
- the Pyramid web application development framework.
- </p>
+ <div id="wrap">
+ <div id="top">
+ <div class="top align-center">
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
</div>
- </div>
- <div id="bottom">
- <div class="bottom">
- <div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
- <input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
- </form>
+ <div id="middle">
+ <div class="middle align-center">
+ <p class="app-welcome">
+ Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
+ the Pyramid web application development framework.
+ </p>
</div>
- <div id="right" class="align-left">
- <h3>Pyramid links</h3>
- <ul class="links">
- <li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
- </li>
- <li>
- <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
- </li>
- </ul>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div id="left" class="align-right">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
+ <input type="text" id="q" name="q" value="" />
+ <input type="submit" id="x" value="Go" />
+ </form>
+ </div>
+ <div id="right" class="align-left">
+ <h2>Pyramid links</h2>
+ <ul class="links">
+ <li>
+ <a href="http://pylonsproject.org">Pylons Website</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
+ </li>
+ <li>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
+ </li>
+ <li>
+ <a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
+ </li>
+ </ul>
+ </div>
</div>
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt
index 50719f9e9..97b87c44f 100644
--- a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt
+++ b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt
@@ -1,29 +1,60 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>${page.__name__} - Pyramid tutorial wiki
- (based on TurboGears 20-Minute Wiki)
- </title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.__name__} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
-<div style="float:right; width: 10em;"> Viewing
-<span tal:replace="page.__name__">Page Name Goes Here</span> <br/>
-You can return to the
-<a href="${request.application_url}">FrontPage</a>.
-</div>
-
-<div tal:replace="structure content">Page text goes here.</div>
-<p><a tal:attributes="href edit_url" href="">Edit this page</a></p>
-</div>
-
-</body></html>
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Viewing <b><span tal:replace="page.__name__">Page Name Goes
+ Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right"></div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div tal:replace="structure content">
+ Page text goes here.
+ </div>
+ <p>
+ <a tal:attributes="href edit_url" href="">
+ Edit this page
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
+</body>
+</html>
diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py
index c96bc2e9c..42420f2fe 100644
--- a/docs/tutorials/wiki/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki/src/views/tutorial/views.py
@@ -12,7 +12,7 @@ wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
@view_config(context='tutorial.models.Wiki')
def view_wiki(context, request):
- return HTTPFound(location = resource_url(context, request, 'FrontPage'))
+ return HTTPFound(location=resource_url(context, request, 'FrontPage'))
@view_config(context='tutorial.models.Page',
renderer='tutorial:templates/view.pt')
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index 8d30ab807..3f1d2669a 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -125,7 +125,7 @@ Adding ``security.py``
~~~~~~~~~~~~~~~~~~~~~~
Add a ``security.py`` module within your package (in the same directory as
-"__init__.py", "views.py", etc) with the following content:
+:file:`__init__.py`, :file:`views.py`, etc) with the following content:
.. literalinclude:: src/authorization/tutorial/security.py
:linenos:
@@ -202,8 +202,8 @@ Add a ``login.pt`` template to your templates directory. It's
referred to within the login view we just added to ``login.py``.
.. literalinclude:: src/authorization/tutorial/templates/login.pt
- :linenos:
:language: xml
+ :tab-width: 2
Change ``view.pt`` and ``edit.pt``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -212,11 +212,10 @@ We'll also need to change our ``edit.pt`` and ``view.pt`` templates to
display a "Logout" link if someone is logged in. This link will
invoke the logout view.
-To do so we'll add this to both templates within the ``<div
-class="main_content">`` div:
+To do so we'll add this to both templates within the ``<div id="right"
+class="app-welcome align-right">`` div:
.. code-block:: xml
- :linenos:
<span tal:condition="logged_in">
<a href="${request.application_url}/logout">Logout</a>
@@ -261,14 +260,14 @@ Our ``views.py`` module will look something like this when we're done:
Our ``edit.pt`` template will look something like this when we're done:
.. literalinclude:: src/authorization/tutorial/templates/edit.pt
- :linenos:
:language: xml
+ :tab-width: 2
Our ``view.pt`` template will look something like this when we're done:
.. literalinclude:: src/authorization/tutorial/templates/view.pt
- :linenos:
:language: xml
+ :tab-width: 2
Revisiting the Application
---------------------------
@@ -279,5 +278,353 @@ of hitting an edit or add page and submitting the login form with the
hand corner. When we click it, we're logged out, and redirected back
to the front page.
+.. _wiki2_flow_of_authentication:
+
+Overall flow of an authentication
+---------------------------------
+
+Now that you have seen all the pieces of the authentication
+mechanism, here are some examples that show how they all work
+together.
+
+#. Failed login: The user requests ``/FrontPage/edit_page``. The
+ site presents the login form. The user enters ``editor`` as
+ the login, but enters an invalid password ``bad``.
+ The site redisplays the login form with the message "Failed
+ login". See :ref:`failed_login`.
+
+#. The user again requests ``/FrontPage/edit_page``. The site
+ presents the login form, and this time the user enters
+ login ``editor`` and password ``editor``. The site presents
+ the edit form with the content of ``/FrontPage``. The user
+ makes some changes and saves them. See :ref:`good_login`.
+
+#. The user again revisits ``/FrontPage/edit_page``. The site
+ goes immediately to the edit form without requesting
+ credentials. See :ref:`revisit`.
+
+#. The user clicks the ``Logout`` link. See :ref:`logging_out`.
+
+.. _failed_login:
+
+Failed login
+~~~~~~~~~~~~
+
+The process starts when the user enters URL
+``http://localhost:6543/FrontPage/edit_page``. Let's assume that
+this is the first request ever made to the application and the
+page database is empty except for the ``Page`` instance created
+for the front page by the ``initialize_sql`` function in
+:file:`models.py`.
+
+This process involves two complete request/response cycles.
+
+1. From the front page, the user clicks :guilabel:`Edit page`.
+ The request is to ``/FrontPage/edit_page``. The view callable
+ is ``login.login``. The response is the ``login.pt`` template
+ with blank fields.
+
+2. The user enters invalid credentials and clicks :guilabel:`Log
+ in`. A ``POST`` request is sent to ``/FrontPage/edit_page``.
+ The view callable is again ``login.login``. The response is
+ the ``login.pt`` template showing the message "Failed login",
+ with the entry fields displaying their former values.
+
+Cycle 1:
+
+#. During URL dispatch, the route ``'/{pagename}/edit_page'`` is
+ considered for matching. The associated view has a
+ ``view_permission='edit'`` permission attached, so the
+ dispatch logic has to verify that the user has that permission
+ or the route is not considered to match.
+
+ The context for all route matching comes from the configured
+ root factory, :meth:`RootFactory` in :file:`models.py`.
+ This class has an ``__acl__`` attribute that defines the
+ access control list for all routes::
+
+ __acl__ = [ (Allow, Everyone, 'view'),
+ (Allow, 'group:editors', 'edit') ]
+
+ In practice, this means that for any route that requires the
+ ``edit`` permission, the user must be authenticated and
+ have the ``group:editors`` principal or the route is not
+ considered to match.
+
+#. To find the list of the user's principals, the authorization
+ first policy checks to see if the user has a
+ ``paste.auth.auth_tkt`` cookie. Since the user has never been
+ to the site, there is no such cookie, and the user is
+ considered to be unauthenticated.
+
+#. Since the user is unauthenticated, the ``groupfinder``
+ function in :file:`security.py` is called with ``None`` as its
+ ``userid`` argument. The function returns an empty list of
+ principals.
+
+#. Because that list does not contain the ``group:editors``
+ principal, the ``'/{pagename}/edit_page'`` route's ``edit``
+ permission fails, and the route does not match.
+
+#. Because no routes match, the `forbidden view` callable is
+ invoked: the ``login`` function in module ``login.py``.
+
+#. Inside the ``login`` function, the value of ``login_url`` is
+ ``http://localhost:6543/login``, and the value of
+ ``referrer`` is ``http://localhost:6543/FrontPage/edit_page``.
+
+ Because ``request.params`` has no key for ``'came_from'``, the
+ variable ``came_from`` is also set to
+ ``http://localhost:6543/FrontPage/edit_page``. Variables
+ ``message``, ``login``, and ``password`` are set to the empty
+ string.
+
+ Because ``request.params`` has no key for
+ ``'form.submitted'``, the ``login`` function returns this
+ dictionary::
+
+ {'message': '', 'url':'http://localhost:6543/login',
+ 'came_from':'http://localhost:6543/FrontPage/edit_page',
+ 'login':'', 'password':''}
+
+#. This dictionary is used to render the ``login.pt`` template.
+ In the form, the ``action`` attribute is
+ ``http://localhost:6543/login``, and the value of
+ ``came_from`` is included in that form as a hidden field
+ by this line in the template::
+
+ <input type="hidden" name="came_from" value="${came_from}"/>
+
+Cycle 2:
+
+#. The user enters incorrect credentials and clicks the
+ :guilabel:`Log in` button, which does a ``POST`` request to
+ URL ``http://localhost:6543/login``. The name of the
+ :guilabel:`Log in` button in this form is ``form.submitted``.
+
+#. The route with pattern ``'/login'`` matches this URL, so
+ control is passed again to the ``login`` view callable.
+
+#. The ``login_url`` and ``referrer`` have the same value
+ this time (``http://localhost:6543/login``), so variable
+ ``referrer`` is set to ``'/'``.
+
+ Since ``request.params`` does have a key ``'form.submitted'``,
+ the values of ``login`` and ``password`` are retrieved from
+ ``request.params``.
+
+ Because the login and password do not match any of the entries
+ in the ``USERS`` dictionary in ``security.py``, variable
+ ``message`` is set to ``'Failed login'``.
+
+ The view callable returns this dictionary::
+
+ {'message':'Failed login',
+ 'url':'http://localhost:6543/login', 'came_from':'/',
+ 'login':'editor', 'password':'bad'}
+
+#. The ``login.pt`` template is rendered using those values.
+
+.. _good_login:
+
+Successful login
+~~~~~~~~~~~~~~~~
+
+In this scenario, the user again requests URL
+``/FrontPage/edit_page``.
+
+This process involves four complete request/response cycles.
+
+1. The user clicks :guilabel:`Edit page`. The view callable is
+ ``login.login``. The response is template ``login.pt``,
+ with all the fields blank.
+
+2. The user enters valid credentials and clicks :guilabel:`Log in`.
+ The view callable is ``login.login``. The response is a
+ redirect to ``/FrontPage/edit_page``.
+
+3. The view callable is ``views.edit_page``. The response
+ renders template ``edit.pt``, displaying the current page
+ content.
+
+4. The user edits the content and clicks :guilabel:`Save`.
+ The view callable is ``views.edit_page``. The response
+ is a redirect to ``/FrontPage``.
+
+Execution proceeds as in :ref:`failed_login`, up to the point
+where the password ``editor`` is successfully matched against the
+value from the ``USERS`` dictionary.
+
+Cycle 2:
+
+#. Within the ``login.login`` view callable, the value of
+ ``login_url`` is ``http://localhost:6543/login``, and the
+ value of ``referrer`` is ``'/'``, and ``came_from`` is
+ ``http://localhost:6543/FrontPage/edit_page`` when this block
+ is executed:
+
+ .. code-block:: python
+
+ if USERS.get(login) == password:
+ headers = remember(request, login)
+ return HTTPFound(location=came_from, headers=headers)
+
+#. Because the password matches this time,
+ :mod:`pyramid.security.remember` returns a sequence of header
+ tuples that will set a ``paste.auth.auth_tkt`` authentication
+ cookie in the user's browser for the login ``'editor'``.
+
+#. The ``HTTPFound`` exception returns a response that redirects
+ the browser to ``http://localhost:6543/FrontPage/edit_page``,
+ including the headers that set the authentication cookie.
+
+Cycle 3:
+
+#. Route pattern ``'/{pagename}/edit_page'`` matches this URL,
+ but the corresponding view is restricted by an ``'edit'``
+ permission.
+
+#. Because the user now has an authentication cookie defining
+ their login name as ``'editor'``, the ``groupfinder`` function
+ is called with that value as its ``userid`` argument.
+
+#. The ``groupfinder`` function returns the list
+ ``['group:editors']``. This satisfies the access control
+ entry ``(Allow, 'group:editors', 'edit')``, which grants the
+ ``edit`` permission. Thus, this route matches, and control
+ passes to view callable ``edit_page``.
+
+#. Within ``edit_page``, ``name`` is set to ``'FrontPage'``, the
+ page name from ``request.matchdict['pagename']``, and
+ ``page`` is set to an instance of :class:`models.Page`
+ that holds the current content of ``FrontPage``.
+
+#. Since this request did not come from a form,
+ ``request.params`` does not have a key for
+ ``'form.submitted'``.
+
+#. The ``edit_page`` function calls
+ :meth:`pyramid.security.authenticated_userid` to find out
+ whether the user is authenticated. Because of the cookies
+ set previously, the variable ``logged_in`` is set to
+ the userid ``'editor'``.
+
+#. The ``edit_page`` function returns this dictionary::
+
+ {'page':page, 'logged_in':'editor',
+ 'save_url':'http://localhost:6543/FrontPage/edit_page'}
+
+#. Template :file:`edit.pt` is rendered with those values.
+ Among other features of this template, these lines
+ cause the inclusion of a :guilabel:`Logout` link::
+
+ <span tal:condition="logged_in">
+ <a href="${request.application_url}/logout">Logout</a>
+ </span>
+
+ For the example case, this link will refer to
+ ``http://localhost:6543/logout``.
+
+ These lines of the template display the current page's
+ content in a form whose ``action`` attribute is
+ ``http://localhost:6543/FrontPage/edit_page``::
+
+ <form action="${save_url}" method="post">
+ <textarea name="body" tal:content="page.data" rows="10" cols="60"/>
+ <input type="submit" name="form.submitted" value="Save"/>
+ </form>
+
+Cycle 4:
+
+#. The user edits the page content and clicks
+ :guilabel:`Save`.
+
+#. URL ``http://localhost:6543/FrontPage/edit_page`` goes through
+ the same routing as before, up until the line that checks
+ whether ``request.params`` has a key ``'form.submitted'``.
+ This time, within the ``edit_page`` view callable, these
+ lines are executed::
+
+ page.data = request.params['body']
+ session.add(page)
+ return HTTPFound(location = route_url('view_page', request,
+ pagename=name))
+
+ The first two lines replace the old page content with the
+ contents of the ``body`` text area from the form, and then
+ update the page stored in the database. The third line
+ causes a response that redirects the browser to
+ ``http://localhost:6543/FrontPage``.
+
+.. _revisit:
+
+Revisiting after authentication
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this case, the user has an authentication cookie set in their
+browser that specifies their login as ``'editor'``. The
+requested URL is ``http://localhost:6543/FrontPage/edit_page``.
+
+This process requires two request/response cycles.
+
+1. The user clicks :guilabel:`Edit page`. The view callable is
+ ``views.edit_page``. The response is ``edit.pt``, showing
+ the current page content.
+
+2. The user edits the content and clicks :guilabel:`Save`.
+ The view callable is ``views.edit_page``. The response is
+ a redirect to ``/Frontpage``.
+
+Cycle 1:
+
+#. The route with pattern ``/{pagename}/edit_page`` matches the
+ URL, and because of the authentication cookie, ``groupfinder``
+ returns a list containing the ``group:editors`` principal,
+ which ``models.RootFactory.__acl__`` uses to grant the
+ ``edit`` permission, so this route matches and dispatches
+ to the view callable :meth:`views.edit_page`.
+
+#. In ``edit_page``, because the request did not come from a form
+ submission, ``request.params`` has no key for
+ ``'form.submitted'``.
+
+#. The variable ``logged_in`` is set to the login name
+ ``'editor'`` by calling ``authenticated_userid``, which
+ extracts it from the authentication cookie.
+
+#. The function returns this dictionary::
+
+ {'page':page,
+ 'save_url':'http://localhost:6543/FrontPage/edit_page',
+ 'logged_in':'editor'}
+
+#. Template :file:`edit.pt` is rendered with the values from
+ that dictionary. Because of the presence of the
+ ``'logged_in'`` entry, a :guilabel:`Logout` link appears.
+
+Cycle 2:
+
+#. The user edits the page content and clicks :guilabel:`Save`.
+
+#. The ``POST`` operation works as in :ref:`good_login`.
+
+.. _logging_out:
+
+Logging out
+~~~~~~~~~~~
+
+This process starts with a request URL
+``http://localhost:6543/logout``.
+
+#. The route with pattern ``'/logout'`` matches and dispatches
+ to the view callable ``logout`` in :file:`login.py`.
+#. The call to :meth:`pyramid.security.forget` returns a list of
+ header tuples that will, when returned with the response,
+ cause the browser to delete the user's authentication cookie.
+#. The view callable returns an ``HTTPFound`` exception that
+ redirects the browser to named route ``view_wiki``, which
+ will translate to URL ``http://localhost:6543``. It
+ also passes along the headers that delete the
+ authentication cookie.
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index e3d611136..acf539e1a 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -212,8 +212,8 @@ Once we're done with the ``view.pt`` template, it will look a lot like
the below:
.. literalinclude:: src/views/tutorial/templates/view.pt
- :linenos:
:language: xml
+ :tab-width: 2
.. note:: The names available for our use in a template are always
those that are present in the dictionary returned by the view
@@ -240,25 +240,26 @@ Once we're done with the ``edit.pt`` template, it will look a lot like
the below:
.. literalinclude:: src/views/tutorial/templates/edit.pt
- :linenos:
:language: xml
+ :tab-width: 2
-Static Resources
-----------------
-Our templates name a single static resource named ``style.css``. We need to
-create this and place it in a file named ``style.css`` within our package's
-``static`` directory. This file is a little too long to replicate within the
-body of this guide, however it is available `online
-<http://github.com/Pylons/pyramid/blob/master/docs/tutorials/wiki2/src/views/tutorial/static/style.css>`_.
+Static Assets
+-------------
+Our templates name a single static asset named ``pylons.css``. We don't need
+to create this file within our package's ``static`` directory because it was
+provided at the time we created the project. This file is a little too long to
+replicate within the body of this guide, however it is available `online
+<http://github.com/Pylons/pyramid/blob/master/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css>`_.
This CSS file will be accessed via
-e.g. ``http://localhost:6543/static/style.css`` by virtue of the call we've
-made to :meth:`pyramid.config.Configurator.add_static_view` within our
-``__init__.py`` file. Any number and type of static resources can be placed
-in this directory (or subdirectories) and are just referred to by URL within
-templates.
+e.g. ``http://localhost:6543/static/pylons.css`` by virtue of the call to
+``add_static_view`` directive we've made in the ``__init__`` file. Any
+number and type of static assets can be placed in this directory (or
+subdirectories) and are just referred to by URL or by using the convenience
+method ``static_url`` e.g. ``request.static_url('{{package}}:static/foo.css')``
+within templates.
Mapping Views to URLs in ``__init__.py``
========================================
diff --git a/docs/tutorials/wiki2/distributing.rst b/docs/tutorials/wiki2/distributing.rst
index f4421e145..9f5db19ae 100644
--- a/docs/tutorials/wiki2/distributing.rst
+++ b/docs/tutorials/wiki2/distributing.rst
@@ -18,7 +18,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut> ..\Scripts\python setup.py sdist
+ c:\pyramidtut> ..\Scripts\python setup.py sdist
.. warning:: If your project files are not checked in to a version
control repository (such as Subversion), the dist tarball will
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index e6fd5e6b9..c957f641e 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -45,13 +45,13 @@ Preparation, UNIX
.. code-block:: text
- $ path/to/my/Python-2.6/bin/virtualenv --no-site-packages bigfntut
+ $ path/to/my/Python-2.6/bin/virtualenv --no-site-packages pyramidtut
-#. Switch to the ``bigfntut`` directory:
+#. Switch to the ``pyramidtut`` directory:
.. code-block:: text
- $ cd bigfntut
+ $ cd pyramidtut
#. (Optional) Consider using ``source bin/activate`` to make your
shell environment wired to use the virtualenv.
@@ -96,13 +96,13 @@ Preparation, Windows
.. code-block:: text
- c:\> c:\Python26\Scripts\virtualenv --no-site-packages bigfntut
+ c:\> c:\Python26\Scripts\virtualenv --no-site-packages pyramidtut
-#. Switch to the ``bigfntut`` directory:
+#. Switch to the ``pyramidtut`` directory:
.. code-block:: text
- c:\> cd bigfntut
+ c:\> cd pyramidtut
#. (Optional) Consider using ``bin\activate.bat`` to make your shell
environment wired to use the virtualenv.
@@ -112,13 +112,13 @@ Preparation, Windows
.. code-block:: text
- c:\bigfntut> Scripts\easy_install pyramid
+ c:\pyramidtut> Scripts\easy_install pyramid
#. Use ``easy_install`` to install various packages from PyPI.
.. code-block:: text
- c:\bigfntut> Scripts\easy_install -i docutils \
+ c:\pyramidtut> Scripts\easy_install -i docutils \
nose coverage zope.sqlalchemy SQLAlchemy repoze.tm2
@@ -133,7 +133,7 @@ variety of templates to generate sample projects. We will use the
that uses :term:`SQLAlchemy` and :term:`URL dispatch`.
The below instructions assume your current working directory is the
-"virtualenv" named "bigfntut".
+"virtualenv" named "pyramidtut".
On UNIX:
@@ -145,7 +145,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut> Scripts\paster create -t pyramid_routesalchemy tutorial
+ c:\pyramidtut> Scripts\paster create -t pyramid_routesalchemy tutorial
.. note:: If you are using Windows, the ``pyramid_routesalchemy``
Paster template may not deal gracefully with installation into a
@@ -173,8 +173,8 @@ On Windows:
.. code-block:: text
- c:\bigfntut> cd tutorial
- c:\bigfntut\tutorial> ..\Scripts\python setup.py develop
+ c:\pyramidtut> cd tutorial
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py develop
.. _sql_running_tests:
@@ -194,7 +194,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut\tutorial> ..\Scripts\python setup.py test -q
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
Starting the Application
========================
@@ -211,7 +211,7 @@ On Windows:
.. code-block:: text
- c:\bifgfntut\tutorial> ..\Scripts\paster serve development.ini --reload
+ c:\pyramidtut\tutorial> ..\Scripts\paster serve development.ini --reload
Exposing Test Coverage Information
==================================
@@ -235,7 +235,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut\tutorial> ..\Scripts\easy_install nose coverage
+ c:\pyramidtut\tutorial> ..\Scripts\easy_install nose coverage
Once ``nose`` and ``coverage`` are installed, we can actually run the
coverage tests.
@@ -250,7 +250,7 @@ On Windows:
.. code-block:: text
- c:\bigfntut\tutorial> ..\Scripts\nosetests --cover-package=tutorial \
+ c:\pyramidtut\tutorial> ..\Scripts\nosetests --cover-package=tutorial \
--cover-erase --with-coverage
Looks like our package's ``models`` module doesn't quite have 100%
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/footerbg.png b/docs/tutorials/wiki2/src/authorization/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/headerbg.png b/docs/tutorials/wiki2/src/authorization/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/ie6.css b/docs/tutorials/wiki2/src/authorization/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/logo.png b/docs/tutorials/wiki2/src/authorization/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki2/src/authorization/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/middlebg.png b/docs/tutorials/wiki2/src/authorization/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css
index c153be07f..fd1914d8d 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid-small.png b/docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid.png b/docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/style.css b/docs/tutorials/wiki2/src/authorization/tutorial/static/style.css
deleted file mode 100644
index cad87e0d4..000000000
--- a/docs/tutorials/wiki2/src/authorization/tutorial/static/style.css
+++ /dev/null
@@ -1,109 +0,0 @@
-html, body {
- color: black;
- background-color: #ddd;
- font: x-small "Lucida Grande", "Lucida Sans Unicode", geneva, sans-serif;
- margin: 0;
- padding: 0;
-}
-
-td, th {padding:3px;border:none;}
-tr th {text-align:left;background-color:#f0f0f0;color:#333;}
-tr.odd td {background-color:#edf3fe;}
-tr.even td {background-color:#fff;}
-
-#header {
- height: 80px;
- width: 777px;
- background: blue URL('../images/header_inner.png') no-repeat;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- margin: 0 auto 0 auto;
-}
-
-a.link, a, a.active {
- color: #369;
-}
-
-
-#main_content {
- color: black;
- font-size: 127%;
- background-color: white;
- width: 757px;
- margin: 0 auto 0 auto;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- padding: 10px;
-}
-
-#sidebar {
- border: 1px solid #aaa;
- background-color: #eee;
- margin: 0.5em;
- padding: 1em;
- float: right;
- width: 200px;
- font-size: 88%;
-}
-
-#sidebar h2 {
- margin-top: 0;
-}
-
-#sidebar ul {
- margin-left: 1.5em;
- padding-left: 0;
-}
-
-h1,h2,h3,h4,h5,h6,#getting_started_steps {
- font-family: "Century Schoolbook L", Georgia, serif;
- font-weight: bold;
-}
-
-h2 {
- font-size: 150%;
-}
-
-#footer {
- border: 1px solid #aaa;
- border-top: 0px none;
- color: #999;
- background-color: white;
- padding: 10px;
- font-size: 80%;
- text-align: center;
- width: 757px;
- margin: 0 auto 1em auto;
-}
-
-.code {
- font-family: monospace;
-}
-
-span.code {
- font-weight: bold;
- background: #eee;
-}
-
-#status_block {
- margin: 0 auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- background: #cec URL('../images/ok.png') left center no-repeat;
- border: 1px solid #9c9;
- width: 450px;
- font-size: 120%;
- font-weight: bolder;
-}
-
-.notice {
- margin: 0.5em auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- width: 450px;
- background: #eef URL('../images/info.png') left center no-repeat;
- border: 1px solid #cce;
-}
-
-.fielderror {
- color: red;
- font-weight: bold;
-}
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/static/transparent.gif b/docs/tutorials/wiki2/src/authorization/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.pt
index 05e2ecd76..cea9b4932 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.pt
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/edit.pt
@@ -1,35 +1,61 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)
- Editing: ${page.name}</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.name} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
- <div style="float:right; width: 10em;"> Viewing
- <span tal:replace="page.name">Page Name Goes Here</span> <br/>
- You can return to the <a href="${request.application_url}"
- >FrontPage</a>.
- <span tal:condition="logged_in">
- <a href="${request.application_url}/logout">Logout</a>
- </span>
- </div>
-
- <div>
- <form action="${save_url}" method="post">
- <textarea name="body" tal:content="page.data" rows="10" cols="60"/>
- <input type="submit" name="form.submitted" value="Save"/>
- </form>
- </div>
-</div>
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Editing <b><span tal:replace="page.name">Page Name
+ Goes Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right">
+ <span tal:condition="logged_in">
+ <a href="${request.application_url}/logout">Logout</a>
+ </span>
+ </div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <form action="${save_url}" method="post">
+ <textarea name="body" tal:content="page.data" rows="10"
+ cols="60"/><br/>
+ <input type="submit" name="form.submitted" value="Save"/>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.pt
index c56983d64..554b4ea87 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.pt
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/login.pt
@@ -1,32 +1,57 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>Login - Pyramid tutorial wiki (based on TurboGears
+ 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<h1>Log In</h1>
-
-<div tal:replace="message"/>
-
-<div class="main_content">
- <form action="${url}" method="post">
- <input type="hidden" name="came_from" value="${came_from}"/>
- <input type="text" name="login" value="${login}"/>
- <br/>
- <input type="password" name="password" value="${password}"/>
- <br/>
- <input type="submit" name="form.submitted" value="Log In"/>
- </form>
-</div>
-
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ <b>Login</b><br/>
+ <span tal:replace="message"/>
+ </div>
+ <div id="right" class="app-welcome align-right"></div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <form action="${url}" method="post">
+ <input type="hidden" name="came_from" value="${came_from}"/>
+ <input type="text" name="login" value="${login}"/><br/>
+ <input type="password" name="password"
+ value="${password}"/><br/>
+ <input type="submit" name="form.submitted" value="Log In"/>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.pt
index 6ad23d44f..e31a342b2 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/mytemplate.pt
@@ -5,23 +5,22 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
- <!--[if !IE 7]>
- <style type="text/css">
- #wrap {display:table;height:100%}
- </style>
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
</head>
<body>
<div id="wrap">
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
<div id="top">
<div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
<p class="app-welcome">
Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
the Pyramid web application development framework.
@@ -31,38 +30,35 @@
<div id="bottom">
<div class="bottom">
<div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
<input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
+ <input type="submit" id="x" value="Go" />
</form>
</div>
<div id="right" class="align-left">
- <h3>Pyramid links</h3>
+ <h2>Pyramid links</h2>
<ul class="links">
<li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/">The Pylons Project Documentation</a>
+ <a href="http://pylonsproject.org">Pylons Website</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
</li>
<li>
<a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
@@ -73,7 +69,7 @@
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.pt b/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.pt
index 0c654250a..7d01aefb9 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.pt
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/templates/view.pt
@@ -1,31 +1,64 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>${page.name} - Pyramid tutorial wiki
- (based on TurboGears 20-Minute Wiki)</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.name} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
-<div style="float:right; width: 10em;"> Viewing
-<span tal:replace="page.name">Page Name Goes Here</span> <br/>
-You can return to the <a href="${request.application_url}">FrontPage</a>.
-<span tal:condition="logged_in">
- <a href="${request.application_url}/logout">Logout</a>
-</span>
-</div>
-
-<div tal:replace="structure content">Page text goes here.</div>
-<p><a tal:attributes="href edit_url" href="">Edit this page</a></p>
-</div>
-
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Viewing <b><span tal:replace="page.name">Page Name
+ Goes Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right">
+ <span tal:condition="logged_in">
+ <a href="${request.application_url}/logout">Logout</a>
+ </span>
+ </div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div tal:replace="structure content">
+ Page text goes here.
+ </div>
+ <p>
+ <a tal:attributes="href edit_url" href="">
+ Edit this page
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
index 1020a8b99..08916f43c 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
@@ -1,6 +1,5 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
def _initTestingDB():
@@ -20,11 +19,10 @@ def _registerRoutes(config):
class ViewWikiTests(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_it(self):
from tutorial.views import view_wiki
@@ -36,12 +34,10 @@ class ViewWikiTests(unittest.TestCase):
class ViewPageTests(unittest.TestCase):
def setUp(self):
self.session = _initTestingDB()
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.session.remove()
- self.config.end()
+ testing.tearDown()
def _callFUT(self, request):
from tutorial.views import view_page
@@ -71,12 +67,11 @@ class ViewPageTests(unittest.TestCase):
class AddPageTests(unittest.TestCase):
def setUp(self):
self.session = _initTestingDB()
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
self.session.remove()
- self.config.end()
+ testing.tearDown()
def _callFUT(self, request):
from tutorial.views import add_page
@@ -104,12 +99,11 @@ class AddPageTests(unittest.TestCase):
class EditPageTests(unittest.TestCase):
def setUp(self):
self.session = _initTestingDB()
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
self.session.remove()
- self.config.end()
+ testing.tearDown()
def _callFUT(self, request):
from tutorial.views import edit_page
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
index 9da906752..4fd010c5c 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
@@ -12,7 +12,8 @@ from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension
-DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
+DBSession = scoped_session(sessionmaker(
+ extension=ZopeTransactionExtension()))
Base = declarative_base()
class MyModel(Base):
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/footerbg.png b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/headerbg.png b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/ie6.css b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/logo.png b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/middlebg.png b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css
index c153be07f..fd1914d8d 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid-small.png b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid.png b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/static/transparent.gif b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
index 6ad23d44f..e31a342b2 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -5,23 +5,22 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
- <!--[if !IE 7]>
- <style type="text/css">
- #wrap {display:table;height:100%}
- </style>
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
</head>
<body>
<div id="wrap">
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
<div id="top">
<div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
<p class="app-welcome">
Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
the Pyramid web application development framework.
@@ -31,38 +30,35 @@
<div id="bottom">
<div class="bottom">
<div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
<input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
+ <input type="submit" id="x" value="Go" />
</form>
</div>
<div id="right" class="align-left">
- <h3>Pyramid links</h3>
+ <h2>Pyramid links</h2>
<ul class="links">
<li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/">The Pylons Project Documentation</a>
+ <a href="http://pylonsproject.org">Pylons Website</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
</li>
<li>
<a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
@@ -73,7 +69,7 @@
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
index fa3788340..5efa6affa 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
@@ -1,5 +1,4 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
def _initTestingDB():
@@ -10,12 +9,11 @@ def _initTestingDB():
class TestMyView(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
_initTestingDB()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_it(self):
from tutorial.views import my_view
diff --git a/docs/tutorials/wiki2/src/models/tutorial/models.py b/docs/tutorials/wiki2/src/models/tutorial/models.py
index 23b8afab8..797fff929 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/models.py
@@ -12,7 +12,8 @@ from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension
-DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
+DBSession = scoped_session(sessionmaker(
+ extension=ZopeTransactionExtension()))
Base = declarative_base()
class Page(Base):
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/footerbg.png b/docs/tutorials/wiki2/src/models/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/headerbg.png b/docs/tutorials/wiki2/src/models/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/ie6.css b/docs/tutorials/wiki2/src/models/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/logo.png b/docs/tutorials/wiki2/src/models/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki2/src/models/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/middlebg.png b/docs/tutorials/wiki2/src/models/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css
index c153be07f..fd1914d8d 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/pyramid-small.png b/docs/tutorials/wiki2/src/models/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/pyramid.png b/docs/tutorials/wiki2/src/models/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/models/tutorial/static/transparent.gif b/docs/tutorials/wiki2/src/models/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
index 6ad23d44f..e31a342b2 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
@@ -5,23 +5,22 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
- <!--[if !IE 7]>
- <style type="text/css">
- #wrap {display:table;height:100%}
- </style>
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
</head>
<body>
<div id="wrap">
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
<div id="top">
<div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
<p class="app-welcome">
Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
the Pyramid web application development framework.
@@ -31,38 +30,35 @@
<div id="bottom">
<div class="bottom">
<div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
<input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
+ <input type="submit" id="x" value="Go" />
</form>
</div>
<div id="right" class="align-left">
- <h3>Pyramid links</h3>
+ <h2>Pyramid links</h2>
<ul class="links">
<li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/">The Pylons Project Documentation</a>
+ <a href="http://pylonsproject.org">Pylons Website</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
</li>
<li>
<a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
@@ -73,7 +69,7 @@
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki2/src/models/tutorial/tests.py b/docs/tutorials/wiki2/src/models/tutorial/tests.py
index 42b0aaada..71f5e21e3 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/tests.py
@@ -1,5 +1,4 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
def _initTestingDB():
@@ -9,12 +8,11 @@ def _initTestingDB():
class TestMyView(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
_initTestingDB()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_it(self):
from tutorial.views import my_view
diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
index 334fde814..1a8d24499 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
@@ -10,7 +10,7 @@ def main(global_config, **settings):
initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'tutorial:static')
- config.add_route('home', '/', view='tutorial.views.view_wiki')
+ config.add_route('view_wiki', '/', view='tutorial.views.view_wiki')
config.add_route('view_page', '/{pagename}',
view='tutorial.views.view_page',
view_renderer='tutorial:templates/view.pt')
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/footerbg.png b/docs/tutorials/wiki2/src/views/tutorial/static/footerbg.png
new file mode 100644
index 000000000..1fbc873da
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/footerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/headerbg.png b/docs/tutorials/wiki2/src/views/tutorial/static/headerbg.png
new file mode 100644
index 000000000..0596f2020
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/headerbg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/ie6.css b/docs/tutorials/wiki2/src/views/tutorial/static/ie6.css
new file mode 100644
index 000000000..b7c8493d8
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/ie6.css
@@ -0,0 +1,8 @@
+* html img,
+* html .png{position:relative;behavior:expression((this.runtimeStyle.behavior="none")&&(this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "',sizingMethod='image')",
+this.src = "static/transparent.gif"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
+this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "',sizingMethod='crop')",
+this.runtimeStyle.backgroundImage = "none")),this.pngSet=true)
+);}
+#wrap{display:table;height:100%}
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/logo.png b/docs/tutorials/wiki2/src/views/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki2/src/views/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/middlebg.png b/docs/tutorials/wiki2/src/views/tutorial/static/middlebg.png
new file mode 100644
index 000000000..2369cfb7d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/middlebg.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css b/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css
index c153be07f..fd1914d8d 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/pylons.css
@@ -4,34 +4,23 @@ body{line-height:1;}
ol,ul{list-style:none;}
blockquote,q{quotes:none;}
blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* remember to define focus styles! */
:focus{outline:0;}
-/* remember to highlight inserts somehow! */
ins{text-decoration:none;}
del{text-decoration:line-through;}
-/* tables still need 'cellspacing="0"' in the markup */
table{border-collapse:collapse;border-spacing:0;}
-/* restyling */
sub{vertical-align:sub;font-size:smaller;line-height:normal;}
sup{vertical-align:super;font-size:smaller;line-height:normal;}
-/* lists */
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;}
-/* nested lists have no top/bottom margins */
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;}
-/* 2 deep unordered lists use a circle */
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;}
-/* 3 deep (or more) unordered lists use a square */
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;/* 28px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h2{font-size:1.5em;/* 24px */
-line-height:1.7em;font-family:helvetica,verdana;}
-h3{font-size:1.25em;/* 20px */
-line-height:1.7em;font-family:helvetica,verdana;}
+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 "Nobile","Lucida Grande",Lucida,Verdana,sans-serif;}
@@ -42,23 +31,26 @@ body h2,
body h3,
body h4,
body h5,
-body h6{font-family:"Nobile","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#144fb2;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;}
-#header{background-color:#e88f00;top:0;font-size:14px;}
-#footer{background-color:#000000;bottom:0;position: relative;margin-top:-40px;clear:both;}
-.header,.footer{width:700px;margin-right:auto;margin-left:auto;}
+body h6{font-family:"Neuton","Lucida Grande",Lucida,Verdana,sans-serif;font-weight:normal;color:#373839;font-style:normal;}
+#wrap{min-height:100%;}
+#header,#footer{width:100%;color:#ffffff;height:40px;position:absolute;text-align:center;line-height:40px;overflow:hidden;font-size:12px;vertical-align:middle;}
+#header{background:#000000;top:0;font-size:14px;}
+#footer{bottom:0;background:#000000 url(footerbg.png) repeat-x 0 top;position:relative;margin-top:-40px;clear:both;}
+.header,.footer{width:750px;margin-right:auto;margin-left:auto;}
.wrapper{width:100%}
-#top,#bottom{width:100%;}
-#top{color:#888;background-color:#eee;height:300px;border-bottom:2px solid #ddd;}
-#bottom{color:#222;background-color:#ffffff;overflow:hidden;padding-bottom:80px;}
-.top,.bottom{width:700px;margin-right:auto;margin-left:auto;}
-.top{padding-top:100px;}
+#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:325px;float:left;padding-right:25px;}
-#right{width:325px;float:right;padding-left:25px;}
+#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;}
@@ -67,7 +59,7 @@ ul.links li{list-style-type:none;font-size:14px;}
form{border-style:none;}
fieldset{border-style:none;}
input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
+input[type=text],input[type=password]{width:205px;}
input[type=submit]{background-color:#ddd;font-weight:bold;}
/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
+body:before{content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/pyramid-small.png b/docs/tutorials/wiki2/src/views/tutorial/static/pyramid-small.png
new file mode 100644
index 000000000..a5bc0ade7
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/pyramid-small.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/pyramid.png b/docs/tutorials/wiki2/src/views/tutorial/static/pyramid.png
new file mode 100644
index 000000000..347e05549
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/pyramid.png
Binary files differ
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/style.css b/docs/tutorials/wiki2/src/views/tutorial/static/style.css
deleted file mode 100644
index cad87e0d4..000000000
--- a/docs/tutorials/wiki2/src/views/tutorial/static/style.css
+++ /dev/null
@@ -1,109 +0,0 @@
-html, body {
- color: black;
- background-color: #ddd;
- font: x-small "Lucida Grande", "Lucida Sans Unicode", geneva, sans-serif;
- margin: 0;
- padding: 0;
-}
-
-td, th {padding:3px;border:none;}
-tr th {text-align:left;background-color:#f0f0f0;color:#333;}
-tr.odd td {background-color:#edf3fe;}
-tr.even td {background-color:#fff;}
-
-#header {
- height: 80px;
- width: 777px;
- background: blue URL('../images/header_inner.png') no-repeat;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- margin: 0 auto 0 auto;
-}
-
-a.link, a, a.active {
- color: #369;
-}
-
-
-#main_content {
- color: black;
- font-size: 127%;
- background-color: white;
- width: 757px;
- margin: 0 auto 0 auto;
- border-left: 1px solid #aaa;
- border-right: 1px solid #aaa;
- padding: 10px;
-}
-
-#sidebar {
- border: 1px solid #aaa;
- background-color: #eee;
- margin: 0.5em;
- padding: 1em;
- float: right;
- width: 200px;
- font-size: 88%;
-}
-
-#sidebar h2 {
- margin-top: 0;
-}
-
-#sidebar ul {
- margin-left: 1.5em;
- padding-left: 0;
-}
-
-h1,h2,h3,h4,h5,h6,#getting_started_steps {
- font-family: "Century Schoolbook L", Georgia, serif;
- font-weight: bold;
-}
-
-h2 {
- font-size: 150%;
-}
-
-#footer {
- border: 1px solid #aaa;
- border-top: 0px none;
- color: #999;
- background-color: white;
- padding: 10px;
- font-size: 80%;
- text-align: center;
- width: 757px;
- margin: 0 auto 1em auto;
-}
-
-.code {
- font-family: monospace;
-}
-
-span.code {
- font-weight: bold;
- background: #eee;
-}
-
-#status_block {
- margin: 0 auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- background: #cec URL('../images/ok.png') left center no-repeat;
- border: 1px solid #9c9;
- width: 450px;
- font-size: 120%;
- font-weight: bolder;
-}
-
-.notice {
- margin: 0.5em auto 0.5em auto;
- padding: 15px 10px 15px 55px;
- width: 450px;
- background: #eef URL('../images/info.png') left center no-repeat;
- border: 1px solid #cce;
-}
-
-.fielderror {
- color: red;
- font-weight: bold;
-}
diff --git a/docs/tutorials/wiki2/src/views/tutorial/static/transparent.gif b/docs/tutorials/wiki2/src/views/tutorial/static/transparent.gif
new file mode 100644
index 000000000..0341802e5
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/static/transparent.gif
Binary files differ
diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/edit.pt b/docs/tutorials/wiki2/src/views/tutorial/templates/edit.pt
index 047a64eb3..f8f63af3b 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/templates/edit.pt
+++ b/docs/tutorials/wiki2/src/views/tutorial/templates/edit.pt
@@ -1,32 +1,57 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)
- Editing: ${page.name}</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.name} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
- <div style="float:right; width: 10em;"> Viewing
- <span tal:replace="page.name">Page Name Goes Here</span> <br/>
- You can return to the <a href="${request.application_url}"
- >FrontPage</a>.
- </div>
-
- <div>
- <form action="${save_url}" method="post">
- <textarea name="body" tal:content="page.data" rows="10" cols="60"/>
- <input type="submit" name="form.submitted" value="Save"/>
- </form>
- </div>
-</div>
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Editing <b><span tal:replace="page.name">Page Name Goes
+ Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right"></div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <form action="${save_url}" method="post">
+ <textarea name="body" tal:content="page.data" rows="10"
+ cols="60"/><br/>
+ <input type="submit" name="form.submitted" value="Save"/>
+ </form>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
index 6ad23d44f..e31a342b2 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
@@ -5,23 +5,22 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
- <link rel="shortcut icon" href="${request.application_url}/static/favicon.ico" />
- <link rel="stylesheet" href="${request.application_url}/static/pylons.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
- <!--[if !IE 7]>
- <style type="text/css">
- #wrap {display:table;height:100%}
- </style>
+ <link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton|Nobile:regular,i,b,bi&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
</head>
<body>
<div id="wrap">
- <div id="header">
- <div class="header">The Pyramid Web Application Development Framework</div>
- </div>
<div id="top">
<div class="top align-center">
- <img src="${request.application_url}/static/logo.png" width="300" height="80"/>
+ <div><img src="${request.static_url('tutorial:static/pyramid.png')}" width="750" height="169" alt="pyramid"/></div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-center">
<p class="app-welcome">
Welcome to <span class="app-name">${project}</span>, an application generated by<br/>
the Pyramid web application development framework.
@@ -31,38 +30,35 @@
<div id="bottom">
<div class="bottom">
<div id="left" class="align-right">
- <h3>Search Pyramid documentation</h3>
- <form method="get" action="http://docs.pylonshq.com/pyramid/dev/search.html">
+ <h2>Search documentation</h2>
+ <form method="get" action="http://docs.pylonsproject.org/projects/pyramid/dev/search.html">
<input type="text" id="q" name="q" value="" />
- <input type="submit" id="x" value="Search" />
+ <input type="submit" id="x" value="Go" />
</form>
</div>
<div id="right" class="align-left">
- <h3>Pyramid links</h3>
+ <h2>Pyramid links</h2>
<ul class="links">
<li>
- <a href="http://pylonshq.com">Pylons Website</a>
- </li>
- <li>
- <a href="http://docs.pylonshq.com/">The Pylons Project Documentation</a>
+ <a href="http://pylonsproject.org">Pylons Website</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#narrative-documentation">Narrative Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#api-documentation">API Documentation</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#api-documentation">API Documentation</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#tutorials">Tutorials</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#tutorials">Tutorials</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#change-history">Change History</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#change-history">Change History</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#sample-applications">Sample Applications</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#sample-applications">Sample Applications</a>
</li>
<li>
- <a href="http://docs.pylonshq.com/pyramid/dev/#support-and-development">Support and Development</a>
+ <a href="http://docs.pylonsproject.org/projects/pyramid/dev/#support-and-development">Support and Development</a>
</li>
<li>
<a href="irc://irc.freenode.net#pyramid">IRC Channel</a>
@@ -73,7 +69,7 @@
</div>
</div>
<div id="footer">
- <div class="footer">© Copyright 2008-2010, Agendaless Consulting.</div>
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
</div>
</body>
</html> \ No newline at end of file
diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/view.pt b/docs/tutorials/wiki2/src/views/tutorial/templates/view.pt
index 86fcc914e..7c8a39f53 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/templates/view.pt
+++ b/docs/tutorials/wiki2/src/views/tutorial/templates/view.pt
@@ -1,28 +1,60 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html
- xmlns="http://www.w3.org/1999/xhtml"
- xmlns:tal="http://xml.zope.org/namespaces/tal">
-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
- <title>${page.name} - Pyramid tutorial wiki
- (based on TurboGears 20-Minute Wiki)</title>
- <link rel="stylesheet" type="text/css"
- href="${request.application_url}/static/style.css" />
+ <title>${page.name} - Pyramid tutorial wiki (based on
+ TurboGears 20-Minute Wiki)</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
+ <meta name="keywords" content="python web application" />
+ <meta name="description" content="pyramid web application" />
+ <link rel="shortcut icon"
+ href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/pylons.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <!--[if lte IE 6]>
+ <link rel="stylesheet"
+ href="${request.static_url('tutorial:static/ie6.css')}"
+ type="text/css" media="screen" charset="utf-8" />
+ <![endif]-->
</head>
-
<body>
-
-<div class="main_content">
-<div style="float:right; width: 10em;"> Viewing
-<span tal:replace="page.name">Page Name Goes Here</span> <br/>
-You can return to the <a href="${request.application_url}">FrontPage</a>.
-</div>
-
-<div tal:replace="structure content">Page text goes here.</div>
-<p><a tal:attributes="href edit_url" href="">Edit this page</a></p>
-</div>
-
+ <div id="wrap">
+ <div id="top-small">
+ <div class="top-small align-center">
+ <div>
+ <img width="220" height="50" alt="pyramid"
+ src="${request.static_url('tutorial:static/pyramid-small.png')}" />
+ </div>
+ </div>
+ </div>
+ <div id="middle">
+ <div class="middle align-right">
+ <div id="left" class="app-welcome align-left">
+ Viewing <b><span tal:replace="page.name">Page Name
+ Goes Here</span></b><br/>
+ You can return to the
+ <a href="${request.application_url}">FrontPage</a>.<br/>
+ </div>
+ <div id="right" class="app-welcome align-right"></div>
+ </div>
+ </div>
+ <div id="bottom">
+ <div class="bottom">
+ <div tal:replace="structure content">
+ Page text goes here.
+ </div>
+ <p>
+ <a tal:attributes="href edit_url" href="">
+ Edit this page
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+ <div id="footer">
+ <div class="footer">© Copyright 2008-2011, Agendaless Consulting.</div>
+ </div>
</body>
</html>
diff --git a/docs/tutorials/wiki2/src/views/tutorial/tests.py b/docs/tutorials/wiki2/src/views/tutorial/tests.py
index 7b770f927..b9797df67 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/tests.py
@@ -1,6 +1,5 @@
import unittest
-from pyramid.config import Configurator
from pyramid import testing
def _initTestingDB():
@@ -20,11 +19,10 @@ def _registerRoutes(config):
class ViewWikiTests(unittest.TestCase):
def setUp(self):
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
- self.config.end()
+ testing.tearDown()
def test_it(self):
from tutorial.views import view_wiki
@@ -36,12 +34,11 @@ class ViewWikiTests(unittest.TestCase):
class ViewPageTests(unittest.TestCase):
def setUp(self):
self.session = _initTestingDB()
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
self.session.remove()
- self.config.end()
+ testing.tearDown()
def _callFUT(self, request):
from tutorial.views import view_page
@@ -71,12 +68,12 @@ class ViewPageTests(unittest.TestCase):
class AddPageTests(unittest.TestCase):
def setUp(self):
self.session = _initTestingDB()
- self.config = Configurator(autocommit=True)
+ self.config = testing.setUp()
self.config.begin()
def tearDown(self):
self.session.remove()
- self.config.end()
+ testing.tearDown()
def _callFUT(self, request):
from tutorial.views import add_page
@@ -104,12 +101,11 @@ class AddPageTests(unittest.TestCase):
class EditPageTests(unittest.TestCase):
def setUp(self):
self.session = _initTestingDB()
- self.config = Configurator(autocommit=True)
- self.config.begin()
+ self.config = testing.setUp()
def tearDown(self):
self.session.remove()
- self.config.end()
+ testing.tearDown()
def _callFUT(self, request):
from tutorial.views import edit_page
diff --git a/docs/zcml.rst b/docs/zcml.rst
deleted file mode 100644
index e5bbe5d4b..000000000
--- a/docs/zcml.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-.. _zcml_directives:
-
-ZCML Directives
-===============
-
-Comprehensive reference material for every ZCML directive provided by
-:app:`Pyramid` is available within this chapter. The ZCML directive
-documentation is organized alphabetically by directive name.
-
-.. toctree::
- :maxdepth: 1
-
- zcml/aclauthorizationpolicy
- zcml/adapter
- zcml/authtktauthenticationpolicy
- zcml/asset
- zcml/configure
- zcml/default_permission
- zcml/forbidden
- zcml/handler
- zcml/include
- zcml/localenegotiator
- zcml/notfound
- zcml/remoteuserauthenticationpolicy
- zcml/renderer
- zcml/repozewho1authenticationpolicy
- zcml/route
- zcml/scan
- zcml/static
- zcml/subscriber
- zcml/translationdir
- zcml/utility
- zcml/view
diff --git a/docs/zcml/aclauthorizationpolicy.rst b/docs/zcml/aclauthorizationpolicy.rst
deleted file mode 100644
index f09531415..000000000
--- a/docs/zcml/aclauthorizationpolicy.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-.. _aclauthorizationpolicy_directive:
-
-``aclauthorizationpolicy``
---------------------------
-
-When this directive is used, authorization information is obtained
-from :term:`ACL` objects attached to :term:`resource` objects.
-
-Attributes
-~~~~~~~~~~
-
-None.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <aclauthorizationpolicy/>
-
-Alternatives
-~~~~~~~~~~~~
-
-You may create an instance of the
-:class:`pyramid.authorization.ACLAuthorizationPolicy` and pass it
-to the :class:`pyramid.config.Configurator` constructor as
-the ``authorization_policy`` argument during initial application
-configuration.
-
-See Also
-~~~~~~~~
-
-See also :ref:`authorization_policies_directives_section` and
-:ref:`security_chapter`.
diff --git a/docs/zcml/adapter.rst b/docs/zcml/adapter.rst
deleted file mode 100644
index 83cce0c39..000000000
--- a/docs/zcml/adapter.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-.. _adapter_directive:
-
-``adapter``
------------
-
-Register a :term:`Zope Component Architecture` "adapter".
-
-Attributes
-~~~~~~~~~~
-
-``factory``
- The adapter factory (often a class).
-
-``provides``
- The :term:`interface` that an adapter instance resulting from a
- lookup will provide.
-
-``for``
- Interfaces or classes to be adapted, separated by spaces,
- e.g. ``interfaces.IFoo interfaces.IBar``.
-
-``name``
- The adapter name.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- for=".foo.IFoo .bar.IBar"
- provides=".interfaces.IMyAdapter"
- factory=".adapters.MyAdapter"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-Use the ``registerAdapter`` method of the ``registry`` attribute of a
-:term:`Configurator` instance during initial application setup.
-
-See Also
-~~~~~~~~
-
-None.
-
diff --git a/docs/zcml/asset.rst b/docs/zcml/asset.rst
deleted file mode 100644
index af7a6db94..000000000
--- a/docs/zcml/asset.rst
+++ /dev/null
@@ -1,65 +0,0 @@
-.. _asset_directive:
-
-``asset``
----------
-
-The ``asset`` directive adds an asset override for a single
-static file/directory asset.
-
-Attributes
-~~~~~~~~~~
-
-``to_override``
- A :term:`asset specification` specifying the asset to be
- overridden.
-
-``override_with``
- A :term:`asset specification` specifying the asset which
- is used as the override.
-
-Examples
-~~~~~~~~
-
-.. topic:: Overriding a Single Asset File
-
- .. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package:templates/mytemplate.pt"
- override_with="another.package:othertemplates/anothertemplate.pt"
- />
-
-.. topic:: Overriding all Assets in a Package
-
- .. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package"
- override_with="another.package"
- />
-
-.. topic:: Overriding all Assets in a Subdirectory of a Package
-
- .. code-block:: xml
- :linenos:
-
- <asset
- to_override="some.package:templates/"
- override_with="another.package:othertemplates/"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-The :meth:`pyramid.config.Configurator.override_asset`
-method can be used instead of the ``resource`` ZCML directive.
-
-This directive can also be invoked as the ``resource`` ZCML directive for
-backwards compatibility purposes.
-
-See Also
-~~~~~~~~
-
-See also :ref:`asset_zcml_directive`.
diff --git a/docs/zcml/authtktauthenticationpolicy.rst b/docs/zcml/authtktauthenticationpolicy.rst
deleted file mode 100644
index 25be4186c..000000000
--- a/docs/zcml/authtktauthenticationpolicy.rst
+++ /dev/null
@@ -1,102 +0,0 @@
-.. _authtktauthenticationpolicy_directive:
-
-``authtktauthenticationpolicy``
--------------------------------
-
-When this directive is used, authentication information is obtained
-from an :mod:`paste.auth.auth_tkt` cookie value, assumed to be set by
-a custom login form.
-
-Attributes
-~~~~~~~~~~
-
-``secret``
- The ``secret`` is a string that will be used to sign the data
- stored by the cookie. It is required and has no default.
-
-``callback``
- The ``callback`` is a Python dotted name to a function passed the
- string representing the userid stored in the cookie and the
- request as positional arguments. The callback is expected to
- return None if the user represented by the string doesn't exist or
- a sequence of group identifiers (possibly empty) if the user does
- exist. If ``callback`` is None, the userid will be assumed to
- exist with no groups. It defaults to ``None``.
-
-``cookie_name``
- The ``cookie_name`` is the name used for the cookie that contains
- the user information. It defaults to ``auth_tkt``.
-
-``secure``
- ``secure`` is a boolean value. If it's set to "true", the cookie
- will only be sent back by the browser over a secure (HTTPS)
- connection. It defaults to "false".
-
-``include_ip``
- ``include_ip`` is a boolean value. If it's set to true, the
- requesting IP address is made part of the authentication data in
- the cookie; if the IP encoded in the cookie differs from the IP of
- the requesting user agent, the cookie is considered invalid. It
- defaults to "false".
-
-``timeout``
- ``timeout`` is an integer value. It represents the maximum age in
- seconds which the auth_tkt ticket will be considered valid. If
- ``timeout`` is specified, and ``reissue_time`` is also specified,
- ``reissue_time`` must be a smaller value than ``timeout``. It
- defaults to ``None``, meaning that the ticket will be considered
- valid forever.
-
-``reissue_time``
- ``reissue_time`` is an integer value. If ``reissue_time`` is
- specified, when we encounter a cookie that is older than the
- reissue time (in seconds), but younger that the ``timeout``, a new
- cookie will be issued. It defaults to ``None``, meaning that
- authentication cookies are never reissued. A value of ``0`` means
- reissue a cookie in the response to every request that requires
- authentication.
-
-``max_age``
- ``max_age`` is the maximum age of the auth_tkt *cookie*, in
- seconds. This differs from ``timeout`` inasmuch as ``timeout``
- represents the lifetime of the ticket contained in the cookie,
- while this value represents the lifetime of the cookie itself.
- When this value is set, the cookie's ``Max-Age`` and ``Expires``
- settings will be set, allowing the auth_tkt cookie to last between
- browser sessions. It is typically nonsensical to set this to a
- value that is lower than ``timeout`` or ``reissue_time``, although
- it is not explicitly prevented. It defaults to ``None``, meaning
- (on all major browser platforms) that auth_tkt cookies will last
- for the lifetime of the user's browser session.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <authtktauthenticationpolicy
- secret="goshiamsosecret"
- callback=".somemodule.somefunc"
- cookie_name="mycookiename"
- secure="false"
- include_ip="false"
- timeout="86400"
- reissue_time="600"
- max_age="31536000"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-You may create an instance of the
-:class:`pyramid.authentication.AuthTktAuthenticationPolicy` and
-pass it to the :class:`pyramid.config.Configurator`
-constructor as the ``authentication_policy`` argument during initial
-application configuration.
-
-See Also
-~~~~~~~~
-
-See also :ref:`authentication_policies_directives_section` and
-:class:`pyramid.authentication.AuthTktAuthenticationPolicy`.
diff --git a/docs/zcml/configure.rst b/docs/zcml/configure.rst
deleted file mode 100644
index cab8ec204..000000000
--- a/docs/zcml/configure.rst
+++ /dev/null
@@ -1,95 +0,0 @@
-.. _configure_directive:
-
-``configure``
--------------
-
-Because :term:`ZCML` is XML, and because XML requires a single root
-tag for each document, every ZCML file used by :app:`Pyramid` must
-contain a ``configure`` container directive, which acts as the root
-XML tag. It is a "container" directive because its only job is to
-contain other directives.
-
-Attributes
-~~~~~~~~~~
-
-``xmlns``
- The default XML namespace used for subdirectives.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- other directives -->
-
- </configure>
-
-.. _word_on_xml_namespaces:
-
-A Word On XML Namespaces
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Usually, the start tag of the ``<configure>`` container tag has a
-default *XML namespace* associated with it. This is usually
-``http://pylonshq.com/pyramid``, named by the ``xmlns`` attribute of
-the ``configure`` start tag.
-
-Using the ``http://pylonshq.com/pyramid`` namespace as the default XML
-namespace isn't strictly necessary; you can use a different default
-namespace as the default. However, if you do, the declaration tags
-which are defined by :app:`Pyramid` such as the ``view`` declaration
-tag will need to be defined in such a way that the XML parser that
-:app:`Pyramid` uses knows which namespace the :mod:`pyramid` tags are
-associated with. For example, the following files are all completely
-equivalent:
-
-.. topic:: Use of A Non-Default XML Namespace
-
- .. code-block:: xml
- :linenos:
-
- <configure xmlns="http://namespaces.zope.org/zope"
- xmlns:pyramid="http://pylonshq.com/pyramid">
-
- <include package="pyramid.includes" />
-
- <pyramid:view
- view="helloworld.hello_world"
- />
-
- </configure>
-
-.. topic:: Use of A Per-Tag XML Namespace Without A Default XML Namespace
-
- .. code-block:: xml
- :linenos:
-
- <configure>
-
- <include package="pyramid.includes" />
-
- <view xmlns="http://pylonshq.com/pyramid"
- view="helloworld.hello_world"
- />
-
- </configure>
-
-For more information about XML namespaces, see `this older, but simple
-XML.com article <http://www.xml.com/pub/a/1999/01/namespaces.html>`_.
-
-The conventions in this document assume that the default XML namespace
-is ``http://pylonshq.com/pyramid``.
-
-Alternatives
-~~~~~~~~~~~~
-
-None.
-
-See Also
-~~~~~~~~
-
-See also :ref:`helloworld_declarative`.
-
diff --git a/docs/zcml/default_permission.rst b/docs/zcml/default_permission.rst
deleted file mode 100644
index 54e720ea6..000000000
--- a/docs/zcml/default_permission.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-.. _default_permission_directive:
-
-``default_permission``
--------------------------------
-
-Set the default permission to be used by all :term:`view
-configuration` registrations.
-
-This directive accepts a single attribute ,``name``, which should be
-used as the default permission string. An example of a permission
-string: ``view``. Adding a default permission makes it unnecessary to
-protect each view configuration with an explicit permission, unless
-your application policy requires some exception for a particular view.
-
-If a default permission is *not* set, views represented by view
-configuration registrations which do not explicitly declare a
-permission will be executable by entirely anonymous users (any
-authorization policy is ignored).
-
-There can be only one default permission active at a time within an
-application, thus the ``default_permission`` directive can only be
-used once in any particular set of ZCML.
-
-Attributes
-~~~~~~~~~~
-
-``name``
- Must be a string representing a :term:`permission`,
- e.g. ``view``.
-
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <default_permission
- name="view"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-Using the ``default_permission`` argument to the
-:class:`pyramid.config.Configurator` constructor can be used
-to achieve the same purpose.
-
-Using the
-:meth:`pyramid.config.Configurator.set_default_permission`
-method can be used to achieve the same purpose when using imperative
-configuration.
-
-See Also
-~~~~~~~~
-
-See also :ref:`setting_a_default_permission`.
diff --git a/docs/zcml/forbidden.rst b/docs/zcml/forbidden.rst
deleted file mode 100644
index 70f65069e..000000000
--- a/docs/zcml/forbidden.rst
+++ /dev/null
@@ -1,78 +0,0 @@
-.. _forbidden_directive:
-
-``forbidden``
--------------
-
-When :app:`Pyramid` can't authorize execution of a view based on
-the :term:`authorization policy` in use, it invokes a :term:`forbidden
-view`. The default forbidden response has a 401 status code and is
-very plain, but it can be overridden as necessary using the
-``forbidden`` ZCML directive.
-
-.. warning::
-
- The ``forbidden`` ZCML directive is deprecated in :app:`Pyramid`
- version 1.3. Instead, you should use the :ref:`view_directive`
- directive with a ``context`` that names the
- :exc:`pyramid.exceptions.Forbidden` class. See
- :ref:`changing_the_forbidden_view` form more information.
-
-Attributes
-~~~~~~~~~~
-
-``view``
- The :term:`dotted Python name` to a :term:`view callable`. This
- attribute is required unless a ``renderer`` attribute also exists.
- If a ``renderer`` attribute exists on the directive, this attribute
- defaults to a view that returns an empty dictionary (see
- :ref:`views_which_use_a_renderer`).
-
-``attr``
- The attribute of the view callable to use if ``__call__`` is not
- correct (has the same meaning as in the context of
- :ref:`view_directive`; see the description of ``attr``
- there).
-
-``renderer``
- This is either a single string term (e.g. ``json``) or a string
- implying a path or :term:`asset specification`
- (e.g. ``templates/views.pt``) used when the view returns a
- non-:term:`response` object. This attribute has the same meaning as
- it would in the context of :ref:`view_directive`; see the
- description of ``renderer`` there).
-
-``wrapper``
- The :term:`view name` (*not* an object dotted name) of another view
- declared elsewhere in ZCML (or via the ``@view_config`` decorator)
- which will receive the response body of this view as the
- ``request.wrapped_body`` attribute of its own request, and the
- response returned by this view as the ``request.wrapped_response``
- attribute of its own request. This attribute has the same meaning
- as it would in the context of :ref:`view_directive`; see the
- description of ``wrapper`` there). Note that the wrapper view
- *should not* be protected by any permission; behavior is undefined
- if it does.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <forbidden
- view="helloworld.views.forbidden_view"/>
-
-Alternatives
-~~~~~~~~~~~~
-
-Use the :ref:`view_directive` directive with a ``context`` that names
-the :exc:`pyramid.exceptions.Forbidden` class.
-
-Use the :meth:`pyramid.config.Configurator.add_view` method,
-passing it a ``context`` which is the
-:exc:`pyramid.exceptions.Forbidden` class.
-
-See Also
-~~~~~~~~
-
-See also :ref:`changing_the_forbidden_view`.
diff --git a/docs/zcml/handler.rst b/docs/zcml/handler.rst
deleted file mode 100644
index 01d442ab6..000000000
--- a/docs/zcml/handler.rst
+++ /dev/null
@@ -1,158 +0,0 @@
-.. _handler_directive:
-
-``handler``
------------
-
-The ``handler`` directive adds the configuration of a :term:`view handler` to
-the :term:`application registry`.
-
-Attributes
-~~~~~~~~~~
-
-``route_name``
- The name of the route, e.g. ``myroute``. This attribute is required. It
- must be unique among all defined handler and route names in a given
- configuration.
-
-``pattern``
- The pattern of the route e.g. ``ideas/{idea}``. This attribute is
- required. See :ref:`route_pattern_syntax` for information about the syntax
- of route patterns. The name ``{action}`` is treated specially in handler
- patterns. See :ref:`using_add_handler` for a discussion of how
- ``{action}`` in handler patterns is treated.
-
-``action``
- If the action name is not specified in the ``pattern``, use this name as the
- handler action (method name).
-
-``factory``
- The :term:`dotted Python name` to a function that will generate a
- :app:`Pyramid` context object when the associated route matches.
- e.g. ``mypackage.resources.MyResource``. If this argument is not
- specified, a default root factory will be used.
-
-``xhr``
- This value should be either ``True`` or ``False``. If this value is
- specified and is ``True``, the :term:`request` must possess an
- ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header for this
- route to match. This is useful for detecting AJAX requests issued
- from jQuery, Prototype and other Javascript libraries. If this
- predicate returns false, route matching continues.
-
-``traverse``
- If you would like to cause the :term:`context` to be something other
- than the :term:`root` object when this route matches, you can spell
- a traversal pattern as the ``traverse`` argument. This traversal
- pattern will be used as the traversal path: traversal will begin at
- the root object implied by this route (either the global root, or
- the object returned by the ``factory`` associated with this route).
-
- The syntax of the ``traverse`` argument is the same as it is for
- ``pattern``. For example, if the ``pattern`` provided to the
- ``route`` directive is ``articles/{article}/edit``, and the
- ``traverse`` argument provided to the ``route`` directive is
- ``/{article}``, when a request comes in that causes the route to
- match in such a way that the ``article`` match value is '1' (when
- the request URI is ``/articles/1/edit``), the traversal path will be
- generated as ``/1``. This means that the root object's
- ``__getitem__`` will be called with the name ``1`` during the
- traversal phase. If the ``1`` object exists, it will become the
- :term:`context` of the request. :ref:`traversal_chapter` has more
- information about traversal.
-
- If the traversal path contains segment marker names which are not
- present in the ``pattern`` argument, a runtime error will occur.
- The ``traverse`` pattern should not contain segment markers that do
- not exist in the ``pattern``.
-
- A similar combining of routing and traversal is available when a
- route is matched which contains a ``*traverse`` remainder marker in
- its ``pattern`` (see :ref:`using_traverse_in_a_route_pattern`). The
- ``traverse`` argument to the ``route`` directive allows you to
- associate route patterns with an arbitrary traversal path without
- using a a ``*traverse`` remainder marker; instead you can use other
- match information.
-
- Note that the ``traverse`` argument to the ``handler`` directive is
- ignored when attached to a route that has a ``*traverse`` remainder
- marker in its pattern.
-
-``request_method``
- A string representing an HTTP method name, e.g. ``GET``, ``POST``,
- ``HEAD``, ``DELETE``, ``PUT``. If this argument is not specified,
- this route will match if the request has *any* request method. If
- this predicate returns false, route matching continues.
-
-``path_info``
- The value of this attribute represents a regular expression pattern
- that will be tested against the ``PATH_INFO`` WSGI environment
- variable. If the regex matches, this predicate will be true. If
- this predicate returns false, route matching continues.
-
-``request_param``
- This value can be any string. A view declaration with this
- attribute ensures that the associated route will only match when the
- request has a key in the ``request.params`` dictionary (an HTTP
- ``GET`` or ``POST`` variable) that has a name which matches the
- supplied value. If the value supplied to the attribute has a ``=``
- sign in it, e.g. ``request_params="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 route to "match" the current request. If this predicate
- returns false, route matching continues.
-
-``header``
- The value of this attribute represents an HTTP header name or a
- header name/value pair. If the value contains a ``:`` (colon), it
- will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*``
- or ``Host:localhost``). The *value* of an attribute that represent
- a name/value pair should be a regular expression. If the value does
- not contain a colon, the entire value will be considered to be the
- header name (e.g. ``If-Modified-Since``). If the value evaluates to
- a header name only without a value, the header specified by the name
- must be present in the request for this predicate to be true. If
- the value evaluates to a header name/value pair, the header
- specified by the name must be present in the request *and* the
- regular expression specified as the value must match the header
- value. Whether or not the value represents a header name or a
- header name/value pair, the case of the header name is not
- significant. If this predicate returns false, route matching
- continues.
-
-``accept``
- The value of this attribute represents a match query for one or more
- mimetypes in the ``Accept`` HTTP request header. If this value is
- specified, it must be in one of the following forms: a mimetype
- match token in the form ``text/plain``, a wildcard mimetype match
- token in the form ``text/*`` or a match-all wildcard mimetype match
- token in the form ``*/*``. If any of the forms matches the
- ``Accept`` header of the request, this predicate will be true. If
- this predicate returns false, route matching continues.
-
-``custom_predicates``
- This value should be a sequence of references to custom predicate
- callables. Use custom predicates when no set of predefined
- predicates does what you need. Custom predicates can be combined
- with predefined predicates as necessary. Each custom predicate
- callable should accept two arguments: ``info`` and ``request``
- and should return either ``True`` or ``False`` after doing arbitrary
- evaluation of the info and/or the request. If all custom and
- non-custom predicate callables return ``True`` the associated route
- will be considered viable for a given request. If any predicate
- callable returns ``False``, route matching continues. Note that the
- value ``info`` passed to a custom route predicate is a dictionary
- containing matching information; see :ref:`custom_route_predicates`
- for more information about ``info``.
-
-
-Alternatives
-~~~~~~~~~~~~
-
-You can also add a :term:`route configuration` via:
-
-- Using the :meth:`pyramid.config.Configurator.add_handler` method.
-
-See Also
-~~~~~~~~
-
-See also :ref:`handlers_chapter`.
diff --git a/docs/zcml/include.rst b/docs/zcml/include.rst
deleted file mode 100644
index f55caa07c..000000000
--- a/docs/zcml/include.rst
+++ /dev/null
@@ -1,71 +0,0 @@
-.. _include_directive:
-
-``include``
------------
-
-The ``include`` directive includes configuration from an external ZCML
-file. Use of the ``include`` tag allows a user to split configuration
-across multiple ZCML files, and allows package distributors to provide
-default ZCML configuration for specific purposes which can be
-included by the integrator of the package as necessary.
-
-Attributes
-~~~~~~~~~~
-
-``package``
- A :term:`dotted Python name` which references a Python :term:`package`.
-
-``file``
- An absolute or relative filename which references a ZCML file.
-
-The ``package`` and ``file`` attributes can be used together or
-separately as necessary.
-
-Examples
-~~~~~~~~
-
-.. topic:: Loading the File Named ``configure.zcml`` from a Package Implicitly
-
- .. code-block:: xml
- :linenos:
-
- <include package="some.package" />
-
-.. topic:: Loading the File Named ``other.zcml`` From the Current Package
-
- .. code-block:: xml
- :linenos:
-
- <include file="other.zcml" />
-
-.. topic:: Loading a File From a Subdirectory of the Current Package
-
- .. code-block:: xml
- :linenos:
-
- <include file="subdir/other.zcml" />
-
-.. topic:: Loading the File Named ``/absolute/path/other.zcml``
-
- .. code-block:: xml
- :linenos:
-
- <include file="/absolute/path/other.zcml" />
-
-.. topic:: Loading the File Named ``other.zcml`` From a Package Explicitly
-
- .. code-block:: xml
- :linenos:
-
- <include package="some.package" file="other.zcml" />
-
-Alternatives
-~~~~~~~~~~~~
-
-None.
-
-See Also
-~~~~~~~~
-
-See also :ref:`helloworld_declarative`.
-
diff --git a/docs/zcml/localenegotiator.rst b/docs/zcml/localenegotiator.rst
deleted file mode 100644
index c90e649f6..000000000
--- a/docs/zcml/localenegotiator.rst
+++ /dev/null
@@ -1,39 +0,0 @@
-.. _localenegotiator_directive:
-
-``localenegotiator``
---------------------
-
-Set the :term:`locale negotiator` for the current configurator to
-support localization of text.
-
-Attributes
-~~~~~~~~~~
-
-``negotiator``
-
- The :term:`dotted Python name` to a :term:`locale negotiator`
- implementation. This attribute is required. If it begins with a
- dot (``.``), the name will be considered relative to the directory
- in which the ZCML file which contains this directive lives.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <localenegotiator
- negotiator="some.package.module.my_locale_negotiator"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-Use :meth:`pyramid.config.Configurator.set_locale_negotiator`
-method instance during initial application setup.
-
-See Also
-~~~~~~~~
-
-See also :ref:`activating_translation`.
-
diff --git a/docs/zcml/notfound.rst b/docs/zcml/notfound.rst
deleted file mode 100644
index 739eccd49..000000000
--- a/docs/zcml/notfound.rst
+++ /dev/null
@@ -1,78 +0,0 @@
-.. _notfound_directive:
-
-``notfound``
-------------
-
-.. warning::
-
- The ``notfound`` ZCML directive is deprecated in :app:`Pyramid`
- version 1.0. Instead, you should use the :ref:`view_directive`
- directive with a ``context`` that names the
- :exc:`pyramid.exceptions.NotFound` class. See
- :ref:`changing_the_notfound_view` form more information.
-
-When :app:`Pyramid` can't map a URL to view code, it invokes a
-:term:`not found view`. The default not found view is very plain, but
-the view callable used can be configured via the ``notfound`` ZCML
-tag.
-
-Attributes
-~~~~~~~~~~
-
-``view``
- The :term:`dotted Python name` to a :term:`view callable`. This
- attribute is required unless a ``renderer`` attribute also exists.
- If a ``renderer`` attribute exists on the directive, this attribute
- defaults to a view that returns an empty dictionary (see
- :ref:`views_which_use_a_renderer`).
-
-``attr``
- The attribute of the view callable to use if ``__call__`` is not
- correct (has the same meaning as in the context of
- :ref:`view_directive`; see the description of ``attr``
- there).
-
-``renderer``
- This is either a single string term (e.g. ``json``) or a string
- implying a path or :term:`asset specification`
- (e.g. ``templates/views.pt``) used when the view returns a
- non-:term:`response` object. This attribute has the same meaning as
- it would in the context of :ref:`view_directive`; see the
- description of ``renderer`` there).
-
-``wrapper``
- The :term:`view name` (*not* an object dotted name) of another view
- declared elsewhere in ZCML (or via the ``@view_config`` decorator)
- which will receive the response body of this view as the
- ``request.wrapped_body`` attribute of its own request, and the
- response returned by this view as the ``request.wrapped_response``
- attribute of its own request. This attribute has the same meaning
- as it would in the context of :ref:`view_directive`; see
- the description of ``wrapper`` there). Note that the wrapper view
- *should not* be protected by any permission; behavior is undefined
- if it does.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <notfound
- view="helloworld.views.notfound_view"/>
-
-Alternatives
-~~~~~~~~~~~~
-
-Use the :ref:`view_directive` directive with a ``context`` that names
-the :exc:`pyramid.exceptions.NotFound` class.
-
-Use the :meth:`pyramid.config.Configurator.add_view` method,
-passing it a ``context`` which is the
-:exc:`pyramid.exceptions.NotFound` class.
-
-See Also
-~~~~~~~~
-
-See also :ref:`changing_the_notfound_view`.
-
diff --git a/docs/zcml/remoteuserauthenticationpolicy.rst b/docs/zcml/remoteuserauthenticationpolicy.rst
deleted file mode 100644
index 56e73ee7a..000000000
--- a/docs/zcml/remoteuserauthenticationpolicy.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-.. _remoteuserauthenticationpolicy_directive:
-
-``remoteuserauthenticationpolicy``
-----------------------------------
-
-When this directive is used, authentication information is obtained
-from a ``REMOTE_USER`` key in the WSGI environment, assumed to
-be set by a WSGI server or an upstream middleware component.
-
-Attributes
-~~~~~~~~~~
-
-``environ_key``
- The ``environ_key`` is the name that will be used to obtain the
- remote user value from the WSGI environment. It defaults to
- ``REMOTE_USER``.
-
-``callback``
- The ``callback`` is a Python dotted name to a function passed the
- string representing the remote user and the request as positional
- arguments. The callback is expected to return None if the user
- represented by the string doesn't exist or a sequence of group
- identifiers (possibly empty) if the user does exist. If
- ``callback`` is None, the userid will be assumed to exist with no
- groups. It defaults to ``None``.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <remoteuserauthenticationpolicy
- environ_key="REMOTE_USER"
- callback=".somemodule.somefunc"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-You may create an instance of the
-:class:`pyramid.authentication.RemoteUserAuthenticationPolicy` and
-pass it to the :class:`pyramid.config.Configurator`
-constructor as the ``authentication_policy`` argument during initial
-application configuration.
-
-See Also
-~~~~~~~~
-
-See also :ref:`authentication_policies_directives_section` and
-:class:`pyramid.authentication.RemoteUserAuthenticationPolicy`.
diff --git a/docs/zcml/renderer.rst b/docs/zcml/renderer.rst
deleted file mode 100644
index c7beead32..000000000
--- a/docs/zcml/renderer.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-.. _renderer_directive:
-
-``renderer``
-------------
-
-The ``renderer`` ZCML directive can be used to override an existing
-existing :term:`renderer` or to add a new renderer.
-
-Attributes
-~~~~~~~~~~
-
-``factory``
- A :term:`dotted Python name` referencing a callable object that
- accepts a renderer name and returns a :term:`renderer` object.
-
-``name``
- The renderer name, which is a string.
-
-Examples
-~~~~~~~~
-
-.. topic:: Registering a Non-Template Renderer
-
- .. code-block:: xml
- :linenos:
-
- <renderer
- factory="some.renderer"
- name="mynewrenderer"
- />
-
-.. topic:: Registering a Template Renderer
-
- .. code-block:: xml
- :linenos:
-
- <renderer
- factory="some.jinja2.renderer"
- name=".jinja2"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-The :meth:`pyramid.config.Configurator.add_renderer` method
-is equivalent to the ``renderer`` ZCML directive.
-
-See Also
-~~~~~~~~
-
-See also :ref:`adding_and_overriding_renderers`.
diff --git a/docs/zcml/repozewho1authenticationpolicy.rst b/docs/zcml/repozewho1authenticationpolicy.rst
deleted file mode 100644
index 11907ce31..000000000
--- a/docs/zcml/repozewho1authenticationpolicy.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-.. _repozewho1authenticationpolicy_directive:
-
-``repozewho1authenticationpolicy``
-----------------------------------
-
-When this directive is used, authentication information is obtained
-from a ``repoze.who.identity`` key in the WSGI environment, assumed to
-be set by :term:`repoze.who` middleware.
-
-Attributes
-~~~~~~~~~~
-
-``identifier_name``
- The ``identifier_name`` controls the name used to look up the
- :term:`repoze.who` "identifier" plugin within
- ``request.environ['repoze.who.plugins']`` which is used by this
- policy to "remember" and "forget" credentials. It defaults to
- ``auth_tkt``.
-
-``callback``
- The ``callback`` is a Python dotted name to a function passed the
- repoze.who identity and the request as positional arguments. The
- callback is expected to return None if the user represented by the
- identity doesn't exist or a sequence of group identifiers
- (possibly empty) if the user does exist. If ``callback`` is None,
- the userid will be assumed to exist with no groups. It defaults
- to ``None``.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <repozewho1authenticationpolicy
- identifier_name="auth_tkt"
- callback=".somemodule.somefunc"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-You may create an instance of the
-:class:`pyramid.authentication.RepozeWho1AuthenticationPolicy` and
-pass it to the :class:`pyramid.config.Configurator`
-constructor as the ``authentication_policy`` argument during initial
-application configuration.
-
-See Also
-~~~~~~~~
-
-See also :ref:`authentication_policies_directives_section` and
-:class:`pyramid.authentication.RepozeWho1AuthenticationPolicy`.
diff --git a/docs/zcml/route.rst b/docs/zcml/route.rst
deleted file mode 100644
index 0f94fa11b..000000000
--- a/docs/zcml/route.rst
+++ /dev/null
@@ -1,223 +0,0 @@
-.. _route_directive:
-
-``route``
----------
-
-The ``route`` directive adds a single :term:`route configuration` to
-the :term:`application registry`.
-
-Attributes
-~~~~~~~~~~
-
-``pattern``
- The pattern of the route e.g. ``ideas/{idea}``. This attribute is
- required. See :ref:`route_pattern_syntax` for information
- about the syntax of route patterns.
-
- .. note:: For backwards compatibility purposes, the ``path``
- attribute can also be used instead of ``pattern``.
-
-``name``
- The name of the route, e.g. ``myroute``. This attribute is
- required. It must be unique among all defined routes in a given
- configuration.
-
-``factory``
- The :term:`dotted Python name` to a function that will generate a
- :app:`Pyramid` context object when this route matches.
- e.g. ``mypackage.resources.MyResource``. If this argument is not
- specified, a default root factory will be used.
-
-``view``
- The :term:`dotted Python name` to a function that will be used as a
- view callable when this route matches.
- e.g. ``mypackage.views.my_view``.
-
-``xhr``
- This value should be either ``True`` or ``False``. If this value is
- specified and is ``True``, the :term:`request` must possess an
- ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header for this
- route to match. This is useful for detecting AJAX requests issued
- from jQuery, Prototype and other Javascript libraries. If this
- predicate returns false, route matching continues.
-
-``traverse``
- If you would like to cause the :term:`context` to be something other
- than the :term:`root` object when this route matches, you can spell
- a traversal pattern as the ``traverse`` argument. This traversal
- pattern will be used as the traversal path: traversal will begin at
- the root object implied by this route (either the global root, or
- the object returned by the ``factory`` associated with this route).
-
- The syntax of the ``traverse`` argument is the same as it is for
- ``pattern``. For example, if the ``pattern`` provided to the
- ``route`` directive is ``articles/{article}/edit``, and the
- ``traverse`` argument provided to the ``route`` directive is
- ``/{article}``, when a request comes in that causes the route to
- match in such a way that the ``article`` match value is '1' (when
- the request URI is ``/articles/1/edit``), the traversal path will be
- generated as ``/1``. This means that the root object's
- ``__getitem__`` will be called with the name ``1`` during the
- traversal phase. If the ``1`` object exists, it will become the
- :term:`context` of the request. :ref:`traversal_chapter` has more
- information about traversal.
-
- If the traversal path contains segment marker names which are not
- present in the ``pattern`` argument, a runtime error will occur.
- The ``traverse`` pattern should not contain segment markers that do
- not exist in the ``pattern``.
-
- A similar combining of routing and traversal is available when a
- route is matched which contains a ``*traverse`` remainder marker in
- its ``pattern`` (see :ref:`using_traverse_in_a_route_pattern`). The
- ``traverse`` argument to the ``route`` directive allows you to
- associate route patterns with an arbitrary traversal path without
- using a a ``*traverse`` remainder marker; instead you can use other
- match information.
-
- Note that the ``traverse`` argument to the ``route`` directive is
- ignored when attached to a route that has a ``*traverse`` remainder
- marker in its pattern.
-
-``request_method``
- A string representing an HTTP method name, e.g. ``GET``, ``POST``,
- ``HEAD``, ``DELETE``, ``PUT``. If this argument is not specified,
- this route will match if the request has *any* request method. If
- this predicate returns false, route matching continues.
-
-``path_info``
- The value of this attribute represents a regular expression pattern
- that will be tested against the ``PATH_INFO`` WSGI environment
- variable. If the regex matches, this predicate will be true. If
- this predicate returns false, route matching continues.
-
-``request_param``
- This value can be any string. A view declaration with this
- attribute ensures that the associated route will only match when the
- request has a key in the ``request.params`` dictionary (an HTTP
- ``GET`` or ``POST`` variable) that has a name which matches the
- supplied value. If the value supplied to the attribute has a ``=``
- sign in it, e.g. ``request_params="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 route to "match" the current request. If this predicate
- returns false, route matching continues.
-
-``header``
- The value of this attribute represents an HTTP header name or a
- header name/value pair. If the value contains a ``:`` (colon), it
- will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*``
- or ``Host:localhost``). The *value* of an attribute that represent
- a name/value pair should be a regular expression. If the value does
- not contain a colon, the entire value will be considered to be the
- header name (e.g. ``If-Modified-Since``). If the value evaluates to
- a header name only without a value, the header specified by the name
- must be present in the request for this predicate to be true. If
- the value evaluates to a header name/value pair, the header
- specified by the name must be present in the request *and* the
- regular expression specified as the value must match the header
- value. Whether or not the value represents a header name or a
- header name/value pair, the case of the header name is not
- significant. If this predicate returns false, route matching
- continues.
-
-``accept``
- The value of this attribute represents a match query for one or more
- mimetypes in the ``Accept`` HTTP request header. If this value is
- specified, it must be in one of the following forms: a mimetype
- match token in the form ``text/plain``, a wildcard mimetype match
- token in the form ``text/*`` or a match-all wildcard mimetype match
- token in the form ``*/*``. If any of the forms matches the
- ``Accept`` header of the request, this predicate will be true. If
- this predicate returns false, route matching continues.
-
-``custom_predicates``
-
- This value should be a sequence of references to custom predicate
- callables. Use custom predicates when no set of predefined
- predicates does what you need. Custom predicates can be combined
- with predefined predicates as necessary. Each custom predicate
- callable should accept two arguments: ``info`` and ``request``
- and should return either ``True`` or ``False`` after doing arbitrary
- evaluation of the info and/or the request. If all custom and
- non-custom predicate callables return ``True`` the associated route
- will be considered viable for a given request. If any predicate
- callable returns ``False``, route matching continues. Note that the
- value ``info`` passed to a custom route predicate is a dictionary
- containing matching information; see :ref:`custom_route_predicates`
- for more information about ``info``.
-
-``view_context``
- The :term:`dotted Python name` to a class or an interface that the
- :term:`context` of the view should match for the view named by the
- route to be used. This attribute is only useful if the ``view``
- attribute is used. If this attribute is not specified, the default
- (``None``) will be used.
-
- If the ``view`` attribute is not provided, this attribute has no
- effect.
-
- This attribute can also be spelled as ``view_for`` or ``for_``;
- these are valid older spellings.
-
-``view_permission``
- The permission name required to invoke the view associated with this
- route. e.g. ``edit``. (see :ref:`using_security_with_urldispatch`
- for more information about permissions).
-
- If the ``view`` attribute is not provided, this attribute has no
- effect.
-
- This attribute can also be spelled as ``permission``.
-
-``view_renderer``
- This is either a single string term (e.g. ``json``) or a string
- implying a path or :term:`asset specification`
- (e.g. ``templates/views.pt``). If the renderer value is a single
- term (does not contain a dot ``.``), the specified term will be used
- to look up a renderer implementation, and that renderer
- implementation will be used to construct a response from the view
- return value. If the renderer term contains a dot (``.``), the
- specified term will be treated as a path, and the filename extension
- of the last element in the path will be used to look up the renderer
- implementation, which will be passed the full path. The renderer
- implementation will be used to construct a response from the view
- return value. See :ref:`views_which_use_a_renderer` for more
- information.
-
- If the ``view`` attribute is not provided, this attribute has no
- effect.
-
- This attribute can also be spelled as ``renderer``.
-
-``view_attr``
- The view machinery defaults to using the ``__call__`` method of the
- view callable (or the function itself, if the view callable is a
- function) to obtain a response dictionary. The ``attr`` value allows
- you to vary the method attribute used to obtain the response. For
- example, if your view was a class, and the class has a method named
- ``index`` and you wanted to use this method instead of the class'
- ``__call__`` method to return the response, you'd say
- ``attr="index"`` in the view configuration for the view. This is
- most useful when the view definition is a class.
-
- If the ``view`` attribute is not provided, this attribute has no
- effect.
-
-``use_global_views``
- When a request matches this route, and view lookup cannot find a view
- which has a 'route_name' predicate argument that matches the route,
- try to fall back to using a view that otherwise matches the context,
- request, and view name (but does not match the route name predicate).
-
-Alternatives
-~~~~~~~~~~~~
-
-You can also add a :term:`route configuration` via:
-
-- Using the :meth:`pyramid.config.Configurator.add_route` method.
-
-See Also
-~~~~~~~~
-
-See also :ref:`urldispatch_chapter`.
diff --git a/docs/zcml/scan.rst b/docs/zcml/scan.rst
deleted file mode 100644
index df2cdd281..000000000
--- a/docs/zcml/scan.rst
+++ /dev/null
@@ -1,34 +0,0 @@
-.. _scan_directive:
-
-``scan``
---------
-
-To make use of :term:`configuration decoration` decorators, you must
-perform a :term:`scan`. A scan finds these decorators in code. The
-``scan`` ZCML directive tells :app:`Pyramid` to begin such a scan.
-
-Attributes
-~~~~~~~~~~
-
-``package``
- The package to scan or the single dot (``.``), meaning the
- "current" package (the package in which the ZCML file lives).
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <scan package="."/>
-
-Alternatives
-~~~~~~~~~~~~
-
-The :meth:`pyramid.config.Configurator.scan` method performs
-the same job as the ``scan`` ZCML directive.
-
-See Also
-~~~~~~~~
-
-See also :ref:`mapping_views_using_a_decorator_section`.
diff --git a/docs/zcml/static.rst b/docs/zcml/static.rst
deleted file mode 100644
index 9538d18f0..000000000
--- a/docs/zcml/static.rst
+++ /dev/null
@@ -1,89 +0,0 @@
-.. _static_directive:
-
-``static``
-----------
-
-Use of the ``static`` ZCML directive or allows you to serve static
-resources (such as JavaScript and CSS files) within a
-:app:`Pyramid` application. This mechanism makes static files
-available at a name relative to the application root URL.
-
-Attributes
-~~~~~~~~~~
-
-``name``
- The (application-root-relative) URL prefix of the static directory.
- For example, to serve static files from ``/static`` in most
- applications, you would provide a ``name`` of ``static``.
-
-``path``
- A path to a directory on disk where the static files live. This
- path may either be 1) absolute (e.g. ``/foo/bar/baz``) 2)
- Python-package-relative (e.g. (``packagename:foo/bar/baz``) or 3)
- relative to the package directory in which the ZCML file which
- contains the directive (e.g. ``foo/bar/baz``).
-
-``cache_max_age``
- The number of seconds that the static resource can be cached, as
- represented in the returned response's ``Expires`` and/or
- ``Cache-Control`` headers, when any static file is served from this
- directive. This defaults to 3600 (5 minutes). Optional.
-
-``permission``
- Used to specify the :term:`permission` required by a user to execute
- this static view. This value defaults to the string
- ``__no_permission_required__``. The ``__no_permission_required__``
- string is a special sentinel which indicates that, even if a
- :term:`default permission` exists for the current application, the
- static view should be renderered to completely anonymous users.
- This default value is permissive because, in most web apps, static
- resources seldom need protection from viewing. You should use this
- option only if you register a static view which points at a
- directory that contains resources which should be shown only if the
- calling user has (according to the :term:`authorization policy`) a
- particular permission.
-
-Examples
-~~~~~~~~
-
-.. topic:: Serving Static Files from an Absolute Path
-
- .. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="/var/www/static"
- />
-
-.. topic:: Serving Static Files from a Package-Relative Path
-
- .. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="some_package:a/b/c/static"
- />
-
-.. topic:: Serving Static Files from a Current-Package-Relative Path
-
- .. code-block:: xml
- :linenos:
-
- <static
- name="static"
- path="static_files"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-:meth:`pyramid.config.Configurator.add_static_view` can also
-be used to add a static view.
-
-See Also
-~~~~~~~~
-
-See also :ref:`static_resources_section` and
-:ref:`generating_static_resource_urls`.
diff --git a/docs/zcml/subscriber.rst b/docs/zcml/subscriber.rst
deleted file mode 100644
index 25c4abf2e..000000000
--- a/docs/zcml/subscriber.rst
+++ /dev/null
@@ -1,45 +0,0 @@
-.. _subscriber_directive:
-
-``subscriber``
---------------
-
-The ``subscriber`` ZCML directive configures an :term:`subscriber`
-callable to listen for events broadcast by the :app:`Pyramid` web
-framework.
-
-Attributes
-~~~~~~~~~~
-
-``for``
- The class or :term:`interface` that you are subscribing the listener for,
- e.g. :class:`pyramid.events.NewRequest`. Registering a subscriber for a
- specific class or interface limits the event types that the subscriber
- will receive to those specified by the interface or class. Default:
- ``zope.interface.Interface`` (implying *any* event type).
-
-``handler``
- A :term:`dotted Python name` which references an event handler
- callable. The callable should accept a single argument: ``event``.
- The return value of the callable is ignored.
-
-Examples
-~~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <subscriber
- for="pyramid.events.NewRequest"
- handler=".subscribers.handle_new_request"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-You can also register an event listener by using the
-:meth:`pyramid.config.Configurator.add_subscriber` method.
-
-See Also
-~~~~~~~~
-
-See also :ref:`events_chapter`.
diff --git a/docs/zcml/translationdir.rst b/docs/zcml/translationdir.rst
deleted file mode 100644
index 5cf615d26..000000000
--- a/docs/zcml/translationdir.rst
+++ /dev/null
@@ -1,64 +0,0 @@
-.. _translationdir_directive:
-
-``translationdir``
-------------------
-
-Add a :term:`gettext` :term:`translation directory` to the current
-configuration for use in localization of text.
-
-Attributes
-~~~~~~~~~~
-
-``dir``
- The path to the translation directory. This path may either be 1)
- absolute (e.g. ``/foo/bar/baz``) 2) Python-package-relative
- (e.g. ``packagename:foo/bar/baz``) or 3) relative to the package
- directory in which the ZCML file which contains the directive
- (e.g. ``foo/bar/baz``).
-
-Example 1
-~~~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <!-- relative to configure.zcml file -->
-
- <translationdir
- dir="locale"
- />
-
-Example 2
-~~~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <!-- relative to another package -->
-
- <translationdir
- dir="another.package:locale"
- />
-
-Example 3
-~~~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <!-- an absolute directory name -->
-
- <translationdir
- dir="/usr/share/locale"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-Use :meth:`pyramid.config.Configurator.add_translation_dirs`
-method instance during initial application setup.
-
-See Also
-~~~~~~~~
-
-See also :ref:`activating_translation`.
diff --git a/docs/zcml/utility.rst b/docs/zcml/utility.rst
deleted file mode 100644
index 1341dfb83..000000000
--- a/docs/zcml/utility.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-.. _utility_directive:
-
-``utility``
------------
-
-Register a :term:`Zope Component Architecture` "utility".
-
-Attributes
-~~~~~~~~~~
-
-``component``
- The utility component (cannot be specified if ``factory`` is
- specified).
-
-``factory``
- A factory that creates a component (cannot be specified if
- ``component`` is specified).
-
-``provides``
- The :term:`interface` that an utility instance resulting from a
- lookup will provide.
-
-``name``
- The utility name.
-
-Example
-~~~~~~~
-
-.. code-block:: xml
- :linenos:
-
- <utility
- provides=".interfaces.IMyUtility"
- component=".utilities.MyUtility"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-Use the ``registerUtility`` method of the ``registry`` attribute of a
-:term:`Configurator` instance during initial application setup.
-
-See Also
-~~~~~~~~
-
-None.
diff --git a/docs/zcml/view.rst b/docs/zcml/view.rst
deleted file mode 100644
index b4fabdc2c..000000000
--- a/docs/zcml/view.rst
+++ /dev/null
@@ -1,252 +0,0 @@
-.. _view_directive:
-
-``view``
---------
-
-A ``view`` declaration directs :app:`Pyramid` to create a single
-:term:`view configuration` registration in the current
-:term:`application registry`.
-
-The ``view`` ZCML directive has many possible attributes. Some of the
-attributes are descriptive or influence rendering. Other attributes
-are :term:`predicate` attributes, meaning that they imply an
-evaluation to true or false when view lookup is performed.
-
-*All* predicates named in a view configuration must evaluate to true
-in order for the view callable it names to be considered "invokable"
-for a given request. See :ref:`view_lookup` for a description of how
-a view configuration matches (or doesn't match) during a request.
-
-The possible attributes of the ``view`` ZCML directive are described
-below. They are divided into predicate and non-predicate categories.
-
-Attributes
-~~~~~~~~~~
-
-Non-Predicate Attributes
-########################
-
-``view``
- The :term:`dotted Python name` to a :term:`view callable`. This
- attribute is required unless a ``renderer`` attribute also exists.
- If a ``renderer`` attribute exists on the directive, this attribute
- defaults to a view that returns an empty dictionary (see
- :ref:`views_which_use_a_renderer`).
-
-``permission``
- The name of a *permission* that the user must possess in order to
- call the view. See :ref:`view_security_section` for more
- information about view security and permissions.
-
-``attr``
- The view machinery defaults to using the ``__call__`` method of the
- view callable (or the function itself, if the view callable is a
- function) to obtain a response dictionary. The ``attr`` value
- allows you to vary the method attribute used to obtain the response.
- For example, if your view was a class, and the class has a method
- named ``index`` and you wanted to use this method instead of the
- class' ``__call__`` method to return the response, you'd say
- ``attr="index"`` in the view configuration for the view. This is
- most useful when the view definition is a class.
-
-``renderer``
- This is either a single string term (e.g. ``json``) or a string
- implying a path or :term:`asset specification`
- (e.g. ``templates/views.pt``). If the renderer value is a single
- term (does not contain a dot ``.``), the specified term will be used
- to look up a renderer implementation, and that renderer
- implementation will be used to construct a response from the view
- return value. If the renderer term contains a dot (``.``), the
- specified term will be treated as a path, and the filename extension
- of the last element in the path will be used to look up the renderer
- implementation, which will be passed the full path. The renderer
- implementation will be used to construct a response from the view
- return value.
-
- Note that if the view itself returns a response (see
- :ref:`the_response`), the specified renderer implementation is never
- called.
-
- When the renderer is a path, although a path is usually just a
- simple relative pathname (e.g. ``templates/foo.pt``, implying that a
- template named "foo.pt" is in the "templates" directory relative to
- the directory in which the ZCML file is defined), a path can be
- absolute, starting with a slash on UNIX or a drive letter prefix on
- Windows. The path can alternately be a :term:`asset
- specification` in the form
- ``some.dotted.package_name:relative/path``, making it possible to
- address template assets which live in a separate package.
-
- The ``renderer`` attribute is optional. If it is not defined, the
- "null" renderer is assumed (no rendering is performed and the value
- is passed back to the upstream BFG machinery unmolested).
-
-``wrapper``
- The :term:`view name` (*not* an object dotted name) of another view
- declared elsewhere in ZCML (or via the ``@view_config`` decorator)
- which will receive the response body of this view as the
- ``request.wrapped_body`` attribute of its own request, and the
- response returned by this view as the ``request.wrapped_response``
- attribute of its own request. Using a wrapper makes it possible to
- "chain" views together to form a composite response. The response
- of the outermost wrapper view will be returned to the user. The
- wrapper view will be found as any view is found: see
- :ref:`view_lookup`. The "best" wrapper view will be found based on
- the lookup ordering: "under the hood" this wrapper view is looked up
- via ``pyramid.view.render_view_to_response(context, request,
- 'wrapper_viewname')``. The context and request of a wrapper view is
- the same context and request of the inner view. If this attribute
- is unspecified, no view wrapping is done.
-
-Predicate Attributes
-####################
-
-``name``
- The *view name*. Read the :ref:`traversal_chapter` to understand
- the concept of a view name.
-
-``context``
- A :term:`dotted Python name` representing the Python class that the
- :term:`context` must be an instance of, *or* the :term:`interface`
- that the :term:`context` must provide in order for this view to be
- found and called. This predicate is true when the :term:`context`
- is an instance of the represented class or if the :term:`context`
- provides the represented interface; it is otherwise false. An
- alternate name for this attribute is ``for`` (this is an older
- spelling).
-
-``route_name``
- *This attribute services an advanced feature that isn't often used
- unless you want to perform traversal after a route has matched.*
- This value must match the ``name`` of a ``<route>`` declaration (see
- :ref:`urldispatch_chapter`) that must match before this view will be
- called. Note that the ``route`` configuration referred to by
- ``route_name`` usually has a ``*traverse`` token in the value of its
- ``path``, representing a part of the path that will be used by
- traversal against the result of the route's :term:`root factory`.
- See :ref:`hybrid_chapter` for more information on using this
- advanced feature.
-
-``request_type``
- This value should be a :term:`dotted Python name` string
- representing the :term:`interface` that the :term:`request` must
- have in order for this view to be found and called. The presence of
- this attribute is largely for backwards compatibility with
- older iterations of this framework.
-
-``request_method``
- This value can either be one of the strings 'GET', 'POST', 'PUT',
- 'DELETE', or 'HEAD' representing an HTTP ``REQUEST_METHOD``. A view
- declaration with this attribute ensures that the view will only be
- called when the request's ``method`` (aka ``REQUEST_METHOD``) string
- matches the supplied value.
-
-``request_param``
- This value can be any string. A view declaration with this
- attribute ensures that the view will only be called when the request
- has a key in the ``request.params`` dictionary (an HTTP ``GET`` or
- ``POST`` variable) that has a name which matches the supplied value.
- If the value supplied to the attribute has a ``=`` sign in it,
- e.g. ``request_params="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 request.
-
-``containment``
- This value should be a :term:`dotted Python name` string
- representing the class that a graph traversal parent object of the
- :term:`context` must be an instance of (or :term:`interface` that a
- parent object must provide) in order for this view to be found and
- called. Your resources must be "location-aware" to use this feature.
- See :ref:`location_aware` for more information about
- location-awareness.
-
-``xhr``
- This value should be either ``True`` or ``False``. If this value is
- specified and is ``True``, the :term:`request` must possess an
- ``HTTP_X_REQUESTED_WITH`` (aka ``X-Requested-With``) header that has
- the value ``XMLHttpRequest`` for this view to be found and called.
- This is useful for detecting AJAX requests issued from jQuery,
- Prototype and other Javascript libraries.
-
-``accept``
- The value of this attribute represents a match query for one or more
- mimetypes in the ``Accept`` HTTP request header. If this value is
- specified, it must be in one of the following forms: a mimetype
- match token in the form ``text/plain``, a wildcard mimetype match
- token in the form ``text/*`` or a match-all wildcard mimetype match
- token in the form ``*/*``. If any of the forms matches the
- ``Accept`` header of the request, this predicate will be true.
-
-``header``
- The value of this attribute represents an HTTP header name or a
- header name/value pair. If the value contains a ``:`` (colon), it
- will be considered a name/value pair (e.g. ``User-Agent:Mozilla/.*``
- or ``Host:localhost``). The *value* of an attribute that represent
- a name/value pair should be a regular expression. If the value does
- not contain a colon, the entire value will be considered to be the
- header name (e.g. ``If-Modified-Since``). If the value evaluates to
- a header name only without a value, the header specified by the name
- must be present in the request for this predicate to be true. If
- the value evaluates to a header name/value pair, the header
- specified by the name must be present in the request *and* the
- regular expression specified as the value must match the header
- value. Whether or not the value represents a header name or a
- header name/value pair, the case of the header name is not
- significant.
-
-``path_info``
- The value of this attribute represents a regular expression pattern
- that will be tested against the ``PATH_INFO`` WSGI environment
- variable. If the regex matches, this predicate will be true.
-
-``custom_predicates``
- This value should be a sequence of references to custom predicate
- callables (e.g. ``dotted.name.one dotted.name.two``, if used in
- ZCML; a :term:`dotted Python name` to each callable separated by a
- space). Use custom predicates when no set of predefined predicates
- do what you need. Custom predicates can be combined with predefined
- predicates as necessary. Each custom predicate callable should
- accept two arguments: ``context`` and ``request`` and should return
- either ``True`` or ``False`` after doing arbitrary evaluation of the
- context and/or the request. If all callables return ``True``, the
- associated view callable will be considered viable for a given
- request.
-
-Examples
-~~~~~~~~
-
-.. topic:: Registering A Default View for a Class
-
- .. code-block:: xml
- :linenos:
-
- <view
- context=".resources.MyResource"
- view=".views.hello_world"
- />
-
-.. topic:: Registering A View With a Predicate
-
- .. code-block:: xml
- :linenos:
-
- <view
- context=".resources.MyResource"
- view=".views.hello_world_post"
- request_method="POST"
- />
-
-Alternatives
-~~~~~~~~~~~~
-
-You can also add a :term:`view configuration` via:
-
-- Using the :class:`pyramid.view.view_config` class as a decorator.
-
-- Using the :meth:`pyramid.config.Configurator.add_view` method.
-
-See Also
-~~~~~~~~
-
-See also :ref:`views_chapter`.