summaryrefslogtreecommitdiff
path: root/docs/tutorials
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2010-12-22 22:34:20 -0500
committerChris McDonough <chrism@plope.com>2010-12-22 22:34:20 -0500
commit2a5ae0346df95e5b4f9a7d8531574dce70abe31f (patch)
tree7b03626c0bb639e3432f9e5245b61327cbefc775 /docs/tutorials
parent319793d9b3d127ba2a9245713ef4f01b32918e95 (diff)
downloadpyramid-2a5ae0346df95e5b4f9a7d8531574dce70abe31f.tar.gz
pyramid-2a5ae0346df95e5b4f9a7d8531574dce70abe31f.tar.bz2
pyramid-2a5ae0346df95e5b4f9a7d8531574dce70abe31f.zip
- The ``pyramid_zodb`` Paster template no longer employs ZCML. Instead, it
is based on scanning. - Changed the "ZODB + Traversal Wiki Tutorial" based on changes to ``pyramid_zodb`` Paster template.
Diffstat (limited to 'docs/tutorials')
-rw-r--r--docs/tutorials/wiki/authorization.rst70
-rw-r--r--docs/tutorials/wiki/basiclayout.rst180
-rw-r--r--docs/tutorials/wiki/definingmodels.rst127
-rw-r--r--docs/tutorials/wiki/definingviews.rst468
-rw-r--r--docs/tutorials/wiki/index.rst1
-rw-r--r--docs/tutorials/wiki/src/authorization/development.ini30
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/__init__.py17
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/configure.zcml25
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/login.py13
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/views.py16
-rw-r--r--docs/tutorials/wiki/src/basiclayout/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki/src/basiclayout/development.ini29
-rw-r--r--docs/tutorials/wiki/src/basiclayout/setup.cfg1
-rw-r--r--docs/tutorials/wiki/src/basiclayout/setup.py8
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py4
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/configure.zcml17
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt104
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/tests.py1
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/views.py4
-rw-r--r--docs/tutorials/wiki/src/models/development.ini29
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/__init__.py6
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/configure.zcml17
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/views.py3
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/CHANGES.txt4
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/README.txt4
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/development.ini19
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/setup.cfg28
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/setup.py44
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/__init__.py21
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/configure.zcml13
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/models.py22
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/static/favicon.icobin1406 -> 0 bytes
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/static/logo.pngbin6641 -> 0 bytes
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/static/pylons.css73
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/static/style.css109
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/templates/edit.pt30
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/templates/mytemplate.pt69
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/templates/view.pt26
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/tests.py124
-rw-r--r--docs/tutorials/wiki/src/viewdecorators/tutorial/views.py62
-rw-r--r--docs/tutorials/wiki/src/views/development.ini30
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/__init__.py7
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/configure.zcml36
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/views.py12
-rw-r--r--docs/tutorials/wiki/viewdecorators.rst240
45 files changed, 657 insertions, 1488 deletions
diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst
index 062c553b5..8cf9ded49 100644
--- a/docs/tutorials/wiki/authorization.rst
+++ b/docs/tutorials/wiki/authorization.rst
@@ -2,14 +2,13 @@
Adding Authorization
====================
-Our application currently allows anyone with access to the server to
-view, edit, and add pages to our wiki. For purposes of demonstration
-we'll change our application to allow people whom are members of a
-*group* named ``group:editors`` to add and edit wiki pages but we'll
-continue allowing anyone with access to the server to view pages.
-:app:`Pyramid` provides facilities for *authorization* and
-*authentication*. We'll make use of both features to provide security
-to our application.
+Our application currently allows anyone with access to the server to view,
+edit, and add pages to our wiki. For purposes of demonstration we'll change
+our application to allow people whom are members of a *group* named
+``group:editors`` to add and edit wiki pages but we'll continue allowing
+anyone with access to the server to view pages. :app:`Pyramid` provides
+facilities for *authorization* and *authentication*. We'll make use of both
+features to provide security to our application.
The source code for this tutorial stage can be browsed via
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/
@@ -19,33 +18,31 @@ The source code for this tutorial stage can be browsed via
Configuring a ``pyramid`` Authentication Policy
--------------------------------------------------
-For any :app:`Pyramid` application to perform authorization, we
-need to add a ``security.py`` module and we'll need to change our
-:term:`application registry` to add an :term:`authentication policy`
-and a :term:`authorization policy`.
+For any :app:`Pyramid` application to perform authorization, we need to add a
+``security.py`` module and we'll need to change our :term:`application
+registry` to add an :term:`authentication policy` and a :term:`authorization
+policy`.
-Changing ``configure.zcml``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Changing ``__init__.py``
+~~~~~~~~~~~~~~~~~~~~~~~~
-We'll change our ``configure.zcml`` file to enable an
-``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to
-enable declarative security checking. We'll also add a new view
-stanza, which specifies a :term:`forbidden view`. This configures our
-login view to show up when :app:`Pyramid` detects that a view
-invocation can not be authorized. When you're done, your
-``configure.zcml`` will look like so:
+We'll change our ``__init__.py`` file to enable an
+``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to enable
+declarative security checking. We'll also add a new view stanza, which
+specifies a :term:`forbidden view`. This configures our login view to show
+up when :app:`Pyramid` detects that a view invocation can not be authorized.
+When you're done, your ``__init__.py`` will look like so:
-.. literalinclude:: src/authorization/tutorial/configure.zcml
+.. literalinclude:: src/authorization/tutorial/__init__.py
:linenos:
:language: xml
-Note that the ``authtktauthenticationpolicy`` tag has two attributes:
-``secret`` and ``callback``. ``secret`` is a string representing an
-encryption key used by the "authentication ticket" machinery
-represented by this policy: it is required. The ``callback`` is a
-string, representing a :term:`dotted Python name`, which points at the
-``groupfinder`` function in the current directory's ``security.py``
-file. We haven't added that module yet, but we're about to.
+Note that the creation of an ``AuthTktAuthenticationPolicy`` requires two
+arguments: ``secret`` and ``callback``. ``secret`` is a string representing
+an encryption key used by the "authentication ticket" machinery represented
+by this policy: it is required. The ``callback`` is a reference to a
+``groupfinder`` function in the ``tutorial`` package's ``security.py`` file.
+We haven't added that module yet, but we're about to.
Adding ``security.py``
~~~~~~~~~~~~~~~~~~~~~~
@@ -59,14 +56,13 @@ content:
:language: python
The ``groupfinder`` function defined here is an authorization policy
-"callback"; it is a callable that accepts a userid and a request. If
-the userid exists in the set of users known by the system, the
-callback will return a sequence of group identifiers (or an empty
-sequence if the user isn't a member of any groups). If the userid
-*does not* exist in the system, the callback will return ``None``. In
-a production system this data will most often come from a database,
-but here we use "dummy" data to represent user and groups
-sources. Note that the ``editor`` user is a member of the
+"callback"; it is a callable that accepts a userid and a request. If the
+userid exists in the set of users known by the system, the callback will
+return a sequence of group identifiers (or an empty sequence if the user
+isn't a member of any groups). If the userid *does not* exist in the system,
+the callback will return ``None``. In a production system this data will
+most often come from a database, but here we use "dummy" data to represent
+user and groups sources. Note that the ``editor`` user is a member of the
``group:editors`` group in our dummy group data (the ``GROUPS`` data
structure).
diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst
index c7c722f70..8e6e89e57 100644
--- a/docs/tutorials/wiki/basiclayout.rst
+++ b/docs/tutorials/wiki/basiclayout.rst
@@ -21,9 +21,9 @@ well as to contain application configuration code.
When you run the application using the ``paster`` command using the
``development.ini`` generated config file, the application configuration
-points at an Setuptools *entry point* described as ``egg:tutorial#app``. In
-our application, because the application's ``setup.py`` file says so, this
-entry point happens to be the ``app`` function within the file named
+points at an Setuptools *entry point* described as ``egg:tutorial``. In our
+application, because the application's ``setup.py`` file says so, this entry
+point happens to be the ``main`` function within the file named
``__init__.py``:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
@@ -48,55 +48,31 @@ entry point happens to be the ``app`` function within the file named
factory` and the settings keywords parsed by PasteDeploy. The root
factory is named ``get_root``.
-#. *Line 16*. Load the
- ``configure.zcml`` file from our package using the
- :meth:`pyramid.config.Configurator.load_zcml` method.
-
-#. *Line 17*. Use the
+#. *Line 16*. Register a 'static view' which answers requests which start
+ with with URL path ``/static`` using the
+ :meth:`pyramid.config.Configurator.add_static_view method`. This
+ statement registers a view that will serve up static assets, such as CSS
+ and image files, for us, in this case, at
+ ``http://localhost:6543/static/`` and below. The first argument is the
+ "name" ``static``, which indicates that the URL path prefix of the view
+ will be ``/static``. the The second argument of this tag is the "path",
+ which is an :term:`asset specification`, so it finds the resources it
+ should serve within the ``static`` directory inside the ``tutorial``
+ package.
+
+#. *Line 17*. Perform a :term:`scan`. A scan will find :term:`configuration
+ decoration`, such as view configuration decorators
+ (e.g. ``@view_config``) in the source code of the ``tutorial`` package and
+ will take actions based on these decorators. The argument to
+ :meth:`~pyramid.config.Configurator.scan` is the package name to scan,
+ which is ``tutorial``.
+
+#. *Line 18*. Use the
:meth:`pyramid.config.Configurator.make_wsgi_app` method
to return a :term:`WSGI` application.
-Configuration With ``configure.zcml``
---------------------------------------
-
-The ``pyramid_zodb`` template uses :term:`ZCML` to perform system
-configuration. The ZCML file generated by the template looks like the
-following:
-
- .. literalinclude:: src/basiclayout/tutorial/configure.zcml
- :linenos:
- :language: xml
-
-#. *Line 1*. The root ``<configure>`` element.
-
-#. *Line 4*. Boilerplate, the comment explains.
-
-#. *Lines 6-10*. Register a ``<view>`` that names a ``context`` type
- that is a class. ``.views.my_view`` is a *function* we write
- (generated by the ``pyramid_zodb`` template) that is given a
- ``context`` object and a ``request`` and which returns a
- dictionary. The ``renderer`` tag indicates that the
- ``templates/mytemplate.pt`` template should be used to turn the
- dictionary returned by the view into a response.
- ``templates/mytemplate.pt`` is a *relative* path: it names the
- ``mytemplate.pt`` file which lives in the ``templates``
- subdirectory of the directory in which this ``configure.zcml``
- lives in. In this case, it means it lives in the ``tutorial``
- package's ``templates`` directory as ``mytemplate.pt``
-
- Since this ``<view>`` doesn't have a ``name`` attribute, it is the
- "default" view for that class.
-
-#. *Lines 12-15*. Register a ``static`` view which answers requests
- which start with ``/static``. This is a view that will serve up
- static resources for us, in this case, at
- ``http://localhost:6543/static/`` and below. The ``path`` element
- of this tag is a relative directory name, so it finds the resources
- it should serve within the ``static`` directory inside
- the ``tutorial`` package.
-
-Content Models with ``models.py``
----------------------------------
+Resources and Models with ``models.py``
+---------------------------------------
:app:`Pyramid` uses the word :term:`resource` to describe objects arranged
hierarchically in a :term:`resource tree`. This tree is consulted by
@@ -114,14 +90,13 @@ Here is the source for ``models.py``:
:linenos:
:language: py
-#. *Lines 3-4*. The ``MyModel`` class we referred to in the ZCML file
- named ``configure.zcml`` is implemented here. Instances of this
- class will be capable of being persisted in :term:`ZODB` because
- the class inherits from the
- :class:`persistent.mapping.PersistentMapping` class. The
- ``__parent__`` and ``__name__`` are important parts of the
- :term:`traversal` protocol. By default, have these as ``None``
- indicating that this is the :term:`root` object.
+#. *Lines 3-4*. The ``MyModel`` :term:`resource` class is implemented here.
+ Instances of this class will be capable of being persisted in :term:`ZODB`
+ because the class inherits from the
+ :class:`persistent.mapping.PersistentMapping` class. The ``__parent__``
+ and ``__name__`` are important parts of the :term:`traversal` protocol.
+ By default, have these as ``None`` indicating that this is the
+ :term:`root` object.
#. *Lines 6-12*. ``appmaker`` is used to return the *application
root* object. It is called on *every request* to the
@@ -134,3 +109,94 @@ Here is the source for ``models.py``:
commit the transaction. We then return the application root
object.
+Views With ``views.py``
+-----------------------
+
+Our paster template generated a default ``views.py`` on our behalf. It
+contains a single view, which is used to render the page shown when you visit
+the URL ``http://localhost:6543/``.
+
+Here is the source for ``views.py``:
+
+ .. literalinclude:: src/basiclayout/tutorial/views.py
+ :linenos:
+ :language: py
+
+Let's try to understand the components in this module:
+
+#. *Lines 1-2*. Perform some dependency imports.
+
+#. *Line 4*. Use the :func:`pyramid.view.view_config` :term:`configuration
+ decoration` to perform a :term:`view configuration` registration. This
+ view configuration registration will be activated when the application is
+ started. It will be activated by virtue of it being found as the result
+ of a :term:`scan` (when Line 17 of ``__init__.py`` is run).
+
+ The ``@view_config`` decorator accepts a number of keyword arguments. We
+ use two keyword arguments here: ``context`` and ``renderer``.
+
+ The ``context`` argument signifies that the decorated view callable should
+ only be run when :term:`traversal` finds the ``tutorial.models.MyModel``
+ :term:`resource` to be the :term:`context` of a request. In English, this
+ means that when the URL ``/`` is visited, because ``MyModel`` is the root
+ model, this view callable will be invoked.
+
+ The ``renderer`` argument names an :term:`asset specification` of
+ ``tutorial:templates/mytemplate.pt``. This asset specification points at
+ a :term:`Chameleon` template which lives in the ``mytemplate.pt`` file
+ within the ``templates`` directory of the ``tutorial`` package. And
+ indeed if you look in the ``templates`` directory of this package, you'll
+ see a ``mytemplate.pt`` template file, which renders the default home page
+ of the generated project.
+
+ Since this call to ``@view_config`` doesn't pass a ``name`` argument, the
+ ``my_view`` function which it decorates represents the "default" view
+ callable used when the context is of the type ``MyModel``.
+
+#. *Lines 5-6*. We define a :term:`view callable` named ``my_view``, which
+ we decorated in the step above. This view callable is a *function* we
+ write generated by the ``pyramid_zodb`` template that is given a
+ ``request`` and which returns a dictionary. The ``mytemplate.pt``
+ :term:`renderer` named by the asset specification in the step above will
+ convert this dictionary to a :term:`response` on our behalf.
+
+ The function returns the dictionary ``{'project':'tutorial'}``. This
+ dictionary is used by the template named by the ``mytemplate.pt`` asset
+ specification to fill in certain values on the page.
+
+The WSGI Pipeline in ``development.ini``
+----------------------------------------
+
+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
+
+
+Note the existence of a ``[pipeline:main]`` section which specifies our WSGI
+pipeline. This "pipeline" will be served up as our WSGI application. As far
+as the WSGI server is concerned the pipeline *is* our application. Simpler
+configurations don't use a pipeline: instead they expose a single WSGI
+application as "main". Our setup is more complicated, so we use a pipeline
+composed of :term:`middleware`.
+
+The ``egg:WebError#evalerror`` middleware is at the "top" of the pipeline.
+This is middleware which displays debuggable errors in the browser while
+you're developing (not recommended for deployment).
+
+The ``egg:repoze.zodbconn#closer`` middleware is in the middle of the
+pipeline. This is a piece of middleware which closes the ZODB connection
+opened by the ``PersistentApplicationFinder`` at the end of the request.
+
+The ``egg:repoze.tm#tm`` middleware is the last piece of middleware in the
+pipeline. This commits a transaction near the end of the request unless
+there's an exception raised.
+
+The final line in the ``[pipeline:main]`` section is ``tutorial``, which
+refers to the ``[app:tutorial]`` section above it. The ``[app:tutorial]``
+section is the section which actually defines our application settings. The
+values within this section are passed as ``**settings`` to the ``main``
+function we defined in ``__init__.py`` when the server is started via
+``paster serve``.
diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst
index f317d31dd..078a8e014 100644
--- a/docs/tutorials/wiki/definingmodels.rst
+++ b/docs/tutorials/wiki/definingmodels.rst
@@ -20,21 +20,21 @@ The source code for this tutorial stage can be browsed via
Deleting the Database
---------------------
-We're going to remove the ``MyModel`` Python model class from our
-``models.py`` file. Since this class is referred to within our
-persistent storage (represented on disk as a file named ``Data.fs``),
+In a subsequent step, we're going to remove the ``MyModel`` Python model
+class from our ``models.py`` file. Since this class is referred to within
+our persistent storage (represented on disk as a file named ``Data.fs``),
we'll have strange things happen the next time we want to visit the
-application in a browser. Remove the ``Data.fs`` from the
-``tutorial`` directory before proceeding any further. It's always
-fine to do this as long as you don't care about the content of the
-database; the database itself will be recreated as necessary.
+application in a browser. Remove the ``Data.fs`` from the ``tutorial``
+directory before proceeding any further. It's always fine to do this as long
+as you don't care about the content of the database; the database itself will
+be recreated as necessary.
Adding Model Classes
--------------------
The next thing we want to do is remove the ``MyModel`` class from the
-generated ``models.py`` file. The ``MyModel`` class is only a sample
-and we're not going to use it.
+generated ``models.py`` file. The ``MyModel`` class is only a sample and
+we're not going to use it.
.. note::
@@ -45,46 +45,43 @@ and we're not going to use it.
Python subpackage of your application package named ``models``) ,
but this is only by convention.
-Then, we'll add a ``Wiki`` class. Because this is a ZODB application,
-this class should inherit from
-:class:`persistent.mapping.PersistentMapping`. We want it to inherit
-from the :class:`persistent.mapping.PersistentMapping` class because
-our Wiki class will be a mapping of wiki page names to ``Page``
-objects. The :class:`persistent.mapping.PersistentMapping` class
-provides our class with mapping behavior, and makes sure that our Wiki
-page is stored as a "first-class" persistent object in our ZODB
-database.
-
-Our ``Wiki`` class should also have a ``__name__`` attribute set to
-``None`` at class scope, and should have a ``__parent__`` attribute
-set to ``None`` at class scope as well. If a model has a
-``__parent__`` attribute of ``None`` in a traversal-based
-:app:`Pyramid` application, it means that it's the :term:`root`
-model. The ``__name__`` of the root model is also always ``None``.
+Then, we'll add a ``Wiki`` class. Because this is a ZODB application, this
+class should inherit from :class:`persistent.mapping.PersistentMapping`. We
+want it to inherit from the :class:`persistent.mapping.PersistentMapping`
+class because our Wiki class will be a mapping of wiki page names to ``Page``
+objects. The :class:`persistent.mapping.PersistentMapping` class provides
+our class with mapping behavior, and makes sure that our Wiki page is stored
+as a "first-class" persistent object in our ZODB database.
+
+Our ``Wiki`` class should also have a ``__name__`` attribute set to ``None``
+at class scope, and should have a ``__parent__`` attribute set to ``None`` at
+class scope as well. If a model has a ``__parent__`` attribute of ``None``
+in a traversal-based :app:`Pyramid` application, it means that it's the
+:term:`root` model. The ``__name__`` of the root model is also always
+``None``.
Then we'll add a ``Page`` class. This class should inherit from the
-:class:`persistent.Persistent` class. We'll also give it an
-``__init__`` method that accepts a single parameter named ``data``.
-This parameter will contain the :term:`ReStructuredText` body
-representing the wiki page content. Note that ``Page`` objects don't
-have an initial ``__name__`` or ``__parent__`` attribute. All objects
-in a traversal graph must have a ``__name__`` and a ``__parent__``
-attribute. We don't specify these here because both ``__name__`` and
-``__parent__`` will be set by by a :term:`view` function when a Page
-is added to our Wiki mapping.
-
-Add an Appmaker
----------------
-
-We're using a mini-framework callable named
-``PersistentApplicationFinder`` in our application (see ``__init__.py``).
-A ``PersistentApplicationFinder`` accepts a ZODB URL as well as an
-"appmaker" callback. This callback typically lives in the
-``models.py`` file.
-
-We want to change the appmaker function in our ``models.py`` file so
-that our application root is a Wiki instance, and we'll also slot a
-single page object (the front page) into the wiki.
+:class:`persistent.Persistent` class. We'll also give it an ``__init__``
+method that accepts a single parameter named ``data``. This parameter will
+contain the :term:`ReStructuredText` body representing the wiki page content.
+Note that ``Page`` objects don't have an initial ``__name__`` or
+``__parent__`` attribute. All objects in a traversal graph must have a
+``__name__`` and a ``__parent__`` attribute. We don't specify these here
+because both ``__name__`` and ``__parent__`` will be set by by a :term:`view`
+function when a Page is added to our Wiki mapping.
+
+As a last step, we want to change the ``appmaker`` function in our
+``models.py`` file so that the :term:`root` :term:`resource` of our
+application is a Wiki instance. We'll also slot a single page object (the
+front page) into the Wiki within the ``appmaker``. This will provide
+:term:`traversal` a :term:`resource tree` to work against when it attempts to
+resolve URLs to resources.
+
+We're using a mini-framework callable named ``PersistentApplicationFinder``
+in our application (see ``__init__.py``). A ``PersistentApplicationFinder``
+accepts a ZODB URL as well as an "appmaker" callback. This callback
+typically lives in the ``models.py`` file. We'll just change this function,
+making the necessary edits.
Looking at the Result of Our Edits to ``models.py``
---------------------------------------------------
@@ -96,19 +93,37 @@ something like this:
:linenos:
:language: python
+Removing View Configuration
+---------------------------
+
+In a previous step in this chapter, we removed the
+``tutorial.models.MyModel`` class. However, our ``views.py`` module still
+attempts to import this class. Temporarily, we'll change ``views.py`` so
+that it no longer references ``MyModel`` by removing its imports and removing
+a reference to it from the arguments passed to the ``@view_config``
+:term:`configuration decoration` decorator which sits atop the ``my_view``
+view callable.
+
+The result of all of our edits to ``views.py`` will end up looking
+something like this:
+
+.. literalinclude:: src/models/tutorial/views.py
+ :linenos:
+ :language: python
+
Testing the Models
------------------
-To make sure the code we just wrote works, we write tests for the
-model classes and the appmaker. Changing ``tests.py``, we'll write a
-separate test class for each model class, and we'll write a test class
-for the ``appmaker``.
+To make sure the code we just wrote works, we write tests for the model
+classes and the appmaker. Changing ``tests.py``, we'll write a separate test
+class for each model class, and we'll write a test class for the
+``appmaker``.
-To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided
-as a result of the ``pyramid_zodb`` project generator. We'll add
-three test classes: one for the ``Page`` model named
-``PageModelTests``, one for the ``Wiki`` model named
-``WikiModelTests``, and one for the appmaker named ``AppmakerTests``.
+To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a
+result of the ``pyramid_zodb`` project generator. We'll add three test
+classes: one for the ``Page`` model named ``PageModelTests``, one for the
+``Wiki`` model named ``WikiModelTests``, and one for the appmaker named
+``AppmakerTests``.
When we're done changing ``tests.py``, it will look something like so:
diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst
index 5250cb5e5..53f5ff994 100644
--- a/docs/tutorials/wiki/definingviews.rst
+++ b/docs/tutorials/wiki/definingviews.rst
@@ -2,28 +2,37 @@
Defining Views
==============
-A :term:`view callable` in a traversal-based :app:`Pyramid`
-application is typically a simple Python function that accepts two
-parameters: :term:`context`, and :term:`request`. A view callable is
-assumed to return a :term:`response` object.
-
-.. note:: A :app:`Pyramid` view can also be defined as callable which accepts
- *one* arguments: a :term:`request`. You'll see this one-argument pattern
- used in other :app:`Pyramid` tutorials and applications. It was also used
- in the ``my_view`` view callable that we deleted in the last chapter.
- Either calling convention will work in any :app:`Pyramid` application; the
- calling conventions can be used interchangeably as necessary. In
- :term:`traversal` based applications, such as this tutorial, the context
- is used frequently within the body of a view method, so it makes sense to
- use the two-argument syntax in this application. However, in :term:`url
- dispatch` based applications, the context object is rarely used in the
- view body itself, so within code that uses URL-dispatch-only, it's common
- to define views as callables that accept only a request to avoid the
- visual "noise".
-
-We're going to define several :term:`view callable` functions then
-wire them into :app:`Pyramid` using some :term:`view
-configuration` via :term:`ZCML`.
+Conventionally, :term:`view callable` objects are defined within a
+``views.py`` module in an :app:`Pyramid` application. There is nothing
+automagically special about the filename ``views.py``. Files implementing
+views often have ``view`` in their filenames (or may live in a Python
+subpackage of your application package named ``views``), but this is only by
+convention. However, a project may have many views throughout its codebase
+in arbitrarily-named files. In this application, we'll be continuing to use
+the ``views.py`` module, because there's no reason to break convention.
+
+A :term:`view callable` in a :app:`Pyramid` application is typically a simple
+Python function that accepts a single parameter: :term:`request`. A view
+callable is assumed to return a :term:`response` object.
+
+However, a :app:`Pyramid` view can also be defined as callable which accepts
+*two* arguments: a :term:`context` and a :term:`request`. In :term:`url
+dispatch` based applications, the context object is rarely used in the view
+body itself, so within code that uses URL-dispatch-only, it's common to
+define views as callables that accept only a request to avoid the visual
+"noise". This application, however, uses :term:`traversal` to map URLs to
+resources, so we're often interested in the context; it's not "noise" to use.
+
+The single-arg (``request`` -only) or two-arg (``context`` and ``request``)
+calling conventions will work in any :app:`Pyramid` application for any view;
+they can be used interchangeably as necessary. In :term:`traversal` based
+applications, such as the application we're building in this tutorial, the
+context is used frequently within the body of a view method, so we'll be
+using the two-argument ``(context, request)`` syntax in this application for
+views that we add.
+
+We're going to define several :term:`view callable` functions then wire them
+into :app:`Pyramid` using some :term:`view configuration`.
The source code for this tutorial stage can be browsed via
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/views/
@@ -32,30 +41,28 @@ The source code for this tutorial stage can be browsed via
Adding View Functions
=====================
-We're going to add four :term:`view callable` functions to our
-``views.py`` module. One view (named ``view_wiki``) will display the
-wiki itself (it will answer on the root URL), another named
-``view_page`` will display an individual page, another named
-``add_page`` will allow a page to be added, and a final view named
-``edit_page`` will allow a page to be edited.
-
-.. note::
-
- There is nothing automagically special about the filename
- ``views.py``. A project may have many views throughout its codebase
- in arbitrarily-named files. Files implementing views often have
- ``view`` in their filenames (or may live in a Python subpackage of
- your application package named ``views``), but this is only by
- convention.
+We're going to add four :term:`view callable` functions to our ``views.py``
+module. One view (named ``view_wiki``) will display the wiki itself (it will
+answer on the root URL), another named ``view_page`` will display an
+individual page, another named ``add_page`` will allow a page to be added,
+and a final view named ``edit_page`` will allow a page to be edited.
The ``view_wiki`` view function
-------------------------------
The ``view_wiki`` function will be configured to respond as the default view
-of a ``Wiki`` model object. It always redirects to the ``Page`` object named
-"FrontPage". It returns an instance of the
-:class:`pyramid.httpexceptions.HTTPFound` class (instances of which implement
-the WebOb :term:`response` interface), and the
+callable for a ``Wiki`` resource object. We'll provide it with a
+``@view_config`` decorator which names the class ``tutorial.models.Wiki`` as
+its context. This means that when a Wiki object is the context, and no
+:term:`view name` exists in the request, this view will be used. The view
+configuration associated with ``view_wiki`` does not use a ``renderer``
+because the view callable always returns a :term:`response` object rather
+than a dictionary. No renderer is necessary when a view returns a response
+object.
+
+The view callable always redirects to the ``Page`` object named "FrontPage".
+It returns an instance of the :class:`pyramid.httpexceptions.HTTPFound` class
+(instances of which implement the WebOb :term:`response` interface), and the
:func:`pyramid.url.resource_url` API. :func:`pyramid.url.resource_url`
constructs a URL to the ``FrontPage`` page resource
(e.g. ``http://localhost:6543/FrontPage``), and uses it as the "location" of
@@ -64,114 +71,130 @@ the HTTPFound response, forming an HTTP redirect.
The ``view_page`` view function
-------------------------------
-The ``view_page`` function will be configured to respond as the
-default view of a ``Page`` object. The ``view_page`` function renders
-the :term:`ReStructuredText` body of a page (stored as the ``data``
-attribute of the context passed to the view; the context will be a
-Page object) as HTML. Then it substitutes an HTML anchor for each
-*WikiWord* reference in the rendered HTML using a compiled regular
+The ``view_page`` function will be configured to respond as the default view
+of a ``Page`` resource. We'll provide it with a ``@view_config`` decorator
+which names the class ``tutorial.models.Wiki`` as its context. This means
+that when a Page object is the context, and no :term:`view name` exists in
+the request, this view will be used. We inform :app:`Pyramid` this view will
+use the ``templates/view.pt`` template file as a ``renderer``.
+
+The ``view_page`` function generates the :term:`ReStructuredText` body of a
+page (stored as the ``data`` attribute of the context passed to the view; the
+context will be a Page object) as HTML. Then it substitutes an HTML anchor
+for each *WikiWord* reference in the rendered HTML using a compiled regular
expression.
The curried function named ``check`` is used as the first argument to
-``wikiwords.sub``, indicating that it should be called to provide a
-value for each WikiWord match found in the content. If the wiki (our
-page's ``__parent__``) already contains a page with the matched
-WikiWord name, the ``check`` function generates a view link to be used
-as the substitution value and returns it. If the wiki does not
-already contain a page with with the matched WikiWord name, the
-function generates an "add" link as the substitution value and returns
+``wikiwords.sub``, indicating that it should be called to provide a value for
+each WikiWord match found in the content. If the wiki (our page's
+``__parent__``) already contains a page with the matched WikiWord name, the
+``check`` function generates a view link to be used as the substitution value
+and returns it. If the wiki does not already contain a page with with the
+matched WikiWord name, the function generates an "add" link as the
+substitution value and returns it.
+
+As a result, the ``content`` variable is now a fully formed bit of HTML
+containing various view and add links for WikiWords based on the content of
+our current page object.
+
+We then generate an edit URL (because it's easier to do here than in the
+template), and we wrap up a number of arguments in a dictionary and return
it.
-As a result, the ``content`` variable is now a fully formed bit of
-HTML containing various view and add links for WikiWords based on the
-content of our current page object.
-
-We then generate an edit URL (because it's easier to do here than in
-the template), and we wrap up a number of arguments in a dictionary
-and return it.
-
-The arguments we wrap into a dictionary include ``page``, ``content``,
-and ``edit_url``. As a result, the *template* associated with this
-view callable will be able to use these names to perform various
-rendering tasks. The template associated with this view callable will
-be a template which lives in ``templates/view.pt``, which we'll
-associate with this view via the :term:`view configuration` which
-lives in the ``configure.zcml`` file.
-
-Note the contrast between this view callable and the ``view_wiki``
-view callable. In the ``view_wiki`` view callable, we return a
-:term:`response` object. In the ``view_page`` view callable, we
-return a *dictionary*. It is *always* fine to return a
-:term:`response` object from a :app:`Pyramid` view. Returning a
-dictionary is allowed only when there is a :term:`renderer` associated
-with the view callable in the view configuration.
+The arguments we wrap into a dictionary include ``page``, ``content``, and
+``edit_url``. As a result, the *template* associated with this view callable
+(via ``renderer=`` in its configuration) will be able to use these names to
+perform various rendering tasks. The template associated with this view
+callable will be a template which lives in ``templates/view.pt``.
+
+Note the contrast between this view callable and the ``view_wiki`` view
+callable. In the ``view_wiki`` view callable, we unconditionally return a
+:term:`response` object. In the ``view_page`` view callable, we return a
+*dictionary*. It is *always* fine to return a :term:`response` object from a
+:app:`Pyramid` view. Returning a dictionary is allowed only when there is a
+:term:`renderer` associated with the view callable in the view configuration.
The ``add_page`` view function
------------------------------
-The ``add_page`` function will be invoked when a user clicks on a
-WikiWord which isn't yet represented as a page in the system. The
-``check`` function within the ``view_page`` view generates URLs to
-this view. It also acts as a handler for the form that is generated
-when we want to add a page object. The ``context`` of the
-``add_page`` view is always a Wiki object (*not* a Page object).
-
-The request :term:`subpath` in :app:`Pyramid` is the sequence of
-names that are found *after* the view name in the URL segments given
-in the ``PATH_INFO`` of the WSGI request as the result of
-:term:`traversal`. If our add view is invoked via,
-e.g. ``http://localhost:6543/add_page/SomeName``, the :term:`subpath`
-will be a tuple: ``('SomeName',)``.
-
-The add view takes the zeroth element of the subpath (the wiki page
-name), and aliases it to the name attribute in order to know the name
-of the page we're trying to add.
+The ``add_page`` function will be configured to respond when the context is a
+Wiki and the :term:`view_name` is ``add_page``. We'll provide it with a
+``@view_config`` decorator which names the string ``add_page`` as its
+:term:`view name` (via name=), the class ``tutorial.models.Wiki`` as its
+context, and the renderer named ``templates/edit.pt``. This means that when
+a Wiki object is the context, and a :term:`view name` exists as the result of
+traverasal named ``add_page``, this view will be used. We inform
+:app:`Pyramid` this view will use the ``templates/edit.pt`` template file as
+a ``renderer``. We share the same template between add and edit views, thus
+``edit.pt`` instead of ``add.pt``.
+
+The ``add_page`` function will be invoked when a user clicks on a WikiWord
+which isn't yet represented as a page in the system. The ``check`` function
+within the ``view_page`` view generates URLs to this view. It also acts as a
+handler for the form that is generated when we want to add a page object.
+The ``context`` of the ``add_page`` view is always a Wiki object (*not* a
+Page object).
+
+The request :term:`subpath` in :app:`Pyramid` is the sequence of names that
+are found *after* the :term:`view name` in the URL segments given in the
+``PATH_INFO`` of the WSGI request as the result of :term:`traversal`. If our
+add view is invoked via, e.g. ``http://localhost:6543/add_page/SomeName``,
+the :term:`subpath` will be a tuple: ``('SomeName',)``.
+
+The add view takes the zeroth element of the subpath (the wiki page name),
+and aliases it to the name attribute in order to know the name of the page
+we're trying to add.
If the view rendering is *not* a result of a form submission (if the
-expression ``'form.submitted' in request.params`` is ``False``), the
-view renders a template. To do so, it generates a "save url" which
-the template use as the form post URL during rendering. We're lazy
-here, so we're trying to use the same template (``templates/edit.pt``)
-for the add view as well as the page edit view. To do so, we create a
-dummy Page object in order to satisfy the edit form's desire to have
-*some* page object exposed as ``page``, and we'll render the template
-to a response.
-
-If the view rendering *is* a result of a form submission (if the
-expression ``'form.submitted' in request.params`` is ``True``), we
-scrape the page body from the form data, create a Page object using
-the name in the subpath and the page body, and save it into "our
-context" (the wiki) using the ``__setitem__`` method of the
-context. We then redirect back to the ``view_page`` view (the default
-view for a page) for the newly created page.
+expression ``'form.submitted' in request.params`` is ``False``), the view
+renders a template. To do so, it generates a "save url" which the template
+use as the form post URL during rendering. We're lazy here, so we're trying
+to use the same template (``templates/edit.pt``) for the add view as well as
+the page edit view. To do so, we create a dummy Page object in order to
+satisfy the edit form's desire to have *some* page object exposed as
+``page``, and we'll render the template to a response.
+
+If the view rendering *is* a result of a form submission (if the expression
+``'form.submitted' in request.params`` is ``True``), we scrape the page body
+from the form data, create a Page object using the name in the subpath and
+the page body, and save it into "our context" (the wiki) using the
+``__setitem__`` method of the context. We then redirect back to the
+``view_page`` view (the default view for a page) for the newly created page.
The ``edit_page`` view function
-------------------------------
-The ``edit_page`` function will be invoked when a user clicks the
-"Edit this Page" button on the view form. It renders an edit form but
-it also acts as the handler for the form it renders. The ``context``
-of the ``edit_page`` view will *always* be a Page object (never a Wiki
-object).
+The ``edit_page`` function will be configured to respond when the context is
+a Page and the :term:`view_name` is ``edit_page``. We'll provide it with a
+``@view_config`` decorator which names the string ``edit_page`` as its
+:term:`view name` (via name=), the class ``tutorial.models.Page`` as its
+context, and the renderer named ``templates/edit.pt``. This means that when
+a Page object is the context, and a :term:`view name` exists as the result of
+traverasal named ``edit_page``, this view will be used. We inform
+:app:`Pyramid` this view will use the ``templates/edit.pt`` template file as
+a ``renderer``.
+
+The ``edit_page`` function will be invoked when a user clicks the "Edit this
+Page" button on the view form. It renders an edit form but it also acts as
+the handler for the form it renders. The ``context`` of the ``edit_page``
+view will *always* be a Page object (never a Wiki object).
If the view execution is *not* a result of a form submission (if the
-expression ``'form.submitted' in request.params`` is ``False``), the
-view simply renders the edit form, passing the request, the page
-object, and a save_url which will be used as the action of the
-generated form.
-
-If the view execution *is* a result of a form submission (if the
-expression ``'form.submitted' in request.params`` is ``True``), the
-view grabs the ``body`` element of the request parameter and sets it
-as the ``data`` attribute of the page context. It then redirects to
-the default view of the context (the page), which will always be the
-``view_page`` view.
+expression ``'form.submitted' in request.params`` is ``False``), the view
+simply renders the edit form, passing the request, the page object, and a
+save_url which will be used as the action of the generated form.
+
+If the view execution *is* a result of a form submission (if the expression
+``'form.submitted' in request.params`` is ``True``), the view grabs the
+``body`` element of the request parameter and sets it as the ``data``
+attribute of the page context. It then redirects to the default view of the
+context (the page), which will always be the ``view_page`` view.
Viewing the Result of Our Edits to ``views.py``
===============================================
-The result of all of our edits to ``views.py`` will leave it looking
-like this:
+The result of all of our edits to ``views.py`` will leave it looking like
+this:
.. literalinclude:: src/views/tutorial/views.py
:linenos:
@@ -181,20 +204,24 @@ Adding Templates
================
Most view callables we've added expected to be rendered via a
-:term:`template`. Each template is a :term:`Chameleon` template. The
-default templating system in :app:`Pyramid` is a variant of
-:term:`ZPT` provided by Chameleon. These templates will live in the
-``templates`` directory of our tutorial package.
+:term:`template`. The default templating systems in :app:`Pyramid` are
+:term:`Chameleon` and :term:`Mako`. Chameleon is a variant of :term:`ZPT`,
+which is an XML-based templating language. Mako is a non-XML-based
+templating language. Because we have to pick one, we'll use Chameleon for
+this tutorial.
+
+The templates we create will live in the ``templates`` directory of our
+tutorial package. Chameleon templates must have a ``.pt`` extension to be
+recognized as such.
The ``view.pt`` Template
------------------------
-The ``view.pt`` template is used for viewing a single wiki page. It
-is used by the ``view_page`` view function. It should have a div that
-is "structure replaced" with the ``content`` value provided by the
-view. It should also have a link on the rendered page that points at
-the "edit" URL (the URL which invokes the ``edit_page`` view for the
-page being viewed).
+The ``view.pt`` template is used for viewing a single wiki page. It is used
+by the ``view_page`` view function. It should have a div that is "structure
+replaced" with the ``content`` value provided by the view. It should also
+have a link on the rendered page that points at the "edit" URL (the URL which
+invokes the ``edit_page`` view for the page being viewed).
Once we're done with the ``view.pt`` template, it will look a lot like
the below:
@@ -203,29 +230,28 @@ the below:
:linenos:
:language: xml
-.. 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 templates make use of a ``request`` object that
- none of our tutorial views return in their dictionary. This value
- appears as if "by magic". However, ``request`` is one of several
- names that are available "by default" in a template when a template
- renderer is used. See :ref:`chameleon_template_renderers` for more
- information about other names that are available by default in a
- template when a Chameleon template is used as a renderer.
+.. 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
+ templates make use of a ``request`` object that none of our tutorial views
+ return in their dictionary. This value appears as if "by magic".
+ However, ``request`` is one of several names that are available "by
+ default" in a template when a template renderer is used. See
+ :ref:`chameleon_template_renderers` for more information about other names
+ that are available by default in a template when a template is used as a
+ renderer.
The ``edit.pt`` Template
------------------------
-The ``edit.pt`` template is used for adding and editing a wiki page.
-It is used by the ``add_page`` and ``edit_page`` view functions. It
-should display a page containing a form that POSTs back to the
-"save_url" argument supplied by the view. The form should have a
-"body" textarea field (the page data), and a submit button that has
-the name "form.submitted". The textarea in the form should be filled
-with any existing page data when it is rendered.
+The ``edit.pt`` template is used for adding and editing a wiki page. It is
+used by the ``add_page`` and ``edit_page`` view functions. It should display
+a page containing a form that POSTs back to the "save_url" argument supplied
+by the view. The form should have a "body" textarea field (the page data),
+and a submit button that has the name "form.submitted". The textarea in the
+form should be filled with any existing page data when it is rendered.
-Once we're done with the ``edit.pt`` template, it will look a lot like
-the below:
+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:
@@ -241,23 +267,22 @@ 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>`_.
This CSS file will be accessed via
-e.g. ``http://localhost:6543/static/style.css`` by virtue of the ``static``
-directive we've defined in the ``configure.zcml`` 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/style.css`` by virtue of the call to
+``add_static_view`` directive we've made in the ``__init__`` 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.
Testing the Views
=================
-We'll modify our ``tests.py`` file, adding tests for each view
-function we added above. As a result, we'll *delete* the
-``ViewTests`` test in the file, and add four other test classes:
-``ViewWikiTests``, ``ViewPageTests``, ``AddPageTests``, and
-``EditPageTests``. These test the ``view_wiki``, ``view_page``,
-``add_page``, and ``edit_page`` views respectively.
+We'll modify our ``tests.py`` file, adding tests for each view function we
+added above. As a result, we'll *delete* the ``ViewTests`` test in the file,
+and add four other test classes: ``ViewWikiTests``, ``ViewPageTests``,
+``AddPageTests``, and ``EditPageTests``. These test the ``view_wiki``,
+``view_page``, ``add_page``, and ``edit_page`` views respectively.
-Once we're done with the ``tests.py`` module, it will look a lot like
-the below:
+Once we're done with the ``tests.py`` module, it will look a lot like the
+below:
.. literalinclude:: src/views/tutorial/tests.py
:linenos:
@@ -266,9 +291,9 @@ the below:
Running the Tests
=================
-We can run these tests by using ``setup.py test`` in the same way we
-did in :ref:`running_tests`. Assuming our shell's current working
-directory is the "tutorial" distribution directory:
+We can run these tests by using ``setup.py test`` in the same way we did in
+:ref:`running_tests`. Assuming our shell's current working directory is the
+"tutorial" distribution directory:
On UNIX:
@@ -292,101 +317,11 @@ The expected result looks something like:
OK
-Mapping Views to URLs in ``configure.zcml``
-===========================================
-
-The ``configure.zcml`` file contains ``view`` declarations which serve
-to map URLs (via :term:`traversal`) to view functions. This is also
-known as :term:`view configuration`. You'll need to add four ``view``
-declarations to ``configure.zcml``.
-
-#. Add a declaration which maps the "Wiki" class in our ``models.py``
- file to the view named ``view_wiki`` in our ``views.py`` file with
- no view name. This is the default view for a Wiki. It does not
- use a ``renderer`` because the ``view_wiki`` view callable always
- returns a *response* object rather than a dictionary.
-
-#. Add a declaration which maps the "Wiki" class in our ``models.py``
- file to the view named ``add_page`` in our ``views.py`` file with
- the view name ``add_page``. Associate this view with the
- ``templates/edit.pt`` template file via the ``renderer`` attribute.
- This view will use the :term:`Chameleon` ZPT renderer configured
- with the ``templates/edit.pt`` template to render non-*response*
- return values from the ``add_page`` view. This is the add view for
- a new Page.
-
-#. Add a declaration which maps the "Page" class in our ``models.py``
- file to the view named ``view_page`` in our ``views.py`` file with
- no view name. Associate this view with the ``templates/view.pt``
- template file via the ``renderer`` attribute. This view will use
- the :term:`Chameleon` ZPT renderer configured with the
- ``templates/view.pt`` template to render non-*response* return
- values from the ``view_page`` view. This is the default view for a
- Page.
-
-#. Add a declaration which maps the "Page" class in our ``models.py``
- file to the view named ``edit_page`` in our ``views.py`` file with
- the view name ``edit_page``. Associate this view with the
- ``templates/edit.pt`` template file via the ``renderer`` attribute.
- This view will use the :term:`Chameleon` ZPT renderer configured
- with the ``templates/edit.pt`` template to render non-*response*
- return values from the ``edit_page`` view. This is the edit view
- for a page.
-
-As a result of our edits, the ``configure.zcml`` file should look
-something like so:
-
-.. literalinclude:: src/views/tutorial/configure.zcml
- :linenos:
- :language: xml
-
-Examining ``development.ini``
-=============================
-
-Let's take a look at our ``development.ini`` file. The contents of the
-file are as follows:
-
-.. literalinclude:: src/models/development.ini
- :linenos:
- :language: ini
-
-The WSGI Pipeline
------------------
-
-Within ``development.ini``, note the existence of a ``[pipeline:main]``
-section which specifies our WSGI pipeline. This "pipeline" will be
-served up as our WSGI application. As far as the WSGI server is
-concerned the pipeline *is* our application. Simpler configurations
-don't use a pipeline: instead they expose a single WSGI application as
-"main". Our setup is more complicated, so we use a pipeline.
-
-``egg:repoze.zodbconn#closer`` is at the "top" of the pipeline. This
-is a piece of middleware which closes the ZODB connection opened by
-the PersistentApplicationFinder at the end of the request.
-
-``egg:repoze.tm#tm`` is the second piece of middleware in the
-pipeline. This commits a transaction near the end of the request
-unless there's an exception raised.
-
-Adding an Element to the Pipeline
----------------------------------
-
-Let's add a piece of middleware to the WSGI pipeline:
-``egg:Paste#evalerror`` middleware which displays debuggable errors in
-the browser while you're developing (not recommended for deployment).
-Let's insert evalerror into the pipeline right below
-"egg:repoze.zodbconn#closer", making our resulting ``development.ini``
-file look like so:
-
-.. literalinclude:: src/views/development.ini
- :linenos:
- :language: ini
-
Viewing the Application in a Browser
====================================
-Once we've set up the WSGI pipeline properly, we can finally examine
-our application in a browser. The views we'll try are as follows:
+Once we've completed our edits, we can finally examine our application in a
+browser. The views we'll try are as follows:
- Visiting ``http://localhost:6543/`` in a browser invokes the
``view_wiki`` view. This always redirects to the ``view_page`` view
@@ -406,9 +341,4 @@ our application in a browser. The views we'll try are as follows:
- To generate an error, visit ``http://localhost:6543/add_page`` which
will generate an ``IndexError`` for the expression
``request.subpath[0]``. You'll see an interactive traceback
- facility provided by evalerror.
-
-
-
-
-
+ facility provided by :term:`WebError`.
diff --git a/docs/tutorials/wiki/index.rst b/docs/tutorials/wiki/index.rst
index 68f724902..589935047 100644
--- a/docs/tutorials/wiki/index.rst
+++ b/docs/tutorials/wiki/index.rst
@@ -22,7 +22,6 @@ tutorial can be browsed at
basiclayout
definingmodels
definingviews
- viewdecorators
authorization
distributing
diff --git a/docs/tutorials/wiki/src/authorization/development.ini b/docs/tutorials/wiki/src/authorization/development.ini
index a102b721b..6f4c33d93 100644
--- a/docs/tutorials/wiki/src/authorization/development.ini
+++ b/docs/tutorials/wiki/src/authorization/development.ini
@@ -4,12 +4,14 @@ reload_templates = true
debug_authorization = false
debug_notfound = false
debug_routematch = false
+debug_templates = true
+default_locale_name = en
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
pipeline =
+ egg:WebError#evalerror
egg:repoze.zodbconn#closer
- egg:Paste#evalerror
egg:repoze.tm#tm
tutorial
@@ -17,3 +19,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py
index 742627a3f..3e9266754 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py
@@ -1,6 +1,11 @@
-from pyramid.config import Configurator
from repoze.zodbconn.finder import PersistentApplicationFinder
+
+from pyramid.config import Configurator
+from pyramid.authentication import AuthTktAuthenticationPolicy
+from pyramid.authorization import ACLAuthorizationPolicy
+
from tutorial.models import appmaker
+from tutorial.security import groupfinder
def main(global_config, **settings):
""" This function returns a WSGI application.
@@ -8,6 +13,9 @@ def main(global_config, **settings):
It is usually called by the PasteDeploy framework during
``paster serve``.
"""
+ authn_policy = AuthTktAuthenticationPolicy(secret='sosecret',
+ callback=groupfinder)
+ authz_policy = ACLAuthorizationPolicy()
zodb_uri = settings.get('zodb_uri')
if zodb_uri is None:
raise ValueError("No 'zodb_uri' in application configuration.")
@@ -15,6 +23,9 @@ def main(global_config, **settings):
finder = PersistentApplicationFinder(zodb_uri, appmaker)
def get_root(request):
return finder(request.environ)
- config = Configurator(root_factory=get_root, settings=settings)
- config.load_zcml('configure.zcml')
+ config = Configurator(root_factory=get_root, settings=settings,
+ authentication_policy=authn_policy,
+ authorization_policy=authz_policy)
+ config.add_static_view('static', 'tutorial:static')
+ config.scan('tutorial')
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/configure.zcml b/docs/tutorials/wiki/src/authorization/tutorial/configure.zcml
deleted file mode 100644
index d0e65516e..000000000
--- a/docs/tutorials/wiki/src/authorization/tutorial/configure.zcml
+++ /dev/null
@@ -1,25 +0,0 @@
-<configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- this must be included for the view declarations to work -->
- <include package="pyramid.includes" />
-
- <scan package="."/>
-
- <view
- view=".login.login"
- renderer="templates/login.pt"
- context="pyramid.exceptions.Forbidden"/>
-
- <authtktauthenticationpolicy
- secret="sosecret"
- callback=".security.groupfinder"
- />
-
- <aclauthorizationpolicy/>
-
- <static
- name="static"
- path="static"
- />
-
-</configure>
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/login.py b/docs/tutorials/wiki/src/authorization/tutorial/login.py
index a1194feb0..59e71a1d9 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/login.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/login.py
@@ -1,15 +1,16 @@
from pyramid.httpexceptions import HTTPFound
-from pyramid.view import view_config
-from pyramid.url import resource_url
-
from pyramid.security import remember
from pyramid.security import forget
+from pyramid.view import view_config
+from pyramid.url import resource_url
-from tutorial.models import Wiki
from tutorial.security import USERS
-@view_config(context=Wiki, name='login', renderer='templates/login.pt')
+@view_config(context='pyramid.exceptions.Forbidden',
+ renderer='templates/login.pt')
+@view_config(context='tutorial.models.Wiki', name='login',
+ renderer='templates/login.pt')
def login(request):
login_url = resource_url(request.context, request, 'login')
referrer = request.url
@@ -36,7 +37,7 @@ def login(request):
password = password,
)
-@view_config(context=Wiki, name='logout')
+@view_config(context='tutorial.models.Wiki', name='logout')
def logout(request):
headers = forget(request)
return HTTPFound(location = resource_url(request.context, request),
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py
index 3143ab552..183cb2a8d 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py
@@ -3,22 +3,20 @@ import re
from pyramid.httpexceptions import HTTPFound
from pyramid.url import resource_url
-
-from pyramid.security import authenticated_userid
-
from pyramid.view import view_config
+from pyramid.security import authenticated_userid
from tutorial.models import Page
-from tutorial.models import Wiki
# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
-@view_config(context=Wiki, permission='view')
+@view_config(context='tutorial.models.Wiki', permission='view')
def view_wiki(context, request):
return HTTPFound(location = resource_url(context, request, 'FrontPage'))
-@view_config(context=Page, renderer='templates/view.pt', permission='view')
+@view_config(context='tutorial.models.Page',
+ renderer='templates/view.pt', permission='view')
def view_page(context, request):
wiki = context.__parent__
@@ -41,7 +39,8 @@ def view_page(context, request):
return dict(page = context, content = content, edit_url = edit_url,
logged_in = logged_in)
-@view_config(context=Wiki, name='add_page', renderer='templates/edit.pt',
+@view_config(name='add_page', context='tutorial.models.Wiki',
+ renderer='templates/edit.pt',
permission='edit')
def add_page(context, request):
name = request.subpath[0]
@@ -61,7 +60,8 @@ def add_page(context, request):
return dict(page = page, save_url = save_url, logged_in = logged_in)
-@view_config(context=Page, name='edit_page', renderer='templates/edit.pt',
+@view_config(name='edit_page', context='tutorial.models.Page',
+ renderer='templates/edit.pt',
permission='edit')
def edit_page(context, request):
if 'form.submitted' in request.params:
diff --git a/docs/tutorials/wiki/src/basiclayout/CHANGES.txt b/docs/tutorials/wiki/src/basiclayout/CHANGES.txt
index ffa255da8..35a34f332 100644
--- a/docs/tutorials/wiki/src/basiclayout/CHANGES.txt
+++ b/docs/tutorials/wiki/src/basiclayout/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version
diff --git a/docs/tutorials/wiki/src/basiclayout/development.ini b/docs/tutorials/wiki/src/basiclayout/development.ini
index fdae922e9..6f4c33d93 100644
--- a/docs/tutorials/wiki/src/basiclayout/development.ini
+++ b/docs/tutorials/wiki/src/basiclayout/development.ini
@@ -4,10 +4,13 @@ reload_templates = true
debug_authorization = false
debug_notfound = false
debug_routematch = false
+debug_templates = true
+default_locale_name = en
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
pipeline =
+ egg:WebError#evalerror
egg:repoze.zodbconn#closer
egg:repoze.tm#tm
tutorial
@@ -16,3 +19,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki/src/basiclayout/setup.cfg b/docs/tutorials/wiki/src/basiclayout/setup.cfg
index 3d7ea6e23..23b2ad983 100644
--- a/docs/tutorials/wiki/src/basiclayout/setup.cfg
+++ b/docs/tutorials/wiki/src/basiclayout/setup.cfg
@@ -25,4 +25,3 @@ domain = tutorial
input_file = tutorial/locale/tutorial.pot
output_dir = tutorial/locale
previous = true
-
diff --git a/docs/tutorials/wiki/src/basiclayout/setup.py b/docs/tutorials/wiki/src/basiclayout/setup.py
index a0de6ec81..7fb15b782 100644
--- a/docs/tutorials/wiki/src/basiclayout/setup.py
+++ b/docs/tutorials/wiki/src/basiclayout/setup.py
@@ -19,9 +19,8 @@ setup(name='tutorial',
description='tutorial',
long_description=README + '\n\n' + CHANGES,
classifiers=[
- "Intended Audience :: Developers",
- "Framework :: Pylons",
"Programming Language :: Python",
+ "Framework :: Pylons",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
],
@@ -32,8 +31,8 @@ setup(name='tutorial',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
- install_requires=requires,
- tests_require=requires,
+ install_requires = requires,
+ tests_require= requires,
test_suite="tutorial",
entry_points = """\
[paste.app_factory]
@@ -41,3 +40,4 @@ setup(name='tutorial',
""",
paster_plugins=['pyramid'],
)
+
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py
index 8325865c0..a9f776980 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py
@@ -13,6 +13,6 @@ def main(global_config, **settings):
def get_root(request):
return finder(request.environ)
config = Configurator(root_factory=get_root, settings=settings)
- config.load_zcml('configure.zcml')
+ config.add_static_view('static', 'tutorial:static')
+ config.scan('tutorial')
return config.make_wsgi_app()
-
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/configure.zcml b/docs/tutorials/wiki/src/basiclayout/tutorial/configure.zcml
deleted file mode 100644
index ab7fd6fbe..000000000
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/configure.zcml
+++ /dev/null
@@ -1,17 +0,0 @@
-<configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- this must be included for the view declarations to work -->
- <include package="pyramid.includes" />
-
- <view
- context=".models.MyModel"
- view=".views.my_view"
- renderer="templates/mytemplate.pt"
- />
-
- <static
- name="static"
- path="static"
- />
-
-</configure>
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
index a5a0dd214..6ad23d44f 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -8,57 +8,67 @@
<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>
+ <![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="header">
+ <div class="header">The Pyramid Web Application Development Framework</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="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>
- <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">
+ <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>
+ <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/">The Pylons Project Documentation</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>
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
index 26ee6671e..0a3d507a0 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
@@ -16,3 +16,4 @@ class ViewTests(unittest.TestCase):
request = testing.DummyRequest()
info = my_view(request)
self.assertEqual(info['project'], 'tutorial')
+
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
index 93d619d83..555f49e6d 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
@@ -1,2 +1,6 @@
+from pyramid.view import view_config
+from tutorial.models import MyModel
+
+@view_config(context=MyModel, renderer='tutorial:templates/mytemplate.pt')
def my_view(request):
return {'project':'tutorial'}
diff --git a/docs/tutorials/wiki/src/models/development.ini b/docs/tutorials/wiki/src/models/development.ini
index fdae922e9..6f4c33d93 100644
--- a/docs/tutorials/wiki/src/models/development.ini
+++ b/docs/tutorials/wiki/src/models/development.ini
@@ -4,10 +4,13 @@ reload_templates = true
debug_authorization = false
debug_notfound = false
debug_routematch = false
+debug_templates = true
+default_locale_name = en
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
pipeline =
+ egg:WebError#evalerror
egg:repoze.zodbconn#closer
egg:repoze.tm#tm
tutorial
@@ -16,3 +19,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki/src/models/tutorial/__init__.py b/docs/tutorials/wiki/src/models/tutorial/__init__.py
index cf0d14b2d..bf0f683bf 100644
--- a/docs/tutorials/wiki/src/models/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/models/tutorial/__init__.py
@@ -4,9 +4,6 @@ from tutorial.models import appmaker
def main(global_config, **settings):
""" This function returns a WSGI application.
-
- It is usually called by the PasteDeploy framework during
- ``paster serve``.
"""
zodb_uri = settings.get('zodb_uri')
if zodb_uri is None:
@@ -16,6 +13,7 @@ def main(global_config, **settings):
def get_root(request):
return finder(request.environ)
config = Configurator(root_factory=get_root, settings=settings)
- config.load_zcml('configure.zcml')
+ config.add_static_view('static', 'tutorial:static')
+ config.scan('tutorial')
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/models/tutorial/configure.zcml b/docs/tutorials/wiki/src/models/tutorial/configure.zcml
deleted file mode 100644
index 38675eb13..000000000
--- a/docs/tutorials/wiki/src/models/tutorial/configure.zcml
+++ /dev/null
@@ -1,17 +0,0 @@
-<configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- this must be included for the view declarations to work -->
- <include package="pyramid.includes" />
-
- <view
- context=".models.Wiki"
- view=".views.my_view"
- renderer="templates/mytemplate.pt"
- />
-
- <static
- name="static"
- path="static"
- />
-
-</configure>
diff --git a/docs/tutorials/wiki/src/models/tutorial/views.py b/docs/tutorials/wiki/src/models/tutorial/views.py
index 93d619d83..2346602c9 100644
--- a/docs/tutorials/wiki/src/models/tutorial/views.py
+++ b/docs/tutorials/wiki/src/models/tutorial/views.py
@@ -1,2 +1,5 @@
+from pyramid.view import view_config
+
+@view_config(renderer='tutorial:templates/mytemplate.pt')
def my_view(request):
return {'project':'tutorial'}
diff --git a/docs/tutorials/wiki/src/viewdecorators/CHANGES.txt b/docs/tutorials/wiki/src/viewdecorators/CHANGES.txt
deleted file mode 100644
index ffa255da8..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/CHANGES.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-0.0
----
-
-- Initial version
diff --git a/docs/tutorials/wiki/src/viewdecorators/README.txt b/docs/tutorials/wiki/src/viewdecorators/README.txt
deleted file mode 100644
index d41f7f90f..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/README.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-tutorial README
-
-
-
diff --git a/docs/tutorials/wiki/src/viewdecorators/development.ini b/docs/tutorials/wiki/src/viewdecorators/development.ini
deleted file mode 100644
index a102b721b..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/development.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-[app:tutorial]
-use = egg:tutorial
-reload_templates = true
-debug_authorization = false
-debug_notfound = false
-debug_routematch = false
-zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
-
-[pipeline:main]
-pipeline =
- egg:repoze.zodbconn#closer
- egg:Paste#evalerror
- egg:repoze.tm#tm
- tutorial
-
-[server:main]
-use = egg:Paste#http
-host = 0.0.0.0
-port = 6543
diff --git a/docs/tutorials/wiki/src/viewdecorators/setup.cfg b/docs/tutorials/wiki/src/viewdecorators/setup.cfg
deleted file mode 100644
index 3d7ea6e23..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/setup.cfg
+++ /dev/null
@@ -1,28 +0,0 @@
-[nosetests]
-match=^test
-nocapture=1
-cover-package=tutorial
-with-coverage=1
-cover-erase=1
-
-[compile_catalog]
-directory = tutorial/locale
-domain = tutorial
-statistics = true
-
-[extract_messages]
-add_comments = TRANSLATORS:
-output_file = tutorial/locale/tutorial.pot
-width = 80
-
-[init_catalog]
-domain = tutorial
-input_file = tutorial/locale/tutorial.pot
-output_dir = tutorial/locale
-
-[update_catalog]
-domain = tutorial
-input_file = tutorial/locale/tutorial.pot
-output_dir = tutorial/locale
-previous = true
-
diff --git a/docs/tutorials/wiki/src/viewdecorators/setup.py b/docs/tutorials/wiki/src/viewdecorators/setup.py
deleted file mode 100644
index 5ee1333bc..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/setup.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import os
-
-from setuptools import setup, find_packages
-
-here = os.path.abspath(os.path.dirname(__file__))
-README = open(os.path.join(here, 'README.txt')).read()
-CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
-
-requires = [
- 'pyramid',
- 'repoze.zodbconn',
- 'repoze.tm',
- 'ZODB3',
- 'WebError',
- 'docutils',
- ]
-
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Intended Audience :: Developers",
- "Framework :: Pylons",
- "Programming Language :: Python",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- install_requires=requires,
- tests_require=requires,
- test_suite="tutorial",
- entry_points = """\
- [paste.app_factory]
- main = tutorial:main
- """,
- paster_plugins = ['pyramid'],
- )
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/__init__.py b/docs/tutorials/wiki/src/viewdecorators/tutorial/__init__.py
deleted file mode 100644
index cf0d14b2d..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/__init__.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from pyramid.config import Configurator
-from repoze.zodbconn.finder import PersistentApplicationFinder
-from tutorial.models import appmaker
-
-def main(global_config, **settings):
- """ This function returns a WSGI application.
-
- It is usually called by the PasteDeploy framework during
- ``paster serve``.
- """
- zodb_uri = settings.get('zodb_uri')
- if zodb_uri is None:
- raise ValueError("No 'zodb_uri' in application configuration.")
-
- finder = PersistentApplicationFinder(zodb_uri, appmaker)
- def get_root(request):
- return finder(request.environ)
- config = Configurator(root_factory=get_root, settings=settings)
- config.load_zcml('configure.zcml')
- return config.make_wsgi_app()
-
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/configure.zcml b/docs/tutorials/wiki/src/viewdecorators/tutorial/configure.zcml
deleted file mode 100644
index be5b84c43..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/configure.zcml
+++ /dev/null
@@ -1,13 +0,0 @@
-<configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- this must be included for the view declarations to work -->
- <include package="pyramid.includes" />
-
- <scan package="."/>
-
- <static
- name="static"
- path="static"
- />
-
-</configure>
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/models.py b/docs/tutorials/wiki/src/viewdecorators/tutorial/models.py
deleted file mode 100644
index 9761856c6..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/models.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from persistent import Persistent
-from persistent.mapping import PersistentMapping
-
-class Wiki(PersistentMapping):
- __name__ = None
- __parent__ = None
-
-class Page(Persistent):
- def __init__(self, data):
- self.data = data
-
-def appmaker(zodb_root):
- if not 'app_root' in zodb_root:
- app_root = Wiki()
- frontpage = Page('This is the front page')
- app_root['FrontPage'] = frontpage
- frontpage.__name__ = 'FrontPage'
- frontpage.__parent__ = app_root
- zodb_root['app_root'] = app_root
- import transaction
- transaction.commit()
- return zodb_root['app_root']
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/static/favicon.ico b/docs/tutorials/wiki/src/viewdecorators/tutorial/static/favicon.ico
deleted file mode 100644
index 71f837c9e..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/static/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/static/logo.png b/docs/tutorials/wiki/src/viewdecorators/tutorial/static/logo.png
deleted file mode 100644
index 88f5d9865..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/static/pylons.css b/docs/tutorials/wiki/src/viewdecorators/tutorial/static/pylons.css
deleted file mode 100644
index c153be07f..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/static/pylons.css
+++ /dev/null
@@ -1,73 +0,0 @@
-html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;/* 16px */
-vertical-align:baseline;background:transparent;}
-body{line-height:1;}
-ol,ul{list-style:none;}
-blockquote,q{quotes:none;}
-blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}
-/* 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;}
-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;}
-a{color:#1b61d6;text-decoration:none;}
-a:hover{color:#e88f00;text-decoration:underline;}
-body h1,
-body h2,
-body h3,
-body h4,
-body h5,
-body h6{font-family:"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;}
-.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;}
-.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;}
-.align-left{text-align:left;}
-.align-right{text-align:right;}
-.align-center{text-align:center;}
-ul.links{margin:0;padding:0;}
-ul.links li{list-style-type:none;font-size:14px;}
-form{border-style:none;}
-fieldset{border-style:none;}
-input{color:#222;border:1px solid #ccc;font-family:sans-serif;font-size:12px;line-height:16px;}
-input[type=text]{}
-input[type=submit]{background-color:#ddd;font-weight:bold;}
-/*Opera Fix*/
-body:before {content:"";height:100%;float:left;width:0;margin-top:-32767px;}
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/static/style.css b/docs/tutorials/wiki/src/viewdecorators/tutorial/static/style.css
deleted file mode 100644
index cad87e0d4..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/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/viewdecorators/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/viewdecorators/tutorial/templates/edit.pt
deleted file mode 100644
index 525bd43df..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/templates/edit.pt
+++ /dev/null
@@ -1,30 +0,0 @@
-<!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">
-
-<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" />
-</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>
-</body>
-</html>
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/viewdecorators/tutorial/templates/mytemplate.pt
deleted file mode 100644
index a5a0dd214..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/templates/mytemplate.pt
+++ /dev/null
@@ -1,69 +0,0 @@
-<!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 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" />
-</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>
- </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>
- <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>
- </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/tutorials/wiki/src/viewdecorators/tutorial/templates/view.pt b/docs/tutorials/wiki/src/viewdecorators/tutorial/templates/view.pt
deleted file mode 100644
index 0fc68aa2f..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/templates/view.pt
+++ /dev/null
@@ -1,26 +0,0 @@
-<!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">
-
-<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" />
-</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>
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/tests.py b/docs/tutorials/wiki/src/viewdecorators/tutorial/tests.py
deleted file mode 100644
index aaf753816..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/tests.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import unittest
-
-from pyramid import testing
-
-class PageModelTests(unittest.TestCase):
-
- def _getTargetClass(self):
- from tutorial.models import Page
- return Page
-
- def _makeOne(self, data=u'some data'):
- return self._getTargetClass()(data=data)
-
- def test_constructor(self):
- instance = self._makeOne()
- self.assertEqual(instance.data, u'some data')
-
-class WikiModelTests(unittest.TestCase):
-
- def _getTargetClass(self):
- from tutorial.models import Wiki
- return Wiki
-
- def _makeOne(self):
- return self._getTargetClass()()
-
- def test_it(self):
- wiki = self._makeOne()
- self.assertEqual(wiki.__parent__, None)
- self.assertEqual(wiki.__name__, None)
-
-class AppmakerTests(unittest.TestCase):
- def _callFUT(self, zodb_root):
- from tutorial.models import appmaker
- return appmaker(zodb_root)
-
- def test_it(self):
- root = {}
- self._callFUT(root)
- self.assertEqual(root['app_root']['FrontPage'].data,
- 'This is the front page')
-
-class ViewWikiTests(unittest.TestCase):
- def test_it(self):
- from tutorial.views import view_wiki
- context = testing.DummyResource()
- request = testing.DummyRequest()
- response = view_wiki(context, request)
- self.assertEqual(response.location, 'http://example.com/FrontPage')
-
-class ViewPageTests(unittest.TestCase):
- def _callFUT(self, context, request):
- from tutorial.views import view_page
- return view_page(context, request)
-
- def test_it(self):
- wiki = testing.DummyResource()
- wiki['IDoExist'] = testing.DummyResource()
- context = testing.DummyResource(data='Hello CruelWorld IDoExist')
- context.__parent__ = wiki
- context.__name__ = 'thepage'
- request = testing.DummyRequest()
- info = self._callFUT(context, request)
- self.assertEqual(info['page'], context)
- self.assertEqual(
- info['content'],
- '<div class="document">\n'
- '<p>Hello <a href="http://example.com/add_page/CruelWorld">'
- 'CruelWorld</a> '
- '<a href="http://example.com/IDoExist/">'
- 'IDoExist</a>'
- '</p>\n</div>\n')
- self.assertEqual(info['edit_url'],
- 'http://example.com/thepage/edit_page')
-
-
-class AddPageTests(unittest.TestCase):
- def _callFUT(self, context, request):
- from tutorial.views import add_page
- return add_page(context, request)
-
- def test_it_notsubmitted(self):
- from pyramid.url import resource_url
- context = testing.DummyResource()
- request = testing.DummyRequest()
- request.subpath = ['AnotherPage']
- info = self._callFUT(context, request)
- self.assertEqual(info['page'].data,'')
- self.assertEqual(info['save_url'],
- resource_url(
- context, request, 'add_page', 'AnotherPage'))
-
- def test_it_submitted(self):
- context = testing.DummyResource()
- request = testing.DummyRequest({'form.submitted':True,
- 'body':'Hello yo!'})
- request.subpath = ['AnotherPage']
- self._callFUT(context, request)
- page = context['AnotherPage']
- self.assertEqual(page.data, 'Hello yo!')
- self.assertEqual(page.__name__, 'AnotherPage')
- self.assertEqual(page.__parent__, context)
-
-class EditPageTests(unittest.TestCase):
- def _callFUT(self, context, request):
- from tutorial.views import edit_page
- return edit_page(context, request)
-
- def test_it_notsubmitted(self):
- from pyramid.url import resource_url
- context = testing.DummyResource()
- request = testing.DummyRequest()
- info = self._callFUT(context, request)
- self.assertEqual(info['page'], context)
- self.assertEqual(info['save_url'],
- resource_url(context, request, 'edit_page'))
-
- def test_it_submitted(self):
- context = testing.DummyResource()
- request = testing.DummyRequest({'form.submitted':True,
- 'body':'Hello yo!'})
- response = self._callFUT(context, request)
- self.assertEqual(response.location, 'http://example.com/')
- self.assertEqual(context.data, 'Hello yo!')
diff --git a/docs/tutorials/wiki/src/viewdecorators/tutorial/views.py b/docs/tutorials/wiki/src/viewdecorators/tutorial/views.py
deleted file mode 100644
index c8ac46edf..000000000
--- a/docs/tutorials/wiki/src/viewdecorators/tutorial/views.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from docutils.core import publish_parts
-import re
-
-from pyramid.httpexceptions import HTTPFound
-from pyramid.url import resource_url
-from pyramid.view import view_config
-
-from tutorial.models import Page
-from tutorial.models import Wiki
-
-# regular expression used to find WikiWords
-wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
-
-@view_config(context=Wiki)
-def view_wiki(context, request):
- return HTTPFound(location = resource_url(context, request, 'FrontPage'))
-
-@view_config(context=Page, renderer='templates/view.pt')
-def view_page(context, request):
- wiki = context.__parent__
-
- def check(match):
- word = match.group(1)
- if word in wiki:
- page = wiki[word]
- view_url = resource_url(page, request)
- return '<a href="%s">%s</a>' % (view_url, word)
- else:
- add_url = request.application_url + '/add_page/' + word
- return '<a href="%s">%s</a>' % (add_url, word)
-
- content = publish_parts(context.data, writer_name='html')['html_body']
- content = wikiwords.sub(check, content)
- edit_url = resource_url(context, request, 'edit_page')
- return dict(page = context, content = content, edit_url = edit_url)
-
-@view_config(context=Wiki, name='add_page', renderer='templates/edit.pt')
-def add_page(context, request):
- name = request.subpath[0]
- if 'form.submitted' in request.params:
- body = request.params['body']
- page = Page(body)
- page.__name__ = name
- page.__parent__ = context
- context[name] = page
- return HTTPFound(location = resource_url(page, request))
- save_url = resource_url(context, request, 'add_page', name)
- page = Page('')
- page.__name__ = name
- page.__parent__ = context
- return dict(page = page, save_url = save_url)
-
-@view_config(context=Page, name='edit_page', renderer='templates/edit.pt')
-def edit_page(context, request):
- if 'form.submitted' in request.params:
- context.data = request.params['body']
- return HTTPFound(location = resource_url(context, request))
-
- return dict(page = context,
- save_url = resource_url(context, request, 'edit_page'))
-
-
diff --git a/docs/tutorials/wiki/src/views/development.ini b/docs/tutorials/wiki/src/views/development.ini
index a102b721b..6f4c33d93 100644
--- a/docs/tutorials/wiki/src/views/development.ini
+++ b/docs/tutorials/wiki/src/views/development.ini
@@ -4,12 +4,14 @@ reload_templates = true
debug_authorization = false
debug_notfound = false
debug_routematch = false
+debug_templates = true
+default_locale_name = en
zodb_uri = file://%(here)s/Data.fs?connection_cache_size=20000
[pipeline:main]
pipeline =
+ egg:WebError#evalerror
egg:repoze.zodbconn#closer
- egg:Paste#evalerror
egg:repoze.tm#tm
tutorial
@@ -17,3 +19,29 @@ pipeline =
use = egg:Paste#http
host = 0.0.0.0
port = 6543
+
+# Begin logging configuration
+
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
+
+# End logging configuration
diff --git a/docs/tutorials/wiki/src/views/tutorial/__init__.py b/docs/tutorials/wiki/src/views/tutorial/__init__.py
index cf0d14b2d..91f7c2624 100644
--- a/docs/tutorials/wiki/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/views/tutorial/__init__.py
@@ -4,9 +4,6 @@ from tutorial.models import appmaker
def main(global_config, **settings):
""" This function returns a WSGI application.
-
- It is usually called by the PasteDeploy framework during
- ``paster serve``.
"""
zodb_uri = settings.get('zodb_uri')
if zodb_uri is None:
@@ -16,6 +13,6 @@ def main(global_config, **settings):
def get_root(request):
return finder(request.environ)
config = Configurator(root_factory=get_root, settings=settings)
- config.load_zcml('configure.zcml')
+ config.add_static_view('static', 'tutorial:static')
+ config.scan('tutorial')
return config.make_wsgi_app()
-
diff --git a/docs/tutorials/wiki/src/views/tutorial/configure.zcml b/docs/tutorials/wiki/src/views/tutorial/configure.zcml
deleted file mode 100644
index c1b1d6ce8..000000000
--- a/docs/tutorials/wiki/src/views/tutorial/configure.zcml
+++ /dev/null
@@ -1,36 +0,0 @@
-<configure xmlns="http://pylonshq.com/pyramid">
-
- <!-- this must be included for the view declarations to work -->
- <include package="pyramid.includes" />
-
- <static
- name="static"
- path="static"
- />
-
- <view
- context=".models.Wiki"
- view=".views.view_wiki"
- />
-
- <view
- context=".models.Wiki"
- name="add_page"
- view=".views.add_page"
- renderer="templates/edit.pt"
- />
-
- <view
- context=".models.Page"
- view=".views.view_page"
- renderer="templates/view.pt"
- />
-
- <view
- context=".models.Page"
- name="edit_page"
- view=".views.edit_page"
- renderer="templates/edit.pt"
- />
-
-</configure>
diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py
index 8437fdc51..c96bc2e9c 100644
--- a/docs/tutorials/wiki/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki/src/views/tutorial/views.py
@@ -3,15 +3,19 @@ import re
from pyramid.httpexceptions import HTTPFound
from pyramid.url import resource_url
+from pyramid.view import view_config
from tutorial.models import Page
# regular expression used to find WikiWords
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'))
+@view_config(context='tutorial.models.Page',
+ renderer='tutorial:templates/view.pt')
def view_page(context, request):
wiki = context.__parent__
@@ -29,7 +33,9 @@ def view_page(context, request):
content = wikiwords.sub(check, content)
edit_url = resource_url(context, request, 'edit_page')
return dict(page = context, content = content, edit_url = edit_url)
-
+
+@view_config(name='add_page', context='tutorial.models.Wiki',
+ renderer='tutorial:templates/edit.pt')
def add_page(context, request):
name = request.subpath[0]
if 'form.submitted' in request.params:
@@ -44,7 +50,9 @@ def add_page(context, request):
page.__name__ = name
page.__parent__ = context
return dict(page = page, save_url = save_url)
-
+
+@view_config(name='edit_page', context='tutorial.models.Page',
+ renderer='tutorial:templates/edit.pt')
def edit_page(context, request):
if 'form.submitted' in request.params:
context.data = request.params['body']
diff --git a/docs/tutorials/wiki/viewdecorators.rst b/docs/tutorials/wiki/viewdecorators.rst
deleted file mode 100644
index c2f068d86..000000000
--- a/docs/tutorials/wiki/viewdecorators.rst
+++ /dev/null
@@ -1,240 +0,0 @@
-==========================================================
-Using View Decorators Rather than ZCML ``view`` directives
-==========================================================
-
-So far we've been using :term:`ZCML` to map model types to views.
-It's often easier to use the :class:`pyramid.view.view_config` view
-decorator to do this mapping. Using view decorators provides better
-locality of reference for the mapping, because you can see which model
-types and view names the view will serve right next to the view
-function itself. In this mode, however, you lose the ability for some
-views to be overridden "from the outside" (by someone using your
-application as a framework, as explained in the
-:ref:`extending_chapter`). Since this application is not meant to be
-a framework, it makes sense for us to switch over to using view
-decorators.
-
-Adding View Decorators
-======================
-
-We're going to import the :class:`pyramid.view.view_config` callable.
-This callable can be used as a function, class, or method decorator.
-We'll use it to decorate our ``view_wiki``, ``view_page``,
-``add_page`` and ``edit_page`` view functions.
-
-The :class:`pyramid.view.view_config` callable accepts a number of
-arguments:
-
-``context``
-
- The model type which the :term:`context` of our view will be, in our
- case a class.
-
-``name``
-
- The name of the view.
-
-``renderer``
-
- The renderer (usually a *template name*) that will be used when the
- view returns a non-:term:`response` object.
-
-There are other arguments which this callable accepts, but these are
-the ones we're going to use.
-
-The ``view_wiki`` view function
--------------------------------
-
-The decorator above the ``view_wiki`` function will be:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- @view_config(context=Wiki)
-
-This indicates that the view is for the Wiki class and has the *empty*
-view_name (indicating the :term:`default view` for the Wiki class).
-After injecting this decorator, we can now *remove* the following from
-our ``configure.zcml`` file:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".models.Wiki"
- view=".views.view_wiki"
- />
-
-Our new decorator takes its place.
-
-The ``view_page`` view function
--------------------------------
-
-The decorator above the ``view_page`` function will be:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- @view_config(context=Page, renderer='templates/view.pt')
-
-This indicates that the view is for the Page class and has the *empty*
-view_name (indicating the :term:`default view` for the Page class).
-After injecting this decorator, we can now *remove* the following from
-our ``configure.zcml`` file:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".models.Page"
- view=".views.view_page"
- renderer="templates/view.pt"
- />
-
-Our new decorator takes its place.
-
-The ``add_page`` view function
-------------------------------
-
-The decorator above the ``add_page`` function will be:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- @view_config(context=Wiki, name='add_page', renderer='templates/edit.pt')
-
-This indicates that the view is for the Wiki class and has the
-``add_page`` view_name. After injecting this decorator, we can now
-*remove* the following from our ``configure.zcml`` file:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".models.Wiki"
- name="add_page"
- view=".views.add_page"
- renderer="templates/edit.pt"
- />
-
-Our new decorator takes its place.
-
-The ``edit_page`` view function
--------------------------------
-
-The decorator above the ``edit_page`` function will be:
-
-.. ignore-next-block
-.. code-block:: python
- :linenos:
-
- @view_config(context=Page, name='edit_page', renderer='templates/edit.pt')
-
-This indicates that the view is for the Page class and has the
-``edit_page`` view_name. After injecting this decorator, we can now
-*remove* the following from our ``configure.zcml`` file:
-
-.. code-block:: xml
- :linenos:
-
- <view
- context=".models.Page"
- name="edit_page"
- view=".views.edit_page"
- renderer="templates/edit.pt"
- />
-
-Our new decorator takes its place.
-
-Adding a Scan Directive
-=======================
-
-In order for our decorators to be recognized, we must add a bit of
-boilerplate to our ``configure.zcml`` file which tells
-:app:`Pyramid` to kick off a :term:`scan` at startup time. Add the
-following tag anywhere beneath the ``<include
-package="pyramid.includes">`` tag but before the ending
-``</configure>`` tag within ``configure.zcml``:
-
-.. code-block:: xml
- :linenos:
-
- <scan package="."/>
-
-Viewing the Result of Our Edits to ``views.py``
-===============================================
-
-The result of all of our edits to ``views.py`` will leave it looking
-like this:
-
-.. literalinclude:: src/viewdecorators/tutorial/views.py
- :linenos:
- :language: python
-
-Viewing the Results of Our Edits to ``configure.zcml``
-======================================================
-
-The result of all of our edits to ``configure.zcml`` will leave it
-looking like this:
-
-.. literalinclude:: src/viewdecorators/tutorial/configure.zcml
- :linenos:
- :language: xml
-
-Running the Tests
-=================
-
-We can run these tests by using ``setup.py test`` in the same way we
-did in :ref:`running_tests`. Assuming our shell's current working
-directory is the "tutorial" distribution directory:
-
-On UNIX:
-
-.. code-block:: text
-
- $ ../bin/python setup.py test -q
-
-On Windows:
-
-.. code-block:: text
-
- c:\bigfntut\tutorial> ..\Scripts\python setup.py test -q
-
-Hopefully nothing will have changed. The expected result looks
-something like:
-
-.. code-block:: text
-
- .........
- ----------------------------------------------------------------------
- Ran 9 tests in 0.203s
-
- OK
-
-Viewing the Application in a Browser
-====================================
-
-Once we've set up the WSGI pipeline properly, we can finally examine
-our application in a browser. We'll make sure that we didn't break
-any views by trying each of them.
-
-- Visiting ``http://localhost:6543/`` in a
- browser invokes the ``view_wiki`` view. This always redirects to
- the ``view_page`` view of the FrontPage page object.
-
-- Visiting ``http://localhost:6543/FrontPage/`` in a browser invokes
- the ``view_page`` view of the front page page object. This is
- because it's the *default view* (a view without a ``name``) for Page
- objects.
-
-- Visiting ``http://localhost:6543/FrontPage/edit_page`` in a browser
- invokes the edit view for the front page object.
-
-- Visiting ``http://localhost:6543/add_page/SomePageName`` in a
- browser invokes the add view for a page.
-
-
-