summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt5
m---------docs/_themes0
-rw-r--r--docs/glossary.rst5
-rw-r--r--docs/tutorials/wiki2/authorization.rst153
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst58
-rw-r--r--docs/tutorials/wiki2/definingmodels.rst104
-rw-r--r--docs/tutorials/wiki2/definingviews.rst161
-rw-r--r--docs/tutorials/wiki2/installation.rst2
-rw-r--r--docs/tutorials/wiki2/src/authorization/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/authorization/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/authorization/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/authorization/setup.py3
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/__init__.py25
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/login.py37
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/models.py37
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/security.py1
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/tests.py23
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/views.py76
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/setup.py2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/models.py37
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py25
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/views.py8
-rw-r--r--docs/tutorials/wiki2/src/models/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/models/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/models/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/models/setup.py2
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/__init__.py12
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/models.py33
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt2
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/tests.py24
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/views.py14
-rw-r--r--docs/tutorials/wiki2/src/tests/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/tests/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/tests/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/tests/setup.py3
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/__init__.py25
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/login.py37
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/models.py37
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py36
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/security.py1
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/tests.py63
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/views.py76
-rw-r--r--docs/tutorials/wiki2/src/views/README.txt3
-rw-r--r--docs/tutorials/wiki2/src/views/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/views/production.ini1
-rw-r--r--docs/tutorials/wiki2/src/views/setup.py2
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/__init__.py17
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/models.py30
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py1
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py35
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt2
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/tests.py17
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/views.py17
-rw-r--r--docs/tutorials/wiki2/tests.rst4
-rw-r--r--pyramid/scaffolds/__init__.py4
-rw-r--r--pyramid/scaffolds/alchemy/+package+/models.py16
-rw-r--r--pyramid/scaffolds/alchemy/+package+/scripts/populate.py35
-rw-r--r--pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl30
-rw-r--r--pyramid/scaffolds/alchemy/+package+/tests.py_tmpl2
-rw-r--r--pyramid/scaffolds/alchemy/+package+/views.py_tmpl8
72 files changed, 875 insertions, 644 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index efc0dbb64..ce36750b6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -86,6 +86,11 @@ Dependencies
- Pyramid no longer depends on the Paste or PasteScript packages.
+Documentation
+-------------
+
+- The SQLAlchemy Wiki tutorial has been updated. It now uses
+ ``@view_config`` decorators and an explicit database population script.
Scaffolds
---------
diff --git a/docs/_themes b/docs/_themes
-Subproject 03e5e5aaaeddc4c9aea887478c7e7b379a127b6
+Subproject d0c25c1398f7c975db6fc174ef957764242ccb8
diff --git a/docs/glossary.rst b/docs/glossary.rst
index c98637698..39933cf4c 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -936,3 +936,8 @@ Glossary
email. See its `documentation
<https://docs.pylonsproject.org/projects/pyramid_exclog/dev/>`_.
+ console script
+ A script written to the ``bin`` (on UNIX, or ``Scripts`` on Windows)
+ directory of a Python installation or virtualenv as the result of
+ running ``setup.py install`` or ``setup.py develop``.
+
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index df5e228fd..ab04ea405 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -4,27 +4,22 @@
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 only people whom 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.
-:app:`Pyramid` provides facilities for :term:`authorization` and
-:term:`authentication`. We'll make use of both features to provide security
-to our application.
-
-We will add an :term:`authentication policy` and an
-:term:`authorization policy` to our :term:`application
-registry`, add a ``security.py`` module, create a :term:`root factory`
-with an :term:`ACL`, and add :term:`permission` declarations to
-the ``edit_page`` and ``add_page`` views.
-
-Then we will add ``login`` and ``logout`` views, and modify the
-existing views to make them return a ``logged_in`` flag to the
-renderer.
-
-Finally, we will add a ``login.pt`` template and change the existing
-``view.pt`` and ``edit.pt`` to show a "Logout" link when not logged in.
+: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`)
+to add and edit wiki pages but we'll continue allowing anyone with access to
+the server to view pages.
+
+To do so, we'll add an :term:`authentication policy` and an
+:term:`authorization policy`. We'll also add a ``security.py`` module,
+create a :term:`root factory` with an :term:`ACL`, and add :term:`permission`
+declarations to the ``edit_page`` and ``add_page`` views. Then we'll add
+``login`` and ``logout`` views, and modify the existing views to make them
+return a ``logged_in`` flag to the renderer. Finally, we will add a
+``login.pt`` template and change the existing ``view.pt`` and ``edit.pt`` to
+show a "Logout" link when not logged in.
The source code for this tutorial stage can be browsed at
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/authorization/
@@ -54,7 +49,7 @@ inside our ``models.py`` file. Add the following statements to your
``models.py`` file:
.. literalinclude:: src/authorization/tutorial/models.py
- :lines: 3-4,45-50
+ :lines: 1-4,35-39
:linenos:
:language: python
@@ -92,14 +87,14 @@ We'll change our ``__init__.py`` file to enable an
declarative security checking. We need to import the new policies:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 2-3,8
+ :lines: 2-3,7
:linenos:
:language: python
Then, we'll add those policies to the configuration:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 15-21
+ :lines: 16-22
:linenos:
:language: python
@@ -111,49 +106,12 @@ represented by this policy: it is required. The ``callback`` is a
``groupfinder`` function in the current directory's ``security.py`` file. We
haven't added that module yet, but we're about to.
-We'll also change ``__init__.py``, adding a call to
-:meth:`pyramid.config.Configurator.add_view` that points at our ``login``
-:term:`view callable`. This is also known as a :term:`forbidden view`:
-
-.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 25,41-43
- :linenos:
- :language: python
-
-A forbidden view configures our newly created login view to show up when
-:app:`Pyramid` detects that a view invocation can not be authorized.
-
-A ``logout`` :term:`view callable` will allow users to log out later:
-
-.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 26,34
- :linenos:
- :language: python
-
-We'll also add ``permission`` arguments with the value ``edit`` to the
-``edit_page`` and ``add_page`` views. This indicates that the view
-callables which these views reference cannot be invoked without the
-authenticated user possessing the ``edit`` permission with respect to the
-current context.
-
-.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 37-40
- :linenos:
- :language: python
-
-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.
-
Viewing Your Changes
~~~~~~~~~~~~~~~~~~~~
-When we're done configuring a root factory, adding an authorization policy,
-and adding views, your application's ``__init__.py`` will look like this:
+When we're done configuring a root factory, adding a authentication and
+authorization policies, and adding routes for ``/login`` and ``/logout``,
+your application's ``__init__.py`` will look like this:
.. literalinclude:: src/authorization/tutorial/__init__.py
:linenos:
@@ -191,30 +149,54 @@ views, the ``editor`` user should be able to add and edit pages.
Adding Login and Logout Views
-----------------------------
-We'll add a ``login`` view callable which renders a login form and
-processes the post from the login form, checking credentials.
+To our ``views.py`` we'll add a ``login`` view callable which renders a login
+form and processes the post from the login form, checking credentials.
We'll also add a ``logout`` view callable to our application and
provide a link to it. This view will clear the credentials of the
logged in user and redirect back to the front page.
-We'll add a different file (for presentation convenience) to add login
-and the logout view callables. Add a file named ``login.py`` to your
-application (in the same directory as ``views.py``) with the following
-content:
+The ``login`` view callable will look something like this:
-.. literalinclude:: src/authorization/tutorial/login.py
+.. literalinclude:: src/authorization/tutorial/views.py
+ :pyobject: login
:linenos:
:language: python
+The ``logout`` view callable will look something like this:
+
+.. literalinclude:: src/authorization/tutorial/views.py
+ :pyobject: logout
+ :linenos:
+ :language: python
+
+The ``login`` view callable is decorated with two ``@view_config``
+decorators, one which associates it with the ``login`` route, the other which
+associates it with the ``HTTPForbidden`` context. The one which associates
+it with the ``login`` route makes it visible when we visit ``/login``. The
+one which associates it with the ``HTTPForbidden`` context makes it the
+: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.
+
+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``.
+
+We'll need to import some stuff to service the needs of these two functions:
+the ``HTTPForbidden`` exception, a number of values from the
+``pyramid.security`` module, and a value from our newly added
+``tutorial.security`` package.
+
Changing Existing Views
-----------------------
Then we need to change each of our ``view_page``, ``edit_page`` and
-``add_page`` views in ``views.py`` to pass a "logged in" parameter to its
-template. We'll add something like this to each view body:
+``add_page`` view callables in ``views.py``. Within each of these views,
+we'll need to pass a "logged in" parameter to its template. We'll add
+something like this to each view body:
-.. ignore-next-block
.. code-block:: python
:linenos:
@@ -224,7 +206,6 @@ template. We'll add something like this to each view body:
We'll then change the return value of these views to pass the `resulting
`logged_in`` value to the template, e.g.:
-.. ignore-next-block
.. code-block:: python
:linenos:
@@ -233,6 +214,28 @@ We'll then change the return value of these views to pass the `resulting
logged_in = logged_in,
edit_url = edit_url)
+We'll also need to add a ``permission`` value to the ``@view_config``
+decorator for each of the ``add_page`` and ``edit_page`` view callables. For
+each, we'll add ``permission='edit'``, for example:
+
+.. code-block:: python
+ :linenos:
+
+ @view_config(route_name='edit_page', renderer='templates/edit.pt',
+ permission='edit')
+
+See the ``permission='edit'`` we added there? This indicates that the view
+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 the ``login.pt`` Template
--------------------------------
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index dc5664c5b..77658970d 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -128,19 +128,20 @@ 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.
-Here is the code in the ``views.py`` file within our package:
+Here is the entirety of code in the ``views.py`` file within our package:
.. literalinclude:: src/basiclayout/tutorial/views.py
:linenos:
:language: py
-The important part to point out here is the ``@view_config`` decorator. In
-fact, ``@view_config`` is so important that we're going to ignore the rest of
-the code in the module at this point just to explain it. The
-``@view_config`` decorator associates the function it decorates with a
-:term:`view configuration`. The view configuration names a ``route_name``
-(``home``), and names a ``renderer``, which is a template which lives in the
-``templates`` subdirectory of the package.
+The important part to point out here is the ``@view_config`` decorator which
+sits atop the ``my_view`` function. In fact, ``@view_config`` is so
+important that we're going to ignore the rest of the code in the module at
+this point just to explain it. The ``@view_config`` decorator associates the
+function it decorates with a :term:`view configuration`. The view
+configuration names a ``route_name`` (``home``), and names a ``renderer``,
+which is a template which lives in the ``templates`` subdirectory of the
+package.
As the result of this view configuration, when the pattern associated with
the view named ``home`` is matched during a request, the function named
@@ -164,9 +165,14 @@ Content Models with ``models.py``
---------------------------------
In a SQLAlchemy-based application, a *model* object is an object composed by
-querying the SQL database. SQLAlchemy is an "object relational mapper" (an
-ORM). The ``models.py`` file is where the ``alchemy`` scaffold put the
-classes that implement our models.
+querying the SQL database. The ``models.py`` file is where the ``alchemy``
+scaffold put the classes that implement our models.
+
+Here is the complete source for ``models.py``:
+
+ .. literalinclude:: src/basiclayout/tutorial/models.py
+ :linenos:
+ :language: py
Let's take a look. First, we need some imports to support later code.
@@ -178,7 +184,7 @@ Let's take a look. First, we need some imports to support later code.
Next we set up a SQLAlchemy "DBSession" object:
.. literalinclude:: src/basiclayout/tutorial/models.py
- :lines: 15-16
+ :lines: 16
:linenos:
:language: py
@@ -202,30 +208,6 @@ within the ``__init__`` function itself. The ``MyModel`` class also has a
``__tablename__`` attribute. This informs SQLAlchemy which table to use to
store the data representing instances of this class.
-Next we define a function named ``populate`` which adds a single
-model instance into our SQL storage and commits a transaction:
-
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :pyobject: populate
- :linenos:
- :language: py
-
-The function doesn't do a lot in this case, but it's there to illustrate
-how an application requiring many objects to be set up could work.
-
-Lastly we have a function named ``initialize_sql`` which receives a SQL
-database engine and binds it to our SQLAlchemy DBSession object. It also
-calls the ``populate`` function, to do initial database population. This
-is the initialization function that is called from __init__.py above.
-
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :pyobject: initialize_sql
- :linenos:
- :language: py
-
-Here is the complete source for ``models.py``:
-
- .. literalinclude:: src/basiclayout/tutorial/models.py
- :linenos:
- :language: py
+That's about all there is to it to models, views, and initialization code in
+our stock application.
diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst
index bc2c2de5f..cd295e993 100644
--- a/docs/tutorials/wiki2/definingmodels.rst
+++ b/docs/tutorials/wiki2/definingmodels.rst
@@ -15,29 +15,25 @@ Making Edits to ``models.py``
.. note::
- There is nothing automagically special about the filename
- ``models.py``. A project may have many models throughout its
- codebase in arbitrarily-named files. Files implementing models
- often have ``model`` in their filenames (or they may live in a
- Python subpackage of your application package named ``models``) ,
- but this is only by convention.
+ There is nothing automagically special about the filename ``models.py``. A
+ project may have many models throughout its codebase in arbitrarily-named
+ files. Files implementing models often have ``model`` in their filenames
+ (or they may live in a Python subpackage of your application package named
+ ``models``) , but this is only by convention.
-The first thing we want to do is remove the stock ``MyModel`` class from the
-generated ``models.py`` file. The ``MyModel`` class is only a sample and
-we're not going to use it.
-
-Next, we'll remove the :class:`sqlalchemy.Unicode` import and replace it
-with :class:`sqlalchemy.Text`.
+Here's what our ``models.py`` file should look like after this step:
.. literalinclude:: src/models/tutorial/models.py
- :lines: 5
:linenos:
:language: py
-Then, we'll add a ``Page`` class. Because this is a SQLAlchemy
-application, this class should inherit from an instance of
-:class:`sqlalchemy.ext.declarative.declarative_base`. Declarative
-SQLAlchemy models are easier to use than directly-mapped ones.
+The first thing we've done is to do is remove the stock ``MyModel`` class
+from the generated ``models.py`` file. The ``MyModel`` class is only a
+sample and we're not going to use it.
+
+Then, we added a ``Page`` class. Because this is a SQLAlchemy application,
+this class inherits from an instance of
+:class:`sqlalchemy.ext.declarative.declarative_base`.
.. literalinclude:: src/models/tutorial/models.py
:pyobject: Page
@@ -54,24 +50,18 @@ in the table. The ``name`` attribute will be a text attribute, each value of
which needs to be unique within the column. The ``data`` attribute is a text
attribute that will hold the body of each page.
-We'll also remove our ``populate`` function. We'll inline the populate step
-into ``initialize_sql``, changing our ``initialize_sql`` function to add a
-FrontPage object to our database at startup time.
-
-.. literalinclude:: src/models/tutorial/models.py
- :pyobject: initialize_sql
- :linenos:
- :language: python
-
-Here, we're using a slightly different binding syntax. It is otherwise
-largely the same as the ``initialize_sql`` in the pcreate-generated
-``models.py``.
+Changing ``scripts/populate.py``
+--------------------------------
-Our ``DBSession`` assignment stays the same as the original generated
-``models.py``.
+We haven't looked at the guts of this file yet, but within the ``scripts``
+directory of your ``tutorial`` package is a file named ``populate.py``. Code
+in this file is executed whenever we run the ``populate_tutorial`` command
+(as we did in the installation step of this tutorial).
-Looking at the Result of all Our Edits to ``models.py``
--------------------------------------------------------
+Since we've changed our model, we need to make changes to our ``populate.py``
+script. In particular, we'll replace our import of ``MyModel`` with one of
+``Page`` and we'll change the very end of the script to create a ``Page``
+rather than a ``MyModel`` and add it to our ``DBSession``.
The result of all of our edits to ``models.py`` will end up looking
something like this:
@@ -80,10 +70,52 @@ something like this:
:linenos:
:language: python
-Populating the Database
------------------------
+Repopulating the Database
+-------------------------
+
+Because our model has changed, in order to repopulate the database, we need
+to rerun the ``populate_tutorial`` command to pick up the changes you've made
+to both the models.py file and to the populate.py file. From the root of the
+``tutorial`` project, directory execute the following commands.
+
+On UNIX:
+
+.. code-block:: text
+
+ $ ../bin/populate_tutorial development.ini
+
+On Windows:
+
+.. code-block:: text
-XXX The ``populate_tutorial`` :term:`console script``.
+ c:\pyramidtut\tutorial> ..\Scripts\populate_tutorial development.ini
+
+Success will look something like this::
+
+ 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ PRAGMA table_info("pages")
+ 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2011-11-27 01:22:45,277 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ CREATE TABLE pages (
+ id INTEGER NOT NULL,
+ name TEXT,
+ data TEXT,
+ PRIMARY KEY (id),
+ UNIQUE (name)
+ )
+
+
+ 2011-11-27 01:22:45,278 INFO [sqlalchemy.engine.base.Engine][MainThread] ()
+ 2011-11-27 01:22:45,397 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ COMMIT
+ 2011-11-27 01:22:45,400 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ BEGIN (implicit)
+ 2011-11-27 01:22:45,401 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ INSERT INTO pages (name, data) VALUES (?, ?)
+ 2011-11-27 01:22:45,401 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ ('FrontPage', 'This is the front page')
+ 2011-11-27 01:22:45,402 INFO [sqlalchemy.engine.base.Engine][MainThread]
+ COMMIT
Viewing the Application in a Browser
------------------------------------
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index 21b97f7aa..7f533b635 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -2,34 +2,19 @@
Defining Views
==============
-A :term:`view callable` in a :term:`url dispatch` -based :app:`Pyramid`
-application is typically a simple Python function that accepts a single
-parameter named :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 *two* arguments: a :term:`context` and a
- :term:`request`. You'll see this two-argument pattern used in
- other :app:`Pyramid` tutorials and applications. Either calling
- convention will work in any :app:`Pyramid` application; the
- calling conventions can be used interchangeably as necessary. In
- :term:`url dispatch` based applications, however, the context
- object is rarely used in the view body itself, so within this
- tutorial we define views as callables that accept only a request to
- avoid the visual "noise". If you do need the ``context`` within a
- view function that only takes the request as a single argument, you
- can obtain it via ``request.context``.
-
-The request passed to every view that is called as the result of a route
-match has an attribute named ``matchdict`` that contains the elements placed
-into the URL by the ``pattern`` of a ``route`` statement. For instance, if a
-call to :meth:`pyramid.config.Configurator.add_route` in ``__init__.py`` had
-the pattern ``{one}/{two}``, and the URL at ``http://example.com/foo/bar``
-was invoked, matching this pattern, the ``matchdict`` dictionary attached to
-the request passed to the view would have a ``'one'`` key with the value
-``'foo'`` and a ``'two'`` key with the value ``'bar'``.
+A :term:`view callable` in a :app:`Pyramid` application is typically a simple
+Python function that accepts a single parameter named :term:`request`. A
+view callable is assumed to return a :term:`response` object.
+
+The request object passed to every view that is called as the result of a
+route match has an attribute named ``matchdict`` that contains the elements
+placed into the URL by the ``pattern`` of a ``route`` statement. For
+instance, if a call to :meth:`pyramid.config.Configurator.add_route` in
+``__init__.py`` had the pattern ``{one}/{two}``, and the URL at
+``http://example.com/foo/bar`` was invoked, matching this pattern, the
+``matchdict`` dictionary attached to the request passed to the view would
+have a ``'one'`` key with the value ``'foo'`` and a ``'two'`` key with the
+value ``'bar'``.
The source code for this tutorial stage can be browsed at
`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src/views/
@@ -52,24 +37,56 @@ Our resulting ``setup.py`` should look like so:
:linenos:
:language: python
-.. note:: After these new dependencies are added, you will need to
- rerun ``python setup.py develop`` inside the root of the
- ``tutorial`` package to obtain and register the newly added
- dependency package.
+Running ``setup.py develop``
+============================
+
+Since a new software dependency was added, you will need to rerun ``python
+setup.py develop`` inside the root of the ``tutorial`` package to obtain and
+register the newly added dependency distribution.
+
+Make sure your current working directory is the root of the project (the
+directory in which setup.py lives) and execute the following command.
+
+On UNIX:
+
+.. code-block:: text
+
+ $ cd tutorial
+ $ ../bin/python setup.py develop
-Adding View Functions
-=====================
+On Windows:
-We'll get rid of our ``my_view`` view function in our ``views.py`` file.
-It's only an example and isn't relevant to our application.
+.. code-block:: text
-Then we're going to add four :term:`view callable` functions to our
-``views.py`` module. One view callable (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 callable named ``edit_page`` will allow a page
-to be edited. We'll describe each one briefly and show the resulting
-``views.py`` file afterward.
+ c:\pyramidtut> cd tutorial
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py develop
+
+Success executing this command will end with a line to the console something
+like::
+
+ Finished processing dependencies for tutorial==0.0
+
+Changing the ``views.py`` File
+==============================
+
+We're going to edit our ``views.py`` in a rather major way. The result of
+all of our edits to ``views.py`` will leave it looking like this:
+
+.. literalinclude:: src/views/tutorial/views.py
+ :linenos:
+ :language: python
+
+We've gotten rid of the ``my_view`` view function and its decorator that was
+added when we originally rendered the ``alchemy`` scaffold. It was only an
+example and isn't relevant to our application.
+
+Then we added four :term:`view callable` functions to our ``views.py``
+module. One view callable (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 callable named ``edit_page`` will allow a page to be edited.
+We'll describe each one briefly and show the resulting ``views.py`` file
+afterward.
.. note::
@@ -195,16 +212,6 @@ If the view execution *is* a result of a form submission (if the expression
attribute of the page object. It then redirects to the ``view_page`` view
of the wiki page.
-Viewing the Result of all Our Edits to ``views.py``
-===================================================
-
-The result of all of our edits to ``views.py`` will leave it looking
-like this:
-
-.. literalinclude:: src/views/tutorial/views.py
- :linenos:
- :language: python
-
Adding Templates
================
@@ -270,47 +277,41 @@ subdirectories) and are just referred to by URL or by using the convenience
method ``static_url``
e.g. ``request.static_url('{{package}}:static/foo.css')`` within templates.
-Mapping Views to URLs in ``__init__.py``
-========================================
+Adding Routes to ``__init__.py``
+================================
The ``__init__.py`` file contains
-:meth:`pyramid.config.Configurator.add_view` calls which serve to map
-routes via :term:`url dispatch` to views. First, we’ll get rid of the
-existing route created by the template using the name ``'home'``. It’s only an
-example and isn’t relevant to our application.
+:meth:`pyramid.config.Configurator.add_route` calls which serve to add routes
+to our application. First, we’ll get rid of the existing route created by
+the template using the name ``'home'``. It’s only an example and isn’t
+relevant to our application.
We then need to add four calls to ``add_route``. Note that the *ordering* of
these declarations is very important. ``route`` declarations are matched in
the order they're found in the ``__init__.py`` file.
#. Add a declaration which maps the pattern ``/`` (signifying the root URL)
- to the route named ``view_wiki``.
+ to the route named ``view_wiki``. It maps to our ``view_wiki`` view
+ callable by virtue of the ``@view_config`` attached to the ``view_wiki``
+ view function indicating ``route_name='view_wiki'``.
#. Add a declaration which maps the pattern ``/{pagename}`` to the route named
- ``view_page``. This is the regular view for a page.
+ ``view_page``. This is the regular view for a page. It maps
+ to our ``view_page`` view callable by virtue of the ``@view_config``
+ attached to the ``view_page`` view function indicating
+ ``route_name='view_page'``.
#. Add a declaration which maps the pattern ``/add_page/{pagename}`` to the
- route named ``add_page``. This is the add view for a new page.
+ route named ``add_page``. This is the add view for a new page. It maps
+ to our ``add_page`` view callable by virtue of the ``@view_config``
+ attached to the ``add_page`` view function indicating
+ ``route_name='add_page'``.
#. Add a declaration which maps the pattern ``/{pagename}/edit_page`` to the
- route named ``edit_page``. This is the edit view for a page.
-
-After we've defined the routes for our application, we can register views
-to handle the processing and rendering that needs to happen when each route is
-requested.
-
-#. Add a declaration which maps the ``view_wiki`` route to the view named
- ``view_wiki`` in our ``views.py`` file. This is the :term:`default view`
- for the wiki.
-
-#. Add a declaration which maps the ``view_page`` route to the view named
- ``view_page`` in our ``views.py`` file.
-
-#. Add a declaration which maps the ``add_page`` route to the view named
- ``add_page`` in our ``views.py`` file.
-
-#. Add a declaration which maps the ``edit_page`` route to the view named
- ``edit_page`` in our ``views.py`` file.
+ route named ``edit_page``. This is the edit view for a page. It maps
+ to our ``edit_page`` view callable by virtue of the ``@view_config``
+ attached to the ``edit_page`` view function indicating
+ ``route_name='edit_page'``.
As a result of our edits, the ``__init__.py`` file should look
something like so:
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index 381e0a90f..be97f1cb3 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -253,7 +253,7 @@ You will see an error page with a title something like this::
Oh no! Something isn't working!
-This happens because we haven't populated the database with any table
+This happens because we haven't populated the SQL database with any table
information yet. We need to use the ``populate_tutorial`` :term:`console
script` to populate our database before we can see the page render correctly.
diff --git a/docs/tutorials/wiki2/src/authorization/README.txt b/docs/tutorials/wiki2/src/authorization/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/authorization/README.txt
+++ b/docs/tutorials/wiki2/src/authorization/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/authorization/development.ini
+++ b/docs/tutorials/wiki2/src/authorization/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/authorization/production.ini b/docs/tutorials/wiki2/src/authorization/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/authorization/production.ini
+++ b/docs/tutorials/wiki2/src/authorization/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/authorization/setup.py b/docs/tutorials/wiki2/src/authorization/setup.py
index 439a86923..09769bfff 100644
--- a/docs/tutorials/wiki2/src/authorization/setup.py
+++ b/docs/tutorials/wiki2/src/authorization/setup.py
@@ -42,6 +42,7 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
-
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
index cca52fdfe..04dd5fe82 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
@@ -4,14 +4,15 @@ from pyramid.authorization import ACLAuthorizationPolicy
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
from tutorial.security import groupfinder
+from .models import DBSession
+
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
authn_policy = AuthTktAuthenticationPolicy(
'sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
@@ -19,27 +20,13 @@ def main(global_config, **settings):
root_factory='tutorial.models.RootFactory',
authentication_policy=authn_policy,
authorization_policy=authz_policy)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
-
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
config.add_route('view_page', '/{pagename}')
config.add_route('add_page', '/add_page/{pagename}')
config.add_route('edit_page', '/{pagename}/edit_page')
-
- config.add_view('tutorial.views.view_wiki', route_name='view_wiki')
- config.add_view('tutorial.login.login', route_name='login',
- renderer='tutorial:templates/login.pt')
- config.add_view('tutorial.login.logout', route_name='logout')
- config.add_view('tutorial.views.view_page', route_name='view_page',
- renderer='tutorial:templates/view.pt')
- config.add_view('tutorial.views.add_page', route_name='add_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.views.edit_page', route_name='edit_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.login.login',
- context='pyramid.httpexceptions.HTTPForbidden',
- renderer='tutorial:templates/login.pt')
+ config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/login.py b/docs/tutorials/wiki2/src/authorization/tutorial/login.py
deleted file mode 100644
index 5a825d8d6..000000000
--- a/docs/tutorials/wiki2/src/authorization/tutorial/login.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from pyramid.httpexceptions import HTTPFound
-from pyramid.security import remember
-from pyramid.security import forget
-
-from tutorial.security import USERS
-
-def login(request):
- login_url = request.route_url('login')
- referrer = request.url
- if referrer == login_url:
- referrer = '/' # never use the login form itself as came_from
- came_from = request.params.get('came_from', referrer)
- message = ''
- login = ''
- password = ''
- if 'form.submitted' in request.params:
- login = request.params['login']
- password = request.params['password']
- if USERS.get(login) == password:
- headers = remember(request, login)
- return HTTPFound(location = came_from,
- headers = headers)
- message = 'Failed login'
-
- return dict(
- message = message,
- url = request.application_url + '/login',
- came_from = came_from,
- login = login,
- password = password,
- )
-
-def logout(request):
- headers = forget(request)
- return HTTPFound(location = request.route_url('view_wiki'),
- headers = headers)
-
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/models.py b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
index 832545cb1..c3bdcbea5 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/models.py
@@ -1,17 +1,20 @@
-import transaction
+from pyramid.security import (
+ Allow,
+ Everyone,
+ )
-from pyramid.security import Allow
-from pyramid.security import Everyone
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -29,20 +32,6 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'This is the front page')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
-
class RootFactory(object):
__acl__ = [ (Allow, Everyone, 'view'),
(Allow, 'group:editors', 'edit') ]
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py
new file mode 100644
index 000000000..981adff38
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv, settings=None):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/security.py b/docs/tutorials/wiki2/src/authorization/tutorial/security.py
index cfd13071e..d88c9c71f 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/security.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/security.py
@@ -5,4 +5,3 @@ GROUPS = {'editor':['group:editors']}
def groupfinder(userid, request):
if userid in USERS:
return GROUPS.get(userid, [])
-
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
index 332031ba4..31d2dc6d5 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/tests.py
@@ -1,15 +1,20 @@
import unittest
-
+import transaction
from pyramid import testing
def _initTestingDB():
- from tutorial.models import DBSession
- from tutorial.models import Base
from sqlalchemy import create_engine
+ from tutorial.models import (
+ DBSession,
+ Page,
+ Base
+ )
engine = create_engine('sqlite://')
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
Base.metadata.create_all(engine)
+ DBSession.configure(bind=engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
return DBSession
def _registerRoutes(config):
@@ -20,14 +25,16 @@ def _registerRoutes(config):
class ViewWikiTests(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
+ self.session = _initTestingDB()
def tearDown(self):
+ self.session.remove()
testing.tearDown()
def _callFUT(self, request):
from tutorial.views import view_wiki
return view_wiki(request)
-
+
def test_it(self):
_registerRoutes(self.config)
request = testing.DummyRequest()
@@ -40,6 +47,7 @@ class ViewPageTests(unittest.TestCase):
self.config = testing.setUp()
def tearDown(self):
+ self.session.remove()
testing.tearDown()
def _callFUT(self, request):
@@ -121,7 +129,8 @@ class EditPageTests(unittest.TestCase):
self.session.add(page)
info = self._callFUT(request)
self.assertEqual(info['page'], page)
- self.assertEqual(info['save_url'], 'http://example.com/abc/edit_page')
+ self.assertEqual(info['save_url'],
+ 'http://example.com/abc/edit_page')
def test_it_submitted(self):
from tutorial.models import Page
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views.py b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
index fc85d4585..375f1f5a5 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/views.py
@@ -1,20 +1,36 @@
import re
-
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound, HTTPNotFound
-from pyramid.security import authenticated_userid
+from pyramid.httpexceptions import (
+ HTTPFound,
+ HTTPNotFound,
+ HTTPForbidden,
+ )
+
+from pyramid.view import view_config
+
+from pyramid.security import (
+ remember,
+ forget,
+ authenticated_userid,
+ )
-from tutorial.models import DBSession
-from tutorial.models import Page
+from .models import (
+ DBSession,
+ Page,
+ )
+
+from .security import USERS
# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
+@view_config(route_name='view_wiki')
def view_wiki(request):
return HTTPFound(location = request.route_url('view_page',
pagename='FrontPage'))
+@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
pagename = request.matchdict['pagename']
session = DBSession()
@@ -35,10 +51,11 @@ def view_page(request):
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(check, content)
edit_url = request.route_url('edit_page', pagename=pagename)
- logged_in = authenticated_userid(request)
return dict(page=page, content=content, edit_url=edit_url,
- logged_in=logged_in)
+ logged_in=authenticated_userid(request))
+@view_config(route_name='add_page', renderer='templates/edit.pt',
+ permission='edit')
def add_page(request):
name = request.matchdict['pagename']
if 'form.submitted' in request.params:
@@ -50,9 +67,11 @@ def add_page(request):
pagename=name))
save_url = request.route_url('add_page', pagename=name)
page = Page('', '')
- logged_in = authenticated_userid(request)
- return dict(page=page, save_url=save_url, logged_in=logged_in)
+ return dict(page=page, save_url=save_url,
+ logged_in=authenticated_userid(request))
+@view_config(route_name='edit_page', renderer='templates/edit.pt',
+ permission='edit')
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
@@ -62,10 +81,43 @@ def edit_page(request):
session.add(page)
return HTTPFound(location = request.route_url('view_page',
pagename=name))
-
- logged_in = authenticated_userid(request)
return dict(
page=page,
save_url = request.route_url('edit_page', pagename=name),
- logged_in = logged_in,
+ logged_in=authenticated_userid(request),
)
+
+@view_config(route_name='login', renderer='templates/login.pt')
+@view_config(context=HTTPForbidden, renderer='templates/login.pt')
+def login(request):
+ login_url = request.route_url('login')
+ referrer = request.url
+ if referrer == login_url:
+ referrer = '/' # never use the login form itself as came_from
+ came_from = request.params.get('came_from', referrer)
+ message = ''
+ login = ''
+ password = ''
+ if 'form.submitted' in request.params:
+ login = request.params['login']
+ password = request.params['password']
+ if USERS.get(login) == password:
+ headers = remember(request, login)
+ return HTTPFound(location = came_from,
+ headers = headers)
+ message = 'Failed login'
+
+ return dict(
+ message = message,
+ url = request.application_url + '/login',
+ came_from = came_from,
+ login = login,
+ password = password,
+ )
+
+@view_config(route_name='logout')
+def logout(request):
+ headers = forget(request)
+ return HTTPFound(location = request.route_url('view_wiki'),
+ headers = headers)
+
diff --git a/docs/tutorials/wiki2/src/basiclayout/README.txt b/docs/tutorials/wiki2/src/basiclayout/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/basiclayout/README.txt
+++ b/docs/tutorials/wiki2/src/basiclayout/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/basiclayout/development.ini b/docs/tutorials/wiki2/src/basiclayout/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/basiclayout/development.ini
+++ b/docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/basiclayout/production.ini b/docs/tutorials/wiki2/src/basiclayout/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/basiclayout/production.ini
+++ b/docs/tutorials/wiki2/src/basiclayout/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/basiclayout/setup.py b/docs/tutorials/wiki2/src/basiclayout/setup.py
index 3ab493912..0ca918cab 100644
--- a/docs/tutorials/wiki2/src/basiclayout/setup.py
+++ b/docs/tutorials/wiki2/src/basiclayout/setup.py
@@ -41,6 +41,8 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
index 1f2cfd307..253341563 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
@@ -13,3 +13,4 @@ def main(global_config, **settings):
config.add_route('home', '/')
config.scan()
return config.make_wsgi_app()
+
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
index 9b687931b..b6ac15429 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models.py
@@ -1,43 +1,28 @@
-import transaction
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Unicode
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
-DBSession = scoped_session(sessionmaker(
- extension=ZopeTransactionExtension()))
+DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
class MyModel(Base):
__tablename__ = 'models'
id = Column(Integer, primary_key=True)
- name = Column(Unicode(255), unique=True)
+ name = Column(Text, unique=True)
value = Column(Integer)
def __init__(self, name, value):
self.name = name
self.value = value
-def populate():
- session = DBSession()
- model = MyModel(name=u'root',value=55)
- session.add(model)
- session.flush()
- transaction.commit()
-
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- populate()
- except IntegrityError:
- transaction.abort()
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py
new file mode 100644
index 000000000..0e828465f
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ MyModel,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=1)
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
index 14b88d16a..fbfa9870b 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -6,9 +6,9 @@
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
<link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
- <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
index 5efa6affa..653d061e4 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
@@ -1,23 +1,32 @@
import unittest
+import transaction
+
from pyramid import testing
-def _initTestingDB():
- from sqlalchemy import create_engine
- from tutorial.models import initialize_sql
- session = initialize_sql(create_engine('sqlite://'))
- return session
+from .models import DBSession
class TestMyView(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
- _initTestingDB()
+ from sqlalchemy import create_engine
+ engine = create_engine('sqlite://')
+ from .models import (
+ Base,
+ MyModel,
+ )
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=55)
+ DBSession.add(model)
def tearDown(self):
+ DBSession.remove()
testing.tearDown()
def test_it(self):
- from tutorial.views import my_view
+ from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['root'].name, 'root')
+ self.assertEqual(info['one'].name, 'one')
self.assertEqual(info['project'], 'tutorial')
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py
index 631af9b6a..3e6abf2c2 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/views.py
@@ -1,9 +1,11 @@
from pyramid.view import view_config
-from .models import DBSession
-from .models import MyModel
+from .models import (
+ DBSession,
+ MyModel,
+ )
@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
- one = DBSession.query(MyModel).filter(MyModel.name==u'root').first()
+ one = DBSession.query(MyModel).filter(MyModel.name=='one').first()
return {'one':one, 'project':'tutorial'}
diff --git a/docs/tutorials/wiki2/src/models/README.txt b/docs/tutorials/wiki2/src/models/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/models/README.txt
+++ b/docs/tutorials/wiki2/src/models/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/models/development.ini b/docs/tutorials/wiki2/src/models/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/models/development.ini
+++ b/docs/tutorials/wiki2/src/models/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/models/production.ini b/docs/tutorials/wiki2/src/models/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/models/production.ini
+++ b/docs/tutorials/wiki2/src/models/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/models/setup.py b/docs/tutorials/wiki2/src/models/setup.py
index 3ab493912..0ca918cab 100644
--- a/docs/tutorials/wiki2/src/models/setup.py
+++ b/docs/tutorials/wiki2/src/models/setup.py
@@ -41,6 +41,8 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
index fda7c9ce6..253341563 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
@@ -1,16 +1,16 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
+from .models import DBSession
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
config = Configurator(settings=settings)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
- config.add_view('tutorial.views.my_view', route_name='home',
- renderer='templates/mytemplate.pt')
+ config.scan()
return config.make_wsgi_app()
+
diff --git a/docs/tutorials/wiki2/src/models/tutorial/models.py b/docs/tutorials/wiki2/src/models/tutorial/models.py
index 30f77a0b9..499396c5b 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/models.py
@@ -1,19 +1,19 @@
-import transaction
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
-DBSession = scoped_session(sessionmaker(
- extension=ZopeTransactionExtension()))
+DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
class Page(Base):
@@ -27,16 +27,3 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'This is the front page')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
diff --git a/docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py
new file mode 100644
index 000000000..03188e8ad
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
index 14b88d16a..fbfa9870b 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.pt
@@ -6,9 +6,9 @@
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
<link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
- <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
diff --git a/docs/tutorials/wiki2/src/models/tutorial/tests.py b/docs/tutorials/wiki2/src/models/tutorial/tests.py
index 71f5e21e3..653d061e4 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/tests.py
@@ -1,22 +1,32 @@
import unittest
+import transaction
+
from pyramid import testing
-def _initTestingDB():
- from tutorial.models import initialize_sql
- session = initialize_sql('sqlite://')
- return session
+from .models import DBSession
class TestMyView(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
- _initTestingDB()
+ from sqlalchemy import create_engine
+ engine = create_engine('sqlite://')
+ from .models import (
+ Base,
+ MyModel,
+ )
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=55)
+ DBSession.add(model)
def tearDown(self):
+ DBSession.remove()
testing.tearDown()
def test_it(self):
- from tutorial.views import my_view
+ from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['root'].name, 'root')
+ self.assertEqual(info['one'].name, 'one')
self.assertEqual(info['project'], 'tutorial')
diff --git a/docs/tutorials/wiki2/src/models/tutorial/views.py b/docs/tutorials/wiki2/src/models/tutorial/views.py
index e550e3257..3e6abf2c2 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/views.py
@@ -1,7 +1,11 @@
-from tutorial.models import DBSession
-from tutorial.models import MyModel
+from pyramid.view import view_config
+from .models import (
+ DBSession,
+ MyModel,
+ )
+
+@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
- dbsession = DBSession()
- root = dbsession.query(MyModel).filter(MyModel.name==u'root').first()
- return {'root':root, 'project':'tutorial'}
+ one = DBSession.query(MyModel).filter(MyModel.name=='one').first()
+ return {'one':one, 'project':'tutorial'}
diff --git a/docs/tutorials/wiki2/src/tests/README.txt b/docs/tutorials/wiki2/src/tests/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/tests/README.txt
+++ b/docs/tutorials/wiki2/src/tests/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/tests/development.ini
+++ b/docs/tutorials/wiki2/src/tests/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/tests/production.ini
+++ b/docs/tutorials/wiki2/src/tests/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py
index 6de8a1fbe..f965ccc6e 100644
--- a/docs/tutorials/wiki2/src/tests/setup.py
+++ b/docs/tutorials/wiki2/src/tests/setup.py
@@ -43,6 +43,7 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
-
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
index cca52fdfe..04dd5fe82 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/__init__.py
@@ -4,14 +4,15 @@ from pyramid.authorization import ACLAuthorizationPolicy
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
from tutorial.security import groupfinder
+from .models import DBSession
+
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
authn_policy = AuthTktAuthenticationPolicy(
'sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
@@ -19,27 +20,13 @@ def main(global_config, **settings):
root_factory='tutorial.models.RootFactory',
authentication_policy=authn_policy,
authorization_policy=authz_policy)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
-
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
config.add_route('login', '/login')
config.add_route('logout', '/logout')
config.add_route('view_page', '/{pagename}')
config.add_route('add_page', '/add_page/{pagename}')
config.add_route('edit_page', '/{pagename}/edit_page')
-
- config.add_view('tutorial.views.view_wiki', route_name='view_wiki')
- config.add_view('tutorial.login.login', route_name='login',
- renderer='tutorial:templates/login.pt')
- config.add_view('tutorial.login.logout', route_name='logout')
- config.add_view('tutorial.views.view_page', route_name='view_page',
- renderer='tutorial:templates/view.pt')
- config.add_view('tutorial.views.add_page', route_name='add_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.views.edit_page', route_name='edit_page',
- renderer='tutorial:templates/edit.pt', permission='edit')
- config.add_view('tutorial.login.login',
- context='pyramid.httpexceptions.HTTPForbidden',
- renderer='tutorial:templates/login.pt')
+ config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/login.py b/docs/tutorials/wiki2/src/tests/tutorial/login.py
deleted file mode 100644
index 5a825d8d6..000000000
--- a/docs/tutorials/wiki2/src/tests/tutorial/login.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from pyramid.httpexceptions import HTTPFound
-from pyramid.security import remember
-from pyramid.security import forget
-
-from tutorial.security import USERS
-
-def login(request):
- login_url = request.route_url('login')
- referrer = request.url
- if referrer == login_url:
- referrer = '/' # never use the login form itself as came_from
- came_from = request.params.get('came_from', referrer)
- message = ''
- login = ''
- password = ''
- if 'form.submitted' in request.params:
- login = request.params['login']
- password = request.params['password']
- if USERS.get(login) == password:
- headers = remember(request, login)
- return HTTPFound(location = came_from,
- headers = headers)
- message = 'Failed login'
-
- return dict(
- message = message,
- url = request.application_url + '/login',
- came_from = came_from,
- login = login,
- password = password,
- )
-
-def logout(request):
- headers = forget(request)
- return HTTPFound(location = request.route_url('view_wiki'),
- headers = headers)
-
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/models.py b/docs/tutorials/wiki2/src/tests/tutorial/models.py
index 832545cb1..c3bdcbea5 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/models.py
@@ -1,17 +1,20 @@
-import transaction
+from pyramid.security import (
+ Allow,
+ Everyone,
+ )
-from pyramid.security import Allow
-from pyramid.security import Everyone
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -29,20 +32,6 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'This is the front page')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
-
class RootFactory(object):
__acl__ = [ (Allow, Everyone, 'view'),
(Allow, 'group:editors', 'edit') ]
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py
new file mode 100644
index 000000000..de74f4d63
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/scripts/populate.py
@@ -0,0 +1,36 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv, settings=None):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ if settings is None:
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/security.py b/docs/tutorials/wiki2/src/tests/tutorial/security.py
index cfd13071e..d88c9c71f 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/security.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/security.py
@@ -5,4 +5,3 @@ GROUPS = {'editor':['group:editors']}
def groupfinder(userid, request):
if userid in USERS:
return GROUPS.get(userid, [])
-
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests.py b/docs/tutorials/wiki2/src/tests/tutorial/tests.py
index 8439e2748..557d1b1be 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/tests.py
@@ -1,16 +1,20 @@
import unittest
-
+import transaction
from pyramid import testing
-
def _initTestingDB():
- from tutorial.models import DBSession
- from tutorial.models import Base
from sqlalchemy import create_engine
- engine = create_engine('sqlite:///:memory:')
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
+ from tutorial.models import (
+ DBSession,
+ Page,
+ Base
+ )
+ engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
+ DBSession.configure(bind=engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
return DBSession
def _registerRoutes(config):
@@ -39,28 +43,6 @@ class PageModelTests(unittest.TestCase):
self.assertEqual(instance.name, 'SomeName')
self.assertEqual(instance.data, 'some data')
-class InitializeSqlTests(unittest.TestCase):
-
- def setUp(self):
- from tutorial.models import DBSession
- DBSession.remove()
-
- def tearDown(self):
- from tutorial.models import DBSession
- DBSession.remove()
-
- def _callFUT(self, engine):
- from tutorial.models import initialize_sql
- return initialize_sql(engine)
-
- def test_it(self):
- from sqlalchemy import create_engine
- engine = create_engine('sqlite:///:memory:')
- self._callFUT(engine)
- from tutorial.models import DBSession, Page
- self.assertEqual(DBSession.query(Page).one().data,
- 'This is the front page')
-
class ViewWikiTests(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
@@ -191,10 +173,11 @@ class FunctionalTests(unittest.TestCase):
def setUp(self):
from tutorial import main
- settings = { 'sqlalchemy.url': 'sqlite:///:memory:'}
+ settings = { 'sqlalchemy.url': 'sqlite://'}
app = main({}, **settings)
from webtest import TestApp
self.testapp = TestApp(app)
+ _initTestingDB()
def tearDown(self):
del self.testapp
@@ -263,3 +246,23 @@ class FunctionalTests(unittest.TestCase):
self.testapp.get(self.editor_login, status=302)
res = self.testapp.get('/FrontPage', status=200)
self.assertTrue('FrontPage' in res.body)
+
+class Test_populate(unittest.TestCase):
+ def setUp(self):
+ from tutorial.models import DBSession
+ DBSession.remove()
+
+ def tearDown(self):
+ from tutorial.models import DBSession
+ DBSession.remove()
+
+ def _callFUT(self, settings):
+ from tutorial.scripts.populate import main
+ main(['foo', 'development.ini'], settings)
+
+ def test_it(self):
+ self._callFUT({'sqlalchemy.url':'sqlite://'})
+ from tutorial.models import DBSession, Page
+ self.assertEqual(DBSession.query(Page).one().data,
+ 'This is the front page')
+
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views.py b/docs/tutorials/wiki2/src/tests/tutorial/views.py
index fc85d4585..375f1f5a5 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/views.py
@@ -1,20 +1,36 @@
import re
-
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound, HTTPNotFound
-from pyramid.security import authenticated_userid
+from pyramid.httpexceptions import (
+ HTTPFound,
+ HTTPNotFound,
+ HTTPForbidden,
+ )
+
+from pyramid.view import view_config
+
+from pyramid.security import (
+ remember,
+ forget,
+ authenticated_userid,
+ )
-from tutorial.models import DBSession
-from tutorial.models import Page
+from .models import (
+ DBSession,
+ Page,
+ )
+
+from .security import USERS
# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
+@view_config(route_name='view_wiki')
def view_wiki(request):
return HTTPFound(location = request.route_url('view_page',
pagename='FrontPage'))
+@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
pagename = request.matchdict['pagename']
session = DBSession()
@@ -35,10 +51,11 @@ def view_page(request):
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(check, content)
edit_url = request.route_url('edit_page', pagename=pagename)
- logged_in = authenticated_userid(request)
return dict(page=page, content=content, edit_url=edit_url,
- logged_in=logged_in)
+ logged_in=authenticated_userid(request))
+@view_config(route_name='add_page', renderer='templates/edit.pt',
+ permission='edit')
def add_page(request):
name = request.matchdict['pagename']
if 'form.submitted' in request.params:
@@ -50,9 +67,11 @@ def add_page(request):
pagename=name))
save_url = request.route_url('add_page', pagename=name)
page = Page('', '')
- logged_in = authenticated_userid(request)
- return dict(page=page, save_url=save_url, logged_in=logged_in)
+ return dict(page=page, save_url=save_url,
+ logged_in=authenticated_userid(request))
+@view_config(route_name='edit_page', renderer='templates/edit.pt',
+ permission='edit')
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
@@ -62,10 +81,43 @@ def edit_page(request):
session.add(page)
return HTTPFound(location = request.route_url('view_page',
pagename=name))
-
- logged_in = authenticated_userid(request)
return dict(
page=page,
save_url = request.route_url('edit_page', pagename=name),
- logged_in = logged_in,
+ logged_in=authenticated_userid(request),
)
+
+@view_config(route_name='login', renderer='templates/login.pt')
+@view_config(context=HTTPForbidden, renderer='templates/login.pt')
+def login(request):
+ login_url = request.route_url('login')
+ referrer = request.url
+ if referrer == login_url:
+ referrer = '/' # never use the login form itself as came_from
+ came_from = request.params.get('came_from', referrer)
+ message = ''
+ login = ''
+ password = ''
+ if 'form.submitted' in request.params:
+ login = request.params['login']
+ password = request.params['password']
+ if USERS.get(login) == password:
+ headers = remember(request, login)
+ return HTTPFound(location = came_from,
+ headers = headers)
+ message = 'Failed login'
+
+ return dict(
+ message = message,
+ url = request.application_url + '/login',
+ came_from = came_from,
+ login = login,
+ password = password,
+ )
+
+@view_config(route_name='logout')
+def logout(request):
+ headers = forget(request)
+ return HTTPFound(location = request.route_url('view_wiki'),
+ headers = headers)
+
diff --git a/docs/tutorials/wiki2/src/views/README.txt b/docs/tutorials/wiki2/src/views/README.txt
index d41f7f90f..6f851e9b7 100644
--- a/docs/tutorials/wiki2/src/views/README.txt
+++ b/docs/tutorials/wiki2/src/views/README.txt
@@ -1,4 +1 @@
tutorial README
-
-
-
diff --git a/docs/tutorials/wiki2/src/views/development.ini b/docs/tutorials/wiki2/src/views/development.ini
index d1e262324..4f7493cba 100644
--- a/docs/tutorials/wiki2/src/views/development.ini
+++ b/docs/tutorials/wiki2/src/views/development.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
@@ -19,7 +20,7 @@ port = 6543
# Begin logging configuration
[loggers]
-keys = root, sqlalchemy
+keys = root, tutorial, sqlalchemy
[handlers]
keys = console
@@ -31,6 +32,11 @@ keys = generic
level = INFO
handlers = console
+[logger_tutorial]
+level = DEBUG
+handlers =
+qualname = tutorial
+
[logger_sqlalchemy]
level = INFO
handlers =
diff --git a/docs/tutorials/wiki2/src/views/production.ini b/docs/tutorials/wiki2/src/views/production.ini
index ac02acf3f..53eaf20a1 100644
--- a/docs/tutorials/wiki2/src/views/production.ini
+++ b/docs/tutorials/wiki2/src/views/production.ini
@@ -1,5 +1,6 @@
[app:main]
use = egg:tutorial
+
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
diff --git a/docs/tutorials/wiki2/src/views/setup.py b/docs/tutorials/wiki2/src/views/setup.py
index 439a86923..9c0e88eb0 100644
--- a/docs/tutorials/wiki2/src/views/setup.py
+++ b/docs/tutorials/wiki2/src/views/setup.py
@@ -42,6 +42,8 @@ setup(name='tutorial',
entry_points = """\
[paste.app_factory]
main = tutorial:main
+ [console_scripts]
+ populate_tutorial = tutorial.scripts.populate:main
""",
)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
index 7d79f7a1f..b30d593cf 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
@@ -1,25 +1,18 @@
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
-from tutorial.models import initialize_sql
+from .models import DBSession
def main(global_config, **settings):
- """ This function returns a WSGI application.
+ """ This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
- initialize_sql(engine)
+ DBSession.configure(bind=engine)
config = Configurator(settings=settings)
- config.add_static_view('static', 'tutorial:static', cache_max_age=3600)
+ config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('view_wiki', '/')
config.add_route('view_page', '/{pagename}')
config.add_route('add_page', '/add_page/{pagename}')
config.add_route('edit_page', '/{pagename}/edit_page')
- config.add_view('tutorial.views.view_wiki', route_name='view_wiki')
- config.add_view('tutorial.views.view_page', route_name='view_page',
- renderer='tutorial:templates/view.pt')
- config.add_view('tutorial.views.add_page', route_name='add_page',
- renderer='tutorial:templates/edit.pt')
- config.add_view('tutorial.views.edit_page', route_name='edit_page',
- renderer='tutorial:templates/edit.pt')
+ config.scan()
return config.make_wsgi_app()
-
diff --git a/docs/tutorials/wiki2/src/views/tutorial/models.py b/docs/tutorials/wiki2/src/views/tutorial/models.py
index 30506f67e..499396c5b 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/models.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/models.py
@@ -1,14 +1,15 @@
-import transaction
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Text
-
-from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -26,16 +27,3 @@ class Page(Base):
self.name = name
self.data = data
-def initialize_sql(engine):
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
- Base.metadata.create_all(engine)
- try:
- transaction.begin()
- session = DBSession()
- page = Page('FrontPage', 'initial data')
- session.add(page)
- transaction.commit()
- except IntegrityError:
- # already created
- transaction.abort()
diff --git a/docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py
new file mode 100644
index 000000000..5bb534f79
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/scripts/__init__.py
@@ -0,0 +1 @@
+# package
diff --git a/docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py b/docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py
new file mode 100644
index 000000000..03188e8ad
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/tutorial/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ Page,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
index 14b88d16a..fbfa9870b 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki2/src/views/tutorial/templates/mytemplate.pt
@@ -6,9 +6,9 @@
<meta name="keywords" content="python web application" />
<meta name="description" content="pyramid web application" />
<link rel="shortcut icon" href="${request.static_url('tutorial:static/favicon.ico')}" />
+ <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/nobile/stylesheet.css" media="screen" />
<link rel="stylesheet" href="http://static.pylonsproject.org/fonts/neuton/stylesheet.css" media="screen" />
- <link rel="stylesheet" href="${request.static_url('tutorial:static/pylons.css')}" type="text/css" media="screen" charset="utf-8" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="${request.static_url('tutorial:static/ie6.css')}" type="text/css" media="screen" charset="utf-8" />
<![endif]-->
diff --git a/docs/tutorials/wiki2/src/views/tutorial/tests.py b/docs/tutorials/wiki2/src/views/tutorial/tests.py
index 668bf5479..31d2dc6d5 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/tests.py
@@ -1,15 +1,20 @@
import unittest
-
+import transaction
from pyramid import testing
def _initTestingDB():
- from tutorial.models import DBSession
- from tutorial.models import Base
from sqlalchemy import create_engine
+ from tutorial.models import (
+ DBSession,
+ Page,
+ Base
+ )
engine = create_engine('sqlite://')
- DBSession.configure(bind=engine)
- Base.metadata.bind = engine
Base.metadata.create_all(engine)
+ DBSession.configure(bind=engine)
+ with transaction.manager:
+ model = Page('FrontPage', 'This is the front page')
+ DBSession.add(model)
return DBSession
def _registerRoutes(config):
@@ -20,8 +25,10 @@ def _registerRoutes(config):
class ViewWikiTests(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
+ self.session = _initTestingDB()
def tearDown(self):
+ self.session.remove()
testing.tearDown()
def _callFUT(self, request):
diff --git a/docs/tutorials/wiki2/src/views/tutorial/views.py b/docs/tutorials/wiki2/src/views/tutorial/views.py
index e04b96ae4..5c49dd2e8 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/views.py
@@ -1,19 +1,26 @@
import re
-
from docutils.core import publish_parts
-from pyramid.httpexceptions import HTTPFound, HTTPNotFound
+from pyramid.httpexceptions import (
+ HTTPFound,
+ HTTPNotFound,
+ )
+from pyramid.view import view_config
-from tutorial.models import DBSession
-from tutorial.models import Page
+from .models import (
+ DBSession,
+ Page,
+ )
# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
+@view_config(route_name='view_wiki')
def view_wiki(request):
return HTTPFound(location = request.route_url('view_page',
pagename='FrontPage'))
+@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
pagename = request.matchdict['pagename']
session = DBSession()
@@ -36,6 +43,7 @@ def view_page(request):
edit_url = request.route_url('edit_page', pagename=pagename)
return dict(page=page, content=content, edit_url=edit_url)
+@view_config(route_name='add_page', renderer='templates/edit.pt')
def add_page(request):
name = request.matchdict['pagename']
if 'form.submitted' in request.params:
@@ -49,6 +57,7 @@ def add_page(request):
page = Page('', '')
return dict(page=page, save_url=save_url)
+@view_config(route_name='edit_page', renderer='templates/edit.pt')
def edit_page(request):
name = request.matchdict['pagename']
session = DBSession()
diff --git a/docs/tutorials/wiki2/tests.rst b/docs/tutorials/wiki2/tests.rst
index 8fa8ea3ae..25cf2c25e 100644
--- a/docs/tutorials/wiki2/tests.rst
+++ b/docs/tutorials/wiki2/tests.rst
@@ -14,8 +14,8 @@ 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 two test classes: one for the
-``Page`` model named ``PageModelTests``, one for the ``initialize_sql``
-function named ``InitializeSqlTests``.
+``Page`` model named ``PageModelTests``, and one for the ``populate`` script
+named ``Test_populate``.
Testing the Views
=================
diff --git a/pyramid/scaffolds/__init__.py b/pyramid/scaffolds/__init__.py
index dfde9d855..dc6926024 100644
--- a/pyramid/scaffolds/__init__.py
+++ b/pyramid/scaffolds/__init__.py
@@ -2,16 +2,12 @@ import binascii
import os
from pyramid.compat import native_
-from pyramid.compat import text_
from pyramid.scaffolds.template import Template
class PyramidTemplate(Template):
def pre(self, command, output_dir, vars):
vars['random_string'] = native_(binascii.hexlify(os.urandom(20)))
- # placeholder text values
- vars['one'] = text_('one')
- vars['two'] = text_('two')
package_logger = vars['package']
if package_logger == 'root':
# Rename the app logger in the rare case a project is named 'root'
diff --git a/pyramid/scaffolds/alchemy/+package+/models.py b/pyramid/scaffolds/alchemy/+package+/models.py
index 000dadd91..b6ac15429 100644
--- a/pyramid/scaffolds/alchemy/+package+/models.py
+++ b/pyramid/scaffolds/alchemy/+package+/models.py
@@ -1,11 +1,15 @@
-from sqlalchemy import Column
-from sqlalchemy import Integer
-from sqlalchemy import Unicode
+from sqlalchemy import (
+ Column,
+ Integer,
+ Text,
+ )
from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import scoped_session
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import (
+ scoped_session,
+ sessionmaker,
+ )
from zope.sqlalchemy import ZopeTransactionExtension
@@ -15,7 +19,7 @@ Base = declarative_base()
class MyModel(Base):
__tablename__ = 'models'
id = Column(Integer, primary_key=True)
- name = Column(Unicode(255), unique=True)
+ name = Column(Text, unique=True)
value = Column(Integer)
def __init__(self, name, value):
diff --git a/pyramid/scaffolds/alchemy/+package+/scripts/populate.py b/pyramid/scaffolds/alchemy/+package+/scripts/populate.py
new file mode 100644
index 000000000..0e828465f
--- /dev/null
+++ b/pyramid/scaffolds/alchemy/+package+/scripts/populate.py
@@ -0,0 +1,35 @@
+import os
+import sys
+import transaction
+
+from sqlalchemy import engine_from_config
+
+from pyramid.paster import (
+ get_appsettings,
+ setup_logging,
+ )
+
+from ..models import (
+ DBSession,
+ MyModel,
+ Base,
+ )
+
+def usage(argv):
+ cmd = os.path.basename(argv[0])
+ print('usage: %s <config_uri>\n'
+ '(example: "%s development.ini")' % (cmd, cmd))
+ sys.exit(1)
+
+def main(argv=sys.argv):
+ if len(argv) != 2:
+ usage(argv)
+ config_uri = argv[1]
+ setup_logging(config_uri)
+ settings = get_appsettings(config_uri)
+ engine = engine_from_config(settings, 'sqlalchemy.')
+ DBSession.configure(bind=engine)
+ Base.metadata.create_all(engine)
+ with transaction.manager:
+ model = MyModel(name='one', value=1)
+ DBSession.add(model)
diff --git a/pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl b/pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl
deleted file mode 100644
index dd11a64d7..000000000
--- a/pyramid/scaffolds/alchemy/+package+/scripts/populate.py_tmpl
+++ /dev/null
@@ -1,30 +0,0 @@
-import os
-import sys
-import logging.config
-
-from paste.deploy.loadwsgi import appconfig
-from sqlalchemy import engine_from_config
-import transaction
-
-from ..models import DBSession
-from ..models import MyModel
-from ..models import Base
-
-def usage(argv):
- print('usage: %s <Pyramid ini filename>' % os.path.basename(argv[0]))
- sys.exit(1)
-
-def main(argv=sys.argv):
- try:
- config_filename = argv[1]
- except IndexError:
- usage(argv)
- config_filename = os.path.abspath(config_filename)
- logging.config.fileConfig(config_filename)
- settings = appconfig('config:' + config_filename)
- engine = engine_from_config(settings, 'sqlalchemy.')
- DBSession.configure(bind=engine)
- Base.metadata.create_all(engine)
- with transaction.manager:
- model = MyModel(name={{repr(one)}}, value=1)
- DBSession.add(model)
diff --git a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
index 3b4b028a9..729b337cb 100644
--- a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
+++ b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl
@@ -17,7 +17,7 @@ class TestMyView(unittest.TestCase):
DBSession.configure(bind=engine)
Base.metadata.create_all(engine)
with transaction.manager:
- model = MyModel(name={{repr(one)}}, value=55)
+ model = MyModel(name='one', value=55)
DBSession.add(model)
def tearDown(self):
diff --git a/pyramid/scaffolds/alchemy/+package+/views.py_tmpl b/pyramid/scaffolds/alchemy/+package+/views.py_tmpl
index 568b73c18..b7b23fc67 100644
--- a/pyramid/scaffolds/alchemy/+package+/views.py_tmpl
+++ b/pyramid/scaffolds/alchemy/+package+/views.py_tmpl
@@ -1,9 +1,11 @@
from pyramid.view import view_config
-from .models import DBSession
-from .models import MyModel
+from .models import (
+ DBSession,
+ MyModel,
+ )
@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
- one = DBSession.query(MyModel).filter(MyModel.name=={{repr(one)}}).first()
+ one = DBSession.query(MyModel).filter(MyModel.name=='one').first()
return {'one':one, 'project':'{{project}}'}