summaryrefslogtreecommitdiff
path: root/docs/tutorials
diff options
context:
space:
mode:
authorcewing <cris@crisewing.com>2017-05-22 12:09:41 -0700
committercewing <cris@crisewing.com>2017-05-22 12:09:41 -0700
commitb033b966420b673bf0222c3576d3238773433d0f (patch)
treeba5d63e118ba5ebbad901b5c1558adff04224686 /docs/tutorials
parent7c680930d09d20bfa05249e01553e6488e61f1ca (diff)
parent8c4d422965b633f31967ceed1e6cc25cc616d0bf (diff)
downloadpyramid-b033b966420b673bf0222c3576d3238773433d0f.tar.gz
pyramid-b033b966420b673bf0222c3576d3238773433d0f.tar.bz2
pyramid-b033b966420b673bf0222c3576d3238773433d0f.zip
Merge branch 'master' into issue.2614
Diffstat (limited to 'docs/tutorials')
-rw-r--r--docs/tutorials/modwsgi/index.rst84
-rw-r--r--docs/tutorials/wiki/authorization.rst88
-rw-r--r--docs/tutorials/wiki/background.rst2
-rw-r--r--docs/tutorials/wiki/basiclayout.rst28
-rw-r--r--docs/tutorials/wiki/definingmodels.rst6
-rw-r--r--docs/tutorials/wiki/definingviews.rst51
-rw-r--r--docs/tutorials/wiki/design.rst7
-rw-r--r--docs/tutorials/wiki/distributing.rst9
-rw-r--r--docs/tutorials/wiki/index.rst7
-rw-r--r--docs/tutorials/wiki/installation.rst270
-rw-r--r--docs/tutorials/wiki/src/authorization/.coveragerc3
-rw-r--r--docs/tutorials/wiki/src/authorization/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki/src/authorization/README.txt27
-rw-r--r--docs/tutorials/wiki/src/authorization/development.ini10
-rw-r--r--docs/tutorials/wiki/src/authorization/production.ini11
-rw-r--r--docs/tutorials/wiki/src/authorization/pytest.ini3
-rw-r--r--docs/tutorials/wiki/src/authorization/setup.py61
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/__init__.py2
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/security.py17
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt1
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt1
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt67
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt1
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki/src/authorization/tutorial/views.py6
-rw-r--r--docs/tutorials/wiki/src/basiclayout/.coveragerc3
-rw-r--r--docs/tutorials/wiki/src/basiclayout/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki/src/basiclayout/README.txt27
-rw-r--r--docs/tutorials/wiki/src/basiclayout/development.ini10
-rw-r--r--docs/tutorials/wiki/src/basiclayout/production.ini11
-rw-r--r--docs/tutorials/wiki/src/basiclayout/pytest.ini3
-rw-r--r--docs/tutorials/wiki/src/basiclayout/setup.py60
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py2
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt10
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki/src/basiclayout/tutorial/views.py2
-rw-r--r--docs/tutorials/wiki/src/installation/.coveragerc3
-rw-r--r--docs/tutorials/wiki/src/installation/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki/src/installation/README.txt27
-rw-r--r--docs/tutorials/wiki/src/installation/development.ini10
-rw-r--r--docs/tutorials/wiki/src/installation/production.ini11
-rw-r--r--docs/tutorials/wiki/src/installation/pytest.ini3
-rw-r--r--docs/tutorials/wiki/src/installation/setup.py60
-rw-r--r--docs/tutorials/wiki/src/installation/tutorial/__init__.py2
-rw-r--r--docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt10
-rw-r--r--docs/tutorials/wiki/src/installation/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki/src/installation/tutorial/views.py2
-rw-r--r--docs/tutorials/wiki/src/models/.coveragerc3
-rw-r--r--docs/tutorials/wiki/src/models/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki/src/models/README.txt27
-rw-r--r--docs/tutorials/wiki/src/models/development.ini10
-rw-r--r--docs/tutorials/wiki/src/models/production.ini11
-rw-r--r--docs/tutorials/wiki/src/models/pytest.ini3
-rw-r--r--docs/tutorials/wiki/src/models/setup.py60
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/__init__.py2
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt10
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki/src/models/tutorial/views.py2
-rw-r--r--docs/tutorials/wiki/src/tests/.coveragerc3
-rw-r--r--docs/tutorials/wiki/src/tests/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki/src/tests/README.txt27
-rw-r--r--docs/tutorials/wiki/src/tests/development.ini10
-rw-r--r--docs/tutorials/wiki/src/tests/production.ini11
-rw-r--r--docs/tutorials/wiki/src/tests/pytest.ini3
-rw-r--r--docs/tutorials/wiki/src/tests/setup.py61
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/__init__.py2
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/security.py17
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt1
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/templates/login.pt1
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/templates/view.pt1
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/tests.py11
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/views.py6
-rw-r--r--docs/tutorials/wiki/src/views/.coveragerc3
-rw-r--r--docs/tutorials/wiki/src/views/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki/src/views/README.txt27
-rw-r--r--docs/tutorials/wiki/src/views/development.ini10
-rw-r--r--docs/tutorials/wiki/src/views/production.ini11
-rw-r--r--docs/tutorials/wiki/src/views/pytest.ini3
-rw-r--r--docs/tutorials/wiki/src/views/setup.py60
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/__init__.py2
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt67
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/templates/view.pt1
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki/src/views/tutorial/views.py12
-rw-r--r--docs/tutorials/wiki/tests.rst18
-rw-r--r--docs/tutorials/wiki2/authentication.rst2
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst14
-rw-r--r--docs/tutorials/wiki2/definingmodels.rst143
-rw-r--r--docs/tutorials/wiki2/definingviews.rst14
-rw-r--r--docs/tutorials/wiki2/design.rst33
-rw-r--r--docs/tutorials/wiki2/distributing.rst12
-rw-r--r--docs/tutorials/wiki2/index.rst7
-rw-r--r--docs/tutorials/wiki2/installation.rst340
-rw-r--r--docs/tutorials/wiki2/src/authentication/.coveragerc3
-rw-r--r--docs/tutorials/wiki2/src/authentication/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki2/src/authentication/MANIFEST.in2
-rw-r--r--docs/tutorials/wiki2/src/authentication/README.txt31
-rw-r--r--docs/tutorials/wiki2/src/authentication/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/authentication/production.ini11
-rw-r--r--docs/tutorials/wiki2/src/authentication/pytest.ini3
-rw-r--r--docs/tutorials/wiki2/src/authentication/setup.py65
-rw-r--r--docs/tutorials/wiki2/src/authentication/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki2/src/authentication/tutorial/views/default.py6
-rw-r--r--docs/tutorials/wiki2/src/authorization/.coveragerc3
-rw-r--r--docs/tutorials/wiki2/src/authorization/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki2/src/authorization/MANIFEST.in2
-rw-r--r--docs/tutorials/wiki2/src/authorization/README.txt31
-rw-r--r--docs/tutorials/wiki2/src/authorization/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/authorization/production.ini11
-rw-r--r--docs/tutorials/wiki2/src/authorization/pytest.ini3
-rw-r--r--docs/tutorials/wiki2/src/authorization/setup.py65
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/views/default.py6
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/.coveragerc3
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/MANIFEST.in2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/README.txt31
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/production.ini11
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/pytest.ini3
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/setup.py65
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja28
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja24
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/views/default.py2
-rw-r--r--docs/tutorials/wiki2/src/installation/.coveragerc3
-rw-r--r--docs/tutorials/wiki2/src/installation/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki2/src/installation/MANIFEST.in2
-rw-r--r--docs/tutorials/wiki2/src/installation/README.txt31
-rw-r--r--docs/tutorials/wiki2/src/installation/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/installation/production.ini11
-rw-r--r--docs/tutorials/wiki2/src/installation/pytest.ini3
-rw-r--r--docs/tutorials/wiki2/src/installation/setup.py65
-rw-r--r--docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py2
-rw-r--r--docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja28
-rw-r--r--docs/tutorials/wiki2/src/installation/tutorial/templates/mytemplate.jinja24
-rw-r--r--docs/tutorials/wiki2/src/installation/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki2/src/installation/tutorial/views/default.py2
-rw-r--r--docs/tutorials/wiki2/src/models/.coveragerc3
-rw-r--r--docs/tutorials/wiki2/src/models/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki2/src/models/MANIFEST.in2
-rw-r--r--docs/tutorials/wiki2/src/models/README.txt31
-rw-r--r--docs/tutorials/wiki2/src/models/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/models/production.ini11
-rw-r--r--docs/tutorials/wiki2/src/models/pytest.ini3
-rw-r--r--docs/tutorials/wiki2/src/models/setup.py65
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja28
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.jinja24
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/views/default.py2
-rw-r--r--docs/tutorials/wiki2/src/tests/.coveragerc3
-rw-r--r--docs/tutorials/wiki2/src/tests/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki2/src/tests/MANIFEST.in2
-rw-r--r--docs/tutorials/wiki2/src/tests/README.txt31
-rw-r--r--docs/tutorials/wiki2/src/tests/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/tests/production.ini11
-rw-r--r--docs/tutorials/wiki2/src/tests/pytest.ini3
-rw-r--r--docs/tutorials/wiki2/src/tests/setup.py65
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py1
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py12
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/tests/test_initdb.py16
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/tests/test_security.py23
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/tests/test_user_model.py67
-rw-r--r--docs/tutorials/wiki2/src/tests/tutorial/views/default.py6
-rw-r--r--docs/tutorials/wiki2/src/views/.coveragerc3
-rw-r--r--docs/tutorials/wiki2/src/views/CHANGES.txt2
-rw-r--r--docs/tutorials/wiki2/src/views/MANIFEST.in2
-rw-r--r--docs/tutorials/wiki2/src/views/README.txt31
-rw-r--r--docs/tutorials/wiki2/src/views/development.ini8
-rw-r--r--docs/tutorials/wiki2/src/views/production.ini11
-rw-r--r--docs/tutorials/wiki2/src/views/pytest.ini3
-rw-r--r--docs/tutorials/wiki2/src/views/setup.py65
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja22
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/tests.py2
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/views/default.py6
-rw-r--r--docs/tutorials/wiki2/tests.rst43
176 files changed, 1726 insertions, 1494 deletions
diff --git a/docs/tutorials/modwsgi/index.rst b/docs/tutorials/modwsgi/index.rst
index c66786b11..170f2ebc8 100644
--- a/docs/tutorials/modwsgi/index.rst
+++ b/docs/tutorials/modwsgi/index.rst
@@ -32,60 +32,71 @@ specific path information for commands and files.
<https://code.google.com/archive/p/modwsgi/wikis/InstallationInstructions.wiki>`_
for your platform into your system's Apache installation.
-#. Create a :term:`virtual environment` which we'll use to install our
- application.
+#. Create a :app:`Pyramid` application. For this tutorial we'll use the
+ ``starter`` :term:`cookiecutter`. See :ref:`project_narr` for more
+ in-depth information about creating a new project.
- .. code-block:: text
+ .. code-block:: bash
$ cd ~
- $ mkdir modwsgi
- $ cd modwsgi
- $ python3 -m venv env
+ $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-starter
-#. Install :app:`Pyramid` into the newly created virtual environment:
+ If prompted for the first item, accept the default ``yes`` by hitting return.
- .. parsed-literal::
+ .. code-block:: text
- $ cd ~/modwsgi/env
- $ $VENV/bin/pip install "pyramid==\ |release|\ "
+ You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.
+ Is it okay to delete and re-clone it? [yes]: yes
+ project_name [Pyramid Scaffold]: myproject
+ repo_name [myproject]: myproject
+ Select template_language:
+ 1 - jinja2
+ 2 - chameleon
+ 3 - mako
+ Choose from 1, 2, 3 [1]: 1
-#. Create and install your :app:`Pyramid` application. For the purposes of
- this tutorial, we'll just be using the ``pyramid_starter`` application as
- a baseline application. Substitute your existing :app:`Pyramid`
- application as necessary if you already have one.
+#. Create a :term:`virtual environment` which we'll use to install our
+ application. It is important to use the same base Python interpreter
+ that was used to build ``mod_wsgi``. For example, if ``mod_wsgi`` was
+ built against the system Python 3.x, then your project should use a
+ virtual environment created from that same system Python 3.x.
- .. code-block:: text
+ .. code-block:: bash
- $ cd ~/modwsgi/env
- $ $VENV/bin/pcreate -s starter myapp
- $ cd myapp
- $ $VENV/bin/pip install -e .
+ $ cd myproject
+ $ python3 -m venv env
+
+#. Install your :app:`Pyramid` application and its dependencies.
+
+ .. code-block:: bash
-#. Within the virtual environment directory (``~/modwsgi/env``), create a
- script named ``pyramid.wsgi``. Give it these contents:
+ $ env/bin/pip install -e .
+
+#. Within the project directory (``~/myproject``), create a script
+ named ``pyramid.wsgi``. Give it these contents:
.. code-block:: python
from pyramid.paster import get_app, setup_logging
- ini_path = '/Users/chrism/modwsgi/env/myapp/production.ini'
+ ini_path = '/Users/chrism/myproject/production.ini'
setup_logging(ini_path)
application = get_app(ini_path, 'main')
- The first argument to ``get_app`` is the project configuration file
- name. It's best to use the ``production.ini`` file provided by your
- scaffold, as it contains settings appropriate for
- production. The second is the name of the section within the .ini file
- that should be loaded by ``mod_wsgi``. The assignment to the name
+ The first argument to :func:`pyramid.paster.get_app` is the project
+ configuration file name. It's best to use the ``production.ini`` file
+ provided by your cookiecutter, as it contains settings appropriate for
+ production. The second is the name of the section within the ``.ini``
+ file that should be loaded by ``mod_wsgi``. The assignment to the name
``application`` is important: mod_wsgi requires finding such an
assignment when it opens the file.
- The call to ``setup_logging`` initializes the standard library's
- `logging` module to allow logging within your application.
+ The call to :func:`pyramid.paster.setup_logging` initializes the standard
+ library's `logging` module to allow logging within your application.
See :ref:`logging_config`.
There is no need to make the ``pyramid.wsgi`` script executable.
However, you'll need to make sure that *two* users have access to change
- into the ``~/modwsgi/env`` directory: your current user (mine is
+ into the ``~/myproject`` directory: your current user (mine is
``chrism`` and the user that Apache will run as often named ``apache`` or
``httpd``). Make sure both of these users can "cd" into that directory.
@@ -101,18 +112,17 @@ specific path information for commands and files.
WSGIApplicationGroup %{GLOBAL}
WSGIPassAuthorization On
WSGIDaemonProcess pyramid user=chrism group=staff threads=4 \
- python-path=/Users/chrism/modwsgi/env/lib/python2.7/site-packages
- WSGIScriptAlias /myapp /Users/chrism/modwsgi/env/pyramid.wsgi
+ python-path=/Users/chrism/myproject/env/lib/python3.5/site-packages
+ WSGIScriptAlias /myapp /Users/chrism/myproject/pyramid.wsgi
- <Directory /Users/chrism/modwsgi/env>
+ <Directory /Users/chrism/myproject>
WSGIProcessGroup pyramid
- Order allow,deny
- Allow from all
+ Require all granted
</Directory>
#. Restart Apache
- .. code-block:: text
+ .. code-block:: bash
$ sudo /usr/sbin/apachectl restart
@@ -122,5 +132,5 @@ specific path information for commands and files.
:term:`mod_wsgi` has many knobs and a great variety of deployment modes. This
is just one representation of how you might use it to serve up a :app:`Pyramid`
application. See the `mod_wsgi configuration documentation
-<https://code.google.com/archive/p/modwsgi/wikis/ConfigurationGuidelines.wiki>`_
+<https://modwsgi.readthedocs.io/en/develop/configuration.html>`_
for more in-depth configuration information.
diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst
index 44097b35b..0ba734f83 100644
--- a/docs/tutorials/wiki/authorization.rst
+++ b/docs/tutorials/wiki/authorization.rst
@@ -18,6 +18,7 @@ require permission, instead of a default "403 Forbidden" page.
We will implement the access control with the following steps:
+* Add password hashing dependencies.
* Add users and groups (``security.py``, a new module).
* Add an :term:`ACL` (``models.py``).
* Add an :term:`authentication policy` and an :term:`authorization policy`
@@ -25,7 +26,7 @@ We will implement the access control with the following steps:
* Add :term:`permission` declarations to the ``edit_page`` and ``add_page``
views (``views.py``).
-Then we will add the login and logout feature:
+Then we will add the login and logout features:
* Add ``login`` and ``logout`` views (``views.py``).
* Add a login template (``login.pt``).
@@ -38,11 +39,32 @@ Then we will add the login and logout feature:
Access control
--------------
+
+Add dependencies
+~~~~~~~~~~~~~~~~
+
+Just like in :ref:`wiki_defining_views`, we need a new dependency. We need to add the `bcrypt <https://pypi.python.org/pypi/bcrypt>`_ package, to our tutorial package's ``setup.py`` file by assigning this dependency to the ``requires`` parameter in the ``setup()`` function.
+
+Open ``setup.py`` and edit it to look like the following:
+
+.. literalinclude:: src/authorization/setup.py
+ :linenos:
+ :emphasize-lines: 21
+ :language: python
+
+Only the highlighted line needs to be added.
+
+Do not forget to run ``pip install -e .`` just like in :ref:`wiki-running-pip-install`.
+
+.. note::
+
+ We are using the ``bcrypt`` package from PyPI to hash our passwords securely. There are other one-way hash algorithms for passwords if bcrypt is an issue on your system. Just make sure that it's an algorithm approved for storing passwords versus a generic one-way hash.
+
+
Add users and groups
~~~~~~~~~~~~~~~~~~~~
-Create a new ``tutorial/security.py`` module with the
-following content:
+Create a new ``tutorial/security.py`` module with the following content:
.. literalinclude:: src/authorization/tutorial/security.py
:linenos:
@@ -51,7 +73,7 @@ following content:
The ``groupfinder`` function accepts a userid and a request and
returns one of these values:
-- If the userid exists in the system, it will return a sequence of group
+- If ``userid`` exists in the system, it will return a sequence of group
identifiers (or an empty sequence if the user isn't a member of any groups).
- If the userid *does not* exist in the system, it will return ``None``.
@@ -61,26 +83,38 @@ request)`` returns ``None``. We will use ``groupfinder()`` as an
:term:`authentication policy` "callback" that will provide the
:term:`principal` or principals for a user.
-In a production system, user and group data will most often come from a
+There are two helper methods that will help us later to authenticate users.
+The first is ``hash_password`` which takes a raw password and transforms it using
+bcrypt into an irreversible representation, a process known as "hashing". The
+second method, ``check_password``, will allow us to compare the hashed value of the
+submitted password against the hashed value of the password stored in the user's
+record. If the two hashed values match, then the submitted
+password is valid, and we can authenticate the user.
+
+We hash passwords so that it is impossible to decrypt and use them to
+authenticate in the application. If we stored passwords foolishly in clear text,
+then anyone with access to the database could retrieve any password to authenticate
+as any user.
+
+In a production system, user and group data will most often be saved and come from a
database, but here we use "dummy" data to represent user and groups sources.
Add an ACL
~~~~~~~~~~
Open ``tutorial/models.py`` and add the following import
-statement at the head:
+statement near the top:
.. literalinclude:: src/authorization/tutorial/models.py
- :lines: 4-7
- :linenos:
+ :lines: 4-8
+ :lineno-match:
:language: python
Add the following lines to the ``Wiki`` class:
.. literalinclude:: src/authorization/tutorial/models.py
:lines: 9-13
- :linenos:
- :lineno-start: 9
+ :lineno-match:
:emphasize-lines: 4-5
:language: python
@@ -89,10 +123,10 @@ permission is allowed, and :data:`~pyramid.security.Everyone`, a special
:term:`principal` that is associated to all requests. Both are used in the
:term:`ACE` entries that make up the ACL.
-The ACL is a list that needs to be named `__acl__` and be an attribute of a
+The ACL is a list that needs to be named ``__acl__`` and be an attribute of a
class. We define an :term:`ACL` with two :term:`ACE` entries: the first entry
-allows any user the `view` permission. The second entry allows the
-``group:editors`` principal the `edit` permission.
+allows any user the ``view`` permission. The second entry allows the
+``group:editors`` principal the ``edit`` permission.
The ``Wiki`` class that contains the ACL is the :term:`resource` constructor
for the :term:`root` resource, which is a ``Wiki`` instance. The ACL is
@@ -115,15 +149,14 @@ statements:
.. literalinclude:: src/authorization/tutorial/__init__.py
:lines: 1-8
:linenos:
- :emphasize-lines: 4-5,8
+ :emphasize-lines: 3-6,8
:language: python
Now add those policies to the configuration:
.. literalinclude:: src/authorization/tutorial/__init__.py
:lines: 18-23
- :linenos:
- :lineno-start: 18
+ :lineno-match:
:emphasize-lines: 1-3,5-6
:language: python
@@ -146,12 +179,12 @@ Open ``tutorial/views.py`` and add a ``permission='edit'`` parameter
to the ``@view_config`` decorators for ``add_page()`` and ``edit_page()``:
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 50-52
+ :lines: 49-51
:emphasize-lines: 2-3
:language: python
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 70-72
+ :lines: 68-70
:emphasize-lines: 2-3
:language: python
@@ -213,9 +246,8 @@ cookie.
Now add the ``login`` and ``logout`` views at the end of the file:
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 82-116
- :linenos:
- :lineno-start: 82
+ :lines: 80-
+ :lineno-match:
:language: python
``login()`` has two decorators:
@@ -252,17 +284,17 @@ the return value of ``view_page()``, ``add_page()``, and ``edit_page()`` as
follows:
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 47-48
+ :lines: 46-47
:emphasize-lines: 1-2
:language: python
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 67-68
+ :lines: 65-66
:emphasize-lines: 1-2
:language: python
.. literalinclude:: src/authorization/tutorial/views.py
- :lines: 78-80
+ :lines: 76-78
:emphasize-lines: 2-3
:language: python
@@ -279,7 +311,7 @@ Open ``tutorial/templates/edit.pt`` and
indicated by the highlighted lines.
.. literalinclude:: src/authorization/tutorial/templates/edit.pt
- :lines: 34-38
+ :lines: 35-39
:emphasize-lines: 3-5
:language: html
@@ -313,7 +345,7 @@ Our ``tutorial/views.py`` will look like this when we're done:
.. literalinclude:: src/authorization/tutorial/views.py
:linenos:
- :emphasize-lines: 8,11-15,17,24,29,48,52,68,72,80,82-120
+ :emphasize-lines: 8,11-15,17,24,29,47,51,66,70,78,80-
:language: python
Only the highlighted lines need to be added or edited.
@@ -323,7 +355,7 @@ we're done:
.. literalinclude:: src/authorization/tutorial/templates/edit.pt
:linenos:
- :emphasize-lines: 36-38
+ :emphasize-lines: 37-39
:language: html
Only the highlighted lines need to be added or edited.
@@ -333,7 +365,7 @@ we're done:
.. literalinclude:: src/authorization/tutorial/templates/view.pt
:linenos:
- :emphasize-lines: 36-38
+ :emphasize-lines: 37-39
:language: html
Only the highlighted lines need to be added or edited.
diff --git a/docs/tutorials/wiki/background.rst b/docs/tutorials/wiki/background.rst
index 31dcd6b53..c583b375c 100644
--- a/docs/tutorials/wiki/background.rst
+++ b/docs/tutorials/wiki/background.rst
@@ -13,7 +13,7 @@ Python web framework experience.
To code along with this tutorial, the developer will need a UNIX
machine with development tools (Mac OS X with XCode, any Linux or BSD
-variant, etc.) *or* a Windows system of any kind.
+variant, and so on) *or* a Windows system of any kind.
.. warning::
diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst
index 20bfdf754..d00eab956 100644
--- a/docs/tutorials/wiki/basiclayout.rst
+++ b/docs/tutorials/wiki/basiclayout.rst
@@ -4,7 +4,7 @@
Basic Layout
============
-The starter files generated by the ``zodb`` scaffold are very basic, but
+The starter files generated by the ``zodb`` cookiecutter are very basic, but
they provide a good orientation for the high-level patterns common to most
:term:`traversal`-based (and :term:`ZODB`-based) :app:`Pyramid` projects.
@@ -44,7 +44,11 @@ Open ``tutorial/__init__.py``. It should already contain the following:
#. *Line 15*. Include support for the :term:`Chameleon` template rendering
bindings, allowing us to use the ``.pt`` templates.
-#. *Line 16*. Register a "static view", which answers requests whose URL
+#. *Line 16*. Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction <https://pypi.python.org/pypi/transaction>`_ package.
+
+#. *Line 17*. Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application.
+
+#. *Line 18*. Register a "static view", which answers requests whose URL
paths start with ``/static``, using the
:meth:`pyramid.config.Configurator.add_static_view` method. This
statement registers a view that will serve up static assets, such as CSS
@@ -54,19 +58,19 @@ Open ``tutorial/__init__.py``. It should already contain the following:
will be ``/static``. The second argument of this tag is the "path",
which is a relative :term:`asset specification`, so it finds the resources
it should serve within the ``static`` directory inside the ``tutorial``
- package. Alternatively the scaffold could have used an *absolute* asset
+ package. Alternatively the cookiecutter could have used an *absolute* asset
specification as the path (``tutorial:static``).
-#. *Line 17*. Perform a :term:`scan`. A scan will find :term:`configuration
+#. *Line 19*. Perform a :term:`scan`. A scan will find :term:`configuration
decoration`, such as view configuration decorators (e.g., ``@view_config``)
in the source code of the ``tutorial`` package and will take actions based
on these decorators. We don't pass any arguments to
:meth:`~pyramid.config.Configurator.scan`, which implies that the scan
should take place in the current package (in this case, ``tutorial``).
- The scaffold could have equivalently said ``config.scan('tutorial')``, but
+ The cookiecutter could have equivalently said ``config.scan('tutorial')``, but
it chose to omit the package name argument.
-#. *Line 18*. Use the
+#. *Line 20*. Use the
:meth:`pyramid.config.Configurator.make_wsgi_app` method
to return a :term:`WSGI` application.
@@ -79,7 +83,7 @@ hierarchically in a :term:`resource tree`. This tree is consulted by
tree represents the site structure, but it *also* represents the
:term:`domain model` of the application, because each resource is a node
stored persistently in a :term:`ZODB` database. The ``models.py`` file is
-where the ``zodb`` scaffold put the classes that implement our
+where the ``zodb`` cookiecutter put the classes that implement our
resource objects, each of which also happens to be a domain model object.
Here is the source for ``models.py``:
@@ -93,7 +97,7 @@ Here is the source for ``models.py``:
because the class inherits from the
:class:`persistent.mapping.PersistentMapping` class. The ``__parent__``
and ``__name__`` are important parts of the :term:`traversal` protocol.
- By default, have these as ``None`` indicating that this is the
+ By default, set these to ``None`` to indicate that this is the
:term:`root` object.
#. *Lines 8-14*. ``appmaker`` is used to return the *application
@@ -110,7 +114,7 @@ Here is the source for ``models.py``:
Views With ``views.py``
-----------------------
-Our scaffold generated a default ``views.py`` on our behalf. It
+Our cookiecutter generated a default ``views.py`` on our behalf. It
contains a single view, which is used to render the page shown when you visit
the URL ``http://localhost:6543/``.
@@ -156,7 +160,7 @@ Let's try to understand the components in this module:
#. *Lines 6-7*. We define a :term:`view callable` named ``my_view``, which
we decorated in the step above. This view callable is a *function* we
- write generated by the ``zodb`` scaffold that is given a
+ write generated by the ``zodb`` cookiecutter that is given a
``request`` and which returns a dictionary. The ``mytemplate.pt``
:term:`renderer` named by the asset specification in the step above will
convert this dictionary to a :term:`response` on our behalf.
@@ -168,8 +172,8 @@ Let's try to understand the components in this module:
Configuration in ``development.ini``
------------------------------------
-The ``development.ini`` (in the tutorial :term:`project` directory, as
-opposed to the tutorial :term:`package` directory) looks like this:
+The ``development.ini`` (in the ``tutorial`` :term:`project` directory, as
+opposed to the ``tutorial`` :term:`package` directory) looks like this:
.. literalinclude:: src/basiclayout/development.ini
:language: ini
diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst
index 73dce14d5..419fede62 100644
--- a/docs/tutorials/wiki/definingmodels.rst
+++ b/docs/tutorials/wiki/definingmodels.rst
@@ -4,7 +4,7 @@
Defining the Domain Model
=========================
-The first change we'll make to our stock ``pcreate``-generated application will
+The first change we'll make to our stock cookiecutter-generated application will
be to define two :term:`resource` constructors, one representing a wiki page,
and another representing the wiki as a mapping of wiki page names to page
objects. We'll do this inside our ``models.py`` file.
@@ -50,7 +50,9 @@ The first thing we want to do is remove the ``MyModel`` class from the
generated ``models.py`` file. The ``MyModel`` class is only a sample and
we're not going to use it.
-Then, we'll add a ``Wiki`` class. We want it to inherit from the
+Then we'll add an import at the top for the :class:`persistent.Persistent` class. We'll use this for a new ``Page`` class in a moment.
+
+Then we'll add a ``Wiki`` class. We want it to inherit from the
:class:`persistent.mapping.PersistentMapping` class because it provides
mapping behavior, and it makes sure that our Wiki page is stored as a
"first-class" persistent object in our ZODB database.
diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst
index ac94d8059..442d5ed18 100644
--- a/docs/tutorials/wiki/definingviews.rst
+++ b/docs/tutorials/wiki/definingviews.rst
@@ -4,7 +4,7 @@
Defining Views
==============
-A :term:`view callable` in a :term:`traversal` -based :app:`Pyramid`
+A :term:`view callable` in a :term:`traversal`-based :app:`Pyramid`
application is typically a simple Python function that accepts two
parameters: :term:`context` and :term:`request`. A view callable is
assumed to return a :term:`response` object.
@@ -16,7 +16,7 @@ assumed to return a :term:`response` object.
this one-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:`traversal` based applications,
+ interchangeably as necessary. In :term:`traversal`-based applications,
URLs are mapped to a context :term:`resource`, and since our
:term:`resource tree` also represents our application's
"domain model", we're often interested in the context because
@@ -36,7 +36,7 @@ Declaring Dependencies in Our ``setup.py`` File
The view code in our application will depend on a package which is not a
dependency of the original "tutorial" application. The original "tutorial"
-application was generated by the ``pcreate`` command; it doesn't know
+application was generated by the cookiecutter; it doesn't know
about our custom application requirements.
We need to add a dependency on the ``docutils`` package to our ``tutorial``
@@ -52,6 +52,7 @@ Open ``setup.py`` and edit it to look like the following:
Only the highlighted line needs to be added.
+.. _wiki-running-pip-install:
Running ``pip install -e .``
============================
@@ -74,15 +75,15 @@ On Windows:
.. code-block:: doscon
- c:\pyramidtut> cd tutorial
- c:\pyramidtut\tutorial> %VENV%\Scripts\pip install -e .
+ c:\> cd tutorial
+ c:\tutorial> %VENV%\Scripts\pip install -e .
Success executing this command will end with a line to the console something
like:
.. code-block:: text
- Successfully installed docutils-0.12 tutorial-0.0
+ Successfully installed docutils-0.13.1 tutorial
Adding view functions in ``views.py``
@@ -98,11 +99,11 @@ like the following:
We added some imports and created a regular expression to find "WikiWords".
We got rid of the ``my_view`` view function and its decorator that was added
-when we originally rendered the ``zodb`` scaffold. It was only an example and
+when we originally rendered the ``zodb`` cookiecutter. 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:
+module:
* ``view_wiki()`` - Displays the wiki itself. It will answer on the root URL.
* ``view_page()`` - Displays an individual page.
@@ -126,8 +127,7 @@ Following is the code for the ``view_wiki`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
:lines: 12-14
- :lineno-start: 12
- :linenos:
+ :lineno-match:
:language: python
.. note:: In our code, we use an *import* that is *relative* to our package
@@ -165,8 +165,7 @@ Here is the code for the ``view_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
:lines: 16-33
- :lineno-start: 16
- :linenos:
+ :lineno-match:
:language: python
The ``view_page`` function is configured to respond as the default view
@@ -219,8 +218,7 @@ Here is the code for the ``add_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
:lines: 35-50
- :lineno-start: 35
- :linenos:
+ :lineno-match:
:language: python
The ``add_page`` function is configured to respond when the context resource
@@ -247,7 +245,7 @@ are found *after* the :term:`view name` in the URL segments given in the
add view is invoked via, e.g., ``http://localhost:6543/add_page/SomeName``,
the :term:`subpath` will be a tuple: ``('SomeName',)``.
-The add view takes the zeroth element of the subpath (the wiki page name),
+The add view takes the zero\ :sup:`th` element of the subpath (the wiki page name),
and aliases it to the name attribute in order to know the name of the page
we're trying to add.
@@ -274,8 +272,7 @@ Here is the code for the ``edit_page`` view function and its decorator:
.. literalinclude:: src/views/tutorial/views.py
:lines: 52-60
- :lineno-start: 52
- :linenos:
+ :lineno-match:
:language: python
The ``edit_page`` function is configured to respond when the context is
@@ -316,26 +313,26 @@ extension to be recognized as such.
The ``view.pt`` template
------------------------
-Create ``tutorial/templates/view.pt`` and add the following
-content:
+Rename ``tutorial/templates/mytemplate.pt`` to ``tutorial/templates/view.pt`` and edit the emphasized lines to look like the following:
.. literalinclude:: src/views/tutorial/templates/view.pt
:linenos:
:language: html
+ :emphasize-lines: 11-12,37-52
This template is used by ``view_page()`` for displaying a single
wiki page. It includes:
- A ``div`` element that is replaced with the ``content`` value provided by
- the view (lines 36-38). ``content`` contains HTML, so the ``structure``
+ the view (lines 37-39). ``content`` contains HTML, so the ``structure``
keyword is used to prevent escaping it (i.e., changing ">" to "&gt;", etc.)
- A link that points at the "edit" URL which invokes the ``edit_page`` view
- for the page being viewed (lines 40-42).
+ for the page being viewed (lines 41-43).
The ``edit.pt`` template
------------------------
-Create ``tutorial/templates/edit.pt`` and add the following content:
+Copy ``tutorial/templates/view.pt`` to ``tutorial/templates/edit.pt`` and edit the emphasized lines to look like the following:
.. literalinclude:: src/views/tutorial/templates/edit.pt
:linenos:
@@ -344,12 +341,12 @@ Create ``tutorial/templates/edit.pt`` and add the following content:
This template is used by ``add_page()`` and ``edit_page()`` for adding and
editing a wiki page. It displays a page containing a form that includes:
-- A 10 row by 60 column ``textarea`` field named ``body`` that is filled
- with any existing page data when it is rendered (line 45).
-- A submit button that has the name ``form.submitted`` (line 48).
+- A 10-row by 60-column ``textarea`` field named ``body`` that is filled
+ with any existing page data when it is rendered (line 46).
+- A submit button that has the name ``form.submitted`` (line 49).
The form POSTs back to the ``save_url`` argument supplied by the view (line
-43). The view will use the ``body`` and ``form.submitted`` values.
+44). The view will use the ``body`` and ``form.submitted`` values.
.. note:: Our templates use a ``request`` object that none of our tutorial
views return in their dictionary. ``request`` is one of several names that
@@ -394,5 +391,5 @@ each of the following URLs, checking that the result is as expected:
- http://localhost:6543/add_page/SomePageName invokes the add view for a Page.
- To generate an error, visit http://localhost:6543/add_page which will
- generate an ``IndexErrorr: tuple index out of range`` error. You'll see an
+ generate an ``IndexError: tuple index out of range`` error. You'll see an
interactive traceback facility provided by :term:`pyramid_debugtoolbar`.
diff --git a/docs/tutorials/wiki/design.rst b/docs/tutorials/wiki/design.rst
index f2a02176b..30d443bb8 100644
--- a/docs/tutorials/wiki/design.rst
+++ b/docs/tutorials/wiki/design.rst
@@ -43,11 +43,8 @@ editing, and viewing wiki pages, plus one view for the wiki front page.
Two templates will be used, one for viewing, and one for both adding
and editing wiki pages.
-The default templating systems in :app:`Pyramid` are
-:term:`Chameleon` and :term:`Mako`. Chameleon is a variant of
-:term:`ZPT`, which is an XML-based templating language. Mako is a
-non-XML-based templating language. Because we had to pick one,
-we chose Chameleon for this tutorial.
+As of version 1.5 :app:`Pyramid` no longer ships with templating systems. In this tutorial, we will use :term:`Chameleon`. Chameleon is a variant of :term:`ZPT`, which is an XML-based templating language.
+
Security
--------
diff --git a/docs/tutorials/wiki/distributing.rst b/docs/tutorials/wiki/distributing.rst
index 386b880e6..fb0a552e0 100644
--- a/docs/tutorials/wiki/distributing.rst
+++ b/docs/tutorials/wiki/distributing.rst
@@ -6,9 +6,8 @@ Distributing Your Application
Once your application works properly, you can create a "tarball" from it by
using the ``setup.py sdist`` command. The following commands assume your
-current working directory is the ``tutorial`` package we've created and that
-the parent directory of the ``tutorial`` package is a virtual environment
-representing a :app:`Pyramid` environment.
+current working directory contains the ``tutorial`` package and the
+``setup.py`` file.
On UNIX:
@@ -20,7 +19,7 @@ On Windows:
.. code-block:: doscon
- c:\pyramidtut> %VENV%\Scripts\python setup.py sdist
+ c:\tutorial> %VENV%\Scripts\python setup.py sdist
The output of such a command will be something like:
@@ -35,7 +34,7 @@ The output of such a command will be something like:
Note that this command creates a tarball in the "dist" subdirectory named
``tutorial-0.0.tar.gz``. You can send this file to your friends to show them
your cool new application. They should be able to install it by pointing the
-``pip install .`` command directly at it. Or you can upload it to `PyPI
+``pip install`` command directly at it. Or you can upload it to `PyPI
<https://pypi.python.org/pypi>`_ and share it with the rest of the world, where
it can be downloaded via ``pip install`` remotely like any other package people
download from PyPI.
diff --git a/docs/tutorials/wiki/index.rst b/docs/tutorials/wiki/index.rst
index 7808c7623..7bd58656b 100644
--- a/docs/tutorials/wiki/index.rst
+++ b/docs/tutorials/wiki/index.rst
@@ -5,13 +5,12 @@ ZODB + Traversal Wiki Tutorial
This tutorial introduces a :term:`ZODB` and :term:`traversal`-based
:app:`Pyramid` application to a developer familiar with Python. It will be
-most familiar to developers with previous :term:`Zope` experience. When the
-is finished, the developer will have created a basic Wiki application with
+most familiar to developers with previous :term:`Zope` experience. When
+finished, the developer will have created a basic Wiki application with
authentication.
For cut and paste purposes, the source code for all stages of this
-tutorial can be browsed on GitHub at `docs/tutorials/wiki/src
-<https://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src>`_,
+tutorial can be browsed on GitHub at `GitHub <https://github.com/Pylons/pyramid/>`_ for a specific branch or version under ``docs/tutorials/wiki/src``,
which corresponds to the same location if you have Pyramid sources.
.. toctree::
diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst
index 6172b122b..de057b1cc 100644
--- a/docs/tutorials/wiki/installation.rst
+++ b/docs/tutorials/wiki/installation.rst
@@ -15,159 +15,125 @@ install Pyramid**. Thereby you will satisfy the following requirements.
* You've satisfied the :ref:`requirements-for-installing-packages`.
-Create directory to contain the project
----------------------------------------
-
-We need a workspace for our project files.
-
-On UNIX
-^^^^^^^
-
-.. code-block:: bash
+Install cookiecutter
+--------------------
+We will use a :term:`cookiecutter` to create a Python package project from a Python package project template. See `Cookiecutter Installation <https://cookiecutter.readthedocs.io/en/latest/installation.html>`_ for instructions.
- $ mkdir ~/pyramidtut
-On Windows
-^^^^^^^^^^
-
-.. code-block:: doscon
-
- c:\> mkdir pyramidtut
-
-
-Create and use a virtual Python environment
--------------------------------------------
+Generate a Pyramid project from a cookiecutter
+----------------------------------------------
-Next let's create a virtual environment workspace for our project. We will use
-the ``VENV`` environment variable instead of the absolute path of the virtual
-environment.
+We will create a Pyramid project in your home directory for UNIX or at the root for Windows. It is assumed you know the path to where you installed ``cookiecutter``. Issue the following commands and override the defaults in the prompts as follows.
On UNIX
^^^^^^^
.. code-block:: bash
- $ export VENV=~/pyramidtut
- $ python3 -m venv $VENV
+ $ cd ~
+ $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-zodb
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> set VENV=c:\pyramidtut
+ c:\> cd \
+ c:\> cookiecutter https://github.com/Pylons/pyramid-cookiecutter-zodb
-Each version of Python uses different paths, so you will need to adjust the
-path to the command for your Python version.
+On all operating systems
+^^^^^^^^^^^^^^^^^^^^^^^^
+If prompted for the first item, accept the default ``yes`` by hitting return.
-Python 2.7:
-
-.. code-block:: doscon
-
- c:\> c:\Python27\Scripts\virtualenv %VENV%
-
-Python 3.5:
-
-.. code-block:: doscon
-
- c:\> c:\Python35\Scripts\python -m venv %VENV%
+.. code-block:: text
+ You've cloned ~/.cookiecutters/pyramid-cookiecutter-zodb before.
+ Is it okay to delete and re-clone it? [yes]: yes
+ project_name [Pyramid Scaffold]: myproj
+ repo_name [myproj]: tutorial
-Upgrade ``pip`` and ``setuptools`` in the virtual environment
--------------------------------------------------------------
+Change directory into your newly created project
+------------------------------------------------
On UNIX
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pip install --upgrade pip setuptools
+ $ cd tutorial
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> %VENV%\Scripts\pip install --upgrade pip setuptools
+ c:\> cd tutorial
-Install Pyramid into the virtual Python environment
----------------------------------------------------
+Set and use a ``VENV`` environment variable
+-------------------------------------------
+
+We will set the ``VENV`` environment variable to the absolute path of the virtual environment, and use it going forward.
On UNIX
^^^^^^^
-.. parsed-literal::
+.. code-block:: bash
- $ $VENV/bin/pip install "pyramid==\ |release|\ "
+ $ export VENV=~/tutorial
On Windows
^^^^^^^^^^
-.. parsed-literal::
-
- c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ "
+.. code-block:: doscon
+ c:\tutorial> set VENV=c:\tutorial
-Change directory to your virtual Python environment
----------------------------------------------------
-Change directory to the ``pyramidtut`` directory, which is both your workspace
-and your virtual environment.
+Create a virtual environment
+----------------------------
On UNIX
^^^^^^^
.. code-block:: bash
- $ cd pyramidtut
+ $ python3 -m venv $VENV
On Windows
^^^^^^^^^^
-.. code-block:: doscon
+Each version of Python uses different paths, so you might need to adjust the path to the command for your Python version. Recent versions of the Python 3 installer for Windows now install a Python launcher.
- c:\> cd pyramidtut
+Python 2.7:
+.. code-block:: doscon
-.. _making_a_project:
+ c:\tutorial> c:\Python27\Scripts\virtualenv %VENV%
-Making a project
-----------------
+Python 3.6:
-Your next step is to create a project. For this tutorial, we will use
-the :term:`scaffold` named ``zodb``, which generates an application
-that uses :term:`ZODB` and :term:`traversal`.
+.. code-block:: doscon
-:app:`Pyramid` supplies a variety of scaffolds to generate sample projects. We
-will use ``pcreate``, a script that comes with Pyramid, to create our project
-using a scaffold.
+ c:\tutorial> python -m venv %VENV%
-By passing ``zodb`` into the ``pcreate`` command, the script creates the files
-needed to use ZODB. By passing in our application name ``tutorial``, the script
-inserts that application name into all the required files.
-The below instructions assume your current working directory is "pyramidtut".
+Upgrade packaging tools in the virtual environment
+--------------------------------------------------
On UNIX
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pcreate -s zodb tutorial
+ $ $VENV/bin/pip install --upgrade pip setuptools
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\pyramidtut> %VENV%\Scripts\pcreate -s zodb tutorial
-
-.. note:: If you are using Windows, the ``zodb`` scaffold may not deal
- gracefully with installation into a location that contains spaces in the
- path. If you experience startup problems, try putting both the virtual
- environment and the project into directories that do not contain spaces in
- their paths.
+ c:\tutorial> %VENV%\Scripts\pip install --upgrade pip setuptools
.. _installing_project_in_dev_mode_zodb:
@@ -175,76 +141,51 @@ On Windows
Installing the project in development mode
------------------------------------------
-In order to do development on the project easily, you must "register" the
-project as a development egg in your workspace using the ``pip install -e .``
-command. In order to do so, change directory to the ``tutorial`` directory that
-you created in :ref:`making_a_project`, and run the ``pip install -e .``
-command using the virtual environment Python interpreter.
+In order to do development on the project easily, you must "register" the project as a development egg in your workspace. We will install testing requirements at the same time. We do so with the following command.
On UNIX
^^^^^^^
.. code-block:: bash
- $ cd tutorial
- $ $VENV/bin/pip install -e .
+ $ $VENV/bin/pip install -e ".[testing]"
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\pyramidtut> cd tutorial
- c:\pyramidtut\tutorial> %VENV%\Scripts\pip install -e .
-
-The console will show ``pip`` checking for packages and installing missing
-packages. Success executing this command will show a line like the following:
-
-.. code-block:: bash
+ c:\tutorial> %VENV%\Scripts\pip install -e ".[testing]"
- Successfully installed BTrees-4.2.0 Chameleon-2.24 Mako-1.0.4 \
- MarkupSafe-0.23 Pygments-2.1.3 ZConfig-3.1.0 ZEO-4.2.0b1 ZODB-4.2.0 \
- ZODB3-3.11.0 mock-2.0.0 pbr-1.8.1 persistent-4.1.1 pyramid-chameleon-0.3 \
- pyramid-debugtoolbar-2.4.2 pyramid-mako-1.0.2 pyramid-tm-0.12.1 \
- pyramid-zodbconn-0.7 six-1.10.0 transaction-1.4.4 tutorial waitress-0.8.10 \
- zc.lockfile-1.1.0 zdaemon-4.1.0 zodbpickle-0.6.0 zodburi-2.0
+On all operating systems
+^^^^^^^^^^^^^^^^^^^^^^^^
+The console will show ``pip`` checking for packages and installing missing packages. Success executing this command will show a line like the following:
-.. _install-testing-requirements-zodb:
+.. code-block:: bash
-Install testing requirements
-----------------------------
+ Successfully installed BTrees-4.3.1 Chameleon-3.0 Mako-1.0.6 \
+ MarkupSafe-0.23 PasteDeploy-1.5.2 Pygments-2.1.3 WebOb-1.6.3 \
+ WebTest-2.0.23 ZConfig-3.1.0 ZEO-5.0.4 ZODB-5.1.1 ZODB3-3.11.0 \
+ beautifulsoup4-4.5.1 coverage-4.2 mock-2.0.0 pbr-1.10.0 persistent-4.2.2 \
+ py-1.4.31 pyramid-1.7.3 pyramid-chameleon-0.3 pyramid-debugtoolbar-3.0.5 \
+ pyramid-mako-1.0.2 pyramid-tm-1.1.1 pyramid-zodbconn-0.7 pytest-3.0.5 \
+ pytest-cov-2.4.0 repoze.lru-0.6 six-1.10.0 transaction-2.0.3 \
+ translationstring-1.3 tutorial venusian-1.0 waitress-1.0.1 \
+ zc.lockfile-1.2.1 zdaemon-4.2.0 zodbpickle-0.6.0 zodburi-2.0 \
+ zope.deprecation-4.2.0 zope.interface-4.3.3
-In order to run tests, we need to install the testing requirements. This is
-done through our project's ``setup.py`` file, in the ``tests_require`` and
-``extras_require`` stanzas, and by issuing the command below for your
-operating system.
+Testing requirements are defined in our project's ``setup.py`` file, in the ``tests_require`` and ``extras_require`` stanzas.
.. literalinclude:: src/installation/setup.py
- :language: python
- :linenos:
- :lineno-start: 22
- :lines: 22-26
+ :language: python
+ :lineno-match:
+ :lines: 22-26
.. literalinclude:: src/installation/setup.py
- :language: python
- :linenos:
- :lineno-start: 45
- :lines: 45-47
-
-On UNIX
-^^^^^^^
-
-.. code-block:: bash
-
- $ $VENV/bin/pip install -e ".[testing]"
-
-On Windows
-^^^^^^^^^^
-
-.. code-block:: doscon
-
- c:\pyramidtut\tutorial> %VENV%\Scripts\pip install -e ".[testing]"
+ :language: python
+ :lineno-match:
+ :lines: 46-48
.. _running_tests:
@@ -269,7 +210,7 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test -q
+ c:\tutorial> %VENV%\Scripts\py.test -q
For a successful test run, you should see output that ends like this:
@@ -284,7 +225,7 @@ Expose test coverage information
You can run the ``py.test`` command to see test coverage information. This
runs the tests in the same way that ``py.test`` does, but provides additional
-"coverage" information, exposing which lines of your project are covered by the
+:term:`coverage` information, exposing which lines of your project are covered by the
tests.
We've already installed the ``pytest-cov`` package into our virtual
@@ -302,41 +243,39 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov \
- --cov-report=term-missing
+ c:\tutorial> %VENV%\Scripts\py.test --cov --cov-report=term-missing
If successful, you will see output something like this:
.. code-block:: bash
- ======================== test session starts ========================
- platform Python 3.5.1, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
- rootdir: /Users/stevepiercy/projects/pyramidtut/tutorial, inifile:
- plugins: cov-2.2.1
- collected 1 items
-
- tutorial/tests.py .
- ------------------ coverage: platform Python 3.5.1 ------------------
- Name Stmts Miss Cover Missing
- ----------------------------------------------------
- tutorial/__init__.py 12 7 42% 7-8, 14-18
- tutorial/models.py 10 6 40% 9-14
- tutorial/tests.py 12 0 100%
- tutorial/views.py 4 0 100%
- ----------------------------------------------------
- TOTAL 38 13 66%
-
- ===================== 1 passed in 0.31 seconds ======================
+ ======================== test session starts ========================
+ platform Python 3.6.0, pytest-3.0.5, py-1.4.31, pluggy-0.4.0
+ rootdir: /Users/stevepiercy/tutorial, inifile:
+ plugins: cov-2.4.0
+ collected 1 items
+
+ tutorial/tests.py .
+ ------------------ coverage: platform Python 3.6.0 ------------------
+ Name Stmts Miss Cover Missing
+ -------------------------------------------------------
+ tutorial/__init__.py 14 9 36% 7-8, 14-20
+ tutorial/models.py 10 6 40% 9-14
+ tutorial/views.py 4 0 100%
+ -------------------------------------------------------
+ TOTAL 28 15 46%
+
+ ===================== 1 passed in 0.31 seconds ======================
Our package doesn't quite have 100% test coverage.
-.. _test_and_coverage_scaffold_defaults_zodb:
+.. _test_and_coverage_cookiecutter_defaults_zodb:
-Test and coverage scaffold defaults
------------------------------------
+Test and coverage cookiecutter defaults
+---------------------------------------
-Scaffolds include configuration defaults for ``py.test`` and test coverage.
+Cookiecutters include configuration defaults for ``py.test`` and test coverage.
These configuration files are ``pytest.ini`` and ``.coveragerc``, located at
the root of your package. Without these defaults, we would need to specify the
path to the module on which we want to run tests and coverage.
@@ -353,11 +292,10 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov=tutorial \
- --cov-report=term-missing tutorial\tests.py -q
+ c:\tutorial> %VENV%\Scripts\py.test --cov=tutorial tutorial\tests.py -q
py.test follows :ref:`conventions for Python test discovery
-<pytest:test discovery>`, and the configuration defaults from the scaffold
+<pytest:test discovery>`, and the configuration defaults from the cookiecutter
tell ``py.test`` where to find the module on which we want to run tests and
coverage.
@@ -370,7 +308,8 @@ coverage.
Start the application
---------------------
-Start the application.
+Start the application. See :ref:`what_is_this_pserve_thing` for more
+information on ``pserve``.
On UNIX
^^^^^^^
@@ -384,7 +323,7 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\pserve development.ini --reload
+ c:\tutorial> %VENV%\Scripts\pserve development.ini --reload
.. note::
@@ -395,9 +334,10 @@ If successful, you will see something like this on your console:
.. code-block:: text
- Starting subprocess with file monitor
- Starting server in PID 82349.
- serving on http://127.0.0.1:6543
+ Starting subprocess with file monitor
+ Starting server in PID 44078.
+ Serving on http://localhost:6543
+ Serving on http://localhost:6543
This means the server is ready to accept requests.
@@ -414,13 +354,13 @@ page. You can read more about the purpose of the icon at
application while you develop.
-Decisions the ``zodb`` scaffold has made for you
-------------------------------------------------
+Decisions the ``zodb`` cookiecutter has made for you
+----------------------------------------------------
-Creating a project using the ``zodb`` scaffold makes the following
+Creating a project using the ``zodb`` cookiecutter makes the following
assumptions:
-- You are willing to use :term:`ZODB` as persistent storage.
+- You are willing to use :term:`ZODB` for persistent storage.
- You are willing to use :term:`traversal` to map URLs to code.
diff --git a/docs/tutorials/wiki/src/authorization/.coveragerc b/docs/tutorials/wiki/src/authorization/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki/src/authorization/CHANGES.txt b/docs/tutorials/wiki/src/authorization/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki/src/authorization/CHANGES.txt
+++ b/docs/tutorials/wiki/src/authorization/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki/src/authorization/README.txt b/docs/tutorials/wiki/src/authorization/README.txt
index dcb3605b8..5ec53bf9d 100644
--- a/docs/tutorials/wiki/src/authorization/README.txt
+++ b/docs/tutorials/wiki/src/authorization/README.txt
@@ -1,12 +1,29 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/pserve development.ini
+- Create a Python virtual environment.
+ python3 -m venv env
+
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki/src/authorization/development.ini b/docs/tutorials/wiki/src/authorization/development.ini
index 6bf4b198e..74e7457d6 100644
--- a/docs/tutorials/wiki/src/authorization/development.ini
+++ b/docs/tutorials/wiki/src/authorization/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,10 +13,7 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_zodbconn
- pyramid_tm
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
# By default, the toolbar only appears for clients from IP addresses
@@ -29,12 +26,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/authorization/production.ini b/docs/tutorials/wiki/src/authorization/production.ini
index 4e9892e7b..60b6fe253 100644
--- a/docs/tutorials/wiki/src/authorization/production.ini
+++ b/docs/tutorials/wiki/src/authorization/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -11,11 +11,7 @@ pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
-pyramid.includes =
- pyramid_tm
- pyramid_zodbconn
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
###
@@ -24,12 +20,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/authorization/pytest.ini b/docs/tutorials/wiki/src/authorization/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki/src/authorization/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki/src/authorization/setup.py b/docs/tutorials/wiki/src/authorization/setup.py
index beeed75c9..4a9f041e3 100644
--- a/docs/tutorials/wiki/src/authorization/setup.py
+++ b/docs/tutorials/wiki/src/authorization/setup.py
@@ -18,37 +18,40 @@ requires = [
'ZODB3',
'waitress',
'docutils',
- ]
+ 'bcrypt',
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py
index 39b94abd1..8af2ee5c0 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py
@@ -22,6 +22,8 @@ def main(global_config, **settings):
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(authz_policy)
config.include('pyramid_chameleon')
+ config.include('pyramid_tm')
+ config.include('pyramid_zodbconn')
config.add_static_view('static', 'static', cache_max_age=3600)
config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/security.py b/docs/tutorials/wiki/src/authorization/tutorial/security.py
index d88c9c71f..cbb3acd5d 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/security.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/security.py
@@ -1,5 +1,18 @@
-USERS = {'editor':'editor',
- 'viewer':'viewer'}
+import bcrypt
+
+
+def hash_password(pw):
+ hashed_pw = bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt())
+ # return unicode instead of bytes because databases handle it better
+ return hashed_pw.decode('utf-8')
+
+def check_password(expected_hash, pw):
+ if expected_hash is not None:
+ return bcrypt.checkpw(pw.encode('utf-8'), expected_hash.encode('utf-8'))
+ return False
+
+USERS = {'editor': hash_password('editor'),
+ 'viewer': hash_password('viewer')}
GROUPS = {'editor':['group:editors']}
def groupfinder(userid, request):
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt
index 823fa8972..19adc5932 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt
+++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt
@@ -23,6 +23,7 @@
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
+
<body>
<div class="starter-template">
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt
index 4a938e9bb..02f7038fe 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt
+++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt
@@ -23,6 +23,7 @@
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
+
<body>
<div class="starter-template">
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt
deleted file mode 100644
index f8cbe2e2c..000000000
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/mytemplate.pt
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html lang="${request.locale_name}">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta name="description" content="pyramid web application">
- <meta name="author" content="Pylons Project">
- <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
-
- <title>ZODB Scaffold for The Pyramid Web Framework</title>
-
- <!-- Bootstrap core CSS -->
- <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
-
- <!-- Custom styles for this scaffold -->
- <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet">
-
- <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
- <!--[if lt IE 9]>
- <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
- <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
- <![endif]-->
- </head>
-
- <body>
-
- <div class="starter-template">
- <div class="container">
- <div class="row">
- <div class="col-md-2">
- <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework">
- </div>
- <div class="col-md-10">
- <div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="links">
- <ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
- <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
- <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
- </ul>
- </div>
- </div>
- <div class="row">
- <div class="copyright">
- Copyright &copy; Pylons Project
- </div>
- </div>
- </div>
- </div>
-
-
- <!-- Bootstrap core JavaScript
- ================================================== -->
- <!-- Placed at the end of the document so the pages load faster -->
- <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
- <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
- </body>
-</html>
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt
index fa35d758d..17a715b50 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt
+++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt
@@ -23,6 +23,7 @@
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
+
<body>
<div class="starter-template">
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/tests.py b/docs/tutorials/wiki/src/authorization/tutorial/tests.py
index 40f3c47af..ca7a47279 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/tests.py
@@ -14,4 +14,4 @@ class ViewTests(unittest.TestCase):
from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views.py b/docs/tutorials/wiki/src/authorization/tutorial/views.py
index c271d2cc1..ea2da01af 100644
--- a/docs/tutorials/wiki/src/authorization/tutorial/views.py
+++ b/docs/tutorials/wiki/src/authorization/tutorial/views.py
@@ -14,7 +14,7 @@ from pyramid.security import (
)
-from .security import USERS
+from .security import USERS, check_password
from .models import Page
# regular expression used to find WikiWords
@@ -43,7 +43,6 @@ def view_page(context, request):
content = publish_parts(context.data, writer_name='html')['html_body']
content = wikiwords.sub(check, content)
edit_url = request.resource_url(context, 'edit_page')
-
return dict(page=context, content=content, edit_url=edit_url,
logged_in=request.authenticated_userid)
@@ -63,7 +62,6 @@ def add_page(context, request):
page = Page('')
page.__name__ = pagename
page.__parent__ = context
-
return dict(page=page, save_url=save_url,
logged_in=request.authenticated_userid)
@@ -94,7 +92,7 @@ def login(request):
if 'form.submitted' in request.params:
login = request.params['login']
password = request.params['password']
- if USERS.get(login) == password:
+ if check_password(USERS.get(login), password):
headers = remember(request, login)
return HTTPFound(location=came_from,
headers=headers)
diff --git a/docs/tutorials/wiki/src/basiclayout/.coveragerc b/docs/tutorials/wiki/src/basiclayout/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki/src/basiclayout/CHANGES.txt b/docs/tutorials/wiki/src/basiclayout/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki/src/basiclayout/CHANGES.txt
+++ b/docs/tutorials/wiki/src/basiclayout/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki/src/basiclayout/README.txt b/docs/tutorials/wiki/src/basiclayout/README.txt
index dcb3605b8..5ec53bf9d 100644
--- a/docs/tutorials/wiki/src/basiclayout/README.txt
+++ b/docs/tutorials/wiki/src/basiclayout/README.txt
@@ -1,12 +1,29 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/pserve development.ini
+- Create a Python virtual environment.
+ python3 -m venv env
+
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki/src/basiclayout/development.ini b/docs/tutorials/wiki/src/basiclayout/development.ini
index 6bf4b198e..74e7457d6 100644
--- a/docs/tutorials/wiki/src/basiclayout/development.ini
+++ b/docs/tutorials/wiki/src/basiclayout/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,10 +13,7 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_zodbconn
- pyramid_tm
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
# By default, the toolbar only appears for clients from IP addresses
@@ -29,12 +26,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/basiclayout/production.ini b/docs/tutorials/wiki/src/basiclayout/production.ini
index 4e9892e7b..60b6fe253 100644
--- a/docs/tutorials/wiki/src/basiclayout/production.ini
+++ b/docs/tutorials/wiki/src/basiclayout/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -11,11 +11,7 @@ pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
-pyramid.includes =
- pyramid_tm
- pyramid_zodbconn
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
###
@@ -24,12 +20,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/basiclayout/pytest.ini b/docs/tutorials/wiki/src/basiclayout/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki/src/basiclayout/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki/src/basiclayout/setup.py b/docs/tutorials/wiki/src/basiclayout/setup.py
index 46b395568..5d1e9c7b5 100644
--- a/docs/tutorials/wiki/src/basiclayout/setup.py
+++ b/docs/tutorials/wiki/src/basiclayout/setup.py
@@ -17,37 +17,39 @@ requires = [
'transaction',
'ZODB3',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py
index f2a86df47..728f7ac02 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py
@@ -13,6 +13,8 @@ def main(global_config, **settings):
"""
config = Configurator(root_factory=root_factory, settings=settings)
config.include('pyramid_chameleon')
+ config.include('pyramid_tm')
+ config.include('pyramid_zodbconn')
config.add_static_view('static', 'static', cache_max_age=3600)
config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
index f8cbe2e2c..3ac122711 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt
@@ -8,7 +8,7 @@
<meta name="author" content="Pylons Project">
<link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
- <title>ZODB Scaffold for The Pyramid Web Framework</title>
+ <title>Cookiecutter ZODB project for the Pyramid Web Framework</title>
<!-- Bootstrap core CSS -->
<link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
@@ -33,18 +33,16 @@
</div>
<div class="col-md-10">
<div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
+ <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB Project</span></h1>
+ <p class="lead">Welcome to <span class="font-normal">${project}</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
</div>
</div>
<div class="row">
<div class="links">
<ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
<li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
+ <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
<li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
</ul>
</div>
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
index 40f3c47af..ca7a47279 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py
@@ -14,4 +14,4 @@ class ViewTests(unittest.TestCase):
from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
index 628ce15ed..c1878bdd0 100644
--- a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
+++ b/docs/tutorials/wiki/src/basiclayout/tutorial/views.py
@@ -4,4 +4,4 @@ from .models import MyModel
@view_config(context=MyModel, renderer='templates/mytemplate.pt')
def my_view(request):
- return {'project': 'tutorial'}
+ return {'project': 'myproj'}
diff --git a/docs/tutorials/wiki/src/installation/.coveragerc b/docs/tutorials/wiki/src/installation/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki/src/installation/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki/src/installation/CHANGES.txt b/docs/tutorials/wiki/src/installation/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki/src/installation/CHANGES.txt
+++ b/docs/tutorials/wiki/src/installation/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki/src/installation/README.txt b/docs/tutorials/wiki/src/installation/README.txt
index dcb3605b8..5ec53bf9d 100644
--- a/docs/tutorials/wiki/src/installation/README.txt
+++ b/docs/tutorials/wiki/src/installation/README.txt
@@ -1,12 +1,29 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/pserve development.ini
+- Create a Python virtual environment.
+ python3 -m venv env
+
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki/src/installation/development.ini b/docs/tutorials/wiki/src/installation/development.ini
index 6bf4b198e..74e7457d6 100644
--- a/docs/tutorials/wiki/src/installation/development.ini
+++ b/docs/tutorials/wiki/src/installation/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,10 +13,7 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_zodbconn
- pyramid_tm
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
# By default, the toolbar only appears for clients from IP addresses
@@ -29,12 +26,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/installation/production.ini b/docs/tutorials/wiki/src/installation/production.ini
index 4e9892e7b..60b6fe253 100644
--- a/docs/tutorials/wiki/src/installation/production.ini
+++ b/docs/tutorials/wiki/src/installation/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -11,11 +11,7 @@ pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
-pyramid.includes =
- pyramid_tm
- pyramid_zodbconn
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
###
@@ -24,12 +20,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/installation/pytest.ini b/docs/tutorials/wiki/src/installation/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki/src/installation/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki/src/installation/setup.py b/docs/tutorials/wiki/src/installation/setup.py
index 46b395568..5d1e9c7b5 100644
--- a/docs/tutorials/wiki/src/installation/setup.py
+++ b/docs/tutorials/wiki/src/installation/setup.py
@@ -17,37 +17,39 @@ requires = [
'transaction',
'ZODB3',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki/src/installation/tutorial/__init__.py b/docs/tutorials/wiki/src/installation/tutorial/__init__.py
index f2a86df47..728f7ac02 100644
--- a/docs/tutorials/wiki/src/installation/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/installation/tutorial/__init__.py
@@ -13,6 +13,8 @@ def main(global_config, **settings):
"""
config = Configurator(root_factory=root_factory, settings=settings)
config.include('pyramid_chameleon')
+ config.include('pyramid_tm')
+ config.include('pyramid_zodbconn')
config.add_static_view('static', 'static', cache_max_age=3600)
config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt
index f8cbe2e2c..3ac122711 100644
--- a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt
@@ -8,7 +8,7 @@
<meta name="author" content="Pylons Project">
<link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
- <title>ZODB Scaffold for The Pyramid Web Framework</title>
+ <title>Cookiecutter ZODB project for the Pyramid Web Framework</title>
<!-- Bootstrap core CSS -->
<link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
@@ -33,18 +33,16 @@
</div>
<div class="col-md-10">
<div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
+ <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB Project</span></h1>
+ <p class="lead">Welcome to <span class="font-normal">${project}</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
</div>
</div>
<div class="row">
<div class="links">
<ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
<li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
+ <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
<li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
</ul>
</div>
diff --git a/docs/tutorials/wiki/src/installation/tutorial/tests.py b/docs/tutorials/wiki/src/installation/tutorial/tests.py
index 40f3c47af..ca7a47279 100644
--- a/docs/tutorials/wiki/src/installation/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/installation/tutorial/tests.py
@@ -14,4 +14,4 @@ class ViewTests(unittest.TestCase):
from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
diff --git a/docs/tutorials/wiki/src/installation/tutorial/views.py b/docs/tutorials/wiki/src/installation/tutorial/views.py
index 628ce15ed..c1878bdd0 100644
--- a/docs/tutorials/wiki/src/installation/tutorial/views.py
+++ b/docs/tutorials/wiki/src/installation/tutorial/views.py
@@ -4,4 +4,4 @@ from .models import MyModel
@view_config(context=MyModel, renderer='templates/mytemplate.pt')
def my_view(request):
- return {'project': 'tutorial'}
+ return {'project': 'myproj'}
diff --git a/docs/tutorials/wiki/src/models/.coveragerc b/docs/tutorials/wiki/src/models/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki/src/models/CHANGES.txt b/docs/tutorials/wiki/src/models/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki/src/models/CHANGES.txt
+++ b/docs/tutorials/wiki/src/models/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki/src/models/README.txt b/docs/tutorials/wiki/src/models/README.txt
index dcb3605b8..5ec53bf9d 100644
--- a/docs/tutorials/wiki/src/models/README.txt
+++ b/docs/tutorials/wiki/src/models/README.txt
@@ -1,12 +1,29 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/pserve development.ini
+- Create a Python virtual environment.
+ python3 -m venv env
+
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki/src/models/development.ini b/docs/tutorials/wiki/src/models/development.ini
index 6bf4b198e..74e7457d6 100644
--- a/docs/tutorials/wiki/src/models/development.ini
+++ b/docs/tutorials/wiki/src/models/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,10 +13,7 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_zodbconn
- pyramid_tm
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
# By default, the toolbar only appears for clients from IP addresses
@@ -29,12 +26,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/models/production.ini b/docs/tutorials/wiki/src/models/production.ini
index 4e9892e7b..60b6fe253 100644
--- a/docs/tutorials/wiki/src/models/production.ini
+++ b/docs/tutorials/wiki/src/models/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -11,11 +11,7 @@ pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
-pyramid.includes =
- pyramid_tm
- pyramid_zodbconn
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
###
@@ -24,12 +20,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/models/pytest.ini b/docs/tutorials/wiki/src/models/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki/src/models/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki/src/models/setup.py b/docs/tutorials/wiki/src/models/setup.py
index 46b395568..5d1e9c7b5 100644
--- a/docs/tutorials/wiki/src/models/setup.py
+++ b/docs/tutorials/wiki/src/models/setup.py
@@ -17,37 +17,39 @@ requires = [
'transaction',
'ZODB3',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki/src/models/tutorial/__init__.py b/docs/tutorials/wiki/src/models/tutorial/__init__.py
index f2a86df47..728f7ac02 100644
--- a/docs/tutorials/wiki/src/models/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/models/tutorial/__init__.py
@@ -13,6 +13,8 @@ def main(global_config, **settings):
"""
config = Configurator(root_factory=root_factory, settings=settings)
config.include('pyramid_chameleon')
+ config.include('pyramid_tm')
+ config.include('pyramid_zodbconn')
config.add_static_view('static', 'static', cache_max_age=3600)
config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
index f8cbe2e2c..3ac122711 100644
--- a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
+++ b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt
@@ -8,7 +8,7 @@
<meta name="author" content="Pylons Project">
<link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
- <title>ZODB Scaffold for The Pyramid Web Framework</title>
+ <title>Cookiecutter ZODB project for the Pyramid Web Framework</title>
<!-- Bootstrap core CSS -->
<link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
@@ -33,18 +33,16 @@
</div>
<div class="col-md-10">
<div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
+ <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB Project</span></h1>
+ <p class="lead">Welcome to <span class="font-normal">${project}</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
</div>
</div>
<div class="row">
<div class="links">
<ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
<li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
+ <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
<li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
</ul>
</div>
diff --git a/docs/tutorials/wiki/src/models/tutorial/tests.py b/docs/tutorials/wiki/src/models/tutorial/tests.py
index 40f3c47af..ca7a47279 100644
--- a/docs/tutorials/wiki/src/models/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/models/tutorial/tests.py
@@ -14,4 +14,4 @@ class ViewTests(unittest.TestCase):
from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
diff --git a/docs/tutorials/wiki/src/models/tutorial/views.py b/docs/tutorials/wiki/src/models/tutorial/views.py
index 628ce15ed..c1878bdd0 100644
--- a/docs/tutorials/wiki/src/models/tutorial/views.py
+++ b/docs/tutorials/wiki/src/models/tutorial/views.py
@@ -4,4 +4,4 @@ from .models import MyModel
@view_config(context=MyModel, renderer='templates/mytemplate.pt')
def my_view(request):
- return {'project': 'tutorial'}
+ return {'project': 'myproj'}
diff --git a/docs/tutorials/wiki/src/tests/.coveragerc b/docs/tutorials/wiki/src/tests/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki/src/tests/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki/src/tests/CHANGES.txt b/docs/tutorials/wiki/src/tests/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki/src/tests/CHANGES.txt
+++ b/docs/tutorials/wiki/src/tests/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki/src/tests/README.txt b/docs/tutorials/wiki/src/tests/README.txt
index dcb3605b8..5ec53bf9d 100644
--- a/docs/tutorials/wiki/src/tests/README.txt
+++ b/docs/tutorials/wiki/src/tests/README.txt
@@ -1,12 +1,29 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/pserve development.ini
+- Create a Python virtual environment.
+ python3 -m venv env
+
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki/src/tests/development.ini b/docs/tutorials/wiki/src/tests/development.ini
index 6bf4b198e..74e7457d6 100644
--- a/docs/tutorials/wiki/src/tests/development.ini
+++ b/docs/tutorials/wiki/src/tests/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,10 +13,7 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_zodbconn
- pyramid_tm
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
# By default, the toolbar only appears for clients from IP addresses
@@ -29,12 +26,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/tests/production.ini b/docs/tutorials/wiki/src/tests/production.ini
index 4e9892e7b..60b6fe253 100644
--- a/docs/tutorials/wiki/src/tests/production.ini
+++ b/docs/tutorials/wiki/src/tests/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -11,11 +11,7 @@ pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
-pyramid.includes =
- pyramid_tm
- pyramid_zodbconn
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
###
@@ -24,12 +20,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/tests/pytest.ini b/docs/tutorials/wiki/src/tests/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki/src/tests/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki/src/tests/setup.py b/docs/tutorials/wiki/src/tests/setup.py
index beeed75c9..4a9f041e3 100644
--- a/docs/tutorials/wiki/src/tests/setup.py
+++ b/docs/tutorials/wiki/src/tests/setup.py
@@ -18,37 +18,40 @@ requires = [
'ZODB3',
'waitress',
'docutils',
- ]
+ 'bcrypt',
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki/src/tests/tutorial/__init__.py b/docs/tutorials/wiki/src/tests/tutorial/__init__.py
index 39b94abd1..8af2ee5c0 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/__init__.py
@@ -22,6 +22,8 @@ def main(global_config, **settings):
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(authz_policy)
config.include('pyramid_chameleon')
+ config.include('pyramid_tm')
+ config.include('pyramid_zodbconn')
config.add_static_view('static', 'static', cache_max_age=3600)
config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/tests/tutorial/security.py b/docs/tutorials/wiki/src/tests/tutorial/security.py
index d88c9c71f..cbb3acd5d 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/security.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/security.py
@@ -1,5 +1,18 @@
-USERS = {'editor':'editor',
- 'viewer':'viewer'}
+import bcrypt
+
+
+def hash_password(pw):
+ hashed_pw = bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt())
+ # return unicode instead of bytes because databases handle it better
+ return hashed_pw.decode('utf-8')
+
+def check_password(expected_hash, pw):
+ if expected_hash is not None:
+ return bcrypt.checkpw(pw.encode('utf-8'), expected_hash.encode('utf-8'))
+ return False
+
+USERS = {'editor': hash_password('editor'),
+ 'viewer': hash_password('viewer')}
GROUPS = {'editor':['group:editors']}
def groupfinder(userid, request):
diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt
index 823fa8972..19adc5932 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt
+++ b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt
@@ -23,6 +23,7 @@
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
+
<body>
<div class="starter-template">
diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt
index 4a938e9bb..02f7038fe 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt
+++ b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt
@@ -23,6 +23,7 @@
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
+
<body>
<div class="starter-template">
diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt
index fa35d758d..17a715b50 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt
+++ b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt
@@ -23,6 +23,7 @@
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
+
<body>
<div class="starter-template">
diff --git a/docs/tutorials/wiki/src/tests/tutorial/tests.py b/docs/tutorials/wiki/src/tests/tutorial/tests.py
index 04beaea44..098e9c1bd 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/tests.py
@@ -122,6 +122,17 @@ class EditPageTests(unittest.TestCase):
self.assertEqual(response.location, 'http://example.com/')
self.assertEqual(context.data, 'Hello yo!')
+class SecurityTests(unittest.TestCase):
+ def test_hashing(self):
+ from .security import hash_password, check_password
+ password = 'secretpassword'
+ hashed_password = hash_password(password)
+ self.assertTrue(check_password(hashed_password, password))
+
+ self.assertFalse(check_password(hashed_password, 'attackerpassword'))
+
+ self.assertFalse(check_password(None, password))
+
class FunctionalTests(unittest.TestCase):
viewer_login = '/login?login=viewer&password=viewer' \
diff --git a/docs/tutorials/wiki/src/tests/tutorial/views.py b/docs/tutorials/wiki/src/tests/tutorial/views.py
index c271d2cc1..ea2da01af 100644
--- a/docs/tutorials/wiki/src/tests/tutorial/views.py
+++ b/docs/tutorials/wiki/src/tests/tutorial/views.py
@@ -14,7 +14,7 @@ from pyramid.security import (
)
-from .security import USERS
+from .security import USERS, check_password
from .models import Page
# regular expression used to find WikiWords
@@ -43,7 +43,6 @@ def view_page(context, request):
content = publish_parts(context.data, writer_name='html')['html_body']
content = wikiwords.sub(check, content)
edit_url = request.resource_url(context, 'edit_page')
-
return dict(page=context, content=content, edit_url=edit_url,
logged_in=request.authenticated_userid)
@@ -63,7 +62,6 @@ def add_page(context, request):
page = Page('')
page.__name__ = pagename
page.__parent__ = context
-
return dict(page=page, save_url=save_url,
logged_in=request.authenticated_userid)
@@ -94,7 +92,7 @@ def login(request):
if 'form.submitted' in request.params:
login = request.params['login']
password = request.params['password']
- if USERS.get(login) == password:
+ if check_password(USERS.get(login), password):
headers = remember(request, login)
return HTTPFound(location=came_from,
headers=headers)
diff --git a/docs/tutorials/wiki/src/views/.coveragerc b/docs/tutorials/wiki/src/views/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki/src/views/CHANGES.txt b/docs/tutorials/wiki/src/views/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki/src/views/CHANGES.txt
+++ b/docs/tutorials/wiki/src/views/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki/src/views/README.txt b/docs/tutorials/wiki/src/views/README.txt
index dcb3605b8..5ec53bf9d 100644
--- a/docs/tutorials/wiki/src/views/README.txt
+++ b/docs/tutorials/wiki/src/views/README.txt
@@ -1,12 +1,29 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/pserve development.ini
+- Create a Python virtual environment.
+ python3 -m venv env
+
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki/src/views/development.ini b/docs/tutorials/wiki/src/views/development.ini
index 6bf4b198e..74e7457d6 100644
--- a/docs/tutorials/wiki/src/views/development.ini
+++ b/docs/tutorials/wiki/src/views/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,10 +13,7 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_zodbconn
- pyramid_tm
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
# By default, the toolbar only appears for clients from IP addresses
@@ -29,12 +26,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/views/production.ini b/docs/tutorials/wiki/src/views/production.ini
index 4e9892e7b..60b6fe253 100644
--- a/docs/tutorials/wiki/src/views/production.ini
+++ b/docs/tutorials/wiki/src/views/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -11,11 +11,7 @@ pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
-pyramid.includes =
- pyramid_tm
- pyramid_zodbconn
-tm.attempts = 3
zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
###
@@ -24,12 +20,11 @@ zodbconn.uri = file://%(here)s/Data.fs?connection_cache_size=20000
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki/src/views/pytest.ini b/docs/tutorials/wiki/src/views/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki/src/views/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki/src/views/setup.py b/docs/tutorials/wiki/src/views/setup.py
index beeed75c9..598ad8146 100644
--- a/docs/tutorials/wiki/src/views/setup.py
+++ b/docs/tutorials/wiki/src/views/setup.py
@@ -18,37 +18,39 @@ requires = [
'ZODB3',
'waitress',
'docutils',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki/src/views/tutorial/__init__.py b/docs/tutorials/wiki/src/views/tutorial/__init__.py
index f2a86df47..728f7ac02 100644
--- a/docs/tutorials/wiki/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki/src/views/tutorial/__init__.py
@@ -13,6 +13,8 @@ def main(global_config, **settings):
"""
config = Configurator(root_factory=root_factory, settings=settings)
config.include('pyramid_chameleon')
+ config.include('pyramid_tm')
+ config.include('pyramid_zodbconn')
config.add_static_view('static', 'static', cache_max_age=3600)
config.scan()
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt
deleted file mode 100644
index f8cbe2e2c..000000000
--- a/docs/tutorials/wiki/src/views/tutorial/templates/mytemplate.pt
+++ /dev/null
@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html lang="${request.locale_name}">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta name="description" content="pyramid web application">
- <meta name="author" content="Pylons Project">
- <link rel="shortcut icon" href="${request.static_url('tutorial:static/pyramid-16x16.png')}">
-
- <title>ZODB Scaffold for The Pyramid Web Framework</title>
-
- <!-- Bootstrap core CSS -->
- <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
-
- <!-- Custom styles for this scaffold -->
- <link href="${request.static_url('tutorial:static/theme.css')}" rel="stylesheet">
-
- <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
- <!--[if lt IE 9]>
- <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
- <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
- <![endif]-->
- </head>
-
- <body>
-
- <div class="starter-template">
- <div class="container">
- <div class="row">
- <div class="col-md-2">
- <img class="logo img-responsive" src="${request.static_url('tutorial:static/pyramid.png')}" alt="pyramid web framework">
- </div>
- <div class="col-md-10">
- <div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">ZODB scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">${project}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="links">
- <ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
- <li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
- <li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
- </ul>
- </div>
- </div>
- <div class="row">
- <div class="copyright">
- Copyright &copy; Pylons Project
- </div>
- </div>
- </div>
- </div>
-
-
- <!-- Bootstrap core JavaScript
- ================================================== -->
- <!-- Placed at the end of the document so the pages load faster -->
- <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js"></script>
- <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script>
- </body>
-</html>
diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt
index 93580658b..5caaef4af 100644
--- a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt
+++ b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt
@@ -23,6 +23,7 @@
<script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
+
<body>
<div class="starter-template">
diff --git a/docs/tutorials/wiki/src/views/tutorial/tests.py b/docs/tutorials/wiki/src/views/tutorial/tests.py
index 40f3c47af..ca7a47279 100644
--- a/docs/tutorials/wiki/src/views/tutorial/tests.py
+++ b/docs/tutorials/wiki/src/views/tutorial/tests.py
@@ -14,4 +14,4 @@ class ViewTests(unittest.TestCase):
from .views import my_view
request = testing.DummyRequest()
info = my_view(request)
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py
index 61517c31d..fd2b0edc1 100644
--- a/docs/tutorials/wiki/src/views/tutorial/views.py
+++ b/docs/tutorials/wiki/src/views/tutorial/views.py
@@ -24,13 +24,13 @@ def view_page(context, request):
view_url = request.resource_url(page)
return '<a href="%s">%s</a>' % (view_url, word)
else:
- add_url = request.application_url + '/add_page/' + word
+ add_url = request.application_url + '/add_page/' + word
return '<a href="%s">%s</a>' % (add_url, word)
content = publish_parts(context.data, writer_name='html')['html_body']
content = wikiwords.sub(check, content)
edit_url = request.resource_url(context, 'edit_page')
- return dict(page = context, content = content, edit_url = edit_url)
+ return dict(page=context, content=content, edit_url=edit_url)
@view_config(name='add_page', context='.models.Wiki',
renderer='templates/edit.pt')
@@ -42,19 +42,19 @@ def add_page(context, request):
page.__name__ = pagename
page.__parent__ = context
context[pagename] = page
- return HTTPFound(location = request.resource_url(page))
+ return HTTPFound(location=request.resource_url(page))
save_url = request.resource_url(context, 'add_page', pagename)
page = Page('')
page.__name__ = pagename
page.__parent__ = context
- return dict(page = page, save_url = save_url)
+ return dict(page=page, save_url=save_url)
@view_config(name='edit_page', context='.models.Page',
renderer='templates/edit.pt')
def edit_page(context, request):
if 'form.submitted' in request.params:
context.data = request.params['body']
- return HTTPFound(location = request.resource_url(context))
+ return HTTPFound(location=request.resource_url(context))
return dict(page=context,
- save_url=request.resource_url(context, 'edit_page'))
+ save_url=request.resource_url(context, 'edit_page')) \ No newline at end of file
diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst
index 85a023cc9..cd82c0118 100644
--- a/docs/tutorials/wiki/tests.rst
+++ b/docs/tutorials/wiki/tests.rst
@@ -16,7 +16,7 @@ We write tests for the ``model`` classes and the ``appmaker``. Changing
we'll write a test class for the ``appmaker``.
To do so, we'll retain the ``tutorial.tests.ViewTests`` class that was
-generated as part of the ``zodb`` scaffold. We'll add three test classes: one
+generated as part of the ``zodb`` cookiecutter. We'll add three test classes: one
for the ``Page`` model named ``PageModelTests``, one for the ``Wiki`` model
named ``WikiModelTests``, and one for the appmaker named ``AppmakerTests``.
@@ -24,8 +24,8 @@ Test the views
==============
We'll modify our ``tests.py`` file, adding tests for each view function we
-added previously. As a result, we'll *delete* the ``ViewTests`` class that
-the ``zodb`` scaffold provided, and add four other test classes:
+added previously. As a result, we'll delete the ``ViewTests`` class that
+the ``zodb`` cookiecutter provided, and add four other test classes:
``ViewWikiTests``, ``ViewPageTests``, ``AddPageTests``, and ``EditPageTests``.
These test the ``view_wiki``, ``view_page``, ``add_page``, and ``edit_page``
views.
@@ -52,25 +52,25 @@ Running the tests
=================
We can run these tests by using ``py.test`` similarly to how we did in
-:ref:`running_tests`. Courtesy of the scaffold, our testing dependencies have
+:ref:`running_tests`. Courtesy of the cookiecutter, our testing dependencies have
already been satisfied and ``py.test`` and coverage have already been
configured, so we can jump right to running tests.
On UNIX:
-.. code-block:: text
+.. code-block:: bash
$ $VENV/bin/py.test -q
On Windows:
-.. code-block:: text
+.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test -q
+ c:\tutorial> %VENV%\Scripts\py.test -q
The expected result should look like the following:
.. code-block:: text
- ........................
- 24 passed in 2.46 seconds
+ .........................
+ 25 passed in 6.87 seconds
diff --git a/docs/tutorials/wiki2/authentication.rst b/docs/tutorials/wiki2/authentication.rst
index 5447db861..ff59ce70b 100644
--- a/docs/tutorials/wiki2/authentication.rst
+++ b/docs/tutorials/wiki2/authentication.rst
@@ -92,7 +92,7 @@ Our authentication policy is expecting a new setting, ``auth.secret``. Open
the file ``development.ini`` and add the highlighted line below:
.. literalinclude:: src/authentication/development.ini
- :lines: 18-20
+ :lines: 17-19
:emphasize-lines: 3
:lineno-match:
:language: ini
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 98a14c644..233231f8d 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -4,7 +4,7 @@
Basic Layout
============
-The starter files generated by the ``alchemy`` scaffold are very basic, but
+The starter files generated by the ``alchemy`` cookiecutter are very basic, but
they provide a good orientation for the high-level patterns common to most
:term:`URL dispatch`-based :app:`Pyramid` projects.
@@ -29,7 +29,6 @@ code:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:end-before: main
- :linenos:
:lineno-match:
:language: py
@@ -38,7 +37,6 @@ the ``main`` function we've defined in our ``__init__.py``:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
:pyobject: main
- :linenos:
:lineno-match:
:language: py
@@ -179,7 +177,7 @@ decorator in order to create a view configuration within our application.
Without being processed by ``scan``, the decorator effectively does nothing.
``@view_config`` is inert without being detected via a :term:`scan`.
-The sample ``my_view()`` created by the scaffold uses a ``try:`` and
+The sample ``my_view()`` created by the cookiecutter uses a ``try:`` and
``except:`` clause to detect if there is a problem accessing the project
database and provide an alternate error response. That response will include
the text shown at the end of the file, which will be displayed in the browser
@@ -191,7 +189,7 @@ Content models with the ``models`` package
In an SQLAlchemy-based application, a *model* object is an object composed by
querying the SQL database. The ``models`` package is where the ``alchemy``
-scaffold put the classes that implement our models.
+cookiecutter put the classes that implement our models.
First, open ``tutorial/models/meta.py``, which should already contain the
following:
@@ -222,7 +220,6 @@ application's database schema.
.. literalinclude:: src/basiclayout/tutorial/models/meta.py
:lines: 15-16
:lineno-match:
- :linenos:
:language: py
Next open ``tutorial/models/mymodel.py``, which should already contain the
@@ -239,7 +236,6 @@ we have defined one named ``MyModel`` in ``mymodel.py``:
.. literalinclude:: src/basiclayout/tutorial/models/mymodel.py
:pyobject: MyModel
:lineno-match:
- :linenos:
:language: py
Our example model does not require an ``__init__`` method because SQLAlchemy
@@ -292,7 +288,6 @@ database engine using :func:`sqlalchemy.engine_from_config` from the
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
:pyobject: get_engine
:lineno-match:
- :linenos:
:language: py
The function ``get_session_factory`` accepts an :term:`SQLAlchemy` database
@@ -303,7 +298,6 @@ used for creating sessions bound to the database engine.
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
:pyobject: get_session_factory
:lineno-match:
- :linenos:
:language: py
The function ``get_tm_session`` registers a database session with a transaction
@@ -314,7 +308,6 @@ unless an exception is raised, in which case the transaction will be aborted.
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
:pyobject: get_tm_session
:lineno-match:
- :linenos:
:language: py
Finally, we define an ``includeme`` function, which is a hook for use with
@@ -328,7 +321,6 @@ of an incoming request to our application.
.. literalinclude:: src/basiclayout/tutorial/models/__init__.py
:pyobject: includeme
:lineno-match:
- :linenos:
:language: py
That's about all there is to it regarding models, views, and initialization
diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst
index 9f7b82d1d..5cebb943c 100644
--- a/docs/tutorials/wiki2/definingmodels.rst
+++ b/docs/tutorials/wiki2/definingmodels.rst
@@ -4,7 +4,7 @@
Defining the Domain Model
=========================
-The first change we'll make to our stock ``pcreate``-generated application will
+The first change we'll make to our stock cookiecutter-generated application will
be to define a wiki page :term:`domain model`.
.. note::
@@ -22,10 +22,10 @@ Declaring dependencies in our ``setup.py`` file
The models code in our application will depend on a package which is not a
dependency of the original "tutorial" application. The original "tutorial"
-application was generated by the ``pcreate`` command; it doesn't know about our
+application was generated by the cookiecutter; it doesn't know about our
custom application requirements.
-We need to add a dependency, the ``bcrypt`` package, to our ``tutorial``
+We need to add a dependency, the `bcrypt <https://pypi.python.org/pypi/bcrypt>`_ package, to our ``tutorial``
package's ``setup.py`` file by assigning this dependency to the ``requires``
parameter in the ``setup()`` function.
@@ -38,6 +38,10 @@ Open ``tutorial/setup.py`` and edit it to look like the following:
Only the highlighted line needs to be added.
+.. note::
+
+ We are using the ``bcrypt`` package from PyPI to hash our passwords securely. There are other one-way hash algorithms for passwords if ``bcrypt`` is an issue on your system. Just make sure that it's an algorithm approved for storing passwords versus a generic one-way hash.
+
Running ``pip install -e .``
============================
@@ -53,31 +57,31 @@ On UNIX:
.. code-block:: bash
- $ cd tutorial
- $ $VENV/bin/pip install -e .
+ $ $VENV/bin/pip install -e .
On Windows:
.. code-block:: doscon
- c:\pyramidtut> cd tutorial
- c:\pyramidtut\tutorial> %VENV%\Scripts\pip install -e .
+ c:\tutorial> %VENV%\Scripts\pip install -e .
Success executing this command will end with a line to the console something
-like this::
+like the following.
- Successfully installed bcrypt-2.0.0 cffi-1.5.2 pycparser-2.14 tutorial-0.0
+.. code-block:: text
+
+ Successfully installed bcrypt-3.1.2 cffi-1.9.1 pycparser-2.17 tutorial
Remove ``mymodel.py``
----------------------
+=====================
Let's delete the file ``tutorial/models/mymodel.py``. The ``MyModel`` class is
only a sample and we're not going to use it.
Add ``user.py``
----------------
+===============
Create a new file ``tutorial/models/user.py`` with the following contents:
@@ -98,12 +102,12 @@ and ``role`` (all instances of :class:`sqlalchemy.schema.Column`). These will
map to columns in the ``users`` table. The ``id`` attribute will be the primary
key in the table. The ``name`` attribute will be a text column, each value of
which needs to be unique within the column. The ``password_hash`` is a nullable
-text attribute that will contain a securely hashed password [1]_. Finally, the
+text attribute that will contain a securely hashed password. Finally, the
``role`` text attribute will hold the role of the user.
There are two helper methods that will help us later when using the user
objects. The first is ``set_password`` which will take a raw password and
-transform it using bcrypt_ into an irreversible representation, a process known
+transform it using ``bcrypt`` into an irreversible representation, a process known
as "hashing". The second method, ``check_password``, will allow us to compare
the hashed value of the submitted password against the hashed value of the
password stored in the user's record in the database. If the two hashed values
@@ -116,7 +120,7 @@ authenticate as any user.
Add ``page.py``
----------------
+===============
Create a new file ``tutorial/models/page.py`` with the following contents:
@@ -138,7 +142,7 @@ guaranteed that an instance of ``page`` will have a corresponding
Edit ``models/__init__.py``
----------------------------
+===========================
Since we are using a package for our models, we also need to update our
``__init__.py`` file to ensure that the models are attached to the metadata.
@@ -155,12 +159,16 @@ Here we align our imports with the names of the models, ``Page`` and ``User``.
Edit ``scripts/initializedb.py``
---------------------------------
+================================
We haven't looked at the details of this file yet, but within the ``scripts``
directory of your ``tutorial`` package is a file named ``initializedb.py``.
Code in this file is executed whenever we run the ``initialize_tutorial_db``
-command, as we did in the installation step of this tutorial [2]_.
+command, as we did in the installation step of this tutorial.
+
+.. note::
+
+ The command is named ``initialize_tutorial_db`` because of the mapping defined in the ``[console_scripts]`` entry point of our project's ``setup.py`` file.
Since we've changed our model, we need to make changes to our
``initializedb.py`` script. In particular, we'll replace our import of
@@ -180,7 +188,7 @@ Only the highlighted lines need to be changed.
Installing the project and re-initializing the database
--------------------------------------------------------
+=======================================================
Because our model has changed, and in order to reinitialize the database, we
need to rerun the ``initialize_tutorial_db`` command to pick up the changes
@@ -191,53 +199,53 @@ Success will look something like this:
.. code-block:: bash
- 2016-05-22 04:12:09,226 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
- 2016-05-22 04:12:09,226 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] ()
- 2016-05-22 04:12:09,226 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
- 2016-05-22 04:12:09,227 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] ()
- 2016-05-22 04:12:09,227 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("users")
- 2016-05-22 04:12:09,227 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ()
- 2016-05-22 04:12:09,228 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("pages")
- 2016-05-22 04:12:09,228 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ()
- 2016-05-22 04:12:09,229 INFO [sqlalchemy.engine.base.Engine:1097][MainThread]
- CREATE TABLE users (
- id INTEGER NOT NULL,
- name TEXT NOT NULL,
- role TEXT NOT NULL,
- password_hash TEXT,
- CONSTRAINT pk_users PRIMARY KEY (id),
- CONSTRAINT uq_users_name UNIQUE (name)
- )
-
-
- 2016-05-22 04:12:09,229 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ()
- 2016-05-22 04:12:09,230 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT
- 2016-05-22 04:12:09,230 INFO [sqlalchemy.engine.base.Engine:1097][MainThread]
- CREATE TABLE pages (
- id INTEGER NOT NULL,
- name TEXT NOT NULL,
- data TEXT NOT NULL,
- creator_id INTEGER NOT NULL,
- CONSTRAINT pk_pages PRIMARY KEY (id),
- CONSTRAINT uq_pages_name UNIQUE (name),
- CONSTRAINT fk_pages_creator_id_users FOREIGN KEY(creator_id) REFERENCES users (id)
- )
-
-
- 2016-05-22 04:12:09,231 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ()
- 2016-05-22 04:12:09,231 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT
- 2016-05-22 04:12:09,782 INFO [sqlalchemy.engine.base.Engine:646][MainThread] BEGIN (implicit)
- 2016-05-22 04:12:09,783 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?)
- 2016-05-22 04:12:09,784 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('editor', 'editor', b'$2b$12$K/WLVKRl5fMAb6UM58ueTetXlE3rlc5cRK5zFPimK598scXBR/xWC')
- 2016-05-22 04:12:09,784 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?)
- 2016-05-22 04:12:09,784 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('basic', 'basic', b'$2b$12$JfwLyCJGv3t.RTSmIrh3B.FKXRT9FevkAqafWdK5oq7Hl4mgAQORe')
- 2016-05-22 04:12:09,785 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO pages (name, data, creator_id) VALUES (?, ?, ?)
- 2016-05-22 04:12:09,785 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('FrontPage', 'This is the front page', 1)
- 2016-05-22 04:12:09,786 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT
+ 2016-12-20 02:51:11,195 INFO [sqlalchemy.engine.base.Engine:1235][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
+ 2016-12-20 02:51:11,195 INFO [sqlalchemy.engine.base.Engine:1236][MainThread] ()
+ 2016-12-20 02:51:11,195 INFO [sqlalchemy.engine.base.Engine:1235][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
+ 2016-12-20 02:51:11,195 INFO [sqlalchemy.engine.base.Engine:1236][MainThread] ()
+ 2016-12-20 02:51:11,196 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] PRAGMA table_info("pages")
+ 2016-12-20 02:51:11,196 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ()
+ 2016-12-20 02:51:11,196 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] PRAGMA table_info("users")
+ 2016-12-20 02:51:11,197 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ()
+ 2016-12-20 02:51:11,197 INFO [sqlalchemy.engine.base.Engine:1140][MainThread]
+ CREATE TABLE users (
+ id INTEGER NOT NULL,
+ name TEXT NOT NULL,
+ role TEXT NOT NULL,
+ password_hash TEXT,
+ CONSTRAINT pk_users PRIMARY KEY (id),
+ CONSTRAINT uq_users_name UNIQUE (name)
+ )
+
+
+ 2016-12-20 02:51:11,197 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ()
+ 2016-12-20 02:51:11,198 INFO [sqlalchemy.engine.base.Engine:719][MainThread] COMMIT
+ 2016-12-20 02:51:11,199 INFO [sqlalchemy.engine.base.Engine:1140][MainThread]
+ CREATE TABLE pages (
+ id INTEGER NOT NULL,
+ name TEXT NOT NULL,
+ data TEXT NOT NULL,
+ creator_id INTEGER NOT NULL,
+ CONSTRAINT pk_pages PRIMARY KEY (id),
+ CONSTRAINT uq_pages_name UNIQUE (name),
+ CONSTRAINT fk_pages_creator_id_users FOREIGN KEY(creator_id) REFERENCES users (id)
+ )
+
+
+ 2016-12-20 02:51:11,199 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ()
+ 2016-12-20 02:51:11,200 INFO [sqlalchemy.engine.base.Engine:719][MainThread] COMMIT
+ 2016-12-20 02:51:11,755 INFO [sqlalchemy.engine.base.Engine:679][MainThread] BEGIN (implicit)
+ 2016-12-20 02:51:11,755 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?)
+ 2016-12-20 02:51:11,755 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ('editor', 'editor', '$2b$12$ds7h2Zb7.l6TEFup5h8f4ekA9GRfEpE1yQGDRvT9PConw73kKuupG')
+ 2016-12-20 02:51:11,756 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] INSERT INTO users (name, role, password_hash) VALUES (?, ?, ?)
+ 2016-12-20 02:51:11,756 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ('basic', 'basic', '$2b$12$KgruXP5Vv7rikr6dGB3TF.flGXYpiE0Li9K583EVomjY.SYmQOsyi')
+ 2016-12-20 02:51:11,757 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] INSERT INTO pages (name, data, creator_id) VALUES (?, ?, ?)
+ 2016-12-20 02:51:11,757 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ('FrontPage', 'This is the front page', 1)
+ 2016-12-20 02:51:11,757 INFO [sqlalchemy.engine.base.Engine:719][MainThread] COMMIT
View the application in a browser
----------------------------------
+=================================
We can't. At this point, our system is in a "non-runnable" state; we'll need
to change view-related files in the next chapter to be able to start the
@@ -250,14 +258,3 @@ your console that ends with this exception:
ImportError: cannot import name MyModel
This will also happen if you attempt to run the tests.
-
-.. _bcrypt: https://pypi.python.org/pypi/bcrypt
-
-.. [1] We are using the bcrypt_ package from PyPI to hash our passwords
- securely. There are other one-way hash algorithms for passwords if
- bcrypt is an issue on your system. Just make sure that it's an
- algorithm approved for storing passwords versus a generic one-way hash.
-
-.. [2] The command is named ``initialize_tutorial_db`` because of the mapping
- defined in the ``[console_scripts]`` entry point of our project's
- ``setup.py`` file.
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index 996bff88c..3c343e155 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -42,7 +42,7 @@ installed, so re-run the ``$VENV/bin/pip install -e .`` command.
Static assets
--------------
+=============
Our templates name static assets, including CSS and images. We don't need
to create these files within our package's ``static`` directory because they
@@ -133,7 +133,7 @@ The highlighted lines need to be added or edited.
We added some imports, and created a regular expression to find "WikiWords".
We got 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
+when we originally rendered the ``alchemy`` cookiecutter. It was only an example
and isn't relevant to our application. We also deleted the ``db_err_msg``
string.
@@ -340,7 +340,7 @@ indicated by the emphasized lines:
.. literalinclude:: src/views/tutorial/templates/layout.jinja2
:linenos:
- :emphasize-lines: 11,35-36
+ :emphasize-lines: 11,35-37
:language: html
Since we're using a templating engine, we can factor common boilerplate out of
@@ -350,7 +350,7 @@ template inheritance via blocks.
- We have defined two placeholders in the layout template where a child
template can override the content. These blocks are named ``subtitle`` (line
11) and ``content`` (line 36).
-- Please refer to the Jinja2_ documentation for more information about template
+- Please refer to the `Jinja2 documentation <http://jinja.pocoo.org/>`_ for more information about template
inheritance.
@@ -375,7 +375,7 @@ This template is used by ``view_page()`` for displaying a single wiki page.
view (line 6). ``content`` contains HTML, so the ``|safe`` filter is used to
prevent escaping it (e.g., changing ">" to "&gt;").
- We create a link that points at the "edit" URL, which when clicked invokes
- the ``edit_page`` view for the requested page (line 9).
+ the ``edit_page`` view for the requested page (lines 8-10).
The ``edit.jinja2`` template
@@ -436,7 +436,7 @@ There are several important things to note about this configuration:
the view.
Finally, we may delete the ``tutorial/templates/mytemplate.jinja2`` template
-that was provided by the ``alchemy`` scaffold, as we have created our own
+that was provided by the ``alchemy`` cookiecutter, as we have created our own
templates for the wiki.
.. note::
@@ -475,5 +475,3 @@ each of the following URLs, checking that the result is as expected:
will generate a ``NoResultFound: No row was found for one()`` error. You'll
see an interactive traceback facility provided by
:term:`pyramid_debugtoolbar`.
-
-.. _jinja2: http://jinja.pocoo.org/
diff --git a/docs/tutorials/wiki2/design.rst b/docs/tutorials/wiki2/design.rst
index 523a6e6d8..515aff276 100644
--- a/docs/tutorials/wiki2/design.rst
+++ b/docs/tutorials/wiki2/design.rst
@@ -23,22 +23,22 @@ We'll be using an SQLite database to hold our wiki data, and we'll be using
Within the database, we will define two tables:
-- The `users` table which will store the `id`, `name`, `password_hash` and
- `role` of each wiki user.
-- The `pages` table, whose elements will store the wiki pages.
- There are four columns: `id`, `name`, `data` and `creator_id`.
+- The ``users`` table which will store the ``id``, ``name``, ``password_hash`` and
+ ``role`` of each wiki user.
+- The ``pages`` table, whose elements will store the wiki pages.
+ There are four columns: ``id``, ``name``, ``data`` and ``creator_id``.
-There is a one-to-many relationship between `users` and `pages` tracking
-the user who created each wiki page defined by the `creator_id` column on the
-`pages` table.
+There is a one-to-many relationship between ``users`` and ``pages`` tracking
+the user who created each wiki page defined by the ``creator_id`` column on the
+``pages`` table.
-URLs like ``/PageName`` will try to find an element in the `pages` table that
+URLs like ``/PageName`` will try to find an element in the ``pages`` table that
has a corresponding name.
To add a page to the wiki, a new row is created and the text is stored in
-`data`.
+``data``.
-A page named ``FrontPage`` containing the text *This is the front page*, will
+A page named ``FrontPage`` containing the text "This is the front page" will
be created when the storage is initialized, and will be used as the wiki home
page.
@@ -61,12 +61,12 @@ We'll eventually be adding security to our application. To do this, we'll
be using a very simple role-based security model. We'll assign a single
role category to each user in our system.
-`basic`
- An authenticated user who can view content and create new pages. A `basic`
+``basic``
+ An authenticated user who can view content and create new pages. A ``basic``
user may also edit the pages they have created but not pages created by
other users.
-`editor`
+``editor``
An authenticated user who can create and edit any content in the system.
In order to accomplish this we'll need to define an authentication policy
@@ -101,16 +101,12 @@ in the following table:
+----------------------+-----------------------+-------------+----------------+------------+
| URL | Action | View | Template | Permission |
-| | | | | |
+======================+=======================+=============+================+============+
| / | Redirect to | view_wiki | | |
| | /FrontPage | | | |
+----------------------+-----------------------+-------------+----------------+------------+
| /PageName | Display existing | view_page | view.jinja2 | view |
| | page [2]_ | [1]_ | | |
-| | | | | |
-| | | | | |
-| | | | | |
+----------------------+-----------------------+-------------+----------------+------------+
| /PageName/edit_page | Display edit form | edit_page | edit.jinja2 | edit |
| | with existing | | | |
@@ -149,14 +145,13 @@ in the following table:
| | login form with | | | |
| | "login failed" | | | |
| | message. | | | |
-| | | | | |
+----------------------+-----------------------+-------------+----------------+------------+
| /logout | Redirect to | logout | | |
| | /FrontPage | | | |
+----------------------+-----------------------+-------------+----------------+------------+
.. [1] This is the default view for a Page context when there is no view name.
-.. [2] Pyramid will return a default 404 Not Found page if the page *PageName*
+.. [2] Pyramid will return a default 404 Not Found page if the page ``PageName``
does not exist yet.
.. [3] ``pyramid.exceptions.Forbidden`` is reached when a user tries to invoke
a view that is not authorized by the authorization policy.
diff --git a/docs/tutorials/wiki2/distributing.rst b/docs/tutorials/wiki2/distributing.rst
index f38a733f4..dd6b1b750 100644
--- a/docs/tutorials/wiki2/distributing.rst
+++ b/docs/tutorials/wiki2/distributing.rst
@@ -19,22 +19,22 @@ On Windows:
.. code-block:: doscon
- c:\pyramidtut> %VENV%\Scripts\python setup.py sdist
+ c:\tutorial> %VENV%\Scripts\python setup.py sdist
The output of such a command will be something like:
.. code-block:: text
running sdist
- # .. more output ..
+ # more output
creating dist
Creating tar archive
removing 'tutorial-0.0' (and everything under it)
-Note that this command creates a tarball in the "dist" subdirectory named
+Note that this command creates a tarball in the ``dist`` subdirectory named
``tutorial-0.0.tar.gz``. You can send this file to your friends to show them
your cool new application. They should be able to install it by pointing the
-``easy_install`` command directly at it. Or you can upload it to `PyPI
+``pip install`` command directly at it. Or you can upload it to `PyPI
<https://pypi.python.org/pypi>`_ and share it with the rest of the world, where
-it can be downloaded via ``easy_install`` remotely like any other package
-people download from PyPI.
+it can be downloaded via ``pip install`` remotely like any other package people
+download from PyPI.
diff --git a/docs/tutorials/wiki2/index.rst b/docs/tutorials/wiki2/index.rst
index 18e9f552e..740a7f014 100644
--- a/docs/tutorials/wiki2/index.rst
+++ b/docs/tutorials/wiki2/index.rst
@@ -4,13 +4,11 @@ SQLAlchemy + URL dispatch wiki tutorial
=======================================
This tutorial introduces an :term:`SQLAlchemy` and :term:`URL dispatch`-based
-:app:`Pyramid` application to a developer familiar with Python. When the
-tutorial is finished, the developer will have created a basic wiki
+:app:`Pyramid` application to a developer familiar with Python. When finished, the developer will have created a basic wiki
application with authentication and authorization.
For cut and paste purposes, the source code for all stages of this tutorial can
-be browsed on GitHub at `docs/tutorials/wiki2/src
-<https://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki2/src>`_,
+be browsed on `GitHub <https://github.com/Pylons/pyramid/>`_,
which corresponds to the same location if you have Pyramid sources.
.. toctree::
@@ -26,4 +24,3 @@ which corresponds to the same location if you have Pyramid sources.
authorization
tests
distributing
-
diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst
index 0440c2d1d..c61d4360d 100644
--- a/docs/tutorials/wiki2/installation.rst
+++ b/docs/tutorials/wiki2/installation.rst
@@ -15,178 +15,137 @@ install Pyramid**. Thereby you will satisfy the following requirements.
* You've satisfied the :ref:`requirements-for-installing-packages`.
-Create directory to contain the project
----------------------------------------
+Install SQLite3 and its development packages
+--------------------------------------------
-We need a workspace for our project files.
+If you used a package manager to install your Python or if you compiled your Python from source, then you must install SQLite3 and its development packages. If you downloaded your Python as an installer from https://www.python.org, then you already have it installed and can skip this step.
-On UNIX
-^^^^^^^
+If you need to install the SQLite3 packages, then, for example, using the Debian system and ``apt-get``, the command would be the following:
.. code-block:: bash
- $ mkdir ~/pyramidtut
-
-On Windows
-^^^^^^^^^^
+ $ sudo apt-get install libsqlite3-dev
-.. code-block:: doscon
- c:\> mkdir pyramidtut
+Install cookiecutter
+--------------------
+We will use a :term:`cookiecutter` to create a Python package project from a Python package project template. See `Cookiecutter Installation <https://cookiecutter.readthedocs.io/en/latest/installation.html>`_ for instructions.
-Create and use a virtual Python environment
--------------------------------------------
+Generate a Pyramid project from a cookiecutter
+----------------------------------------------
-Next let's create a virtual environment workspace for our project. We will use
-the ``VENV`` environment variable instead of the absolute path of the virtual
-environment.
+We will create a Pyramid project in your home directory for UNIX or at the root for Windows. It is assumed you know the path to where you installed ``cookiecutter``. Issue the following commands and override the defaults in the prompts as follows.
On UNIX
^^^^^^^
.. code-block:: bash
- $ export VENV=~/pyramidtut
- $ python3 -m venv $VENV
+ $ cd ~
+ $ cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> set VENV=c:\pyramidtut
-
-Each version of Python uses different paths, so you will need to adjust the
-path to the command for your Python version.
-
-Python 2.7:
-
-.. code-block:: doscon
-
- c:\> c:\Python27\Scripts\virtualenv %VENV%
+ c:\> cd \
+ c:\> cookiecutter https://github.com/Pylons/pyramid-cookiecutter-alchemy
-Python 3.5:
+On all operating systems
+^^^^^^^^^^^^^^^^^^^^^^^^
+If prompted for the first item, accept the default ``yes`` by hitting return.
-.. code-block:: doscon
-
- c:\> c:\Python35\Scripts\python -m venv %VENV%
+.. code-block:: text
+ You've cloned ~/.cookiecutters/pyramid-cookiecutter-alchemy before.
+ Is it okay to delete and re-clone it? [yes]: yes
+ project_name [Pyramid Scaffold]: myproj
+ repo_name [myproj]: tutorial
-Upgrade ``pip`` and ``setuptools`` in the virtual environment
--------------------------------------------------------------
+Change directory into your newly created project
+------------------------------------------------
On UNIX
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pip install --upgrade pip setuptools
+ $ cd tutorial
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\> %VENV%\Scripts\pip install --upgrade pip setuptools
+ c:\> cd tutorial
-Install Pyramid into the virtual Python environment
----------------------------------------------------
+Set and use a ``VENV`` environment variable
+-------------------------------------------
+
+We will set the ``VENV`` environment variable to the absolute path of the virtual environment, and use it going forward.
On UNIX
^^^^^^^
-.. parsed-literal::
+.. code-block:: bash
- $ $VENV/bin/pip install "pyramid==\ |release|\ "
+ $ export VENV=~/tutorial
On Windows
^^^^^^^^^^
-.. parsed-literal::
-
- c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ "
-
-
-Install SQLite3 and its development packages
---------------------------------------------
-
-If you used a package manager to install your Python or if you compiled
-your Python from source, then you must install SQLite3 and its
-development packages. If you downloaded your Python as an installer
-from https://www.python.org, then you already have it installed and can skip
-this step.
-
-If you need to install the SQLite3 packages, then, for example, using
-the Debian system and ``apt-get``, the command would be the following:
-
-.. code-block:: bash
-
- $ sudo apt-get install libsqlite3-dev
+.. code-block:: doscon
+ c:\tutorial> set VENV=c:\tutorial
-Change directory to your virtual Python environment
----------------------------------------------------
-Change directory to the ``pyramidtut`` directory, which is both your workspace
-and your virtual environment.
+Create a virtual environment
+----------------------------
On UNIX
^^^^^^^
.. code-block:: bash
- $ cd pyramidtut
+ $ python3 -m venv $VENV
On Windows
^^^^^^^^^^
-.. code-block:: doscon
+Each version of Python uses different paths, so you will need to adjust the path to the command for your Python version. Recent versions of the Python 3 installer for Windows now install a Python launcher.
- c:\> cd pyramidtut
+Python 2.7:
+.. code-block:: doscon
-.. _sql_making_a_project:
+ c:\tutorial> c:\Python27\Scripts\virtualenv %VENV%
-Making a project
-----------------
+Python 3.6:
-Your next step is to create a project. For this tutorial we will use
-the :term:`scaffold` named ``alchemy`` which generates an application
-that uses :term:`SQLAlchemy` and :term:`URL dispatch`.
+.. code-block:: doscon
-:app:`Pyramid` supplies a variety of scaffolds to generate sample projects. We
-will use ``pcreate``, a script that comes with Pyramid, to create our project
-using a scaffold.
+ c:\tutorial> python -m venv %VENV%
-By passing ``alchemy`` into the ``pcreate`` command, the script creates the
-files needed to use SQLAlchemy. By passing in our application name
-``tutorial``, the script inserts that application name into all the required
-files. For example, ``pcreate`` creates the ``initialize_tutorial_db`` in the
-``pyramidtut/bin`` directory.
-The below instructions assume your current working directory is "pyramidtut".
+Upgrade packaging tools in the virtual environment
+--------------------------------------------------
On UNIX
^^^^^^^
.. code-block:: bash
- $ $VENV/bin/pcreate -s alchemy tutorial
+ $ $VENV/bin/pip install --upgrade pip setuptools
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\pyramidtut> %VENV%\Scripts\pcreate -s alchemy tutorial
-
-.. note:: If you are using Windows, the ``alchemy`` scaffold may not deal
- gracefully with installation into a location that contains spaces in the
- path. If you experience startup problems, try putting both the virtual
- environment and the project into directories that do not contain spaces in
- their paths.
+ c:\tutorial> %VENV%\Scripts\pip install --upgrade pip setuptools
.. _installing_project_in_dev_mode:
@@ -194,74 +153,49 @@ On Windows
Installing the project in development mode
------------------------------------------
-In order to do development on the project easily, you must "register" the
-project as a development egg in your workspace using the ``pip install -e .``
-command. In order to do so, change directory to the ``tutorial`` directory that
-you created in :ref:`sql_making_a_project`, and run the ``pip install -e .``
-command using the virtual environment Python interpreter.
+In order to do development on the project easily, you must "register" the project as a development egg in your workspace. We will install testing requirements at the same time. We do so with the following command.
On UNIX
^^^^^^^
.. code-block:: bash
- $ cd tutorial
- $ $VENV/bin/pip install -e .
+ $ $VENV/bin/pip install -e ".[testing]"
On Windows
^^^^^^^^^^
.. code-block:: doscon
- c:\pyramidtut> cd tutorial
- c:\pyramidtut\tutorial> %VENV%\Scripts\pip install -e .
+ c:\tutorial> %VENV%\Scripts\pip install -e ".[testing]"
-The console will show ``pip`` checking for packages and installing missing
-packages. Success executing this command will show a line like the following:
+On all operating systems
+^^^^^^^^^^^^^^^^^^^^^^^^
-.. code-block:: bash
+The console will show ``pip`` checking for packages and installing missing packages. Success executing this command will show a line like the following:
- Successfully installed Chameleon-2.24 Mako-1.0.4 MarkupSafe-0.23 \
- Pygments-2.1.3 SQLAlchemy-1.0.12 pyramid-chameleon-0.3 \
- pyramid-debugtoolbar-2.4.2 pyramid-mako-1.0.2 pyramid-tm-0.12.1 \
- transaction-1.4.4 tutorial waitress-0.8.10 zope.sqlalchemy-0.7.6
-
-
-.. _install-testing-requirements:
+.. code-block:: bash
-Install testing requirements
-----------------------------
+ Successfully installed Jinja2-2.8 Mako-1.0.6 MarkupSafe-0.23 \
+ PasteDeploy-1.5.2 Pygments-2.1.3 SQLAlchemy-1.1.4 WebOb-1.6.3 \
+ WebTest-2.0.24 beautifulsoup4-4.5.1 coverage-4.2 py-1.4.32 pyramid-1.7.3 \
+ pyramid-debugtoolbar-3.0.5 pyramid-jinja2-2.7 pyramid-mako-1.0.2 \
+ pyramid-tm-1.1.1 pytest-3.0.5 pytest-cov-2.4.0 repoze.lru-0.6 six-1.10.0 \
+ transaction-2.0.3 translationstring-1.3 tutorial venusian-1.0 \
+ waitress-1.0.1 zope.deprecation-4.2.0 zope.interface-4.3.3 \
+ zope.sqlalchemy-0.7.7
-In order to run tests, we need to install the testing requirements. This is
-done through our project's ``setup.py`` file, in the ``tests_require`` and
-``extras_require`` stanzas, and by issuing the command below for your
-operating system.
+Testing requirements are defined in our project's ``setup.py`` file, in the ``tests_require`` and ``extras_require`` stanzas.
.. literalinclude:: src/installation/setup.py
:language: python
- :linenos:
- :lineno-start: 22
+ :lineno-match:
:lines: 22-26
.. literalinclude:: src/installation/setup.py
:language: python
- :linenos:
- :lineno-start: 45
- :lines: 45-47
-
-On UNIX
-^^^^^^^
-
-.. code-block:: bash
-
- $ $VENV/bin/pip install -e ".[testing]"
-
-On Windows
-^^^^^^^^^^
-
-.. code-block:: doscon
-
- c:\pyramidtut\tutorial> %VENV%\Scripts\pip install -e ".[testing]"
+ :lineno-match:
+ :lines: 46-48
.. _sql_running_tests:
@@ -286,7 +220,7 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test -q
+ c:\tutorial> %VENV%\Scripts\py.test -q
For a successful test run, you should see output that ends like this:
@@ -301,7 +235,7 @@ Expose test coverage information
You can run the ``py.test`` command to see test coverage information. This
runs the tests in the same way that ``py.test`` does, but provides additional
-"coverage" information, exposing which lines of your project are covered by the
+:term:`coverage` information, exposing which lines of your project are covered by the
tests.
We've already installed the ``pytest-cov`` package into our virtual
@@ -319,46 +253,45 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov \
- --cov-report=term-missing
+ c:\tutorial> %VENV%\Scripts\py.test --cov --cov-report=term-missing
If successful, you will see output something like this:
.. code-block:: bash
- ======================== test session starts ========================
- platform Python 3.5.1, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
- rootdir: /Users/stevepiercy/projects/pyramidtut/tutorial, inifile:
- plugins: cov-2.2.1
- collected 2 items
-
- tutorial/tests.py ..
- ------------------ coverage: platform Python 3.5.1 ------------------
- Name Stmts Miss Cover Missing
- ----------------------------------------------------------------
- tutorial/__init__.py 8 6 25% 7-12
- tutorial/models/__init__.py 22 0 100%
- tutorial/models/meta.py 5 0 100%
- tutorial/models/mymodel.py 8 0 100%
- tutorial/routes.py 3 2 33% 2-3
- tutorial/scripts/__init__.py 0 0 100%
- tutorial/scripts/initializedb.py 26 16 38% 22-25, 29-45
- tutorial/views/__init__.py 0 0 100%
- tutorial/views/default.py 12 0 100%
- tutorial/views/notfound.py 4 2 50% 6-7
- ----------------------------------------------------------------
- TOTAL 88 26 70%
- ===================== 2 passed in 0.57 seconds ======================
+ ======================== test session starts ========================
+ platform Python 3.6.0, pytest-3.0.5, py-1.4.31, pluggy-0.4.0
+ rootdir: /Users/stevepiercy/tutorial, inifile:
+ plugins: cov-2.4.0
+ collected 2 items
+
+ tutorial/tests.py ..
+ ------------------ coverage: platform Python 3.6.0 ------------------
+ Name Stmts Miss Cover Missing
+ ----------------------------------------------------------------
+ tutorial/__init__.py 8 6 25% 7-12
+ tutorial/models/__init__.py 22 0 100%
+ tutorial/models/meta.py 5 0 100%
+ tutorial/models/mymodel.py 8 0 100%
+ tutorial/routes.py 3 2 33% 2-3
+ tutorial/scripts/__init__.py 0 0 100%
+ tutorial/scripts/initializedb.py 26 16 38% 22-25, 29-45
+ tutorial/views/__init__.py 0 0 100%
+ tutorial/views/default.py 12 0 100%
+ tutorial/views/notfound.py 4 2 50% 6-7
+ ----------------------------------------------------------------
+ TOTAL 88 26 70%
+ ===================== 2 passed in 0.57 seconds ======================
Our package doesn't quite have 100% test coverage.
-.. _test_and_coverage_scaffold_defaults_sql:
+.. _test_and_coverage_cookiecutter_defaults_sql:
-Test and coverage scaffold defaults
------------------------------------
+Test and coverage cookiecutter defaults
+---------------------------------------
-Scaffolds include configuration defaults for ``py.test`` and test coverage.
+Cookiecutters include configuration defaults for ``py.test`` and test coverage.
These configuration files are ``pytest.ini`` and ``.coveragerc``, located at
the root of your package. Without these defaults, we would need to specify the
path to the module on which we want to run tests and coverage.
@@ -375,11 +308,10 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test --cov=tutorial \
- --cov-report=term-missing tutorial\tests.py -q
+ c:\tutorial> %VENV%\Scripts\py.test --cov=tutorial tutorial\tests.py -q
py.test follows :ref:`conventions for Python test discovery
-<pytest:test discovery>`, and the configuration defaults from the scaffold
+<pytest:test discovery>`, and the configuration defaults from the cookiecutter
tell ``py.test`` where to find the module on which we want to run tests and
coverage.
@@ -417,36 +349,36 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\initialize_tutorial_db development.ini
+ c:\tutorial> %VENV%\Scripts\initialize_tutorial_db development.ini
The output to your console should be something like this:
.. code-block:: bash
- 2016-05-22 04:03:28,888 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
- 2016-05-22 04:03:28,888 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] ()
- 2016-05-22 04:03:28,888 INFO [sqlalchemy.engine.base.Engine:1192][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
- 2016-05-22 04:03:28,889 INFO [sqlalchemy.engine.base.Engine:1193][MainThread] ()
- 2016-05-22 04:03:28,890 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] PRAGMA table_info("models")
- 2016-05-22 04:03:28,890 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ()
- 2016-05-22 04:03:28,892 INFO [sqlalchemy.engine.base.Engine:1097][MainThread]
- CREATE TABLE models (
- id INTEGER NOT NULL,
- name TEXT,
- value INTEGER,
- CONSTRAINT pk_models PRIMARY KEY (id)
- )
-
-
- 2016-05-22 04:03:28,892 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ()
- 2016-05-22 04:03:28,893 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT
- 2016-05-22 04:03:28,893 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] CREATE UNIQUE INDEX my_index ON models (name)
- 2016-05-22 04:03:28,893 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ()
- 2016-05-22 04:03:28,894 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT
- 2016-05-22 04:03:28,896 INFO [sqlalchemy.engine.base.Engine:646][MainThread] BEGIN (implicit)
- 2016-05-22 04:03:28,897 INFO [sqlalchemy.engine.base.Engine:1097][MainThread] INSERT INTO models (name, value) VALUES (?, ?)
- 2016-05-22 04:03:28,897 INFO [sqlalchemy.engine.base.Engine:1100][MainThread] ('one', 1)
- 2016-05-22 04:03:28,898 INFO [sqlalchemy.engine.base.Engine:686][MainThread] COMMIT
+ 2016-12-18 21:30:08,675 INFO [sqlalchemy.engine.base.Engine:1235][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
+ 2016-12-18 21:30:08,675 INFO [sqlalchemy.engine.base.Engine:1236][MainThread] ()
+ 2016-12-18 21:30:08,676 INFO [sqlalchemy.engine.base.Engine:1235][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
+ 2016-12-18 21:30:08,676 INFO [sqlalchemy.engine.base.Engine:1236][MainThread] ()
+ 2016-12-18 21:30:08,676 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] PRAGMA table_info("models")
+ 2016-12-18 21:30:08,676 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ()
+ 2016-12-18 21:30:08,677 INFO [sqlalchemy.engine.base.Engine:1140][MainThread]
+ CREATE TABLE models (
+ id INTEGER NOT NULL,
+ name TEXT,
+ value INTEGER,
+ CONSTRAINT pk_models PRIMARY KEY (id)
+ )
+
+
+ 2016-12-18 21:30:08,677 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ()
+ 2016-12-18 21:30:08,678 INFO [sqlalchemy.engine.base.Engine:719][MainThread] COMMIT
+ 2016-12-18 21:30:08,679 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] CREATE UNIQUE INDEX my_index ON models (name)
+ 2016-12-18 21:30:08,679 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ()
+ 2016-12-18 21:30:08,679 INFO [sqlalchemy.engine.base.Engine:719][MainThread] COMMIT
+ 2016-12-18 21:30:08,681 INFO [sqlalchemy.engine.base.Engine:679][MainThread] BEGIN (implicit)
+ 2016-12-18 21:30:08,682 INFO [sqlalchemy.engine.base.Engine:1140][MainThread] INSERT INTO models (name, value) VALUES (?, ?)
+ 2016-12-18 21:30:08,682 INFO [sqlalchemy.engine.base.Engine:1143][MainThread] ('one', 1)
+ 2016-12-18 21:30:08,682 INFO [sqlalchemy.engine.base.Engine:719][MainThread] COMMIT
Success! You should now have a ``tutorial.sqlite`` file in your current
working directory. This is an SQLite database with a single table defined in it
@@ -457,7 +389,8 @@ working directory. This is an SQLite database with a single table defined in it
Start the application
---------------------
-Start the application.
+Start the application. See :ref:`what_is_this_pserve_thing` for more
+information on ``pserve``.
On UNIX
^^^^^^^
@@ -471,7 +404,7 @@ On Windows
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\pserve development.ini --reload
+ c:\tutorial> %VENV%\Scripts\pserve development.ini --reload
.. note::
@@ -482,9 +415,10 @@ If successful, you will see something like this on your console:
.. code-block:: text
- Starting subprocess with file monitor
- Starting server in PID 82349.
- serving on http://127.0.0.1:6543
+ Starting subprocess with file monitor
+ Starting server in PID 44078.
+ Serving on http://localhost:6543
+ Serving on http://localhost:6543
This means the server is ready to accept requests.
@@ -501,13 +435,15 @@ page. You can read more about the purpose of the icon at
application while you develop.
-Decisions the ``alchemy`` scaffold has made for you
----------------------------------------------------
+Decisions the ``alchemy`` cookiecutter has made for you
+-------------------------------------------------------
-Creating a project using the ``alchemy`` scaffold makes the following
+Creating a project using the ``alchemy`` cookiecutter makes the following
assumptions:
-- You are willing to use :term:`SQLAlchemy` as a database access tool.
+- You are willing to use SQLite for persistent storage, although almost any SQL database could be used with SQLAlchemy.
+
+- You are willing to use :term:`SQLAlchemy` for a database access tool.
- You are willing to use :term:`URL dispatch` to map URLs to code.
diff --git a/docs/tutorials/wiki2/src/authentication/.coveragerc b/docs/tutorials/wiki2/src/authentication/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authentication/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki2/src/authentication/CHANGES.txt b/docs/tutorials/wiki2/src/authentication/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki2/src/authentication/CHANGES.txt
+++ b/docs/tutorials/wiki2/src/authentication/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki2/src/authentication/MANIFEST.in b/docs/tutorials/wiki2/src/authentication/MANIFEST.in
index 42cd299b5..05cc195d9 100644
--- a/docs/tutorials/wiki2/src/authentication/MANIFEST.in
+++ b/docs/tutorials/wiki2/src/authentication/MANIFEST.in
@@ -1,2 +1,2 @@
include *.txt *.ini *.cfg *.rst
-recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
+recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
diff --git a/docs/tutorials/wiki2/src/authentication/README.txt b/docs/tutorials/wiki2/src/authentication/README.txt
index 5b0101e5f..81102a869 100644
--- a/docs/tutorials/wiki2/src/authentication/README.txt
+++ b/docs/tutorials/wiki2/src/authentication/README.txt
@@ -1,14 +1,33 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/initialize_tutorial_db development.ini
+- Create a Python virtual environment.
-- $VENV/bin/pserve development.ini
+ python3 -m venv env
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Configure the database.
+
+ env/bin/initialize_tutorial_db development.ini
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki2/src/authentication/development.ini b/docs/tutorials/wiki2/src/authentication/development.ini
index 4a6c9325c..0786c1f66 100644
--- a/docs/tutorials/wiki2/src/authentication/development.ini
+++ b/docs/tutorials/wiki2/src/authentication/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,7 +13,6 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
@@ -29,12 +28,11 @@ auth.secret = seekrit
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/authentication/production.ini b/docs/tutorials/wiki2/src/authentication/production.ini
index a13a0ca19..05d60feec 100644
--- a/docs/tutorials/wiki2/src/authentication/production.ini
+++ b/docs/tutorials/wiki2/src/authentication/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -16,14 +16,17 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
auth.secret = real-seekrit
+###
+# wsgi server configuration
+###
+
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/authentication/pytest.ini b/docs/tutorials/wiki2/src/authentication/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authentication/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki2/src/authentication/setup.py b/docs/tutorials/wiki2/src/authentication/setup.py
index def3ce1f6..cc1aa421c 100644
--- a/docs/tutorials/wiki2/src/authentication/setup.py
+++ b/docs/tutorials/wiki2/src/authentication/setup.py
@@ -19,39 +19,42 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web wsgi bfg pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- [console_scripts]
- initialize_tutorial_db = tutorial.scripts.initializedb:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ 'console_scripts': [
+ 'initialize_tutorial_db = tutorial.scripts.initializedb:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/tests.py b/docs/tutorials/wiki2/src/authentication/tutorial/tests.py
index 99e95efd3..ce650ca7c 100644
--- a/docs/tutorials/wiki2/src/authentication/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/authentication/tutorial/tests.py
@@ -54,7 +54,7 @@ class TestMyViewSuccessCondition(BaseTest):
from .views.default import my_view
info = my_view(dummy_request(self.session))
self.assertEqual(info['one'].name, 'one')
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
class TestMyViewFailureCondition(BaseTest):
diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py b/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py
index 1b071434c..2d058d874 100644
--- a/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py
+++ b/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py
@@ -1,4 +1,4 @@
-import cgi
+from pyramid.compat import escape
import re
from docutils.core import publish_parts
@@ -32,10 +32,10 @@ def view_page(request):
exists = request.dbsession.query(Page).filter_by(name=word).all()
if exists:
view_url = request.route_url('view_page', pagename=word)
- return '<a href="%s">%s</a>' % (view_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (view_url, escape(word))
else:
add_url = request.route_url('add_page', pagename=word)
- return '<a href="%s">%s</a>' % (add_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (add_url, escape(word))
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(add_link, content)
diff --git a/docs/tutorials/wiki2/src/authorization/.coveragerc b/docs/tutorials/wiki2/src/authorization/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki2/src/authorization/CHANGES.txt b/docs/tutorials/wiki2/src/authorization/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki2/src/authorization/CHANGES.txt
+++ b/docs/tutorials/wiki2/src/authorization/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki2/src/authorization/MANIFEST.in b/docs/tutorials/wiki2/src/authorization/MANIFEST.in
index 42cd299b5..05cc195d9 100644
--- a/docs/tutorials/wiki2/src/authorization/MANIFEST.in
+++ b/docs/tutorials/wiki2/src/authorization/MANIFEST.in
@@ -1,2 +1,2 @@
include *.txt *.ini *.cfg *.rst
-recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
+recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
diff --git a/docs/tutorials/wiki2/src/authorization/README.txt b/docs/tutorials/wiki2/src/authorization/README.txt
index 5b0101e5f..81102a869 100644
--- a/docs/tutorials/wiki2/src/authorization/README.txt
+++ b/docs/tutorials/wiki2/src/authorization/README.txt
@@ -1,14 +1,33 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/initialize_tutorial_db development.ini
+- Create a Python virtual environment.
-- $VENV/bin/pserve development.ini
+ python3 -m venv env
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Configure the database.
+
+ env/bin/initialize_tutorial_db development.ini
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki2/src/authorization/development.ini b/docs/tutorials/wiki2/src/authorization/development.ini
index 4a6c9325c..0786c1f66 100644
--- a/docs/tutorials/wiki2/src/authorization/development.ini
+++ b/docs/tutorials/wiki2/src/authorization/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,7 +13,6 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
@@ -29,12 +28,11 @@ auth.secret = seekrit
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/authorization/production.ini b/docs/tutorials/wiki2/src/authorization/production.ini
index a13a0ca19..05d60feec 100644
--- a/docs/tutorials/wiki2/src/authorization/production.ini
+++ b/docs/tutorials/wiki2/src/authorization/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -16,14 +16,17 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
auth.secret = real-seekrit
+###
+# wsgi server configuration
+###
+
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/authorization/pytest.ini b/docs/tutorials/wiki2/src/authorization/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki2/src/authorization/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki2/src/authorization/setup.py b/docs/tutorials/wiki2/src/authorization/setup.py
index def3ce1f6..cc1aa421c 100644
--- a/docs/tutorials/wiki2/src/authorization/setup.py
+++ b/docs/tutorials/wiki2/src/authorization/setup.py
@@ -19,39 +19,42 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web wsgi bfg pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- [console_scripts]
- initialize_tutorial_db = tutorial.scripts.initializedb:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ 'console_scripts': [
+ 'initialize_tutorial_db = tutorial.scripts.initializedb:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py b/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py
index 9358993ea..65c12ed3b 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py
@@ -1,4 +1,4 @@
-import cgi
+from pyramid.compat import escape
import re
from docutils.core import publish_parts
@@ -25,10 +25,10 @@ def view_page(request):
exists = request.dbsession.query(Page).filter_by(name=word).all()
if exists:
view_url = request.route_url('view_page', pagename=word)
- return '<a href="%s">%s</a>' % (view_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (view_url, escape(word))
else:
add_url = request.route_url('add_page', pagename=word)
- return '<a href="%s">%s</a>' % (add_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (add_url, escape(word))
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(add_link, content)
diff --git a/docs/tutorials/wiki2/src/basiclayout/.coveragerc b/docs/tutorials/wiki2/src/basiclayout/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki2/src/basiclayout/CHANGES.txt b/docs/tutorials/wiki2/src/basiclayout/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki2/src/basiclayout/CHANGES.txt
+++ b/docs/tutorials/wiki2/src/basiclayout/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki2/src/basiclayout/MANIFEST.in b/docs/tutorials/wiki2/src/basiclayout/MANIFEST.in
index 42cd299b5..05cc195d9 100644
--- a/docs/tutorials/wiki2/src/basiclayout/MANIFEST.in
+++ b/docs/tutorials/wiki2/src/basiclayout/MANIFEST.in
@@ -1,2 +1,2 @@
include *.txt *.ini *.cfg *.rst
-recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
+recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
diff --git a/docs/tutorials/wiki2/src/basiclayout/README.txt b/docs/tutorials/wiki2/src/basiclayout/README.txt
index 5b0101e5f..81102a869 100644
--- a/docs/tutorials/wiki2/src/basiclayout/README.txt
+++ b/docs/tutorials/wiki2/src/basiclayout/README.txt
@@ -1,14 +1,33 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/initialize_tutorial_db development.ini
+- Create a Python virtual environment.
-- $VENV/bin/pserve development.ini
+ python3 -m venv env
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Configure the database.
+
+ env/bin/initialize_tutorial_db development.ini
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki2/src/basiclayout/development.ini b/docs/tutorials/wiki2/src/basiclayout/development.ini
index 22b733e10..be80882a5 100644
--- a/docs/tutorials/wiki2/src/basiclayout/development.ini
+++ b/docs/tutorials/wiki2/src/basiclayout/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,7 +13,6 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
@@ -27,12 +26,11 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/basiclayout/production.ini b/docs/tutorials/wiki2/src/basiclayout/production.ini
index d2ecfe22a..c01ad9a7e 100644
--- a/docs/tutorials/wiki2/src/basiclayout/production.ini
+++ b/docs/tutorials/wiki2/src/basiclayout/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -14,14 +14,17 @@ pyramid.default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
+###
+# wsgi server configuration
+###
+
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/basiclayout/pytest.ini b/docs/tutorials/wiki2/src/basiclayout/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki2/src/basiclayout/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki2/src/basiclayout/setup.py b/docs/tutorials/wiki2/src/basiclayout/setup.py
index ede0a82ef..d3992a8f2 100644
--- a/docs/tutorials/wiki2/src/basiclayout/setup.py
+++ b/docs/tutorials/wiki2/src/basiclayout/setup.py
@@ -17,39 +17,42 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web wsgi bfg pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- [console_scripts]
- initialize_tutorial_db = tutorial.scripts.initializedb:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ 'console_scripts': [
+ 'initialize_tutorial_db = tutorial.scripts.initializedb:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py
index 3fc82cfba..5ca037787 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/models/__init__.py
@@ -5,7 +5,7 @@ import zope.sqlalchemy
# import or define all models here to ensure they are attached to the
# Base.metadata prior to any initialization routines
-from .mymodel import MyModel # noqa
+from .mymodel import MyModel # flake8: noqa
# run configure_mappers after defining all of the models to ensure
# all relationships can be setup
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2
index ab8c5ea3d..1f658c834 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/layout.jinja2
@@ -8,7 +8,7 @@
<meta name="author" content="Pylons Project">
<link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}">
- <title>Alchemy Scaffold for The Pyramid Web Framework</title>
+ <title>Cookiecutter Alchemy project for the Pyramid Web Framework</title>
<!-- Bootstrap core CSS -->
<link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
@@ -29,7 +29,7 @@
<div class="container">
<div class="row">
<div class="col-md-2">
- <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework">
+ <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png') }}" alt="pyramid web framework">
</div>
<div class="col-md-10">
{% block content %}
@@ -40,10 +40,8 @@
<div class="row">
<div class="links">
<ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
<li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
+ <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
<li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
</ul>
</div>
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja2 b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja2
index 6b49869c4..359f55ffa 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja2
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/templates/mytemplate.jinja2
@@ -2,7 +2,7 @@
{% block content %}
<div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
+ <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy project</span></h1>
+ <p class="lead">Welcome to <span class="font-normal">myproj</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
{% endblock content %}
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
index 99e95efd3..ce650ca7c 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/tests.py
@@ -54,7 +54,7 @@ class TestMyViewSuccessCondition(BaseTest):
from .views.default import my_view
info = my_view(dummy_request(self.session))
self.assertEqual(info['one'].name, 'one')
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
class TestMyViewFailureCondition(BaseTest):
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/views/default.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/views/default.py
index ad0c728d7..a404d4154 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/views/default.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/views/default.py
@@ -13,7 +13,7 @@ def my_view(request):
one = query.filter(MyModel.name == 'one').first()
except DBAPIError:
return Response(db_err_msg, content_type='text/plain', status=500)
- return {'one': one, 'project': 'tutorial'}
+ return {'one': one, 'project': 'myproj'}
db_err_msg = """\
diff --git a/docs/tutorials/wiki2/src/installation/.coveragerc b/docs/tutorials/wiki2/src/installation/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/installation/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki2/src/installation/CHANGES.txt b/docs/tutorials/wiki2/src/installation/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki2/src/installation/CHANGES.txt
+++ b/docs/tutorials/wiki2/src/installation/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki2/src/installation/MANIFEST.in b/docs/tutorials/wiki2/src/installation/MANIFEST.in
index 42cd299b5..05cc195d9 100644
--- a/docs/tutorials/wiki2/src/installation/MANIFEST.in
+++ b/docs/tutorials/wiki2/src/installation/MANIFEST.in
@@ -1,2 +1,2 @@
include *.txt *.ini *.cfg *.rst
-recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
+recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
diff --git a/docs/tutorials/wiki2/src/installation/README.txt b/docs/tutorials/wiki2/src/installation/README.txt
index 5b0101e5f..81102a869 100644
--- a/docs/tutorials/wiki2/src/installation/README.txt
+++ b/docs/tutorials/wiki2/src/installation/README.txt
@@ -1,14 +1,33 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/initialize_tutorial_db development.ini
+- Create a Python virtual environment.
-- $VENV/bin/pserve development.ini
+ python3 -m venv env
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Configure the database.
+
+ env/bin/initialize_tutorial_db development.ini
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki2/src/installation/development.ini b/docs/tutorials/wiki2/src/installation/development.ini
index 22b733e10..be80882a5 100644
--- a/docs/tutorials/wiki2/src/installation/development.ini
+++ b/docs/tutorials/wiki2/src/installation/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,7 +13,6 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
@@ -27,12 +26,11 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/installation/production.ini b/docs/tutorials/wiki2/src/installation/production.ini
index d2ecfe22a..c01ad9a7e 100644
--- a/docs/tutorials/wiki2/src/installation/production.ini
+++ b/docs/tutorials/wiki2/src/installation/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -14,14 +14,17 @@ pyramid.default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
+###
+# wsgi server configuration
+###
+
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/installation/pytest.ini b/docs/tutorials/wiki2/src/installation/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki2/src/installation/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki2/src/installation/setup.py b/docs/tutorials/wiki2/src/installation/setup.py
index ede0a82ef..d3992a8f2 100644
--- a/docs/tutorials/wiki2/src/installation/setup.py
+++ b/docs/tutorials/wiki2/src/installation/setup.py
@@ -17,39 +17,42 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web wsgi bfg pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- [console_scripts]
- initialize_tutorial_db = tutorial.scripts.initializedb:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ 'console_scripts': [
+ 'initialize_tutorial_db = tutorial.scripts.initializedb:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py b/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py
index 3fc82cfba..5ca037787 100644
--- a/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py
+++ b/docs/tutorials/wiki2/src/installation/tutorial/models/__init__.py
@@ -5,7 +5,7 @@ import zope.sqlalchemy
# import or define all models here to ensure they are attached to the
# Base.metadata prior to any initialization routines
-from .mymodel import MyModel # noqa
+from .mymodel import MyModel # flake8: noqa
# run configure_mappers after defining all of the models to ensure
# all relationships can be setup
diff --git a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2
index ab8c5ea3d..1f658c834 100644
--- a/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2
+++ b/docs/tutorials/wiki2/src/installation/tutorial/templates/layout.jinja2
@@ -8,7 +8,7 @@
<meta name="author" content="Pylons Project">
<link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}">
- <title>Alchemy Scaffold for The Pyramid Web Framework</title>
+ <title>Cookiecutter Alchemy project for the Pyramid Web Framework</title>
<!-- Bootstrap core CSS -->
<link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
@@ -29,7 +29,7 @@
<div class="container">
<div class="row">
<div class="col-md-2">
- <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework">
+ <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png') }}" alt="pyramid web framework">
</div>
<div class="col-md-10">
{% block content %}
@@ -40,10 +40,8 @@
<div class="row">
<div class="links">
<ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
<li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
+ <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
<li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
</ul>
</div>
diff --git a/docs/tutorials/wiki2/src/installation/tutorial/templates/mytemplate.jinja2 b/docs/tutorials/wiki2/src/installation/tutorial/templates/mytemplate.jinja2
index 6b49869c4..359f55ffa 100644
--- a/docs/tutorials/wiki2/src/installation/tutorial/templates/mytemplate.jinja2
+++ b/docs/tutorials/wiki2/src/installation/tutorial/templates/mytemplate.jinja2
@@ -2,7 +2,7 @@
{% block content %}
<div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
+ <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy project</span></h1>
+ <p class="lead">Welcome to <span class="font-normal">myproj</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
{% endblock content %}
diff --git a/docs/tutorials/wiki2/src/installation/tutorial/tests.py b/docs/tutorials/wiki2/src/installation/tutorial/tests.py
index 99e95efd3..ce650ca7c 100644
--- a/docs/tutorials/wiki2/src/installation/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/installation/tutorial/tests.py
@@ -54,7 +54,7 @@ class TestMyViewSuccessCondition(BaseTest):
from .views.default import my_view
info = my_view(dummy_request(self.session))
self.assertEqual(info['one'].name, 'one')
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
class TestMyViewFailureCondition(BaseTest):
diff --git a/docs/tutorials/wiki2/src/installation/tutorial/views/default.py b/docs/tutorials/wiki2/src/installation/tutorial/views/default.py
index ad0c728d7..a404d4154 100644
--- a/docs/tutorials/wiki2/src/installation/tutorial/views/default.py
+++ b/docs/tutorials/wiki2/src/installation/tutorial/views/default.py
@@ -13,7 +13,7 @@ def my_view(request):
one = query.filter(MyModel.name == 'one').first()
except DBAPIError:
return Response(db_err_msg, content_type='text/plain', status=500)
- return {'one': one, 'project': 'tutorial'}
+ return {'one': one, 'project': 'myproj'}
db_err_msg = """\
diff --git a/docs/tutorials/wiki2/src/models/.coveragerc b/docs/tutorials/wiki2/src/models/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki2/src/models/CHANGES.txt b/docs/tutorials/wiki2/src/models/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki2/src/models/CHANGES.txt
+++ b/docs/tutorials/wiki2/src/models/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki2/src/models/MANIFEST.in b/docs/tutorials/wiki2/src/models/MANIFEST.in
index 42cd299b5..05cc195d9 100644
--- a/docs/tutorials/wiki2/src/models/MANIFEST.in
+++ b/docs/tutorials/wiki2/src/models/MANIFEST.in
@@ -1,2 +1,2 @@
include *.txt *.ini *.cfg *.rst
-recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
+recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
diff --git a/docs/tutorials/wiki2/src/models/README.txt b/docs/tutorials/wiki2/src/models/README.txt
index 5b0101e5f..81102a869 100644
--- a/docs/tutorials/wiki2/src/models/README.txt
+++ b/docs/tutorials/wiki2/src/models/README.txt
@@ -1,14 +1,33 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/initialize_tutorial_db development.ini
+- Create a Python virtual environment.
-- $VENV/bin/pserve development.ini
+ python3 -m venv env
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Configure the database.
+
+ env/bin/initialize_tutorial_db development.ini
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki2/src/models/development.ini b/docs/tutorials/wiki2/src/models/development.ini
index 22b733e10..be80882a5 100644
--- a/docs/tutorials/wiki2/src/models/development.ini
+++ b/docs/tutorials/wiki2/src/models/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,7 +13,6 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
@@ -27,12 +26,11 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/models/production.ini b/docs/tutorials/wiki2/src/models/production.ini
index d2ecfe22a..c01ad9a7e 100644
--- a/docs/tutorials/wiki2/src/models/production.ini
+++ b/docs/tutorials/wiki2/src/models/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -14,14 +14,17 @@ pyramid.default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
+###
+# wsgi server configuration
+###
+
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/models/pytest.ini b/docs/tutorials/wiki2/src/models/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki2/src/models/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki2/src/models/setup.py b/docs/tutorials/wiki2/src/models/setup.py
index 742a7c59c..faf76aa27 100644
--- a/docs/tutorials/wiki2/src/models/setup.py
+++ b/docs/tutorials/wiki2/src/models/setup.py
@@ -18,39 +18,42 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web wsgi bfg pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- [console_scripts]
- initialize_tutorial_db = tutorial.scripts.initializedb:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ 'console_scripts': [
+ 'initialize_tutorial_db = tutorial.scripts.initializedb:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2
index ab8c5ea3d..1f658c834 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2
+++ b/docs/tutorials/wiki2/src/models/tutorial/templates/layout.jinja2
@@ -8,7 +8,7 @@
<meta name="author" content="Pylons Project">
<link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}">
- <title>Alchemy Scaffold for The Pyramid Web Framework</title>
+ <title>Cookiecutter Alchemy project for the Pyramid Web Framework</title>
<!-- Bootstrap core CSS -->
<link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
@@ -29,7 +29,7 @@
<div class="container">
<div class="row">
<div class="col-md-2">
- <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework">
+ <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png') }}" alt="pyramid web framework">
</div>
<div class="col-md-10">
{% block content %}
@@ -40,10 +40,8 @@
<div class="row">
<div class="links">
<ul>
- <li class="current-version">Generated by v1.7</li>
- <li><i class="glyphicon glyphicon-bookmark icon-muted"></i><a href="http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/">Docs</a></li>
<li><i class="glyphicon glyphicon-cog icon-muted"></i><a href="https://github.com/Pylons/pyramid">Github Project</a></li>
- <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="irc://irc.freenode.net#pyramid">IRC Channel</a></li>
+ <li><i class="glyphicon glyphicon-globe icon-muted"></i><a href="https://webchat.freenode.net/?channels=pyramid">IRC Channel</a></li>
<li><i class="glyphicon glyphicon-home icon-muted"></i><a href="http://pylonsproject.org">Pylons Project</a></li>
</ul>
</div>
diff --git a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.jinja2 b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.jinja2
index 6b49869c4..359f55ffa 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.jinja2
+++ b/docs/tutorials/wiki2/src/models/tutorial/templates/mytemplate.jinja2
@@ -2,7 +2,7 @@
{% block content %}
<div class="content">
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1>
- <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, an&nbsp;application generated&nbsp;by<br>the <span class="font-normal">Pyramid Web Framework 1.7</span>.</p>
+ <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy project</span></h1>
+ <p class="lead">Welcome to <span class="font-normal">myproj</span>, a&nbsp;Pyramid application generated&nbsp;by<br><span class="font-normal">Cookiecutter</span>.</p>
</div>
{% endblock content %}
diff --git a/docs/tutorials/wiki2/src/models/tutorial/tests.py b/docs/tutorials/wiki2/src/models/tutorial/tests.py
index 99e95efd3..ce650ca7c 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/tests.py
@@ -54,7 +54,7 @@ class TestMyViewSuccessCondition(BaseTest):
from .views.default import my_view
info = my_view(dummy_request(self.session))
self.assertEqual(info['one'].name, 'one')
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
class TestMyViewFailureCondition(BaseTest):
diff --git a/docs/tutorials/wiki2/src/models/tutorial/views/default.py b/docs/tutorials/wiki2/src/models/tutorial/views/default.py
index ad0c728d7..a404d4154 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/views/default.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/views/default.py
@@ -13,7 +13,7 @@ def my_view(request):
one = query.filter(MyModel.name == 'one').first()
except DBAPIError:
return Response(db_err_msg, content_type='text/plain', status=500)
- return {'one': one, 'project': 'tutorial'}
+ return {'one': one, 'project': 'myproj'}
db_err_msg = """\
diff --git a/docs/tutorials/wiki2/src/tests/.coveragerc b/docs/tutorials/wiki2/src/tests/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki2/src/tests/CHANGES.txt b/docs/tutorials/wiki2/src/tests/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki2/src/tests/CHANGES.txt
+++ b/docs/tutorials/wiki2/src/tests/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki2/src/tests/MANIFEST.in b/docs/tutorials/wiki2/src/tests/MANIFEST.in
index 42cd299b5..05cc195d9 100644
--- a/docs/tutorials/wiki2/src/tests/MANIFEST.in
+++ b/docs/tutorials/wiki2/src/tests/MANIFEST.in
@@ -1,2 +1,2 @@
include *.txt *.ini *.cfg *.rst
-recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
+recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
diff --git a/docs/tutorials/wiki2/src/tests/README.txt b/docs/tutorials/wiki2/src/tests/README.txt
index 5b0101e5f..81102a869 100644
--- a/docs/tutorials/wiki2/src/tests/README.txt
+++ b/docs/tutorials/wiki2/src/tests/README.txt
@@ -1,14 +1,33 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/initialize_tutorial_db development.ini
+- Create a Python virtual environment.
-- $VENV/bin/pserve development.ini
+ python3 -m venv env
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Configure the database.
+
+ env/bin/initialize_tutorial_db development.ini
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki2/src/tests/development.ini b/docs/tutorials/wiki2/src/tests/development.ini
index 4a6c9325c..0786c1f66 100644
--- a/docs/tutorials/wiki2/src/tests/development.ini
+++ b/docs/tutorials/wiki2/src/tests/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,7 +13,6 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
@@ -29,12 +28,11 @@ auth.secret = seekrit
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/tests/production.ini b/docs/tutorials/wiki2/src/tests/production.ini
index a13a0ca19..05d60feec 100644
--- a/docs/tutorials/wiki2/src/tests/production.ini
+++ b/docs/tutorials/wiki2/src/tests/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -16,14 +16,17 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
auth.secret = real-seekrit
+###
+# wsgi server configuration
+###
+
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/tests/pytest.ini b/docs/tutorials/wiki2/src/tests/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py
index def3ce1f6..cc1aa421c 100644
--- a/docs/tutorials/wiki2/src/tests/setup.py
+++ b/docs/tutorials/wiki2/src/tests/setup.py
@@ -19,39 +19,42 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web wsgi bfg pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- [console_scripts]
- initialize_tutorial_db = tutorial.scripts.initializedb:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ 'console_scripts': [
+ 'initialize_tutorial_db = tutorial.scripts.initializedb:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py b/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py
index f3c0a6fef..c860ef8cf 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/scripts/initializedb.py
@@ -28,6 +28,7 @@ def usage(argv):
def main(argv=sys.argv):
if len(argv) < 2:
usage(argv)
+ return
config_uri = argv[1]
options = parse_vars(argv[2:])
setup_logging(config_uri)
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py
index 715768b2e..0250e71c9 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_functional.py
@@ -11,6 +11,9 @@ class FunctionalTests(unittest.TestCase):
basic_wrong_login = (
'/login?login=basic&password=incorrect'
'&next=FrontPage&form.submitted=Login')
+ basic_login_no_next = (
+ '/login?login=basic&password=basic'
+ '&form.submitted=Login')
editor_login = (
'/login?login=editor&password=editor'
'&next=FrontPage&form.submitted=Login')
@@ -68,6 +71,10 @@ class FunctionalTests(unittest.TestCase):
res = self.testapp.get(self.basic_login, status=302)
self.assertEqual(res.location, 'http://localhost/FrontPage')
+ def test_successful_log_in_no_next(self):
+ res = self.testapp.get(self.basic_login_no_next, status=302)
+ self.assertEqual(res.location, 'http://localhost/')
+
def test_failed_log_in(self):
res = self.testapp.get(self.basic_wrong_login, status=200)
self.assertTrue(b'login' in res.body)
@@ -120,3 +127,8 @@ class FunctionalTests(unittest.TestCase):
self.testapp.get(self.editor_login, status=302)
res = self.testapp.get('/FrontPage', status=200)
self.assertTrue(b'FrontPage' in res.body)
+
+ def test_redirect_to_edit_for_existing_page(self):
+ self.testapp.get(self.editor_login, status=302)
+ res = self.testapp.get('/add_page/FrontPage', status=302)
+ self.assertTrue(b'FrontPage' in res.body)
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_initdb.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_initdb.py
new file mode 100644
index 000000000..f5273456e
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_initdb.py
@@ -0,0 +1,16 @@
+import os
+import unittest
+
+
+class TestInitializeDB(unittest.TestCase):
+
+ def test_usage(self):
+ from ..scripts.initializedb import main
+ with self.assertRaises(SystemExit):
+ main(argv=['foo'])
+
+ def test_run(self):
+ from ..scripts.initializedb import main
+ main(argv=['foo', 'development.ini'])
+ self.assertTrue(os.path.exists('tutorial.sqlite'))
+ os.remove('tutorial.sqlite')
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_security.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_security.py
new file mode 100644
index 000000000..cbec6420d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_security.py
@@ -0,0 +1,23 @@
+import unittest
+from pyramid.testing import DummyRequest
+
+
+class TestMyAuthenticationPolicy(unittest.TestCase):
+
+ def test_no_user(self):
+ request = DummyRequest()
+ request.user = None
+
+ from ..security import MyAuthenticationPolicy
+ policy = MyAuthenticationPolicy(None)
+ self.assertEqual(policy.authenticated_userid(request), None)
+
+ def test_authenticated_user(self):
+ from ..models import User
+ request = DummyRequest()
+ request.user = User()
+ request.user.id = 'foo'
+
+ from ..security import MyAuthenticationPolicy
+ policy = MyAuthenticationPolicy(None)
+ self.assertEqual(policy.authenticated_userid(request), 'foo')
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/tests/test_user_model.py b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_user_model.py
new file mode 100644
index 000000000..9490ac990
--- /dev/null
+++ b/docs/tutorials/wiki2/src/tests/tutorial/tests/test_user_model.py
@@ -0,0 +1,67 @@
+import unittest
+import transaction
+
+from pyramid import testing
+
+
+class BaseTest(unittest.TestCase):
+
+ def setUp(self):
+ from ..models import get_tm_session
+ self.config = testing.setUp(settings={
+ 'sqlalchemy.url': 'sqlite:///:memory:'
+ })
+ self.config.include('..models')
+ self.config.include('..routes')
+
+ session_factory = self.config.registry['dbsession_factory']
+ self.session = get_tm_session(session_factory, transaction.manager)
+
+ self.init_database()
+
+ def init_database(self):
+ from ..models.meta import Base
+ session_factory = self.config.registry['dbsession_factory']
+ engine = session_factory.kw['bind']
+ Base.metadata.create_all(engine)
+
+ def tearDown(self):
+ testing.tearDown()
+ transaction.abort()
+
+ def makeUser(self, name, role):
+ from ..models import User
+ return User(name=name, role=role)
+
+
+class TestSetPassword(BaseTest):
+
+ def test_password_hash_saved(self):
+ user = self.makeUser(name='foo', role='bar')
+ self.assertFalse(user.password_hash)
+
+ user.set_password('secret')
+ self.assertTrue(user.password_hash)
+
+
+class TestCheckPassword(BaseTest):
+
+ def test_password_hash_not_set(self):
+ user = self.makeUser(name='foo', role='bar')
+ self.assertFalse(user.password_hash)
+
+ self.assertFalse(user.check_password('secret'))
+
+ def test_correct_password(self):
+ user = self.makeUser(name='foo', role='bar')
+ user.set_password('secret')
+ self.assertTrue(user.password_hash)
+
+ self.assertTrue(user.check_password('secret'))
+
+ def test_incorrect_password(self):
+ user = self.makeUser(name='foo', role='bar')
+ user.set_password('secret')
+ self.assertTrue(user.password_hash)
+
+ self.assertFalse(user.check_password('incorrect'))
diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py
index 9358993ea..65c12ed3b 100644
--- a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py
+++ b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py
@@ -1,4 +1,4 @@
-import cgi
+from pyramid.compat import escape
import re
from docutils.core import publish_parts
@@ -25,10 +25,10 @@ def view_page(request):
exists = request.dbsession.query(Page).filter_by(name=word).all()
if exists:
view_url = request.route_url('view_page', pagename=word)
- return '<a href="%s">%s</a>' % (view_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (view_url, escape(word))
else:
add_url = request.route_url('add_page', pagename=word)
- return '<a href="%s">%s</a>' % (add_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (add_url, escape(word))
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(add_link, content)
diff --git a/docs/tutorials/wiki2/src/views/.coveragerc b/docs/tutorials/wiki2/src/views/.coveragerc
new file mode 100644
index 000000000..a1d87d03d
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+source = tutorial
+omit = tutorial/test*
diff --git a/docs/tutorials/wiki2/src/views/CHANGES.txt b/docs/tutorials/wiki2/src/views/CHANGES.txt
index 35a34f332..14b902fd1 100644
--- a/docs/tutorials/wiki2/src/views/CHANGES.txt
+++ b/docs/tutorials/wiki2/src/views/CHANGES.txt
@@ -1,4 +1,4 @@
0.0
---
-- Initial version
+- Initial version.
diff --git a/docs/tutorials/wiki2/src/views/MANIFEST.in b/docs/tutorials/wiki2/src/views/MANIFEST.in
index 42cd299b5..05cc195d9 100644
--- a/docs/tutorials/wiki2/src/views/MANIFEST.in
+++ b/docs/tutorials/wiki2/src/views/MANIFEST.in
@@ -1,2 +1,2 @@
include *.txt *.ini *.cfg *.rst
-recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.jinja2 *.pt *.txt *.mak *.mako *.js *.html *.xml
+recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
diff --git a/docs/tutorials/wiki2/src/views/README.txt b/docs/tutorials/wiki2/src/views/README.txt
index 5b0101e5f..81102a869 100644
--- a/docs/tutorials/wiki2/src/views/README.txt
+++ b/docs/tutorials/wiki2/src/views/README.txt
@@ -1,14 +1,33 @@
-tutorial README
-==================
+myproj
+======
Getting Started
---------------
-- cd <directory containing this file>
+- Change directory into your newly created project.
-- $VENV/bin/pip install -e .
+ cd tutorial
-- $VENV/bin/initialize_tutorial_db development.ini
+- Create a Python virtual environment.
-- $VENV/bin/pserve development.ini
+ python3 -m venv env
+- Upgrade packaging tools.
+
+ env/bin/pip install --upgrade pip setuptools wheel
+
+- Install the project in editable mode with its testing requirements.
+
+ env/bin/pip install -e ".[testing]"
+
+- Configure the database.
+
+ env/bin/initialize_tutorial_db development.ini
+
+- Run your project's tests.
+
+ env/bin/pytest
+
+- Run your project.
+
+ env/bin/pserve development.ini
diff --git a/docs/tutorials/wiki2/src/views/development.ini b/docs/tutorials/wiki2/src/views/development.ini
index 22b733e10..be80882a5 100644
--- a/docs/tutorials/wiki2/src/views/development.ini
+++ b/docs/tutorials/wiki2/src/views/development.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -13,7 +13,6 @@ pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
- pyramid_tm
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
@@ -27,12 +26,11 @@ sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
[server:main]
use = egg:waitress#main
-host = 127.0.0.1
-port = 6543
+listen = localhost:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/views/production.ini b/docs/tutorials/wiki2/src/views/production.ini
index d2ecfe22a..c01ad9a7e 100644
--- a/docs/tutorials/wiki2/src/views/production.ini
+++ b/docs/tutorials/wiki2/src/views/production.ini
@@ -1,6 +1,6 @@
###
# app configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
@@ -14,14 +14,17 @@ pyramid.default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/tutorial.sqlite
+###
+# wsgi server configuration
+###
+
[server:main]
use = egg:waitress#main
-host = 0.0.0.0
-port = 6543
+listen = *:6543
###
# logging configuration
-# http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
diff --git a/docs/tutorials/wiki2/src/views/pytest.ini b/docs/tutorials/wiki2/src/views/pytest.ini
new file mode 100644
index 000000000..8b76bc410
--- /dev/null
+++ b/docs/tutorials/wiki2/src/views/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+testpaths = tutorial
+python_files = *.py
diff --git a/docs/tutorials/wiki2/src/views/setup.py b/docs/tutorials/wiki2/src/views/setup.py
index def3ce1f6..cc1aa421c 100644
--- a/docs/tutorials/wiki2/src/views/setup.py
+++ b/docs/tutorials/wiki2/src/views/setup.py
@@ -19,39 +19,42 @@ requires = [
'transaction',
'zope.sqlalchemy',
'waitress',
- ]
+]
tests_require = [
'WebTest >= 1.3.1', # py3 compat
- 'pytest', # includes virtualenv
+ 'pytest',
'pytest-cov',
- ]
+]
-setup(name='tutorial',
- version='0.0',
- description='tutorial',
- long_description=README + '\n\n' + CHANGES,
- classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
- author='',
- author_email='',
- url='',
- keywords='web wsgi bfg pylons pyramid',
- packages=find_packages(),
- include_package_data=True,
- zip_safe=False,
- extras_require={
- 'testing': tests_require,
- },
- install_requires=requires,
- entry_points="""\
- [paste.app_factory]
- main = tutorial:main
- [console_scripts]
- initialize_tutorial_db = tutorial.scripts.initializedb:main
- """,
- )
+setup(
+ name='tutorial',
+ version='0.0',
+ description='myproj',
+ long_description=README + '\n\n' + CHANGES,
+ classifiers=[
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
+ author='',
+ author_email='',
+ url='',
+ keywords='web pyramid pylons',
+ packages=find_packages(),
+ include_package_data=True,
+ zip_safe=False,
+ extras_require={
+ 'testing': tests_require,
+ },
+ install_requires=requires,
+ entry_points={
+ 'paste.app_factory': [
+ 'main = tutorial:main',
+ ],
+ 'console_scripts': [
+ 'initialize_tutorial_db = tutorial.scripts.initializedb:main',
+ ],
+ },
+)
diff --git a/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2 b/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2
index 71785157f..7575de8a7 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2
+++ b/docs/tutorials/wiki2/src/views/tutorial/templates/layout.jinja2
@@ -29,7 +29,7 @@
<div class="container">
<div class="row">
<div class="col-md-2">
- <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png')}}" alt="pyramid web framework">
+ <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png') }}" alt="pyramid web framework">
</div>
<div class="col-md-10">
<div class="content">
diff --git a/docs/tutorials/wiki2/src/views/tutorial/tests.py b/docs/tutorials/wiki2/src/views/tutorial/tests.py
index 99e95efd3..ce650ca7c 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/tests.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/tests.py
@@ -54,7 +54,7 @@ class TestMyViewSuccessCondition(BaseTest):
from .views.default import my_view
info = my_view(dummy_request(self.session))
self.assertEqual(info['one'].name, 'one')
- self.assertEqual(info['project'], 'tutorial')
+ self.assertEqual(info['project'], 'myproj')
class TestMyViewFailureCondition(BaseTest):
diff --git a/docs/tutorials/wiki2/src/views/tutorial/views/default.py b/docs/tutorials/wiki2/src/views/tutorial/views/default.py
index bb6300b75..3b95e0f59 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/views/default.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/views/default.py
@@ -1,4 +1,4 @@
-import cgi
+from pyramid.compat import escape
import re
from docutils.core import publish_parts
@@ -31,10 +31,10 @@ def view_page(request):
exists = request.dbsession.query(Page).filter_by(name=word).all()
if exists:
view_url = request.route_url('view_page', pagename=word)
- return '<a href="%s">%s</a>' % (view_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (view_url, escape(word))
else:
add_url = request.route_url('add_page', pagename=word)
- return '<a href="%s">%s</a>' % (add_url, cgi.escape(word))
+ return '<a href="%s">%s</a>' % (add_url, escape(word))
content = publish_parts(page.data, writer_name='html')['html_body']
content = wikiwords.sub(add_link, content)
diff --git a/docs/tutorials/wiki2/tests.rst b/docs/tutorials/wiki2/tests.rst
index e923ff9cb..e1f83a755 100644
--- a/docs/tutorials/wiki2/tests.rst
+++ b/docs/tutorials/wiki2/tests.rst
@@ -8,7 +8,7 @@ We will now add tests for the models and views as well as a few functional
tests in a new ``tests`` subpackage. Tests ensure that an application works,
and that it continues to work when changes are made in the future.
-The file ``tests.py`` was generated as part of the ``alchemy`` scaffold, but it
+The file ``tests.py`` was generated as part of the ``alchemy`` cookiecutter, but it
is a common practice to put tests into a ``tests`` subpackage, especially as
projects grow in size and complexity. Each module in the test subpackage
should contain tests for its corresponding module in our application. Each
@@ -50,20 +50,36 @@ so on.
View the results of all our edits to ``tests`` subpackage
=========================================================
-Open ``tutorial/tests/test_views.py``, and edit it such that it appears as
-follows:
+Create ``tutorial/tests/test_views.py`` such that it appears as follows:
.. literalinclude:: src/tests/tutorial/tests/test_views.py
:linenos:
:language: python
-Open ``tutorial/tests/test_functional.py``, and edit it such that it appears as
-follows:
+Create ``tutorial/tests/test_functional.py`` such that it appears as follows:
.. literalinclude:: src/tests/tutorial/tests/test_functional.py
:linenos:
:language: python
+Create ``tutorial/tests/test_initdb.py`` such that it appears as follows:
+
+.. literalinclude:: src/tests/tutorial/tests/test_initdb.py
+ :linenos:
+ :language: python
+
+Create ``tutorial/tests/test_security.py`` such that it appears as follows:
+
+.. literalinclude:: src/tests/tutorial/tests/test_security.py
+ :linenos:
+ :language: python
+
+Create ``tutorial/tests/test_user_model.py`` such that it appears as follows:
+
+.. literalinclude:: src/tests/tutorial/tests/test_user_model.py
+ :linenos:
+ :language: python
+
.. note::
@@ -77,32 +93,27 @@ follows:
Running the tests
=================
-We can run these tests similarly to how we did in :ref:`running_tests`:
+We can run these tests similarly to how we did in :ref:`running_tests`, but first delete the SQLite database ``tutorial.sqlite``. If you do not delete the database, then you will see an integrity error when running the tests.
On UNIX:
.. code-block:: bash
+ $ rm tutorial.sqlite
$ $VENV/bin/py.test -q
On Windows:
.. code-block:: doscon
- c:\pyramidtut\tutorial> %VENV%\Scripts\py.test -q
+ c:\tutorial> del tutorial.sqlite
+ c:\tutorial> %VENV%\Scripts\py.test -q
The expected result should look like the following:
.. code-block:: text
- ......................
- 22 passed, 1 pytest-warnings in 5.81 seconds
-
-.. note:: If you use Python 3 during this tutorial, you will see deprecation
- warnings in the output, which we will choose to ignore. In making this
- tutorial run on both Python 2 and 3, the authors prioritized simplicity and
- focus for the learner over accommodating warnings. In your own app or as
- extra credit, you may choose to either drop Python 2 support or hack your
- code to work without warnings on both Python 2 and 3.
+ ................................
+ 32 passed in 9.90 seconds
.. _webtest: http://docs.pylonsproject.org/projects/webtest/en/latest/