Skip to content
Browse files

Merge branch 'master' of github.com:Pylons/pyramid

  • Loading branch information...
2 parents 2c6f63a + fca8f01 commit 3c7d5c803c6e0cf3f51ffc0577b087e7c14855fb @mcdonc mcdonc committed Mar 17, 2012
View
76 docs/tutorials/wiki2/authorization.rst
@@ -7,8 +7,8 @@ Adding Authorization
:app:`Pyramid` provides facilities for :term:`authentication` and
:term:`authorization`. 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. We'll change our
-application to allow only people whom possess a specific username (`editor`)
+the server to view, edit, and add pages to our wiki. We'll change that
+to allow only people who possess a specific username (`editor`)
to add and edit wiki pages but we'll continue allowing anyone with access to
the server to view pages.
@@ -41,13 +41,12 @@ Open ``models.py`` and add the following statements:
:language: python
We're going to start to use a custom :term:`root factory` within our
-``__init__.py`` file. The objects generated by the root factory will be used
-as the :term:`context` of each request to our application. We do this to
-allow :app:`Pyramid` declarative security to work properly. The context
-object generated by the root factory during a request will be decorated with
-security declarations. When we begin to use a custom root factory to generate
-our contexts, we can begin to make use of the declarative security features
-of :app:`Pyramid`.
+``__init__.py`` file. The objects generated by the root factory will
+be used as the :term:`context` of each request to our application.
+Those context objects will be decorated with security
+declarations. When we use a custom root factory to generate
+our contexts, we can begin to make use of the declarative security
+features of :app:`Pyramid`.
We'll modify our ``__init__.py``, passing in a :term:`root factory` to our
:term:`Configurator` constructor. We'll point it at the new class we created
@@ -65,10 +64,12 @@ to a context is interpreted specially by :app:`Pyramid` as an access control
list during view callable execution. See :ref:`assigning_acls` for more
information about what an :term:`ACL` represents.
-.. note: Although we don't use the functionality here, the ``factory`` used
- to create route contexts may differ per-route as opposed to globally. See
- the ``factory`` argument to
- :meth:`pyramid.config.Configurator.add_route` for more info.
+.. note::
+
+ Although we don't use the functionality here, the ``factory`` used
+ to create route contexts may differ per-route as opposed to globally. See
+ the ``factory`` argument to
+ :meth:`pyramid.config.Configurator.add_route` for more info.
We'll pass the ``RootFactory`` we created in the step above in as the
``root_factory`` argument to a :term:`Configurator`.
@@ -147,9 +148,10 @@ We've given the ``editor`` user membership to the ``group:editors`` by
mapping him to this group in the ``GROUPS`` data structure (``GROUPS =
{'editor':['group:editors']}``). Since the ``groupfinder`` function
consults the ``GROUPS`` data structure, this will mean that, as a
-result of the ACL attached to the root returned by the root factory,
-and the permission associated with the ``add_page`` and ``edit_page``
-views, the ``editor`` user should be able to add and edit pages.
+result of the ACL attached to the :term:`context` object returned by
+the root factory, and the permission associated with the ``add_page``
+and ``edit_page`` views, the ``editor`` user should be able to add and
+edit pages.
Adding Login and Logout Views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -176,20 +178,20 @@ The ``logout`` view callable will look something like this:
:language: python
The ``login`` view callable is decorated with two decorators, a
-``@view_config`` decorators, which associates it with the ``login`` route,
-the other a ``@forbidden_view_config`` decorator which turns it in to an
-:term:`exception view` when Pyramid raises a
-:class:`pyramid.httpexceptions.HTTPForbidden` exception. The one which
-associates it with the ``login`` route makes it visible when we visit
-``/login``. The other one makes it a :term:`forbidden view`. The forbidden
-view is displayed whenever Pyramid or your application raises an
-HTTPForbidden exception. In this case, we'll be relying on the forbidden
-view to show the login form whenver someone attempts to execute an action
-which they're not yet authorized to perform.
+``@view_config`` decorator, which associates it with the ``login``
+route, and a ``@forbidden_view_config`` decorator which turns it in to
+an :term:`exception view`. The one which associates it with the
+``login`` route makes it visible when we visit ``/login``. The other
+one makes it a :term:`forbidden view`. The forbidden view is
+displayed whenever Pyramid or your application raises an
+:class:`pyramid.httpexceptions.HTTPForbidden` exception. In this
+case, we'll be relying on the forbidden view to show the login form
+whenver someone attempts to execute an action which they're not yet
+authorized to perform.
The ``logout`` view callable is decorated with a ``@view_config`` decorator
which associates it with the ``logout`` route. This makes it visible when we
-visit ``/login``.
+visit ``/logout``.
We'll need to import some stuff to service the needs of these two functions:
the ``pyramid.view.forbidden_view_config`` class, a number of values from the
@@ -222,8 +224,8 @@ something like this to each view body:
Return a logged_in flag to the renderer
---------------------------------------
-We'll then change the return value of these views to pass the `resulting
-`logged_in`` value to the template, e.g.:
+We'll then change the return value of these views to pass the resulting
+``logged_in`` value to the template, e.g.:
.. code-block:: python
:linenos:
@@ -248,12 +250,14 @@ callables which these views reference cannot be invoked without the
authenticated user possessing the ``edit`` permission with respect to the
current :term:`context`.
-Adding these ``permission`` arguments causes Pyramid to make the assertion
-that only users who possess the effective ``edit`` permission at the time of
-the request may invoke those two views. We've granted the ``group:editors``
-principal the ``edit`` permission at the root model via its ACL, so only the
-a user whom is a member of the group named ``group:editors`` will able to
-invoke the views associated with the ``add_page`` or ``edit_page`` routes.
+Adding these ``permission`` arguments causes Pyramid to make the
+assertion that only users who possess the effective ``edit``
+permission at the time of the request may invoke those two views.
+We've granted the ``group:editors`` :term:`principal` the ``edit``
+permission in the :term:`root factory` via its ACL, so only a user who
+is a member of the group named ``group:editors`` will be able to
+invoke the views associated with the ``add_page`` or ``edit_page``
+routes.
Adding the ``login.pt`` Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -322,7 +326,7 @@ each of the following URLs, check that the result is as expected:
- ``http://localhost:6543/FrontPage`` invokes
the ``view_page`` view of the FrontPage page object.
-- ``http://localhost:6543/edit_page/FrontPage``
+- ``http://localhost:6543/FrontPage/edit_page``
invokes the edit view for the FrontPage object. It is executable by
only the ``editor`` user. If a different user (or the anonymous
user) invokes it, a login form will be displayed. Supplying the
View
15 docs/tutorials/wiki2/basiclayout.rst
@@ -74,7 +74,7 @@ dictionary of settings parsed from the ``.ini`` file, which contains
deployment-related values such as ``pyramid.reload_templates``,
``db_string``, etc.
-``'main`` now calls :meth:`pyramid.config.Configurator.add_static_view` with
+``main`` now calls :meth:`pyramid.config.Configurator.add_static_view` with
two arguments: ``static`` (the name), and ``static`` (the path):
.. literalinclude:: src/basiclayout/tutorial/__init__.py
@@ -123,10 +123,11 @@ Finally, ``main`` is finished configuring things, so it uses the
View Declarations via ``views.py``
----------------------------------
-Mapping a :term:`route` to code that will be executed when that route's
-pattern matches is done by registering a :term:`view configuration`. Our
-application uses the :meth:`pyramid.view.view_config` decorator to map view
-callables to each route, thereby mapping URL patterns to code.
+Mapping a :term:`route` to code that will be executed when a match for
+the route's pattern occurs is done by registering a :term:`view
+configuration`. Our application uses the
+:meth:`pyramid.view.view_config` decorator to map view callables to
+each route, thereby mapping URL patterns to code.
Open ``tutorial/tutorial/views.py``. It should already contain the following:
@@ -151,7 +152,7 @@ Note that ``my_view()`` accepts a single argument named ``request``. This is
the standard call signature for a Pyramid :term:`view callable`.
Remember in our ``__init__.py`` when we executed the
-:meth:`pyramid.config.Configurator.scan` method, e.g. ``config.scan()``? The
+:meth:`pyramid.config.Configurator.scan` method, i.e. ``config.scan()``? The
purpose of calling the scan method was to find and process this
``@view_config`` decorator in order to create a view configuration within our
application. Without being processed by ``scan``, the decorator effectively
@@ -199,7 +200,7 @@ To give a simple example of a model class, we define one named ``MyModel``:
:linenos:
:language: py
-Our sample model has an ``__init__`` that takes a two arguments (``name``,
+Our example model has an ``__init__`` that takes a two arguments (``name``,
and ``value``). It stores these values as ``self.name`` and ``self.value``
within the ``__init__`` function itself. The ``MyModel`` class also has a
``__tablename__`` attribute. This informs SQLAlchemy which table to use to
View
2 docs/tutorials/wiki2/definingmodels.rst
@@ -57,7 +57,7 @@ attribute that will hold the body of each page.
Changing ``scripts/initializedb.py``
------------------------------------
-We haven't looked at the guts of this file yet, but within the ``scripts``
+We haven't looked at the details of this file yet, but within the ``scripts``
directory of your ``tutorial`` package is a file named ``initializedb.py``. Code
in this file is executed whenever we run the ``initialize_tutorial_db`` command
(as we did in the installation step of this tutorial).
View
50 docs/tutorials/wiki2/definingviews.rst
@@ -157,17 +157,19 @@ that ``view_page()`` returns a dictionary (as opposed to a :term:`response`
object) is a cue to :app:`Pyramid` that it should try to use a :term:`renderer`
associated with the view configuration to render a template. In our case,
the template which will be rendered will be the ``templates/view.pt``
-template, as per the configuration put into effect in ``__init__.py``.
+template, as indicated in the ``@view_config`` decorator that is applied to
+``view_page()``.
The ``add_page`` view function
------------------------------
-``add_page()`` is 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 ``matchdict`` attribute of the request passed to the ``add_page()`` view
-will have the values we need to construct URLs and find model objects.
+``add_page()`` is 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.
+``add_page()`` also acts as a handler for the form that is generated
+when we want to add a page object. The ``matchdict`` attribute of the
+request passed to the ``add_page()`` view will have the values we need
+to construct URLs and find model objects.
.. literalinclude:: src/views/tutorial/views.py
:lines: 45-56
@@ -179,17 +181,17 @@ the page we'd like to add. If our add view is invoked via,
e.g. ``http://localhost:6543/add_page/SomeName``, the value for
``'pagename'`` in the ``matchdict`` will be ``'SomeName'``.
-If the view execution is *not* a result of a form submission (if the
+If the view execution is *not* a result of a form submission (i.e. the
expression ``'form.submitted' in request.params`` is ``False``), the view
callable renders a template. To do so, it generates a "save url" which the
template uses 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, 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 :app:`Pyramid` will render the template associated with this
-view to a response.
+we're going 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``. :app:`Pyramid` will render the template associated
+with this view to a response.
-If the view execution *is* a result of a form submission (if the expression
+If the view execution *is* a result of a form submission (i.e. the expression
``'form.submitted' in request.params`` is ``True``), we scrape the page body
from the form data, create a Page object with this page body and the name
taken from ``matchdict['pagename']``, and save it into the database using
@@ -210,12 +212,12 @@ matching the name of the page the user wants to edit.
:linenos:
:language: python
-If the view execution is *not* a result of a form submission (if the
+If the view execution is *not* a result of a form submission (i.e. the
expression ``'form.submitted' in request.params`` is ``False``), the view
simply renders the edit form, passing 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
+If the view execution *is* a result of a form submission (i.e. the expression
``'form.submitted' in request.params`` is ``True``), the view grabs the
``body`` element of the request parameters and sets it as the ``data``
attribute of the page object. It then redirects to the ``view_page`` view
@@ -231,11 +233,12 @@ The views we've added all reference a :term:`template`. Each template is a
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:
@@ -323,11 +326,14 @@ the order they're found in the ``__init__.py`` file.
``route_name='edit_page'``.
As a result of our edits, the ``__init__.py`` file should look
-something like so:
+something like:
.. literalinclude:: src/views/tutorial/__init__.py
:linenos:
:language: python
+ :emphasize-lines: 13-16
+
+(The highlighted lines are the ones that need to be added or edited.)
Viewing the Application in a Browser
====================================
View
12 docs/tutorials/wiki2/design.rst
@@ -4,7 +4,7 @@ Design
Following is a quick overview of our wiki application, to help
us understand the changes that we will be doing next in our
-default files generated by the paster scafffold.
+default files generated by the ``alchemy`` scaffold.
Overall
-------
@@ -34,9 +34,10 @@ be used as the wiki home page.
Views
-----
-There will be four views to handle the normal operations of
-viewing, editing and adding wiki pages. Two additional views
-will handle the login and logout tasks related to security.
+There will be four views to handle the normal operations of adding and
+editing wiki pages, and viewing pages and the wiki front page. Two
+additional views will handle the login and logout tasks related to
+security.
Security
--------
@@ -59,7 +60,8 @@ Security
| Allow | group:editors | Edit |
+----------+----------------+----------------+
-- Permission declarations for the views.
+- Permission declarations are added to the views to assert the
+ security policies as each request is handled.
Summary
View
8 docs/tutorials/wiki2/distributing.rst
@@ -27,12 +27,12 @@ The output of such a command will be something like:
running sdist
# ... more output ...
creating dist
- tar -cf dist/tutorial-0.1.tar tutorial-0.1
- gzip -f9 dist/tutorial-0.1.tar
- removing 'tutorial-0.1' (and everything under it)
+ tar -cf dist/tutorial-0.0.tar tutorial-0.0
+ gzip -f9 dist/tutorial-0.0.tar
+ removing 'tutorial-0.0' (and everything under it)
Note that this command creates a tarball in the "dist" subdirectory
-named ``tutorial-0.1.tar.gz``. You can send this file to your friends
+named ``tutorial-0.0.tar.gz``. You can send this file to your friends
to show them your cool new application. They should be able to
install it by pointing the ``easy_install`` command directly at it.
Or you can upload it to `PyPI <http://pypi.python.org>`_ and share it
View
2 docs/tutorials/wiki2/installation.rst
@@ -141,7 +141,7 @@ On Windows:
c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
-For a successful test run, you should see output like this::
+For a successful test run, you should see output that ends like this::
.
----------------------------------------------------------------------
View
33 docs/tutorials/wiki2/tests.rst
@@ -4,40 +4,38 @@ Adding Tests
We will now add tests for the models and the views and a few functional
tests in the ``tests.py``. Tests ensure that an application works, and
-that it continues to work after some changes are made in the future.
+that it continues to work after changes are made in the future.
Testing the Models
==================
-We write a test class for the model class ``Page`` and another test class
-for the ``initialize_sql`` function.
-
-To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a
-result of the ``alchemy`` scaffold. We'll add a test class named
-``PageModelTests`` for the ``Page`` model.
+To test the model class ``Page`` we'll add a new ``PageModelTests``
+class to our ``tests.py`` file that was generated as part of the
+``alchemy`` scaffold.
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`` class that the ``alchemy`` scaffold provided, 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.
Functional tests
================
-We test the whole application, covering security aspects that are not
+We'll test the whole application, covering security aspects that are not
tested in the unit tests, like logging in, logging out, checking that
the ``viewer`` user cannot add or edit pages, but the ``editor`` user
can, and so on.
Viewing the results of all our edits to ``tests.py``
====================================================
-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:
.. literalinclude:: src/tests/tutorial/tests.py
:linenos:
@@ -55,6 +53,7 @@ Change the ``requires`` list in ``setup.py`` to include ``WebTest``.
:linenos:
:language: python
:lines: 9-20
+ :emphasize-lines: 10
After we've added a dependency on WebTest in ``setup.py``, we need to rerun
``setup.py develop`` to get WebTest installed into our virtualenv. Assuming
@@ -88,12 +87,12 @@ On Windows:
c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
-The expected result looks something like:
+The expected result ends something like:
.. code-block:: text
......................
----------------------------------------------------------------------
- Ran 22 tests in 2.700s
+ Ran 21 tests in 2.700s
OK

0 comments on commit 3c7d5c8

Please sign in to comment.
Something went wrong with that request. Please try again.