From a6d8b494c3de85eceb33ab57a046fb6955f909fc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 16 Nov 2018 05:34:00 -0800 Subject: Remove most Python 2 mentions from docs. Exclusions: - `docs/tutorials/wiki/*` was written for Python 2 and supposedly won't run on Python 3. - `docs/api/compat.rst` because it drops some stuff and moves other bits into `pyramid.util` and should be part of another PR. - Ignored a couple of times where `env27` and `Python 2.` appear in command output, but they are inconsequential. --- docs/glossary.rst | 2 +- docs/narr/install.rst | 3 +-- docs/narr/upgrading.rst | 1 - docs/narr/webob.rst | 3 +-- docs/quick_tour.rst | 15 +++++---------- docs/quick_tutorial/index.rst | 3 +-- docs/quick_tutorial/requirements.rst | 9 ++++----- docs/tutorials/wiki2/background.rst | 2 +- docs/tutorials/wiki2/installation.rst | 10 ---------- 9 files changed, 14 insertions(+), 34 deletions(-) (limited to 'docs') diff --git a/docs/glossary.rst b/docs/glossary.rst index f42b298df..e15d28fa5 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -1071,7 +1071,7 @@ Glossary Green Unicorn Aka ``gunicorn``, a fast :term:`WSGI` server that runs on Unix under - Python 2.6+ or Python 3.1+. See https://gunicorn.org/ for detailed + Python 2.6+ or Python 3.4+. See https://gunicorn.org/ for detailed information. predicate factory diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 248b432d3..268ae5f8d 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -21,8 +21,7 @@ the following sections. .. sidebar:: Python Versions - As of this writing, :app:`Pyramid` is tested against Python 2.7, - Python 3.4, Python 3.5, Python 3.6, Python 3.7, and PyPy. + As of this writing, :app:`Pyramid` is tested against Python 3.4, Python 3.5, Python 3.6, Python 3.7, Python 3.8 (with allowed failures), and PyPy3. :app:`Pyramid` is known to run on all popular Unix-like systems such as Linux, macOS, and FreeBSD, as well as on Windows platforms. It is also known to diff --git a/docs/narr/upgrading.rst b/docs/narr/upgrading.rst index 12e146cf1..87e4647c3 100644 --- a/docs/narr/upgrading.rst +++ b/docs/narr/upgrading.rst @@ -86,7 +86,6 @@ At the time of a Pyramid version release, each supports all versions of Python through the end of their lifespans. The end-of-life for a given version of Python is when security updates are no longer released. -- `Python 2.7 Lifespan `_ 2020-01-01. - `Python 3.4 Lifespan `_ 2019-03-16 . - `Python 3.5 Lifespan `_ 2020-09-13 . - `Python 3.6 Lifespan `_ 2021-12-23. diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index 89dc6e0f1..c9a5a68e1 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -188,8 +188,7 @@ of them. Here are a couple that might be useful: Text (Unicode) ++++++++++++++ -Many of the properties of the request object will be text values (``unicode`` -under Python 2 or ``str`` under Python 3) if the request encoding/charset is +Many of the properties of the request object will be text values (``str`` type) if the request encoding/charset is provided. If it is provided, the values in ``req.POST``, ``req.GET``, ``req.params``, and ``req.cookies`` will contain text. The client *can* indicate the charset with something like ``Content-Type: diff --git a/docs/quick_tour.rst b/docs/quick_tour.rst index 1e2c71cf0..fbafead66 100644 --- a/docs/quick_tour.rst +++ b/docs/quick_tour.rst @@ -15,12 +15,9 @@ If you would prefer to cut and paste the example code in this tour you may brows Installation ============ -Once you have a standard Python environment setup, getting started with Pyramid -is a breeze. Unfortunately "standard" is not so simple in Python. For this -Quick Tour, it means `Python `_, :mod:`python:venv` (or `virtualenv for -Python 2.7 `_), -`pip `_, and `Setuptools -`_. +Once you have a standard Python environment setup, getting started with Pyramid is a breeze. +Unfortunately "standard" is not so simple in Python. +For this Quick Tour, it means `Python `_, :mod:`python:venv`, `pip `_, and `Setuptools `_. To save a little bit of typing and to be certain that we use the modules, scripts, and packages installed in our virtual environment, we'll set an @@ -52,10 +49,8 @@ For Windows: # or for a specific released version c:\\> %VENV%\\Scripts\\pip install "pyramid==\ |release|\ " -Of course Pyramid runs fine on Python 2.7+, as do the examples in this *Quick -Tour*. We're showing Python 3 for simplicity. (Pyramid had production support -for Python 3 in October 2011.) Also for simplicity, the remaining examples will -show only Unix commands. +As of version 2.0, Pyramid runs on Python 3 only. +For simplicity, the remaining examples will show only Unix commands. .. seealso:: See also: :ref:`Quick Tutorial section on Requirements `, diff --git a/docs/quick_tutorial/index.rst b/docs/quick_tutorial/index.rst index b5b7b3313..44a172067 100644 --- a/docs/quick_tutorial/index.rst +++ b/docs/quick_tutorial/index.rst @@ -4,8 +4,7 @@ Quick Tutorial for Pyramid ========================== -Pyramid is a web framework for Python 2 and 3. This tutorial gives a Python -3/2-compatible, high-level tour of the major features. +Pyramid is a web framework for Python 3. This tutorial gives a Python 3-compatible, high-level tour of the major features. This hands-on tutorial covers "a little about a lot": practical introductions to the most common facilities. Fun, fast-paced, and most certainly not aimed at diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index a74c07673..f3ffdf153 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -19,12 +19,11 @@ virtual environment.) This *Quick Tutorial* is based on: -* **Python 3.7**. Pyramid fully supports Python 3.4+ and Python 2.7+. This - tutorial uses **Python 3.7** but runs fine under Python 2.7. +* **Python 3.7**. Pyramid fully supports Python 3.4+. + This tutorial uses **Python 3.7**. -* **venv**. We believe in virtual environments. For this tutorial, we use - Python 3's built-in solution :term:`venv`. For Python 2.7, you can install - :term:`virtualenv`. +* **venv**. We believe in virtual environments. + For this tutorial, we use Python 3's built-in solution :term:`venv`. * **pip**. We use :term:`pip` for package management. diff --git a/docs/tutorials/wiki2/background.rst b/docs/tutorials/wiki2/background.rst index c14d3cb7d..09315a77d 100644 --- a/docs/tutorials/wiki2/background.rst +++ b/docs/tutorials/wiki2/background.rst @@ -17,6 +17,6 @@ variant, etc.) *or* a Windows system of any kind. .. note:: - This tutorial runs on both Python 2 and 3 without modification. + This tutorial runs on Python 3 without modification. Have fun! diff --git a/docs/tutorials/wiki2/installation.rst b/docs/tutorials/wiki2/installation.rst index 924927cd4..705979065 100644 --- a/docs/tutorials/wiki2/installation.rst +++ b/docs/tutorials/wiki2/installation.rst @@ -126,16 +126,6 @@ On Unix On Windows ^^^^^^^^^^ -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. - -Python 2.7: - -.. code-block:: doscon - - c:\Python27\Scripts\virtualenv %VENV% - -Python 3.7: - .. code-block:: doscon python -m venv %VENV% -- cgit v1.2.3 From 699bd8720dc16ef5dd3321ebbeaa6fa94505b33f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 16 Nov 2018 05:38:29 -0800 Subject: Remove virtualenv and explicit py3 mentions --- docs/narr/commandline.rst | 8 ++++---- docs/quick_tutorial/requirements.rst | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'docs') diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index b571a7d7b..962193ec3 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -1006,8 +1006,8 @@ top-level directory, your ``setup.py`` file will look something like this: requires = ['pyramid', 'pyramid_debugtoolbar'] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat - 'pytest', # includes virtualenv + 'WebTest >= 1.3.1', + 'pytest', 'pytest-cov', ] @@ -1073,8 +1073,8 @@ The result will be something like: requires = ['pyramid', 'pyramid_debugtoolbar'] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat - 'pytest', # includes virtualenv + 'WebTest >= 1.3.1', + 'pytest', 'pytest-cov', ] diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index f3ffdf153..2ed9b8b55 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -157,8 +157,7 @@ environment variable. # Windows python -m venv %VENV% -.. seealso:: See also Python 3's :mod:`venv module ` and Python - 2's `virtualenv `_ package. +.. seealso:: See also :mod:`venv module `. Update packaging tools in the virtual environment -- cgit v1.2.3 From 6de8255cb8078dbc8db63c82487cb393ce6b8552 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 05:50:31 -0800 Subject: Remove *_types per b1a257bacc1c4ac2c1401ed02c51d9c6c03685d2 - Remove Python 2 items, and remove explicit mention of Python 3. --- docs/api/compat.rst | 84 +++++++++++++---------------------------------------- 1 file changed, 20 insertions(+), 64 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index bb34f38e4..b54b4868a 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -12,145 +12,101 @@ systems which require compatibility imports. .. autofunction:: ascii_native_ - .. attribute:: binary_type - - Binary type for this platform. For Python 3, it's ``bytes``. For - Python 2, it's ``str``. - .. autofunction:: bytes_ - .. attribute:: class_types - - Sequence of class types for this platform. For Python 3, it's - ``(type,)``. For Python 2, it's ``(type, types.ClassType)``. - .. attribute:: configparser - On Python 2, the ``ConfigParser`` module, on Python 3, the - ``configparser`` module. + The ``configparser`` module. .. function:: escape(v) - On Python 2, the ``cgi.escape`` function, on Python 3, the - ``html.escape`` function. + The ``html.escape`` function. .. function:: exec_(code, globs=None, locs=None) - Exec code in a compatible way on both Python 2 and 3. + Exec code. .. attribute:: im_func - On Python 2, the string value ``im_func``, on Python 3, the string - value ``__func__``. + The string value ``__func__``. .. function:: input_(v) - On Python 2, the ``raw_input`` function, on Python 3, the - ``input`` function. - - .. attribute:: integer_types - - Sequence of integer types for this platform. For Python 3, it's - ``(int,)``. For Python 2, it's ``(int, long)``. + The ``input`` function. .. function:: is_nonstr_iter(v) - Return ``True`` if ``v`` is a non-``str`` iterable on both Python 2 and - Python 3. + Return ``True`` if ``v`` is a non-``str``. .. function:: iteritems_(d) - Return ``d.items()`` on Python 3, ``d.iteritems()`` on Python 2. + Return ``d.items()``. .. function:: itervalues_(d) - Return ``d.values()`` on Python 3, ``d.itervalues()`` on Python 2. + Return ``d.values()``. .. function:: iterkeys_(d) - Return ``d.keys()`` on Python 3, ``d.iterkeys()`` on Python 2. + Return ``d.keys()``. .. attribute:: long - Long type for this platform. For Python 3, it's ``int``. For - Python 2, it's ``long``. + Long type ``int``. .. function:: map_(v) - Return ``list(map(v))`` on Python 3, ``map(v)`` on Python 2. + Return ``list(map(v))``. .. attribute:: pickle ``cPickle`` module if it exists, ``pickle`` module otherwise. - .. attribute:: PY3 - - ``True`` if running on Python 3, ``False`` otherwise. - .. attribute:: PYPY ``True`` if running on PyPy, ``False`` otherwise. .. function:: reraise(tp, value, tb=None) - Reraise an exception in a compatible way on both Python 2 and Python 3, - e.g. ``reraise(*sys.exc_info())``. - - .. attribute:: string_types - - Sequence of string types for this platform. For Python 3, it's - ``(str,)``. For Python 2, it's ``(basestring,)``. + Reraise an exception ``reraise(*sys.exc_info())``. .. attribute:: SimpleCookie - On Python 2, the ``Cookie.SimpleCookie`` class, on Python 3, the ``http.cookies.SimpleCookie`` module. .. autofunction:: text_ - .. attribute:: text_type - - Text type for this platform. For Python 3, it's ``str``. For Python - 2, it's ``unicode``. - .. autofunction:: native_ .. attribute:: urlparse - ``urlparse`` module on Python 2, ``urllib.parse`` module on Python 3. + ``urllib.parse`` .. attribute:: url_quote - ``urllib.quote`` function on Python 2, ``urllib.parse.quote`` function - on Python 3. + ``urllib.parse.quote`` .. attribute:: url_quote_plus - ``urllib.quote_plus`` function on Python 2, ``urllib.parse.quote_plus`` - function on Python 3. + ``urllib.parse.quote_plus`` .. attribute:: url_unquote - ``urllib.unquote`` function on Python 2, ``urllib.parse.unquote`` - function on Python 3. + ``urllib.parse.unquote`` .. attribute:: url_encode - ``urllib.urlencode`` function on Python 2, ``urllib.parse.urlencode`` - function on Python 3. + ``urllib.parse.urlencode`` .. attribute:: url_open - ``urllib2.urlopen`` function on Python 2, ``urllib.request.urlopen`` - function on Python 3. + ``urllib.request.urlopen`` .. function:: url_unquote_text(v, encoding='utf-8', errors='replace') - On Python 2, return ``url_unquote(v).decode(encoding(encoding, errors))``; - on Python 3, return the result of ``urllib.parse.unquote``. + Return the result of ``urllib.parse.unquote``. .. function:: url_unquote_native(v, encoding='utf-8', errors='replace') - On Python 2, return ``native_(url_unquote_text_v, encoding, errors))``; - on Python 3, return the result of ``urllib.parse.unquote``. + Return the result of ``urllib.parse.unquote``. -- cgit v1.2.3 From e6beded7543305b47ef7bc2ba8a0d9ff76ceb5b1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 05:52:12 -0800 Subject: Remove pickle and exec aliases --- docs/api/compat.rst | 8 -------- 1 file changed, 8 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index b54b4868a..c3816f8e9 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -22,10 +22,6 @@ systems which require compatibility imports. The ``html.escape`` function. - .. function:: exec_(code, globs=None, locs=None) - - Exec code. - .. attribute:: im_func The string value ``__func__``. @@ -58,10 +54,6 @@ systems which require compatibility imports. Return ``list(map(v))``. - .. attribute:: pickle - - ``cPickle`` module if it exists, ``pickle`` module otherwise. - .. attribute:: PYPY ``True`` if running on PyPy, ``False`` otherwise. -- cgit v1.2.3 From 4863dfea9783c11e70f1604415dbc32c12d59ac6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 05:55:07 -0800 Subject: Remove iter*, configparser, input_, map_ --- docs/api/compat.rst | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index c3816f8e9..f647c3108 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -14,10 +14,6 @@ systems which require compatibility imports. .. autofunction:: bytes_ - .. attribute:: configparser - - The ``configparser`` module. - .. function:: escape(v) The ``html.escape`` function. @@ -26,34 +22,14 @@ systems which require compatibility imports. The string value ``__func__``. - .. function:: input_(v) - - The ``input`` function. - .. function:: is_nonstr_iter(v) Return ``True`` if ``v`` is a non-``str``. - .. function:: iteritems_(d) - - Return ``d.items()``. - - .. function:: itervalues_(d) - - Return ``d.values()``. - - .. function:: iterkeys_(d) - - Return ``d.keys()``. - .. attribute:: long Long type ``int``. - .. function:: map_(v) - - Return ``list(map(v))``. - .. attribute:: PYPY ``True`` if running on PyPy, ``False`` otherwise. -- cgit v1.2.3 From f84582524b625265ad379e41513770aefe7c6dcd Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 05:56:42 -0800 Subject: Remove SimpleCookie and escape shims --- docs/api/compat.rst | 8 -------- 1 file changed, 8 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index f647c3108..e25290c37 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -14,10 +14,6 @@ systems which require compatibility imports. .. autofunction:: bytes_ - .. function:: escape(v) - - The ``html.escape`` function. - .. attribute:: im_func The string value ``__func__``. @@ -38,10 +34,6 @@ systems which require compatibility imports. Reraise an exception ``reraise(*sys.exc_info())``. - .. attribute:: SimpleCookie - - ``http.cookies.SimpleCookie`` module. - .. autofunction:: text_ .. autofunction:: native_ -- cgit v1.2.3 From 5f59fb7db454e47e9845d74ec2b04e581beca574 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 05:57:06 -0800 Subject: Remove reraise --- docs/api/compat.rst | 4 ---- 1 file changed, 4 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index e25290c37..6f94ea2d4 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -30,10 +30,6 @@ systems which require compatibility imports. ``True`` if running on PyPy, ``False`` otherwise. - .. function:: reraise(tp, value, tb=None) - - Reraise an exception ``reraise(*sys.exc_info())``. - .. autofunction:: text_ .. autofunction:: native_ -- cgit v1.2.3 From 087dc33696b81235468e80b93ee7eee510d40d8e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 05:57:30 -0800 Subject: Remove is_nonstr_iter --- docs/api/compat.rst | 4 ---- 1 file changed, 4 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index 6f94ea2d4..25b81addc 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -18,10 +18,6 @@ systems which require compatibility imports. The string value ``__func__``. - .. function:: is_nonstr_iter(v) - - Return ``True`` if ``v`` is a non-``str``. - .. attribute:: long Long type ``int``. -- cgit v1.2.3 From c2fabed4dceb33c655a498583841769aa78bebbf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 06:00:19 -0800 Subject: Remove urllib.parse shims --- docs/api/compat.rst | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index 25b81addc..d8a4d0cbb 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -29,36 +29,3 @@ systems which require compatibility imports. .. autofunction:: text_ .. autofunction:: native_ - - .. attribute:: urlparse - - ``urllib.parse`` - - .. attribute:: url_quote - - ``urllib.parse.quote`` - - .. attribute:: url_quote_plus - - ``urllib.parse.quote_plus`` - - .. attribute:: url_unquote - - ``urllib.parse.unquote`` - - .. attribute:: url_encode - - ``urllib.parse.urlencode`` - - .. attribute:: url_open - - ``urllib.request.urlopen`` - - .. function:: url_unquote_text(v, encoding='utf-8', errors='replace') - - Return the result of ``urllib.parse.unquote``. - - .. function:: url_unquote_native(v, encoding='utf-8', errors='replace') - - Return the result of ``urllib.parse.unquote``. - -- cgit v1.2.3 From 8b7705f27a6ecc47742ec743de0ced7e8a15eb17 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 06:05:42 -0800 Subject: Remove native_, rename ascii_native_ to ascii_ --- docs/api/compat.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index d8a4d0cbb..f05bdd51b 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -10,7 +10,7 @@ systems which require compatibility imports. .. automodule:: pyramid.compat - .. autofunction:: ascii_native_ + .. autofunction:: ascii_ .. autofunction:: bytes_ @@ -27,5 +27,3 @@ systems which require compatibility imports. ``True`` if running on PyPy, ``False`` otherwise. .. autofunction:: text_ - - .. autofunction:: native_ -- cgit v1.2.3 From 1662edc38e145fa820544fb3aad91ab86e3185da Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 06:07:44 -0800 Subject: Remove long type (should have been removed with other type aliases) --- docs/api/compat.rst | 4 ---- 1 file changed, 4 deletions(-) (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst index f05bdd51b..d1552e644 100644 --- a/docs/api/compat.rst +++ b/docs/api/compat.rst @@ -18,10 +18,6 @@ systems which require compatibility imports. The string value ``__func__``. - .. attribute:: long - - Long type ``int``. - .. attribute:: PYPY ``True`` if running on PyPy, ``False`` otherwise. -- cgit v1.2.3 From 5ec822694f6d2e14513b3a3b03da2315ff996ce7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 06:18:26 -0800 Subject: Update Python source files in docs to use `from html import escape`, now that we ripped it out from `pyramid.compat`. --- docs/quick_tour/views/views.py | 4 ++-- docs/tutorials/wiki2/src/authentication/tutorial/views/default.py | 2 +- docs/tutorials/wiki2/src/authorization/tutorial/views/default.py | 2 +- docs/tutorials/wiki2/src/tests/tutorial/views/default.py | 2 +- docs/tutorials/wiki2/src/views/tutorial/views/default.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'docs') diff --git a/docs/quick_tour/views/views.py b/docs/quick_tour/views/views.py index 95a2b60ca..ffbe1d893 100644 --- a/docs/quick_tour/views/views.py +++ b/docs/quick_tour/views/views.py @@ -1,4 +1,4 @@ -from pyramid.compat import escape +from html import escape from pyramid.httpexceptions import HTTPFound from pyramid.response import Response @@ -16,7 +16,7 @@ def home_view(request): def hello_view(request): name = request.params.get('name', 'No Name') body = '

Hi %s, this redirects

' - # pyramid.compat.escape to prevent Cross-Site Scripting (XSS) [CWE 79] + # Python html.escape to prevent Cross-Site Scripting (XSS) [CWE 79] return Response(body % escape(name)) diff --git a/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py b/docs/tutorials/wiki2/src/authentication/tutorial/views/default.py index 8ed90d5b2..2f0210255 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 @@ -from pyramid.compat import escape +from html import escape import re from docutils.core import publish_parts diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py b/docs/tutorials/wiki2/src/authorization/tutorial/views/default.py index ad271fb46..ad8491b7b 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 @@ -from pyramid.compat import escape +from html import escape import re from docutils.core import publish_parts diff --git a/docs/tutorials/wiki2/src/tests/tutorial/views/default.py b/docs/tutorials/wiki2/src/tests/tutorial/views/default.py index ad271fb46..ad8491b7b 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 @@ -from pyramid.compat import escape +from html import escape import re from docutils.core import publish_parts diff --git a/docs/tutorials/wiki2/src/views/tutorial/views/default.py b/docs/tutorials/wiki2/src/views/tutorial/views/default.py index a866af1de..5e28b64fd 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 @@ -from pyramid.compat import escape +from html import escape import re from docutils.core import publish_parts -- cgit v1.2.3 From c5e93f9f87c6d98be8db51fc3711ea83c881899a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 06:30:45 -0800 Subject: Remove mention of py3 compat --- docs/quick_tour/logging/setup.py | 2 +- docs/quick_tour/package/setup.py | 2 +- docs/quick_tour/sessions/setup.py | 2 +- docs/quick_tour/sqla_demo/setup.py | 2 +- docs/quick_tutorial/cookiecutters/setup.py | 2 +- docs/tutorials/wiki/src/authorization/setup.py | 2 +- docs/tutorials/wiki/src/basiclayout/setup.py | 2 +- docs/tutorials/wiki/src/installation/setup.py | 2 +- docs/tutorials/wiki/src/models/setup.py | 2 +- docs/tutorials/wiki/src/tests/setup.py | 2 +- docs/tutorials/wiki/src/views/setup.py | 2 +- docs/tutorials/wiki2/src/authentication/setup.py | 2 +- docs/tutorials/wiki2/src/authorization/setup.py | 2 +- docs/tutorials/wiki2/src/basiclayout/setup.py | 2 +- docs/tutorials/wiki2/src/installation/setup.py | 2 +- docs/tutorials/wiki2/src/models/setup.py | 2 +- docs/tutorials/wiki2/src/tests/setup.py | 2 +- docs/tutorials/wiki2/src/views/setup.py | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) (limited to 'docs') diff --git a/docs/quick_tour/logging/setup.py b/docs/quick_tour/logging/setup.py index 27b025384..47f21a9dc 100644 --- a/docs/quick_tour/logging/setup.py +++ b/docs/quick_tour/logging/setup.py @@ -17,7 +17,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/quick_tour/package/setup.py b/docs/quick_tour/package/setup.py index 27b025384..47f21a9dc 100644 --- a/docs/quick_tour/package/setup.py +++ b/docs/quick_tour/package/setup.py @@ -17,7 +17,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/quick_tour/sessions/setup.py b/docs/quick_tour/sessions/setup.py index 27b025384..47f21a9dc 100644 --- a/docs/quick_tour/sessions/setup.py +++ b/docs/quick_tour/sessions/setup.py @@ -17,7 +17,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/quick_tour/sqla_demo/setup.py b/docs/quick_tour/sqla_demo/setup.py index 76cd518ca..71ebfab3a 100644 --- a/docs/quick_tour/sqla_demo/setup.py +++ b/docs/quick_tour/sqla_demo/setup.py @@ -23,7 +23,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/quick_tutorial/cookiecutters/setup.py b/docs/quick_tutorial/cookiecutters/setup.py index 9482e7c32..404e7d228 100644 --- a/docs/quick_tutorial/cookiecutters/setup.py +++ b/docs/quick_tutorial/cookiecutters/setup.py @@ -17,7 +17,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/authorization/setup.py b/docs/tutorials/wiki/src/authorization/setup.py index 7011387f6..4a1224664 100644 --- a/docs/tutorials/wiki/src/authorization/setup.py +++ b/docs/tutorials/wiki/src/authorization/setup.py @@ -24,7 +24,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/basiclayout/setup.py b/docs/tutorials/wiki/src/basiclayout/setup.py index e05e279e2..e266a546b 100644 --- a/docs/tutorials/wiki/src/basiclayout/setup.py +++ b/docs/tutorials/wiki/src/basiclayout/setup.py @@ -22,7 +22,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/installation/setup.py b/docs/tutorials/wiki/src/installation/setup.py index e05e279e2..e266a546b 100644 --- a/docs/tutorials/wiki/src/installation/setup.py +++ b/docs/tutorials/wiki/src/installation/setup.py @@ -22,7 +22,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/models/setup.py b/docs/tutorials/wiki/src/models/setup.py index e05e279e2..e266a546b 100644 --- a/docs/tutorials/wiki/src/models/setup.py +++ b/docs/tutorials/wiki/src/models/setup.py @@ -22,7 +22,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/tests/setup.py b/docs/tutorials/wiki/src/tests/setup.py index 7011387f6..4a1224664 100644 --- a/docs/tutorials/wiki/src/tests/setup.py +++ b/docs/tutorials/wiki/src/tests/setup.py @@ -24,7 +24,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/views/setup.py b/docs/tutorials/wiki/src/views/setup.py index a11ae6c8f..2d120224f 100644 --- a/docs/tutorials/wiki/src/views/setup.py +++ b/docs/tutorials/wiki/src/views/setup.py @@ -23,7 +23,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/authentication/setup.py b/docs/tutorials/wiki2/src/authentication/setup.py index e2a30c0e7..18dc1b617 100644 --- a/docs/tutorials/wiki2/src/authentication/setup.py +++ b/docs/tutorials/wiki2/src/authentication/setup.py @@ -25,7 +25,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/authorization/setup.py b/docs/tutorials/wiki2/src/authorization/setup.py index e2a30c0e7..18dc1b617 100644 --- a/docs/tutorials/wiki2/src/authorization/setup.py +++ b/docs/tutorials/wiki2/src/authorization/setup.py @@ -25,7 +25,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/basiclayout/setup.py b/docs/tutorials/wiki2/src/basiclayout/setup.py index 11725dd51..135e51ce8 100644 --- a/docs/tutorials/wiki2/src/basiclayout/setup.py +++ b/docs/tutorials/wiki2/src/basiclayout/setup.py @@ -23,7 +23,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/installation/setup.py b/docs/tutorials/wiki2/src/installation/setup.py index 11725dd51..135e51ce8 100644 --- a/docs/tutorials/wiki2/src/installation/setup.py +++ b/docs/tutorials/wiki2/src/installation/setup.py @@ -23,7 +23,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/models/setup.py b/docs/tutorials/wiki2/src/models/setup.py index 09e3126ea..556e1837d 100644 --- a/docs/tutorials/wiki2/src/models/setup.py +++ b/docs/tutorials/wiki2/src/models/setup.py @@ -24,7 +24,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index e2a30c0e7..18dc1b617 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -25,7 +25,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/views/setup.py b/docs/tutorials/wiki2/src/views/setup.py index e2a30c0e7..18dc1b617 100644 --- a/docs/tutorials/wiki2/src/views/setup.py +++ b/docs/tutorials/wiki2/src/views/setup.py @@ -25,7 +25,7 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat + 'WebTest >= 1.3.1', 'pytest>=3.7.4', 'pytest-cov', ] -- cgit v1.2.3 From ae9453732bcbd4a9812e6cd9232bba6d469a9953 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 17 Nov 2018 15:49:12 -0800 Subject: Remove explicit mention of Python 3 --- docs/quick_tutorial/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/quick_tutorial/index.rst b/docs/quick_tutorial/index.rst index 44a172067..d727502e9 100644 --- a/docs/quick_tutorial/index.rst +++ b/docs/quick_tutorial/index.rst @@ -4,7 +4,7 @@ Quick Tutorial for Pyramid ========================== -Pyramid is a web framework for Python 3. This tutorial gives a Python 3-compatible, high-level tour of the major features. +This tutorial gives a high-level tour of the major features. This hands-on tutorial covers "a little about a lot": practical introductions to the most common facilities. Fun, fast-paced, and most certainly not aimed at -- cgit v1.2.3 From 54fba396ce913c9731f920447d680f1480d8517e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 18 Nov 2018 05:15:42 -0800 Subject: Unpin webtest and pytest --- docs/quick_tour/logging/setup.py | 4 ++-- docs/quick_tour/package/setup.py | 4 ++-- docs/quick_tour/sessions/setup.py | 4 ++-- docs/quick_tour/sqla_demo/setup.py | 4 ++-- docs/quick_tutorial/cookiecutters/setup.py | 4 ++-- docs/tutorials/wiki/src/authorization/setup.py | 4 ++-- docs/tutorials/wiki/src/basiclayout/setup.py | 4 ++-- docs/tutorials/wiki/src/installation/setup.py | 4 ++-- docs/tutorials/wiki/src/models/setup.py | 4 ++-- docs/tutorials/wiki/src/tests/setup.py | 4 ++-- docs/tutorials/wiki/src/views/setup.py | 4 ++-- docs/tutorials/wiki2/src/authentication/setup.py | 4 ++-- docs/tutorials/wiki2/src/authorization/setup.py | 4 ++-- docs/tutorials/wiki2/src/basiclayout/setup.py | 4 ++-- docs/tutorials/wiki2/src/installation/setup.py | 4 ++-- docs/tutorials/wiki2/src/models/setup.py | 4 ++-- docs/tutorials/wiki2/src/tests/setup.py | 4 ++-- docs/tutorials/wiki2/src/views/setup.py | 4 ++-- 18 files changed, 36 insertions(+), 36 deletions(-) (limited to 'docs') diff --git a/docs/quick_tour/logging/setup.py b/docs/quick_tour/logging/setup.py index 47f21a9dc..e9c15db04 100644 --- a/docs/quick_tour/logging/setup.py +++ b/docs/quick_tour/logging/setup.py @@ -17,8 +17,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/quick_tour/package/setup.py b/docs/quick_tour/package/setup.py index 47f21a9dc..e9c15db04 100644 --- a/docs/quick_tour/package/setup.py +++ b/docs/quick_tour/package/setup.py @@ -17,8 +17,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/quick_tour/sessions/setup.py b/docs/quick_tour/sessions/setup.py index 47f21a9dc..e9c15db04 100644 --- a/docs/quick_tour/sessions/setup.py +++ b/docs/quick_tour/sessions/setup.py @@ -17,8 +17,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/quick_tour/sqla_demo/setup.py b/docs/quick_tour/sqla_demo/setup.py index 71ebfab3a..28a8e0815 100644 --- a/docs/quick_tour/sqla_demo/setup.py +++ b/docs/quick_tour/sqla_demo/setup.py @@ -23,8 +23,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/quick_tutorial/cookiecutters/setup.py b/docs/quick_tutorial/cookiecutters/setup.py index 404e7d228..d5d3d018b 100644 --- a/docs/quick_tutorial/cookiecutters/setup.py +++ b/docs/quick_tutorial/cookiecutters/setup.py @@ -17,8 +17,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/authorization/setup.py b/docs/tutorials/wiki/src/authorization/setup.py index 4a1224664..7b405745e 100644 --- a/docs/tutorials/wiki/src/authorization/setup.py +++ b/docs/tutorials/wiki/src/authorization/setup.py @@ -24,8 +24,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/basiclayout/setup.py b/docs/tutorials/wiki/src/basiclayout/setup.py index e266a546b..a4f143d24 100644 --- a/docs/tutorials/wiki/src/basiclayout/setup.py +++ b/docs/tutorials/wiki/src/basiclayout/setup.py @@ -22,8 +22,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/installation/setup.py b/docs/tutorials/wiki/src/installation/setup.py index e266a546b..a4f143d24 100644 --- a/docs/tutorials/wiki/src/installation/setup.py +++ b/docs/tutorials/wiki/src/installation/setup.py @@ -22,8 +22,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/models/setup.py b/docs/tutorials/wiki/src/models/setup.py index e266a546b..a4f143d24 100644 --- a/docs/tutorials/wiki/src/models/setup.py +++ b/docs/tutorials/wiki/src/models/setup.py @@ -22,8 +22,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/tests/setup.py b/docs/tutorials/wiki/src/tests/setup.py index 4a1224664..7b405745e 100644 --- a/docs/tutorials/wiki/src/tests/setup.py +++ b/docs/tutorials/wiki/src/tests/setup.py @@ -24,8 +24,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki/src/views/setup.py b/docs/tutorials/wiki/src/views/setup.py index 2d120224f..3c19db7b9 100644 --- a/docs/tutorials/wiki/src/views/setup.py +++ b/docs/tutorials/wiki/src/views/setup.py @@ -23,8 +23,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/authentication/setup.py b/docs/tutorials/wiki2/src/authentication/setup.py index 18dc1b617..f71998afc 100644 --- a/docs/tutorials/wiki2/src/authentication/setup.py +++ b/docs/tutorials/wiki2/src/authentication/setup.py @@ -25,8 +25,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/authorization/setup.py b/docs/tutorials/wiki2/src/authorization/setup.py index 18dc1b617..f71998afc 100644 --- a/docs/tutorials/wiki2/src/authorization/setup.py +++ b/docs/tutorials/wiki2/src/authorization/setup.py @@ -25,8 +25,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/basiclayout/setup.py b/docs/tutorials/wiki2/src/basiclayout/setup.py index 135e51ce8..746012a74 100644 --- a/docs/tutorials/wiki2/src/basiclayout/setup.py +++ b/docs/tutorials/wiki2/src/basiclayout/setup.py @@ -23,8 +23,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/installation/setup.py b/docs/tutorials/wiki2/src/installation/setup.py index 135e51ce8..746012a74 100644 --- a/docs/tutorials/wiki2/src/installation/setup.py +++ b/docs/tutorials/wiki2/src/installation/setup.py @@ -23,8 +23,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/models/setup.py b/docs/tutorials/wiki2/src/models/setup.py index 556e1837d..b9dc9d93f 100644 --- a/docs/tutorials/wiki2/src/models/setup.py +++ b/docs/tutorials/wiki2/src/models/setup.py @@ -24,8 +24,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/tests/setup.py b/docs/tutorials/wiki2/src/tests/setup.py index 18dc1b617..f71998afc 100644 --- a/docs/tutorials/wiki2/src/tests/setup.py +++ b/docs/tutorials/wiki2/src/tests/setup.py @@ -25,8 +25,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/tutorials/wiki2/src/views/setup.py b/docs/tutorials/wiki2/src/views/setup.py index 18dc1b617..f71998afc 100644 --- a/docs/tutorials/wiki2/src/views/setup.py +++ b/docs/tutorials/wiki2/src/views/setup.py @@ -25,8 +25,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] -- cgit v1.2.3 From fe1740acba6a9bfe5ac3aed41a9a264a9fd30814 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 18 Nov 2018 05:22:54 -0800 Subject: Remove `docs/api/compat.rst`. The remaining items were moved into `pyramid.util`, but we don't want to document anything in that module. --- docs/api/compat.rst | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 docs/api/compat.rst (limited to 'docs') diff --git a/docs/api/compat.rst b/docs/api/compat.rst deleted file mode 100644 index d1552e644..000000000 --- a/docs/api/compat.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. _compat_module: - -:mod:`pyramid.compat` ----------------------- - -The ``pyramid.compat`` module provides platform and version compatibility for -Pyramid and its add-ons across Python platform and version differences. APIs -will be removed from this module over time as Pyramid ceases to support -systems which require compatibility imports. - -.. automodule:: pyramid.compat - - .. autofunction:: ascii_ - - .. autofunction:: bytes_ - - .. attribute:: im_func - - The string value ``__func__``. - - .. attribute:: PYPY - - ``True`` if running on PyPy, ``False`` otherwise. - - .. autofunction:: text_ -- cgit v1.2.3 From f77957109be35d7b93014d5623fae7e670797213 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 19 Nov 2018 02:35:36 -0800 Subject: unpin webtest (missed in first pass) --- docs/narr/commandline.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index 962193ec3..21b2a0839 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -1006,7 +1006,7 @@ top-level directory, your ``setup.py`` file will look something like this: requires = ['pyramid', 'pyramid_debugtoolbar'] tests_require = [ - 'WebTest >= 1.3.1', + 'WebTest', 'pytest', 'pytest-cov', ] @@ -1073,7 +1073,7 @@ The result will be something like: requires = ['pyramid', 'pyramid_debugtoolbar'] tests_require = [ - 'WebTest >= 1.3.1', + 'WebTest', 'pytest', 'pytest-cov', ] -- cgit v1.2.3 From cfaedc5e247af279059ab93fea4c9d7a27ddcf8a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 19 Nov 2018 02:46:18 -0800 Subject: Standardize casing of URL when it is an acronym --- docs/glossary.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/glossary.rst b/docs/glossary.rst index e15d28fa5..2d51bf795 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -165,7 +165,7 @@ Glossary An object representing a node in the :term:`resource tree` of an application. If :term:`traversal` is used, a resource is an element in the resource tree traversed by the system. When traversal is used, a - resource becomes the :term:`context` of a :term:`view`. If :term:`url + resource becomes the :term:`context` of a :term:`view`. If :term:`URL dispatch` is used, a single resource is generated for each request and is used as the context resource of a view. @@ -405,13 +405,13 @@ Glossary the Routes syntax (which was inspired by Ruby On Rails pattern syntax). route - A single pattern matched by the :term:`url dispatch` subsystem, + A single pattern matched by the :term:`URL dispatch` subsystem, which generally resolves to a :term:`root factory` (and then ultimately a :term:`view`). .. seealso:: - See also :term:`url dispatch`. + See also :term:`URL dispatch`. route configuration Route configuration is the act of associating request parameters with a @@ -912,7 +912,7 @@ Glossary :meth:`pyramid.config.Configurator.add_route` and :meth:`pyramid.config.Configurator.add_view` to make it more convenient to register a collection of views as a single class when using - :term:`url dispatch`. View handlers ship as part of the + :term:`URL dispatch`. View handlers ship as part of the :term:`pyramid_handlers` add-on package. Deployment settings -- cgit v1.2.3 From 8c943501e87bed7836bb9ec1b216a561cc3f6be6 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 19 Nov 2018 21:35:37 -0600 Subject: rip out moar unicode prefixes --- docs/glossary.rst | 14 ++++----- docs/narr/hooks.rst | 8 ++--- docs/narr/i18n.rst | 11 ++++--- docs/narr/myproject/setup.py | 4 +-- docs/narr/renderers.rst | 5 ++-- docs/narr/traversal.rst | 6 ++-- docs/narr/urldispatch.rst | 30 +++++++++---------- docs/narr/views.rst | 39 ++++++------------------- docs/narr/webob.rst | 20 +++++-------- docs/tutorials/wiki/src/tests/tutorial/tests.py | 4 +-- 10 files changed, 57 insertions(+), 84 deletions(-) (limited to 'docs') diff --git a/docs/glossary.rst b/docs/glossary.rst index 2d51bf795..97806d958 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -232,7 +232,7 @@ Glossary object *location-aware*. permission - A string or Unicode object that represents an action being taken against + A string that represents an action being taken against a :term:`context` resource. A permission is associated with a view name and a resource type by the developer. Resources are decorated with security declarations (e.g. an :term:`ACL`), which reference these @@ -289,7 +289,7 @@ Glossary :term:`authorization policy`. principal - A *principal* is a string or Unicode object representing an entity, + A *principal* is a string representing an entity, typically a user or group. Principals are provided by an :term:`authentication policy`. For example, if a user has the :term:`userid` `bob`, and is a member of two groups named `group foo` and @@ -298,7 +298,7 @@ Glossary foo` and `group bar`. userid - A *userid* is a string or Unicode object used to identify and authenticate + A *userid* is a string used to identify and authenticate a real-world user or client. A userid is supplied to an :term:`authentication policy` in order to discover the user's :term:`principals `. In the authentication policies which @@ -523,8 +523,8 @@ Glossary from the :term:`physical root`. For example, the physical path of the ``abc`` subobject of the physical root object is ``/abc``. Physical paths can also be specified as tuples where the first element is the empty - string (representing the root), and every other element is a Unicode - object, e.g. ``('', 'abc')``. Physical paths are also sometimes called + string (representing the root), and every other element is a string, + e.g. ``('', 'abc')``. Physical paths are also sometimes called "traversal paths". lineage @@ -755,7 +755,7 @@ Glossary Translation String An instance of :class:`pyramid.i18n.TranslationString`, which - is a class that behaves like a Unicode string, but has several + is a class that behaves like a string, but has several extra attributes such as ``domain``, ``msgid``, and ``mapping`` for use during translation. Translation strings are usually created by hand within software, but are sometimes created on the @@ -779,7 +779,7 @@ Glossary Translator A callable which receives a :term:`translation string` and returns a - translated Unicode object for the purposes of internationalization. A + translated string for the purposes of internationalization. A :term:`localizer` supplies a translator to a :app:`Pyramid` application accessible via its :class:`~pyramid.i18n.Localizer.translate` method. diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 9f405c336..5e67a81c7 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -659,15 +659,15 @@ that implements the following interface: ``virtual_root``, and ``virtual_root_path``. These values are typically the result of a resource tree traversal. ``root`` is the physical root object, ``context`` will be a resource - object, ``view_name`` will be the view name used (a Unicode - name), ``subpath`` will be a sequence of Unicode names that + object, ``view_name`` will be the view name used (a string), + ``subpath`` will be a sequence of strings that followed the view name but were not traversed, ``traversed`` - will be a sequence of Unicode names that were traversed + will be a sequence of strings that were traversed (including the virtual root path, if any) ``virtual_root`` will be a resource object representing the virtual root (or the physical root if traversal was not performed), and ``virtual_root_path`` will be a sequence representing the - virtual root path (a sequence of Unicode names) or None if + virtual root path (a sequence of strings) or None if traversal was not performed. Extra keys for special purpose functionality can be added as diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst index 9b838c7f4..3a4f5af5b 100644 --- a/docs/narr/i18n.rst +++ b/docs/narr/i18n.rst @@ -33,7 +33,7 @@ While you write your software, you can insert specialized markup into your Python code that makes it possible for the system to translate text values into the languages used by your application's users. This markup creates a :term:`translation string`. A translation string is an object that behaves -mostly like a normal Unicode object, except that it also carries around extra +mostly like a normal Unicode string, except that it also carries around extra information related to its job as part of the :app:`Pyramid` translation machinery. @@ -49,7 +49,7 @@ The most primitive way to create a translation string is to use the from pyramid.i18n import TranslationString ts = TranslationString('Add') -This creates a Unicode-like object that is a TranslationString. +This creates a ``str``-like object that is a TranslationString. .. note:: @@ -61,9 +61,8 @@ This creates a Unicode-like object that is a TranslationString. The first argument to :class:`~pyramid.i18n.TranslationString` is the ``msgid``; it is required. It represents the key into the translation mappings -provided by a particular localization. The ``msgid`` argument must be a Unicode -object or an ASCII string. The msgid may optionally contain *replacement -markers*. For instance: +provided by a particular localization. The ``msgid`` argument must be a string. +The msgid may optionally contain *replacement markers*. For instance: .. code-block:: python :linenos: @@ -429,7 +428,7 @@ Performing a Translation A :term:`localizer` has a ``translate`` method which accepts either a :term:`translation string` or a Unicode string and which returns a Unicode -object representing the translation. Generating a translation in a view +string representing the translation. Generating a translation in a view component of an application might look like so: .. code-block:: python diff --git a/docs/narr/myproject/setup.py b/docs/narr/myproject/setup.py index cf626880f..1ee272270 100644 --- a/docs/narr/myproject/setup.py +++ b/docs/narr/myproject/setup.py @@ -17,8 +17,8 @@ requires = [ ] tests_require = [ - 'WebTest >= 1.3.1', # py3 compat - 'pytest>=3.7.4', + 'WebTest', + 'pytest', 'pytest-cov', ] diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst index 493f808d5..6b4982e4b 100644 --- a/docs/narr/renderers.rst +++ b/docs/narr/renderers.rst @@ -145,8 +145,7 @@ used in the ``renderer`` attribute of view configurations. The ``string`` renderer renders a view callable result to a string. If a view callable returns a non-Response object, and the ``string`` renderer is associated in that view's configuration, the result will be to run the object -through the Python ``str`` function to generate a string. Note that if a -Unicode object is returned by the view callable, it is not ``str()``-ified. +through the Python ``str`` function to generate a string. Here's an example of a view that returns a dictionary. If the ``string`` renderer is specified in the configuration for this view, the view will render @@ -496,7 +495,7 @@ interface. A typical class that follows this setup is as follows: def __call__(self, value, system): """ Call the renderer implementation with the value and the system value passed in as arguments and return - the result (a string or unicode object). The value is + the result (a bytes or string object). The value is the return value of a view. The system value is a dictionary containing available system values (e.g., view, context, and request). """ diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst index 9b91e21ba..769d0984c 100644 --- a/docs/narr/traversal.rst +++ b/docs/narr/traversal.rst @@ -237,7 +237,7 @@ uses this algorithm to find a :term:`context` resource and a :term:`view name`. The traversal algorithm by default attempts to first URL-unquote and then Unicode-decode each path segment derived from ``PATH_INFO`` from its - natural byte string (``str`` type) representation. URL unquoting is + natural string representation. URL unquoting is performed using the Python standard library ``urllib.unquote`` function. Conversion from a URL-decoded string into Unicode is attempted using the UTF-8 encoding. If any URL-unquoted path segment in ``PATH_INFO`` is not @@ -246,10 +246,10 @@ uses this algorithm to find a :term:`context` resource and a :term:`view name`. to the ``__getitem__`` of any resource during traversal. Thus a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the - traversal sequence ``[u'a', u'b', u'c']``. + traversal sequence ``['a', 'b', 'c']``. #. :term:`Traversal` begins at the root resource returned by the root factory. - For the traversal sequence ``[u'a', u'b', u'c']``, the root resource's + For the traversal sequence ``['a', 'b', 'c']``, the root resource's ``__getitem__`` is called with the name ``'a'``. Traversal continues through the sequence. In our example, if the root resource's ``__getitem__`` called with the name ``a`` returns a resource (a.k.a. diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 3b737b46d..b9b42a9bd 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -165,8 +165,8 @@ The above pattern will match these URLs, generating the following matchdicts: .. code-block:: text - foo/1/2 -> {'baz':u'1', 'bar':u'2'} - foo/abc/def -> {'baz':u'abc', 'bar':u'def'} + foo/1/2 -> {'baz':'1', 'bar':'2'} + foo/abc/def -> {'baz':'abc', 'bar':'def'} It will not match the following patterns however: @@ -184,7 +184,7 @@ instance, if this route pattern was used: foo/{name}.html The literal path ``/foo/biz.html`` will match the above route pattern, and the -match result will be ``{'name':u'biz'}``. However, the literal path +match result will be ``{'name':'biz'}``. However, the literal path ``/foo/biz`` will not match, because it does not contain a literal ``.html`` at the end of the segment represented by ``{name}.html`` (it only contains ``biz``, not ``biz.html``). @@ -242,7 +242,7 @@ The matchdict will look like so (the value is URL-decoded / UTF-8 decoded): .. code-block:: text - {'bar':u'La Pe\xf1a'} + {'bar': 'La Pe\xf1a'} Literal strings in the path segment should represent the *decoded* value of the ``PATH_INFO`` provided to Pyramid. You don't want to use a URL-encoded value @@ -303,10 +303,10 @@ The above pattern will match these URLs, generating the following matchdicts: .. code-block:: text foo/1/2/ -> - {'baz':u'1', 'bar':u'2', 'fizzle':()} + {'baz':'1', 'bar':'2', 'fizzle':()} foo/abc/def/a/b/c -> - {'baz':u'abc', 'bar':u'def', 'fizzle':(u'a', u'b', u'c')} + {'baz':'abc', 'bar':'def', 'fizzle':('a', 'b', 'c')} Note that when a ``*stararg`` remainder match is matched, the value put into the matchdict is turned into a tuple of path segments representing the @@ -327,7 +327,7 @@ Will generate the following matchdict: .. code-block:: text - {'fizzle':(u'La Pe\xf1a', u'a', u'b', u'c')} + {'fizzle':('La Pe\xf1a', 'a', 'b', 'c')} By default, the ``*stararg`` will parse the remainder sections into a tuple split by segment. Changing the regular expression used to match a marker can @@ -341,8 +341,8 @@ The above pattern will match these URLs, generating the following matchdicts: .. code-block:: text - foo/1/2/ -> {'baz':u'1', 'bar':u'2', 'fizzle':u''} - foo/abc/def/a/b/c -> {'baz':u'abc', 'bar':u'def', 'fizzle': u'a/b/c'} + foo/1/2/ -> {'baz':'1', 'bar':'2', 'fizzle':''} + foo/abc/def/a/b/c -> {'baz':'abc', 'bar':'def', 'fizzle': 'a/b/c'} This occurs because the default regular expression for a marker is ``[^/]+`` which will match everything up to the first ``/``, while ``{fizzle:.*}`` will @@ -562,12 +562,12 @@ Here is an example of a corresponding ``mypackage.views`` module: @view_config(route_name='user') def user_view(request): user = request.matchdict['user'] - return Response(u'The user is {}.'.format(user)) + return Response('The user is {}.'.format(user)) @view_config(route_name='tag') def tag_view(request): tag = request.matchdict['tag'] - return Response(u'The tag is {}.'.format(tag)) + return Response('The tag is {}.'.format(tag)) The above configuration will allow :app:`Pyramid` to service URLs in these forms: @@ -714,13 +714,13 @@ Therefore, if you've added a route like so: .. code-block:: python - config.add_route('la', u'/La Peña/{city}') + config.add_route('la', '/La Peña/{city}') And you later generate a URL using ``route_path`` or ``route_url`` like so: .. code-block:: python - url = request.route_path('la', city=u'Québec') + url = request.route_path('la', city='Québec') You will wind up with the path encoded to UTF-8 and URL-quoted like so: @@ -739,7 +739,7 @@ And you later generate a URL using ``route_path`` or ``route_url`` using a .. code-block:: python - url = request.route_path('abc', foo=u'Québec/biz') + url = request.route_path('abc', foo='Québec/biz') The value you pass will be URL-quoted except for embedded slashes in the result: @@ -752,7 +752,7 @@ You can get a similar result by passing a tuple composed of path elements: .. code-block:: python - url = request.route_path('abc', foo=(u'Québec', u'biz')) + url = request.route_path('abc', foo=('Québec', 'biz')) Each value in the tuple will be URL-quoted and joined by slashes in this case: diff --git a/docs/narr/views.rst b/docs/narr/views.rst index a53063f78..40717c37a 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -442,10 +442,7 @@ browser client, and its ``action`` points at some :app:`Pyramid` view code: :linenos: - - - -
+
@@ -457,8 +454,8 @@ browser client, and its ``action`` points at some :app:`Pyramid` view code: The ``myview`` view code in the :app:`Pyramid` application *must* expect that -the values returned by ``request.params`` will be of type ``unicode``, as -opposed to type ``str``. The following will work to accept a form post from the +the values returned by ``request.params`` will be of type ``str``, as opposed +to type ``bytes``. The following will work to accept a form post from the above form: .. code-block:: python @@ -468,24 +465,12 @@ above form: firstname = request.params['firstname'] lastname = request.params['lastname'] -But the following ``myview`` view code *may not* work, as it tries to decode -already-decoded (``unicode``) values obtained from ``request.params``: - -.. code-block:: python - :linenos: - - def myview(request): - # the .decode('utf-8') will break below if there are any high-order - # characters in the firstname or lastname - firstname = request.params['firstname'].decode('utf-8') - lastname = request.params['lastname'].decode('utf-8') - For implicit decoding to work reliably, you should ensure that every form you render that posts to a :app:`Pyramid` view explicitly defines a charset encoding of UTF-8. This can be done via a response that has a ``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form above, -with a ``meta http-equiv`` tag that implies that the charset is UTF-8 within -the HTML ``head`` of the page containing the form. This must be done +with a ``accept-charset`` tag that implies that informs the browser that the +server expects the form content to be encoded using UTF-8. This must be done explicitly because all known browser clients assume that they should encode form data in the same character set implied by the ``Content-Type`` value of the response containing the form when subsequently submitting that form. There @@ -499,21 +484,15 @@ when it can't decode some high-order character encoded in another character set within form data, e.g., when ``request.params['somename']`` is accessed. If you are using the :class:`~pyramid.response.Response` class to generate a -response, or if you use the ``render_template_*`` templating APIs, the UTF-8 -``charset`` is set automatically as the default via the ``Content-Type`` -header. If you return a ``Content-Type`` header without an explicit -``charset``, a request will add a ``;charset=utf-8`` trailer to the +response, or if you use the ``pyramid.renderers.render_*`` templating APIs, +the UTF-8 ``charset`` is set automatically as the default via the +``Content-Type`` header. If you return a ``Content-Type`` header without an +explicit ``charset``, a request will add a ``;charset=utf-8`` trailer to the ``Content-Type`` header value for you for response content types that are textual (e.g., ``text/html`` or ``application/xml``) as it is rendered. If you are using your own response object, you will need to ensure you do this yourself. -.. note:: Only the *values* of request params obtained via ``request.params``, - ``request.GET`` or ``request.POST`` are decoded to Unicode objects - implicitly in the :app:`Pyramid` default configuration. The keys are still - (byte) strings. - - .. index:: single: view calling convention diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index c9a5a68e1..72f2db42e 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -188,14 +188,10 @@ of them. Here are a couple that might be useful: Text (Unicode) ++++++++++++++ -Many of the properties of the request object will be text values (``str`` type) if the request encoding/charset is -provided. If it is provided, the values in ``req.POST``, ``req.GET``, -``req.params``, and ``req.cookies`` will contain text. The client *can* -indicate the charset with something like ``Content-Type: -application/x-www-form-urlencoded; charset=utf8``, but browsers seldom set -this. You can reset the charset of an existing request with ``newreq = -req.decode('utf-8')``, or during instantiation with ``Request(environ, -charset='utf8')``. +Most of the properties of the request object will be text values. +The values in ``req.POST``, ``req.GET``, ``req.params``, and ``req.cookies`` will contain text and are generated assuming a UTF-8 charset. +The client *can* indicate the charset with something like ``Content-Type: application/x-www-form-urlencoded; charset=utf8``, but browsers seldom set this. +You can reset the charset of an existing request with ``newreq = req.decode('utf-8')``, or during instantiation with ``Request(environ, charset='utf8')``. .. index:: single: multidict (WebOb) @@ -263,7 +259,7 @@ to a :app:`Pyramid` application: jQuery.ajax({type:'POST', url: 'http://localhost:6543/', // the pyramid server data: JSON.stringify({'a':1}), - contentType: 'application/json; charset=utf-8'}); + contentType: 'application/json'}); When such a request reaches a view in your application, the ``request.json_body`` attribute will be available in the view callable body. @@ -279,7 +275,7 @@ For the above view, printed to the console will be: .. code-block:: python - {u'a': 1} + {'a': 1} For bonus points, here's a bit of client-side code that will produce a request that has a body suitable for reading via ``request.json_body`` using Python's @@ -385,8 +381,8 @@ A response object has three fundamental parts: ``response.app_iter`` An iterable (such as a list or generator) that will produce the content of - the response. This is also accessible as ``response.body`` (a string), - ``response.text`` (a unicode object, informed by ``response.charset``), and + the response. This is also accessible as ``response.body`` (bytes), + ``response.text`` (a string, informed by ``response.charset``), and ``response.body_file`` (a file-like object; writing to it appends to ``app_iter``). diff --git a/docs/tutorials/wiki/src/tests/tutorial/tests.py b/docs/tutorials/wiki/src/tests/tutorial/tests.py index 098e9c1bd..d713d3fdd 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/tests.py +++ b/docs/tutorials/wiki/src/tests/tutorial/tests.py @@ -8,12 +8,12 @@ class PageModelTests(unittest.TestCase): from .models import Page return Page - def _makeOne(self, data=u'some data'): + def _makeOne(self, data='some data'): return self._getTargetClass()(data=data) def test_constructor(self): instance = self._makeOne() - self.assertEqual(instance.data, u'some data') + self.assertEqual(instance.data, 'some data') class WikiModelTests(unittest.TestCase): -- cgit v1.2.3 From a08763a9b5213ed352a26c603a6d3722aebe9dd0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Nov 2018 00:42:39 -0800 Subject: proper hyphenation of UTF-8-decoded --- docs/narr/traversal.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/narr/traversal.rst b/docs/narr/traversal.rst index 769d0984c..0282c6096 100644 --- a/docs/narr/traversal.rst +++ b/docs/narr/traversal.rst @@ -242,7 +242,7 @@ uses this algorithm to find a :term:`context` resource and a :term:`view name`. Conversion from a URL-decoded string into Unicode is attempted using the UTF-8 encoding. If any URL-unquoted path segment in ``PATH_INFO`` is not decodeable using the UTF-8 decoding, a :exc:`TypeError` is raised. A - segment will be fully URL-unquoted and UTF8-decoded before it is passed in + segment will be fully URL-unquoted and UTF-8-decoded before it is passed in to the ``__getitem__`` of any resource during traversal. Thus a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the -- cgit v1.2.3 From 1007fa3773a311a72dd7b2e5e8c52584c5d6e416 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Nov 2018 00:55:17 -0800 Subject: proper spacing of interpreter output between a dict's colon and value --- docs/narr/urldispatch.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index b9b42a9bd..129dce8f3 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -165,8 +165,8 @@ The above pattern will match these URLs, generating the following matchdicts: .. code-block:: text - foo/1/2 -> {'baz':'1', 'bar':'2'} - foo/abc/def -> {'baz':'abc', 'bar':'def'} + foo/1/2 -> {'baz': '1', 'bar': '2'} + foo/abc/def -> {'baz': 'abc', 'bar': 'def'} It will not match the following patterns however: @@ -303,10 +303,10 @@ The above pattern will match these URLs, generating the following matchdicts: .. code-block:: text foo/1/2/ -> - {'baz':'1', 'bar':'2', 'fizzle':()} + {'baz': '1', 'bar': '2', 'fizzle': ()} foo/abc/def/a/b/c -> - {'baz':'abc', 'bar':'def', 'fizzle':('a', 'b', 'c')} + {'baz': 'abc', 'bar': 'def', 'fizzle': ('a', 'b', 'c')} Note that when a ``*stararg`` remainder match is matched, the value put into the matchdict is turned into a tuple of path segments representing the @@ -327,7 +327,7 @@ Will generate the following matchdict: .. code-block:: text - {'fizzle':('La Pe\xf1a', 'a', 'b', 'c')} + {'fizzle': ('La Pe\xf1a', 'a', 'b', 'c')} By default, the ``*stararg`` will parse the remainder sections into a tuple split by segment. Changing the regular expression used to match a marker can @@ -341,8 +341,8 @@ The above pattern will match these URLs, generating the following matchdicts: .. code-block:: text - foo/1/2/ -> {'baz':'1', 'bar':'2', 'fizzle':''} - foo/abc/def/a/b/c -> {'baz':'abc', 'bar':'def', 'fizzle': 'a/b/c'} + foo/1/2/ -> {'baz': '1', 'bar': '2', 'fizzle': ''} + foo/abc/def/a/b/c -> {'baz': 'abc', 'bar': 'def', 'fizzle': 'a/b/c'} This occurs because the default regular expression for a marker is ``[^/]+`` which will match everything up to the first ``/``, while ``{fizzle:.*}`` will -- cgit v1.2.3 From 9eec98980d17fee7c27aa1b36a0b8ae74b081e26 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Nov 2018 00:59:57 -0800 Subject: grammar fixes --- docs/narr/views.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 40717c37a..1b4118b85 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -469,7 +469,7 @@ For implicit decoding to work reliably, you should ensure that every form you render that posts to a :app:`Pyramid` view explicitly defines a charset encoding of UTF-8. This can be done via a response that has a ``;charset=UTF-8`` in its ``Content-Type`` header; or, as in the form above, -with a ``accept-charset`` tag that implies that informs the browser that the +with an ``accept-charset`` attribute, informing the browser that the server expects the form content to be encoded using UTF-8. This must be done explicitly because all known browser clients assume that they should encode form data in the same character set implied by the ``Content-Type`` value of -- cgit v1.2.3 From c9d5832707877faac5b94943e00951b69192185d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Nov 2018 01:07:29 -0800 Subject: moar proper spacing of interpreter output between a dict's colon and value --- docs/narr/urldispatch.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 129dce8f3..9372163e8 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -184,7 +184,7 @@ instance, if this route pattern was used: foo/{name}.html The literal path ``/foo/biz.html`` will match the above route pattern, and the -match result will be ``{'name':'biz'}``. However, the literal path +match result will be ``{'name': 'biz'}``. However, the literal path ``/foo/biz`` will not match, because it does not contain a literal ``.html`` at the end of the segment represented by ``{name}.html`` (it only contains ``biz``, not ``biz.html``). @@ -513,7 +513,7 @@ When the ``/site/{id}`` route pattern matches during a request, the When this route matches, a ``matchdict`` will be generated and attached to the request as ``request.matchdict``. If the specific URL matched is ``/site/1``, the ``matchdict`` will be a dictionary with a single key, ``id``; the value -will be the string ``'1'``, ex.: ``{'id':'1'}``. +will be the string ``'1'``, ex.: ``{'id': '1'}``. The ``mypackage.views`` module referred to above might look like so: @@ -581,17 +581,17 @@ forms: - When a URL matches the pattern ``/ideas/{idea}``, the view callable available at the dotted Python pathname ``mypackage.views.idea_view`` will be called. For the specific URL ``/ideas/1``, the ``matchdict`` generated - and attached to the :term:`request` will consist of ``{'idea':'1'}``. + and attached to the :term:`request` will consist of ``{'idea': '1'}``. - When a URL matches the pattern ``/users/{user}``, the view callable available at the dotted Python pathname ``mypackage.views.user_view`` will be called. For the specific URL ``/users/1``, the ``matchdict`` generated and - attached to the :term:`request` will consist of ``{'user':'1'}``. + attached to the :term:`request` will consist of ``{'user': '1'}``. - When a URL matches the pattern ``/tags/{tag}``, the view callable available at the dotted Python pathname ``mypackage.views.tag_view`` will be called. For the specific URL ``/tags/1``, the ``matchdict`` generated and attached to - the :term:`request` will consist of ``{'tag':'1'}``. + the :term:`request` will consist of ``{'tag': '1'}``. In this example we've again associated each of our routes with a :term:`view callable` directly. In all cases, the request, which will have a ``matchdict`` -- cgit v1.2.3 From b1c500c3d4cb269aed254742501040c1c64367c2 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 20 Nov 2018 01:11:09 -0800 Subject: s/msgid/``msgid`` as needed --- docs/narr/i18n.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst index 3a4f5af5b..b8cd396c0 100644 --- a/docs/narr/i18n.rst +++ b/docs/narr/i18n.rst @@ -62,7 +62,7 @@ This creates a ``str``-like object that is a TranslationString. The first argument to :class:`~pyramid.i18n.TranslationString` is the ``msgid``; it is required. It represents the key into the translation mappings provided by a particular localization. The ``msgid`` argument must be a string. -The msgid may optionally contain *replacement markers*. For instance: +The ``msgid`` may optionally contain *replacement markers*. For instance: .. code-block:: python :linenos: @@ -80,14 +80,14 @@ may be supplied at the same time as the replacement marker itself: from pyramid.i18n import TranslationString ts = TranslationString('Add ${number}', mapping={'number':1}) -Any number of replacement markers can be present in the msgid value, any number +Any number of replacement markers can be present in the ``msgid`` value, any number of times. Only markers which can be replaced by the values in the *mapping* will be replaced at translation time. The others will not be interpolated and will be output literally. A translation string should also usually carry a *domain*. The domain represents a translation category to disambiguate it from other translations of -the same msgid, in case they conflict. +the same ``msgid``, in case they conflict. .. code-block:: python :linenos: @@ -99,7 +99,7 @@ the same msgid, in case they conflict. The above translation string named a domain of ``form``. A :term:`translator` function will often use the domain to locate the right translator file on the filesystem which contains translations for a given domain. In this case, if it -were trying to translate our msgid to German, it might try to find a +were trying to translate our ``msgid`` to German, it might try to find a translation from a :term:`gettext` file within a :term:`translation directory` like this one: -- cgit v1.2.3 From b404d4b29e5eaa08fb38e9bd4818e1a2d390c10b Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Fri, 23 Nov 2018 15:54:53 -0600 Subject: fix a couple more doc strings --- docs/glossary.rst | 2 +- docs/narr/hooks.rst | 2 +- docs/narr/webob.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/glossary.rst b/docs/glossary.rst index 97806d958..e21ae2fdc 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -523,7 +523,7 @@ Glossary from the :term:`physical root`. For example, the physical path of the ``abc`` subobject of the physical root object is ``/abc``. Physical paths can also be specified as tuples where the first element is the empty - string (representing the root), and every other element is a string, + string (representing the root), and every other element is a Unicode string, e.g. ``('', 'abc')``. Physical paths are also sometimes called "traversal paths". diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 5e67a81c7..0dac8d426 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -667,7 +667,7 @@ that implements the following interface: will be a resource object representing the virtual root (or the physical root if traversal was not performed), and ``virtual_root_path`` will be a sequence representing the - virtual root path (a sequence of strings) or None if + virtual root path (a sequence of strings) or ``None`` if traversal was not performed. Extra keys for special purpose functionality can be added as diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index 72f2db42e..665bbddc9 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -382,7 +382,7 @@ A response object has three fundamental parts: ``response.app_iter`` An iterable (such as a list or generator) that will produce the content of the response. This is also accessible as ``response.body`` (bytes), - ``response.text`` (a string, informed by ``response.charset``), and + ``response.text`` (a Unicode string, informed by ``response.charset``), and ``response.body_file`` (a file-like object; writing to it appends to ``app_iter``). -- cgit v1.2.3 From 8f6b195b3f1e1f1f2f16e09902540ece823e9cc9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 14:37:11 -0800 Subject: Remove Python versions mention --- docs/tutorials/wiki/background.rst | 5 ----- 1 file changed, 5 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/background.rst b/docs/tutorials/wiki/background.rst index c10ab9e55..1a076de85 100644 --- a/docs/tutorials/wiki/background.rst +++ b/docs/tutorials/wiki/background.rst @@ -15,9 +15,4 @@ To code along with this tutorial, the developer will need a Unix machine with development tools (macOS with XCode, any Linux or BSD variant, and so on) *or* a Windows system of any kind. -.. warning:: - - This tutorial has been written for Python 2. It is unlikely to work - without modification under Python 3. - Have fun! -- cgit v1.2.3 From 4fe2cc396fbfdfb6af78de6dd9190279a6638a19 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 15:05:19 -0800 Subject: Correct grammar, use shorter sentences, rewrap to one sentence per line. --- docs/tutorials/wiki/design.rst | 96 ++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 54 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/design.rst b/docs/tutorials/wiki/design.rst index 30d443bb8..5c86293f6 100644 --- a/docs/tutorials/wiki/design.rst +++ b/docs/tutorials/wiki/design.rst @@ -4,85 +4,77 @@ Design ====== -Following is a quick overview of the design of our wiki application, to help -us understand the changes that we will be making as we work through the -tutorial. +Following is a quick overview of the design of our wiki application to help us understand the changes that we will make as we work through the tutorial. + Overall ------- -We choose to use :term:`reStructuredText` markup in the wiki text. Translation -from reStructuredText to HTML is provided by the widely used ``docutils`` -Python module. We will add this module in the dependency list on the project -``setup.py`` file. +We choose to use :term:`reStructuredText` markup in the wiki text. +Conversion from reStructuredText to HTML is provided by the widely used ``docutils`` Python module. +We will add this module in the dependency list on the project ``setup.py`` file. + Models ------ -The root resource named ``Wiki`` will be a mapping of wiki page -names to page resources. The page resources will be instances -of a *Page* class and they store the text content. +The root resource named ``Wiki`` will be a mapping of wiki page names to page resources. +The page resources will be instances of a *Page* class. +They store the text content. + +URLs like ``/PageName`` will be traversed using Wiki[ *PageName* ] => page. +The resulting context is the page resource of an existing page. -URLs like ``/PageName`` will be traversed using Wiki[ -*PageName* ] => page, and the context that results is the page -resource of an existing page. +To add a page to the wiki, a new instance of the page resource is created. +Its name and reference are added to the Wiki mapping. -To add a page to the wiki, a new instance of the page resource -is created and its name and reference are added to the Wiki -mapping. +A page named ``FrontPage`` containing the text *This is the front page* will be created when the storage is initialized. +It will be used as the wiki home page. -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. Views ----- -There will be three views to handle the normal operations of adding, -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. +There will be three views to handle the normal operations of adding, 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. -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. +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 -------- -We'll eventually be adding security to our application. The components we'll -use to do this are below. +We'll eventually add security to our application. +The components we'll use to do this are below. -- USERS, a dictionary mapping :term:`userids ` to their - corresponding passwords. +- USERS, a dictionary mapping :term:`userids ` to their corresponding passwords. -- GROUPS, a dictionary mapping :term:`userids ` to a - list of groups to which they belong. +- GROUPS, a dictionary mapping :term:`userids ` to a list of groups to which they belong. -- ``groupfinder``, an *authorization callback* that looks up USERS and - GROUPS. It will be provided in a new ``security.py`` file. +- ``groupfinder``, an *authorization callback* that looks up USERS and GROUPS. + It will be provided in a new ``security.py`` file. -- An :term:`ACL` is attached to the root :term:`resource`. Each row below - details an :term:`ACE`: +- An :term:`ACL` is attached to the root :term:`resource`. + Each row below details an :term:`ACE`: - +----------+----------------+----------------+ - | Action | Principal | Permission | - +==========+================+================+ - | Allow | Everyone | View | - +----------+----------------+----------------+ - | Allow | group:editors | Edit | - +----------+----------------+----------------+ + +----------+----------------+----------------+ + | Action | Principal | Permission | + +==========+================+================+ + | Allow | Everyone | View | + +----------+----------------+----------------+ + | Allow | group:editors | Edit | + +----------+----------------+----------------+ -- Permission declarations are added to the views to assert the security - policies as each request is handled. +- Permission declarations are added to the views to assert the security policies as each request is handled. -Two additional views and one template will handle the login and -logout tasks. +Two additional views and one template will handle the login and logout tasks. Summary ------- -The URL, context, actions, template and permission associated to each view are -listed in the following table: +The URL, context, actions, template and permission associated to each view are listed in the following table: +----------------------+-------------+-----------------+-----------------------+------------+------------+ | URL | View | Context | Action | Template | Permission | @@ -139,10 +131,6 @@ listed in the following table: | | | | /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* 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. +.. [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* 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. -- cgit v1.2.3 From 7d2124c28072bf63ce7ad566ad1e2e3d19c22b76 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 15:47:54 -0800 Subject: Correct grammar, use shorter sentences, rewrap to one sentence per line, inline links, update outputs. --- docs/tutorials/wiki/installation.rst | 179 ++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 86 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index d0037e584..b89822e83 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -4,12 +4,13 @@ Installation ============ + Before you begin ---------------- -This tutorial assumes that you have already followed the steps in -:ref:`installing_chapter`, except **do not create a virtual environment or -install Pyramid**. Thereby you will satisfy the following requirements. +This tutorial assumes that you have already followed the steps in :ref:`installing_chapter`, except **do not create a virtual environment or +install Pyramid**. +Thereby you will satisfy the following requirements. * A Python interpreter is installed on your operating system. * You've satisfied the :ref:`requirements-for-installing-packages`. @@ -17,13 +18,17 @@ install Pyramid**. Thereby you will satisfy the following requirements. Install cookiecutter -------------------- -We will use a :term:`cookiecutter` to create a Python package project from a Python package project template. See `Cookiecutter Installation `_ for instructions. +We will use a :term:`cookiecutter` to create a Python package project from a Python package project template. +See `Cookiecutter Installation `_ for instructions. Generate a Pyramid project from a cookiecutter ---------------------------------------------- -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. +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 ^^^^^^^ @@ -33,6 +38,7 @@ On Unix cd ~ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master + On Windows ^^^^^^^^^^ @@ -41,30 +47,33 @@ On Windows cd \ cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master + On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ If prompted for the first item, accept the default ``yes`` by hitting return. .. code-block:: text - You've cloned ~/.cookiecutters/pyramid-cookiecutter-theone before. - Is it okay to delete and re-clone it? [yes]: yes + You've downloaded ~/.cookiecutters/pyramid-cookiecutter-starter before. + Is it okay to delete and re-download it? [yes]: yes project_name [Pyramid Scaffold]: myproj repo_name [myproj]: tutorial Select template_language: 1 - jinja2 2 - chameleon 3 - mako - Choose from 1, 2, 3 [1]: 1 + Choose from 1, 2, 3 [1]: 2 Select backend: 1 - none 2 - sqlalchemy 3 - zodb Choose from 1, 2, 3 [1]: 3 + Change directory into your newly created project ------------------------------------------------ + On Unix ^^^^^^^ @@ -72,6 +81,7 @@ On Unix cd tutorial + On Windows ^^^^^^^^^^ @@ -85,6 +95,7 @@ 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 ^^^^^^^ @@ -92,6 +103,7 @@ On Unix export VENV=~/tutorial + On Windows ^^^^^^^^^^ @@ -103,6 +115,7 @@ On Windows Create a virtual environment ---------------------------- + On Unix ^^^^^^^ @@ -110,17 +123,10 @@ On Unix python3 -m venv $VENV + On Windows ^^^^^^^^^^ -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. - -Python 2.7: - -.. code-block:: doscon - - c:\Python27\Scripts\virtualenv %VENV% - Python 3.7: .. code-block:: doscon @@ -131,6 +137,7 @@ Python 3.7: Upgrade packaging tools in the virtual environment -------------------------------------------------- + On Unix ^^^^^^^ @@ -138,6 +145,7 @@ On Unix $VENV/bin/pip install --upgrade pip setuptools + On Windows ^^^^^^^^^^ @@ -151,7 +159,10 @@ 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. We will install testing requirements at the same time. We do so with the following command. +In order to work on the project, 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 ^^^^^^^ @@ -160,6 +171,7 @@ On Unix $VENV/bin/pip install -e ".[testing]" + On Windows ^^^^^^^^^^ @@ -167,6 +179,7 @@ On Windows %VENV%\Scripts\pip install -e ".[testing]" + On all operating systems ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,16 +187,18 @@ The console will show ``pip`` checking for packages and installing missing packa .. code-block:: bash - 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 + Successfully installed BTrees-4.5.1 Chameleon-3.5 Mako-1.0.7 \ + MarkupSafe-1.1.0 PasteDeploy-1.5.2 Pygments-2.2.0 WebTest-2.0.32 \ + ZConfig-3.3.0 ZEO-5.2.0 ZODB-5.5.1 ZODB3-3.11.0 atomicwrites-1.2.1 \ + attrs-18.2.0 beautifulsoup4-4.6.3 coverage-4.5.2 hupper-1.4.1 \ + more-itertools-4.3.0 persistent-4.4.3 plaster-1.0 plaster-pastedeploy-0.6 \ + pluggy-0.8.0 py-1.7.0 pyramid-1.10.1 pyramid-chameleon-0.3 \ + pyramid-debugtoolbar-4.5 pyramid-mako-1.0.2 pyramid-retry-1.0 \ + pyramid-tm-2.2.1 pyramid-zodbconn-0.8.1 pytest-4.0.0 pytest-cov-2.6.0 \ + repoze.lru-0.7 six-1.11.0 transaction-2.4.0 translationstring-1.3 \ + tutorial venusian-1.1.0 waitress-1.1.0 webob-1.8.4 zc.lockfile-1.4 \ + zdaemon-4.3 zodbpickle-1.0.2 zodburi-2.3.0 zope.deprecation-4.3.0 \ + zope.interface-4.6.0 Testing requirements are defined in our project's ``setup.py`` file, in the ``tests_require`` and ``extras_require`` stanzas. @@ -208,6 +223,7 @@ requirements, you may run the tests for the project. The following commands provide options to ``pytest`` that specify the module for which its tests shall be run, and to run ``pytest`` in quiet mode. + On Unix ^^^^^^^ @@ -215,6 +231,7 @@ On Unix $VENV/bin/pytest -q + On Windows ^^^^^^^^^^ @@ -233,13 +250,11 @@ For a successful test run, you should see output that ends like this: Expose test coverage information -------------------------------- -You can run the ``pytest`` command to see test coverage information. This -runs the tests in the same way that ``pytest`` does, but provides additional -:term:`coverage` information, exposing which lines of your project are covered by the -tests. +You can run the ``pytest`` command to see test coverage information. +This runs the tests in the same way that ``pytest`` does, but provides additional :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 environment, so we can run the tests with coverage. -We've already installed the ``pytest-cov`` package into our virtual -environment, so we can run the tests with coverage. On Unix ^^^^^^^ @@ -248,6 +263,7 @@ On Unix $VENV/bin/pytest --cov --cov-report=term-missing + On Windows ^^^^^^^^^^ @@ -259,23 +275,30 @@ If successful, you will see output something like this: .. code-block:: bash - ======================== 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 + ======================== test session starts ========================= + platform darwin -- Python 3.7.0, pytest-4.0.0, py-1.7.0, pluggy-0.8.0 + rootdir: /Users/stevepiercy/projects/hack-on-pyramid/tutorial, inifile: pytest.ini + plugins: cov-2.6.0 + collected 1 item 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% + [100%] + + ---------- coverage: platform darwin, python 3.7.0-final-0 ----------- + Name Stmts Miss Cover Missing + ----------------------------------------------------------- + tutorial/__init__.py 17 12 29% 7-8, 14-23 + tutorial/models/__init__.py 8 4 50% 9-12 + tutorial/pshell.py 6 6 0% 1-12 + tutorial/routes.py 2 2 0% 1-2 + tutorial/views/__init__.py 0 0 100% + tutorial/views/default.py 4 0 100% + tutorial/views/notfound.py 4 4 0% 1-7 + ----------------------------------------------------------- + TOTAL 41 28 32% + - ===================== 1 passed in 0.31 seconds ====================== + ===================== 1 passed in 0.31 seconds ======================= Our package doesn't quite have 100% test coverage. @@ -285,11 +308,10 @@ Our package doesn't quite have 100% test coverage. Test and coverage cookiecutter defaults --------------------------------------- -The Pyramid cookiecutter includes configuration defaults for ``pytest`` 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. +The Pyramid cookiecutter includes configuration defaults for ``pytest`` 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. + On Unix ^^^^^^^ @@ -305,13 +327,11 @@ On Windows %VENV%\Scripts\pytest --cov=tutorial tutorial\tests.py -q -``pytest`` follows :ref:`conventions for Python test discovery -`, and the configuration defaults from the cookiecutter -tell ``pytest`` where to find the module on which we want to run tests and -coverage. -.. seealso:: See ``pytest``'s documentation for :ref:`pytest:usage` or invoke - ``pytest -h`` to see its full set of options. +``pytest`` follows :ref:`conventions for Python test discovery `. +The configuration defaults from the cookiecutter tell ``pytest`` where to find the module on which we want to run tests and coverage. + +.. seealso:: See ``pytest``'s documentation for :ref:`pytest:usage` or invoke ``pytest -h`` to see its full set of options. .. _wiki-start-the-application: @@ -319,8 +339,9 @@ coverage. Start the application --------------------- -Start the application. See :ref:`what_is_this_pserve_thing` for more -information on ``pserve``. +Start the application. +See :ref:`what_is_this_pserve_thing` for more information on ``pserve``. + On Unix ^^^^^^^ @@ -329,6 +350,7 @@ On Unix $VENV/bin/pserve development.ini --reload + On Windows ^^^^^^^^^^ @@ -336,10 +358,10 @@ On Windows %VENV%\Scripts\pserve development.ini --reload + .. note:: - Your OS firewall, if any, may pop up a dialog asking for authorization - to allow python to accept incoming network connections. + Your OS firewall, if any, may pop up a dialog asking for authorization to allow python to accept incoming network connections. If successful, you will see something like this on your console: @@ -356,13 +378,12 @@ This means the server is ready to accept requests. Visit the application in a browser ---------------------------------- -In a browser, visit http://localhost:6543/. You will see the generated -application's default page. +In a browser, visit http://localhost:6543/. +You will see the generated application's default page. -One thing you'll notice is the "debug toolbar" icon on right hand side of the -page. You can read more about the purpose of the icon at -:ref:`debug_toolbar`. It allows you to get information about your -application while you develop. +One thing you'll notice is the "debug toolbar" icon on right hand side of the page. +You can read more about the purpose of the icon at :ref:`debug_toolbar`. +It allows you to get information about your application while you develop. Decisions the cookiecutter backend option ``zodb`` has made for you @@ -374,24 +395,10 @@ When creating a project and selecting the backend option of ``zodb``, the cookie - You are willing to use :term:`traversal` to map URLs to code. -- You want to use pyramid_zodbconn_, pyramid_tm_, and the transaction_ packages - to manage connections and transactions with :term:`ZODB`. +- You want to use `pyramid_zodbconn `_, `pyramid_tm `_, and the `transaction `_ packages to manage connections and transactions with :term:`ZODB`. .. note:: - :app:`Pyramid` supports any persistent storage mechanism (e.g., an SQL - database or filesystem files). It also supports an additional mechanism to - map URLs to code (:term:`URL dispatch`). However, for the purposes of this - tutorial, we'll only be using :term:`traversal` and :term:`ZODB`. - -.. _pyramid_chameleon: - https://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/ - -.. _pyramid_tm: - https://docs.pylonsproject.org/projects/pyramid-tm/en/latest/ - -.. _pyramid_zodbconn: - https://docs.pylonsproject.org/projects/pyramid-zodbconn/en/latest/ - -.. _transaction: - https://zodb.readthedocs.io/en/latest/transactions.html + :app:`Pyramid` supports any persistent storage mechanism (e.g., an SQL database or filesystem files). + It also supports an additional mechanism to map URLs to code (:term:`URL dispatch`). + However, for the purposes of this tutorial, we will only use :term:`traversal` and :term:`ZODB`. -- cgit v1.2.3 From 638bb50af2847ce309dc29d8054aabe138cb6fc1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 15:53:51 -0800 Subject: remove extra whitespace --- docs/tutorials/wiki/installation.rst | 2 -- 1 file changed, 2 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/installation.rst b/docs/tutorials/wiki/installation.rst index b89822e83..37e3498b2 100644 --- a/docs/tutorials/wiki/installation.rst +++ b/docs/tutorials/wiki/installation.rst @@ -392,9 +392,7 @@ Decisions the cookiecutter backend option ``zodb`` has made for you When creating a project and selecting the backend option of ``zodb``, the cookiecutter makes the following assumptions: - You are willing to use :term:`ZODB` for persistent storage. - - You are willing to use :term:`traversal` to map URLs to code. - - You want to use `pyramid_zodbconn `_, `pyramid_tm `_, and the `transaction `_ packages to manage connections and transactions with :term:`ZODB`. .. note:: -- cgit v1.2.3 From 76ada71ec1d28d8f38f15dcffa311180d99d2daa Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 16:59:32 -0800 Subject: synch up source files with actual cookiecutter results --- docs/tutorials/wiki/src/installation/MANIFEST.in | 2 +- docs/tutorials/wiki/src/installation/pytest.ini | 2 +- docs/tutorials/wiki/src/installation/setup.py | 4 +- .../wiki/src/installation/tutorial/__init__.py | 8 +-- .../wiki/src/installation/tutorial/models.py | 12 ---- .../wiki/src/installation/tutorial/pshell.py | 1 + .../installation/tutorial/templates/mytemplate.pt | 70 +++------------------- .../wiki/src/installation/tutorial/tests.py | 3 +- .../wiki/src/installation/tutorial/views.py | 7 --- 9 files changed, 19 insertions(+), 90 deletions(-) delete mode 100644 docs/tutorials/wiki/src/installation/tutorial/models.py delete mode 100644 docs/tutorials/wiki/src/installation/tutorial/views.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/installation/MANIFEST.in b/docs/tutorials/wiki/src/installation/MANIFEST.in index 81beba1b1..05cc195d9 100644 --- a/docs/tutorials/wiki/src/installation/MANIFEST.in +++ b/docs/tutorials/wiki/src/installation/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.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/wiki/src/installation/pytest.ini b/docs/tutorials/wiki/src/installation/pytest.ini index 8b76bc410..a3489cdf8 100644 --- a/docs/tutorials/wiki/src/installation/pytest.ini +++ b/docs/tutorials/wiki/src/installation/pytest.ini @@ -1,3 +1,3 @@ [pytest] testpaths = tutorial -python_files = *.py +python_files = test*.py diff --git a/docs/tutorials/wiki/src/installation/setup.py b/docs/tutorials/wiki/src/installation/setup.py index a4f143d24..d6d488ed2 100644 --- a/docs/tutorials/wiki/src/installation/setup.py +++ b/docs/tutorials/wiki/src/installation/setup.py @@ -10,15 +10,15 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'plaster_pastedeploy', - 'pyramid >= 1.9a', + 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'waitress', 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', 'ZODB3', - 'waitress', ] tests_require = [ diff --git a/docs/tutorials/wiki/src/installation/tutorial/__init__.py b/docs/tutorials/wiki/src/installation/tutorial/__init__.py index f2b3c9568..bd0c71f5b 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/installation/tutorial/__init__.py @@ -11,13 +11,13 @@ def root_factory(request): def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' with Configurator(settings=settings) as config: - config.include('pyramid_chameleon') + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') config.set_root_factory(root_factory) - config.add_static_view('static', 'static', cache_max_age=3600) + config.include('pyramid_chameleon') + config.include('.routes') config.scan() - return config.make_wsgi_app() + return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/installation/tutorial/models.py b/docs/tutorials/wiki/src/installation/tutorial/models.py deleted file mode 100644 index aca6a4129..000000000 --- a/docs/tutorials/wiki/src/installation/tutorial/models.py +++ /dev/null @@ -1,12 +0,0 @@ -from persistent.mapping import PersistentMapping - - -class MyModel(PersistentMapping): - __parent__ = __name__ = None - - -def appmaker(zodb_root): - if 'app_root' not in zodb_root: - app_root = MyModel() - zodb_root['app_root'] = app_root - return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/installation/tutorial/pshell.py b/docs/tutorials/wiki/src/installation/tutorial/pshell.py index 3d026291b..a7cfa6a27 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/pshell.py +++ b/docs/tutorials/wiki/src/installation/tutorial/pshell.py @@ -1,5 +1,6 @@ from . import models + def setup(env): request = env['request'] diff --git a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt index d63ea8c45..adac4fe35 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/installation/tutorial/templates/mytemplate.pt @@ -1,65 +1,11 @@ - - - - - - - - - +
+
- Cookiecutter ZODB project for the Pyramid Web Framework - - - - - - - - - - - - - -
-
-
-
- -
-
-
-

Pyramid ZODB Project

-

Welcome to ${project}, a Pyramid application generated by
Cookiecutter.

-
-
+
+

Pyramid Starter project

+

Welcome to ${project}, a Pyramid + application generated by
Cookiecutter.

- -
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/installation/tutorial/tests.py b/docs/tutorials/wiki/src/installation/tutorial/tests.py index ca7a47279..6279d9f66 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/tests.py +++ b/docs/tutorials/wiki/src/installation/tutorial/tests.py @@ -11,7 +11,8 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from .views import my_view + from .views.default import my_view request = testing.DummyRequest() info = my_view(request) 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 deleted file mode 100644 index c1878bdd0..000000000 --- a/docs/tutorials/wiki/src/installation/tutorial/views.py +++ /dev/null @@ -1,7 +0,0 @@ -from pyramid.view import view_config -from .models import MyModel - - -@view_config(context=MyModel, renderer='templates/mytemplate.pt') -def my_view(request): - return {'project': 'myproj'} -- cgit v1.2.3 From f326582294868e5529320b532738c8762cf816c5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 17:00:31 -0800 Subject: Add files from cookiecutter --- .../src/installation/tutorial/models/__init__.py | 12 +++++ .../wiki/src/installation/tutorial/routes.py | 2 + .../src/installation/tutorial/templates/404.pt | 10 ++++ .../src/installation/tutorial/templates/layout.pt | 62 ++++++++++++++++++++++ .../src/installation/tutorial/views/__init__.py | 0 .../src/installation/tutorial/views/default.py | 8 +++ .../src/installation/tutorial/views/notfound.py | 7 +++ 7 files changed, 101 insertions(+) create mode 100644 docs/tutorials/wiki/src/installation/tutorial/models/__init__.py create mode 100644 docs/tutorials/wiki/src/installation/tutorial/routes.py create mode 100644 docs/tutorials/wiki/src/installation/tutorial/templates/404.pt create mode 100644 docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt create mode 100644 docs/tutorials/wiki/src/installation/tutorial/views/__init__.py create mode 100644 docs/tutorials/wiki/src/installation/tutorial/views/default.py create mode 100644 docs/tutorials/wiki/src/installation/tutorial/views/notfound.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/installation/tutorial/models/__init__.py b/docs/tutorials/wiki/src/installation/tutorial/models/__init__.py new file mode 100644 index 000000000..aca6a4129 --- /dev/null +++ b/docs/tutorials/wiki/src/installation/tutorial/models/__init__.py @@ -0,0 +1,12 @@ +from persistent.mapping import PersistentMapping + + +class MyModel(PersistentMapping): + __parent__ = __name__ = None + + +def appmaker(zodb_root): + if 'app_root' not in zodb_root: + app_root = MyModel() + zodb_root['app_root'] = app_root + return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/installation/tutorial/routes.py b/docs/tutorials/wiki/src/installation/tutorial/routes.py new file mode 100644 index 000000000..3c0a37992 --- /dev/null +++ b/docs/tutorials/wiki/src/installation/tutorial/routes.py @@ -0,0 +1,2 @@ +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) diff --git a/docs/tutorials/wiki/src/installation/tutorial/templates/404.pt b/docs/tutorials/wiki/src/installation/tutorial/templates/404.pt new file mode 100644 index 000000000..07298940c --- /dev/null +++ b/docs/tutorials/wiki/src/installation/tutorial/templates/404.pt @@ -0,0 +1,10 @@ +
+
+ +
+

Pyramid Starter project

+

404 Page Not Found

+
+ +
+
diff --git a/docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt new file mode 100644 index 000000000..9fdaef00f --- /dev/null +++ b/docs/tutorials/wiki/src/installation/tutorial/templates/layout.pt @@ -0,0 +1,62 @@ + + + + + + + + + + + Cookiecutter Starter project for the Pyramid Web Framework + + + + + + + + + + + + + +
+
+
+
+ +
+
+
No content
+
+
+ +
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki/src/installation/tutorial/views/__init__.py b/docs/tutorials/wiki/src/installation/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/wiki/src/installation/tutorial/views/default.py b/docs/tutorials/wiki/src/installation/tutorial/views/default.py new file mode 100644 index 000000000..5d708d15c --- /dev/null +++ b/docs/tutorials/wiki/src/installation/tutorial/views/default.py @@ -0,0 +1,8 @@ +from pyramid.view import view_config + +from ..models import MyModel + + +@view_config(context=MyModel, renderer='../templates/mytemplate.pt') +def my_view(request): + return {'project': 'myproj'} diff --git a/docs/tutorials/wiki/src/installation/tutorial/views/notfound.py b/docs/tutorials/wiki/src/installation/tutorial/views/notfound.py new file mode 100644 index 000000000..728791d0a --- /dev/null +++ b/docs/tutorials/wiki/src/installation/tutorial/views/notfound.py @@ -0,0 +1,7 @@ +from pyramid.view import notfound_view_config + + +@notfound_view_config(renderer='../templates/404.pt') +def notfound_view(request): + request.response.status = 404 + return {} -- cgit v1.2.3 From 0c4e11c4a64121309cda3b728eca9a6ad9d9959d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 17:59:34 -0800 Subject: Synch up src files --- docs/tutorials/wiki/src/basiclayout/MANIFEST.in | 2 +- docs/tutorials/wiki/src/basiclayout/pytest.ini | 2 +- docs/tutorials/wiki/src/basiclayout/setup.py | 4 +- .../wiki/src/basiclayout/tutorial/__init__.py | 8 +-- .../wiki/src/basiclayout/tutorial/models.py | 12 ---- .../src/basiclayout/tutorial/models/__init__.py | 12 ++++ .../wiki/src/basiclayout/tutorial/pshell.py | 1 + .../wiki/src/basiclayout/tutorial/routes.py | 2 + .../wiki/src/basiclayout/tutorial/templates/404.pt | 10 ++++ .../src/basiclayout/tutorial/templates/layout.pt | 62 +++++++++++++++++++ .../basiclayout/tutorial/templates/mytemplate.pt | 70 +++------------------- .../wiki/src/basiclayout/tutorial/tests.py | 3 +- .../wiki/src/basiclayout/tutorial/views.py | 7 --- .../src/basiclayout/tutorial/views/__init__.py | 0 .../wiki/src/basiclayout/tutorial/views/default.py | 8 +++ .../src/basiclayout/tutorial/views/notfound.py | 7 +++ 16 files changed, 120 insertions(+), 90 deletions(-) delete mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/models.py create mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/models/__init__.py create mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/routes.py create mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/templates/404.pt create mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt delete mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/views.py create mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/views/__init__.py create mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/views/default.py create mode 100644 docs/tutorials/wiki/src/basiclayout/tutorial/views/notfound.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/basiclayout/MANIFEST.in b/docs/tutorials/wiki/src/basiclayout/MANIFEST.in index 81beba1b1..05cc195d9 100644 --- a/docs/tutorials/wiki/src/basiclayout/MANIFEST.in +++ b/docs/tutorials/wiki/src/basiclayout/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.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/wiki/src/basiclayout/pytest.ini b/docs/tutorials/wiki/src/basiclayout/pytest.ini index 8b76bc410..a3489cdf8 100644 --- a/docs/tutorials/wiki/src/basiclayout/pytest.ini +++ b/docs/tutorials/wiki/src/basiclayout/pytest.ini @@ -1,3 +1,3 @@ [pytest] testpaths = tutorial -python_files = *.py +python_files = test*.py diff --git a/docs/tutorials/wiki/src/basiclayout/setup.py b/docs/tutorials/wiki/src/basiclayout/setup.py index a4f143d24..d6d488ed2 100644 --- a/docs/tutorials/wiki/src/basiclayout/setup.py +++ b/docs/tutorials/wiki/src/basiclayout/setup.py @@ -10,15 +10,15 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'plaster_pastedeploy', - 'pyramid >= 1.9a', + 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'waitress', 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', 'ZODB3', - 'waitress', ] tests_require = [ diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py index f2b3c9568..bd0c71f5b 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py @@ -11,13 +11,13 @@ def root_factory(request): def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' with Configurator(settings=settings) as config: - config.include('pyramid_chameleon') + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') config.set_root_factory(root_factory) - config.add_static_view('static', 'static', cache_max_age=3600) + config.include('pyramid_chameleon') + config.include('.routes') config.scan() - return config.make_wsgi_app() + return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/models.py b/docs/tutorials/wiki/src/basiclayout/tutorial/models.py deleted file mode 100644 index aca6a4129..000000000 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/models.py +++ /dev/null @@ -1,12 +0,0 @@ -from persistent.mapping import PersistentMapping - - -class MyModel(PersistentMapping): - __parent__ = __name__ = None - - -def appmaker(zodb_root): - if 'app_root' not in zodb_root: - app_root = MyModel() - zodb_root['app_root'] = app_root - return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/models/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/models/__init__.py new file mode 100644 index 000000000..aca6a4129 --- /dev/null +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/models/__init__.py @@ -0,0 +1,12 @@ +from persistent.mapping import PersistentMapping + + +class MyModel(PersistentMapping): + __parent__ = __name__ = None + + +def appmaker(zodb_root): + if 'app_root' not in zodb_root: + app_root = MyModel() + zodb_root['app_root'] = app_root + return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/pshell.py b/docs/tutorials/wiki/src/basiclayout/tutorial/pshell.py index 3d026291b..a7cfa6a27 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/pshell.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/pshell.py @@ -1,5 +1,6 @@ from . import models + def setup(env): request = env['request'] diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/routes.py b/docs/tutorials/wiki/src/basiclayout/tutorial/routes.py new file mode 100644 index 000000000..3c0a37992 --- /dev/null +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/routes.py @@ -0,0 +1,2 @@ +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/404.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/404.pt new file mode 100644 index 000000000..07298940c --- /dev/null +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/404.pt @@ -0,0 +1,10 @@ +
+
+ +
+

Pyramid Starter project

+

404 Page Not Found

+
+ +
+
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt new file mode 100644 index 000000000..9fdaef00f --- /dev/null +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/layout.pt @@ -0,0 +1,62 @@ + + + + + + + + + + + Cookiecutter Starter project for the Pyramid Web Framework + + + + + + + + + + + + + +
+
+
+
+ +
+
+
No content
+
+
+ +
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt index d63ea8c45..adac4fe35 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/templates/mytemplate.pt @@ -1,65 +1,11 @@ - - - - - - - - - +
+
- Cookiecutter ZODB project for the Pyramid Web Framework - - - - - - - - - - - - - -
-
-
-
- -
-
-
-

Pyramid ZODB Project

-

Welcome to ${project}, a Pyramid application generated by
Cookiecutter.

-
-
+
+

Pyramid Starter project

+

Welcome to ${project}, a Pyramid + application generated by
Cookiecutter.

- -
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py index ca7a47279..6279d9f66 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/tests.py @@ -11,7 +11,8 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from .views import my_view + from .views.default import my_view request = testing.DummyRequest() info = my_view(request) 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 deleted file mode 100644 index c1878bdd0..000000000 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/views.py +++ /dev/null @@ -1,7 +0,0 @@ -from pyramid.view import view_config -from .models import MyModel - - -@view_config(context=MyModel, renderer='templates/mytemplate.pt') -def my_view(request): - return {'project': 'myproj'} diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/views/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/views/default.py b/docs/tutorials/wiki/src/basiclayout/tutorial/views/default.py new file mode 100644 index 000000000..5d708d15c --- /dev/null +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/views/default.py @@ -0,0 +1,8 @@ +from pyramid.view import view_config + +from ..models import MyModel + + +@view_config(context=MyModel, renderer='../templates/mytemplate.pt') +def my_view(request): + return {'project': 'myproj'} diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/views/notfound.py b/docs/tutorials/wiki/src/basiclayout/tutorial/views/notfound.py new file mode 100644 index 000000000..728791d0a --- /dev/null +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/views/notfound.py @@ -0,0 +1,7 @@ +from pyramid.view import notfound_view_config + + +@notfound_view_config(renderer='../templates/404.pt') +def notfound_view(request): + request.response.status = 404 + return {} -- cgit v1.2.3 From 29d6b3b030b0a0a60415dd3fe7e39c7c9b28b189 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:00:45 -0800 Subject: Clean up application configuration in __init__.py --- docs/tutorials/wiki/basiclayout.rst | 105 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 52 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index 49ee6902e..f2c6dbb37 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -4,80 +4,81 @@ Basic Layout ============ -The starter files generated by selecting the ``zodb`` backend in the -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. +The starter files generated by the 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. Application configuration with ``__init__.py`` ---------------------------------------------- -A directory on disk can be turned into a Python :term:`package` by containing -an ``__init__.py`` file. Even if empty, this marks a directory as a Python -package. We use ``__init__.py`` both as a marker, indicating the directory in -which it's contained is a package, and to contain application configuration -code. +A directory on disk can be turned into a Python :term:`package` by containing an ``__init__.py`` file. +Even if empty, this marks a directory as a Python package. +We use ``__init__.py`` both as a marker, indicating the directory in which it is contained is a package, and to contain application configuration code. -When you run the application using the ``pserve`` command using the -``development.ini`` generated configuration file, the application -configuration points at a :term:`Setuptools` :term:`entry point` described as -``egg:tutorial``. In our application, because the application's ``setup.py`` -file says so, this entry point happens to be the ``main`` function within the -file named ``__init__.py``. +When you run the application using the ``pserve`` command using the ``development.ini`` generated configuration file, the application configuration points at a :term:`Setuptools` :term:`entry point` described as ``egg:tutorial``. +In our application, because the application's ``setup.py`` file says so, this entry point happens to be the ``main`` function within the file named ``__init__.py``. -Open ``tutorial/__init__.py``. It should already contain the following: +Open ``tutorial/__init__.py``. +It should already contain the following: .. literalinclude:: src/basiclayout/tutorial/__init__.py - :linenos: - :language: py + :linenos: + :language: py + +#. *Lines 1-3*. + Perform some dependency imports. + +#. *Lines 6-8*. + Define a :term:`root factory` for our Pyramid application. + +#. *Line 11*. + ``__init__.py`` defines a function named ``main``. -#. *Lines 1-3*. Perform some dependency imports. +#. *Line 14*. + Construct a :term:`Configurator` as a :term:`context manager` with the ``settings`` keyword parsed by :term:`PasteDeploy`. See :term:`Deployment settings`. -#. *Lines 6-8*. Define a :term:`root factory` for our Pyramid application. +#. *Line 15*. + Use an explicit transaction manager for apps so that they do not implicitly create new transactions when touching the manager outside of the ``pyramid_tm`` lifecycle. -#. *Line 11*. ``__init__.py`` defines a function named ``main``. +#. *Line 16*. + Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction `_ package. -#. *Line 14*. Use an explicit transaction manager for apps so that they do not implicitly create new transactions when touching the manager outside of the ``pyramid_tm`` lifecycle. +#. *Line 17*. + Include support for ``pyramid_retry`` to retry a request when transient exceptions occur. -#. *Line 15*. Construct a :term:`Configurator` as a :term:`context manager` with the settings keyword parsed by :term:`PasteDeploy`. +#. *Line 18*. + Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application. -#. *Line 16*. Include support for the :term:`Chameleon` template rendering - bindings, allowing us to use the ``.pt`` templates. +#. *Line 19*. + Set a root factory using our function named ``root_factory``. -#. *Line 17*. Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction `_ package. +#. *Line 20*. + Include support for the :term:`Chameleon` template rendering bindings, allowing us to use the ``.pt`` templates. -#. *Line 18*. Include support for ``pyramid_retry`` to retry a request when transient exceptions occur. +#. *Line 21*. + Include routes from the ``.routes`` module. + This registers a "static view" using the :meth:`pyramid.config.Configurator.add_static_view` method. + This view answers requests whose URL path starts with ``/static``. + This statement registers a view that will serve up static assets, such as CSS and image files. + In this case the URL will answer requests at ``http://localhost:6543/static/`` and below. -#. *Line 19*. Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application. + The first argument is the "name" ``static``, which indicates that the URL path prefix of the view will be ``/static``. -#. *Line 20*. Set a root factory using our function named ``root_factory``. + The second argument of this method is the "path". + It is a relative :term:`asset specification`. + It finds the resources it should serve within the ``static`` directory inside the ``tutorial`` package. + Alternatively the cookiecutter could have used an *absolute* asset specification as the path (``tutorial:static``). -#. *Line 21*. 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 - and image files, for us, in this case, at - ``http://localhost:6543/static/`` and below. The first argument is the - "name" ``static``, which indicates that the URL path prefix of the view - will be ``/static``. The 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 cookiecutter could have used an *absolute* asset - specification as the path (``tutorial:static``). + The third argument is an optional ``cache_max_age`` which specifies the number of seconds the static asset will be HTTP-cached. -#. *Line 22*. 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 cookiecutter could have equivalently said ``config.scan('tutorial')``, but - it chose to omit the package name argument. +#. *Line 22*. + 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. + It 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 cookiecutter could have equivalently said ``config.scan('tutorial')``, but it chose to omit the package name argument. -#. *Line 23*. Use the - :meth:`pyramid.config.Configurator.make_wsgi_app` method - to return a :term:`WSGI` application. +#. *Line 23*. + Use the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application. Resources and models with ``models.py`` --------------------------------------- -- cgit v1.2.3 From 9c1091c692c7c05ae9d6c1b8f9a8f83720ed8401 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:01:15 -0800 Subject: Clean up models, now in a package --- docs/tutorials/wiki/basiclayout.rst | 53 +++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index f2c6dbb37..83225c6e1 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -80,42 +80,37 @@ It should already contain the following: #. *Line 23*. Use the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application. -Resources and models with ``models.py`` ---------------------------------------- - -:app:`Pyramid` uses the word :term:`resource` to describe objects arranged -hierarchically in a :term:`resource tree`. This tree is consulted by -:term:`traversal` to map URLs to code. In this application, the resource -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`` cookiecutter put the classes that implement our -resource objects, each of which also happens to be a domain model object. + +Resources and models with ``models`` package +-------------------------------------------- + +:app:`Pyramid` uses the word :term:`resource` to describe objects arranged hierarchically in a :term:`resource tree`. +This tree is consulted by :term:`traversal` to map URLs to code. +In this application, the resource tree represents the site structure, but it *also* represents the :term:`domain model` of the application. +Each resource is a node stored persistently in a :term:`ZODB` database. +The ``models.py`` file is 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``: -.. literalinclude:: src/basiclayout/tutorial/models.py +.. literalinclude:: src/basiclayout/tutorial/models/__init__.py :linenos: :language: python -#. *Lines 4-5*. The ``MyModel`` :term:`resource` class is implemented here. - Instances of this class are capable of being persisted in :term:`ZODB` - because the class inherits from the - :class:`persistent.mapping.PersistentMapping` class. The ``__parent__`` - and ``__name__`` are important parts of the :term:`traversal` protocol. - By default, set these to ``None`` to indicate that this is the - :term:`root` object. - -#. *Lines 8-12*. ``appmaker`` is used to return the *application - root* object. It is called on *every request* to the - :app:`Pyramid` application. It also performs bootstrapping by - *creating* an application root (inside the ZODB root object) if one - does not already exist. It is used by the ``root_factory`` we've defined - in our ``__init__.py``. +#. *Lines 4-5*. + The ``MyModel`` :term:`resource` class is implemented here. + Instances of this class are capable of being persisted in :term:`ZODB` because the class inherits from the :class:`persistent.mapping.PersistentMapping` class. + The ``__parent__`` and ``__name__`` are important parts of the :term:`traversal` protocol. + By default, set these to ``None`` to indicate that this is the :term:`root` object. + +#. *Lines 8-12*. + ``appmaker`` is used to return the *application root* object. + It is called on *every request* to the :app:`Pyramid` application. + It also performs bootstrapping by *creating* an application root (inside the ZODB root object) if one does not already exist. + It is used by the ``root_factory`` we've defined in our ``__init__.py``. - Bootstrapping is done by first seeing if the database has the persistent - application root. If not, we make an instance, store it, and commit the - transaction. We then return the application root object. + Bootstrapping is done by first seeing if the database has the persistent application root. + If not, we make an instance, store it, and commit the transaction. + We then return the application root object. Views With ``views.py`` ----------------------- -- cgit v1.2.3 From b770c31e5713b33f7d77e22a6dc1ddb530d00b9c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:01:25 -0800 Subject: Clean up views, now in a package --- docs/tutorials/wiki/basiclayout.rst | 96 +++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 51 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index 83225c6e1..a1a1da286 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -112,63 +112,57 @@ Here is the source for ``models.py``: If not, we make an instance, store it, and commit the transaction. We then return the application root object. -Views With ``views.py`` ------------------------ -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/``. +View declarations via the ``views`` package +------------------------------------------- -Here is the source for ``views.py``: +Our cookiecutter generated a default ``views`` package on our behalf. +It contains a two views. +which is used to render the page shown when you visit the URL ``http://localhost:6543/``. -.. literalinclude:: src/basiclayout/tutorial/views.py - :linenos: - :language: python +Open ``tutorial/views/default.py`` in the ``views`` package. +It should already contain the following: + +.. literalinclude:: src/basiclayout/tutorial/views/default.py + :linenos: + :language: python Let's try to understand the components in this module: -#. *Lines 1-2*. Perform some dependency imports. - -#. *Line 5*. Use the :func:`pyramid.view.view_config` :term:`configuration - decoration` to perform a :term:`view configuration` registration. This - view configuration registration will be activated when the application is - started. It will be activated by virtue of it being found as the result - of a :term:`scan` (when Line 14 of ``__init__.py`` is run). - - The ``@view_config`` decorator accepts a number of keyword arguments. We - use two keyword arguments here: ``context`` and ``renderer``. - - The ``context`` argument signifies that the decorated view callable should - only be run when :term:`traversal` finds the ``tutorial.models.MyModel`` - :term:`resource` to be the :term:`context` of a request. In English, this - means that when the URL ``/`` is visited, because ``MyModel`` is the root - model, this view callable will be invoked. - - The ``renderer`` argument names an :term:`asset specification` of - ``templates/mytemplate.pt``. This asset specification points at a - :term:`Chameleon` template which lives in the ``mytemplate.pt`` file - within the ``templates`` directory of the ``tutorial`` package. And - indeed if you look in the ``templates`` directory of this package, you'll - see a ``mytemplate.pt`` template file, which renders the default home page - of the generated project. This asset specification is *relative* (to the - view.py's current package). Alternatively we could have used the - absolute asset specification ``tutorial:templates/mytemplate.pt``, but - chose to use the relative version. - - Since this call to ``@view_config`` doesn't pass a ``name`` argument, the - ``my_view`` function which it decorates represents the "default" view - callable used when the context is of the type ``MyModel``. - -#. *Lines 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`` 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. - - The function returns the dictionary ``{'project':'tutorial'}``. This - dictionary is used by the template named by the ``mytemplate.pt`` asset - specification to fill in certain values on the page. +#. *Lines 1-3*. + Perform some dependency imports. + +#. *Line 6*. + Use the :func:`pyramid.view.view_config` :term:`configuration decoration` to perform a :term:`view configuration` registration. + This view configuration registration will be activated when the application is started. + Remember in our application's ``__init__.py`` when we executed the :meth:`pyramid.config.Configurator.scan` method ``config.scan()``? + By calling the scan method, Pyramid's configurator will find and process this ``@view_config`` decorator, and 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 ``@view_config`` decorator accepts a number of keyword arguments. + We use two keyword arguments here: ``context`` and ``renderer``. + + The ``context`` argument signifies that the decorated view callable ``my_view`` should only be run when :term:`traversal` finds the ``tutorial.models.MyModel`` :term:`resource` as the :term:`context` of a request. + In English this means that when the URL ``/`` is visited, and because ``MyModel`` is the root model, this view callable will be invoked. + + The ``renderer`` argument names an :term:`asset specification` of ``templates/mytemplate.pt``. + This asset specification points at a :term:`Chameleon` template which lives in the ``mytemplate.pt`` file within the ``templates`` directory of the ``tutorial`` package. + And indeed if you look in the ``templates`` directory of this package, you will see a ``mytemplate.pt`` template file + This template renders the default home page of the generated project. + This asset specification is *relative* to the ``views`` package. + Alternatively we could have used the absolute asset specification ``tutorial:templates/mytemplate.pt``. + + Since this call to ``@view_config`` doesn't pass a ``name`` argument, the ``my_view`` function which it decorates represents the "default" view callable used when the context is of the type ``MyModel``. + +#. *Lines 7-8*. + A :term:`view callable` named ``my_view`` is defined, which is decorated in the step above. + This view callable is a *function* generated by the cookiecutter. + It is given a single argument, ``request``. + This is the standard call signature for a Pyramid :term:`view callable`. + The function returns the dictionary ``{'project': 'myproj'}``. + This dictionary is used by the template named by the ``mytemplate.pt`` asset specification to fill in certain values on the page. + Configuration in ``development.ini`` ------------------------------------ -- cgit v1.2.3 From a4b1059b4c92f8b25486159cc650a8a94cd62772 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:33:46 -0800 Subject: Rewrite application configuration to mirror the URL-dispatch + SQLAlchemy wiki style --- docs/tutorials/wiki/basiclayout.rst | 160 +++++++++++++++++++++++++++--------- 1 file changed, 120 insertions(+), 40 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index a1a1da286..33e0b4ff3 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -24,62 +24,132 @@ It should already contain the following: :linenos: :language: py -#. *Lines 1-3*. - Perform some dependency imports. +Let's go over this piece-by-piece. +First we need some imports to support later code. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :end-before: root_factory + :lineno-match: + :language: py + +Define a :term:`root factory` for our Pyramid application. +It establishes a connection to ZODB database. +It returns an ``appmaker``, which we will describe in the next section :ref:`wiki-resources-and-models`. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :pyobject: root_factory + :lineno-match: + :language: py + +``__init__.py`` defines a function named ``main``. +Here is the entirety of the ``main`` function that we have defined in our ``__init__.py``: + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :pyobject: main + :lineno-match: + :language: py + +When you invoke the ``pserve development.ini`` command, the ``main`` function above is executed. +It accepts some settings and returns a :term:`WSGI` application. +See :ref:`startup_chapter` for more about ``pserve``. + +Next in ``main``, construct a :term:`Configurator` object using a context manager. +See also :term:`Deployment settings`. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 14 + :lineno-match: + :language: py + +``settings`` is passed to the ``Configurator`` as a keyword argument with the dictionary values passed as the ``**settings`` argument. +This will be a dictionary of settings parsed from the ``.ini`` file, which contains +deployment-related values, such as ``pyramid.reload_templates``, ``zodbconn.uri``, and so on. + +Next use an explicit transaction manager for our application. +This prevents new transactions from being implicitly created when touching the manager outside of the ``pyramid_tm`` lifecycle. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 15 + :lineno-match: + :language: py + +Next include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction `_ package. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 16 + :lineno-match: + :language: py + +Next include support for ``pyramid_retry`` to retry a request when transient exceptions occur. -#. *Lines 6-8*. - Define a :term:`root factory` for our Pyramid application. +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 17 + :lineno-match: + :language: py -#. *Line 11*. - ``__init__.py`` defines a function named ``main``. +Next include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 18 + :lineno-match: + :language: py -#. *Line 14*. - Construct a :term:`Configurator` as a :term:`context manager` with the ``settings`` keyword parsed by :term:`PasteDeploy`. See :term:`Deployment settings`. +Next set a root factory using our function named ``root_factory``. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 19 + :lineno-match: + :language: py + +Next include support for the :term:`Chameleon` template rendering bindings, allowing us to use the ``.pt`` templates. + +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 20 + :lineno-match: + :language: py -#. *Line 15*. - Use an explicit transaction manager for apps so that they do not implicitly create new transactions when touching the manager outside of the ``pyramid_tm`` lifecycle. +Next include routes from the ``.routes`` module. -#. *Line 16*. - Include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction `_ package. +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 21 + :lineno-match: + :language: py -#. *Line 17*. - Include support for ``pyramid_retry`` to retry a request when transient exceptions occur. +This registers a "static view" using the :meth:`pyramid.config.Configurator.add_static_view` method. +This view answers requests whose URL path starts with ``/static``. +This statement registers a view that will serve up static assets, such as CSS and image files. +In this case the URL will answer requests at ``http://localhost:6543/static/`` and below. -#. *Line 18*. - Include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application. +The first argument is the "name" ``static``, which indicates that the URL path prefix of the view will be ``/static``. -#. *Line 19*. - Set a root factory using our function named ``root_factory``. +The second argument of this method is the "path". +It is a relative :term:`asset specification`. +It finds the resources it should serve within the ``static`` directory inside the ``tutorial`` package. +Alternatively the cookiecutter could have used an *absolute* asset specification as the path (``tutorial:static``). -#. *Line 20*. - Include support for the :term:`Chameleon` template rendering bindings, allowing us to use the ``.pt`` templates. +The third argument is an optional ``cache_max_age`` which specifies the number of seconds the static asset will be HTTP-cached. -#. *Line 21*. - Include routes from the ``.routes`` module. - This registers a "static view" using the :meth:`pyramid.config.Configurator.add_static_view` method. - This view answers requests whose URL path starts with ``/static``. - This statement registers a view that will serve up static assets, such as CSS and image files. - In this case the URL will answer requests at ``http://localhost:6543/static/`` and below. +Next perform a :term:`scan`. - The first argument is the "name" ``static``, which indicates that the URL path prefix of the view will be ``/static``. +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 22 + :lineno-match: + :language: py - The second argument of this method is the "path". - It is a relative :term:`asset specification`. - It finds the resources it should serve within the ``static`` directory inside the ``tutorial`` package. - Alternatively the cookiecutter could have used an *absolute* asset specification as the path (``tutorial:static``). +A scan will find :term:`configuration decoration`, such as view configuration decorators (e.g., ``@view_config``) in the source code of the ``tutorial`` package. +It 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 cookiecutter could have equivalently said ``config.scan('tutorial')``, but it chose to omit the package name argument. - The third argument is an optional ``cache_max_age`` which specifies the number of seconds the static asset will be HTTP-cached. +Finally use the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application. -#. *Line 22*. - 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. - It 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 cookiecutter could have equivalently said ``config.scan('tutorial')``, but it chose to omit the package name argument. +.. literalinclude:: src/basiclayout/tutorial/__init__.py + :lines: 23 + :lineno-match: + :language: py -#. *Line 23*. - Use the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application. +.. _wiki-resources-and-models: Resources and models with ``models`` package -------------------------------------------- @@ -163,6 +233,16 @@ Let's try to understand the components in this module: The function returns the dictionary ``{'project': 'myproj'}``. This dictionary is used by the template named by the ``mytemplate.pt`` asset specification to fill in certain values on the page. +Now let us open the ``notfound.py`` module, and describe its function. + +.. literalinclude:: src/basiclayout/tutorial/views/notfound.py + :linenos: + :language: python + +Without repeating ourselves, we will point out the differences between this view and the previous. + +#. + Configuration in ``development.ini`` ------------------------------------ -- cgit v1.2.3 From dd2aefc04435b65d67163c432409b4f76685b93a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:36:31 -0800 Subject: Clean up grammar in models section --- docs/tutorials/wiki/basiclayout.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index 33e0b4ff3..7e6e86143 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -170,16 +170,16 @@ Here is the source for ``models.py``: The ``MyModel`` :term:`resource` class is implemented here. Instances of this class are capable of being persisted in :term:`ZODB` because the class inherits from the :class:`persistent.mapping.PersistentMapping` class. The ``__parent__`` and ``__name__`` are important parts of the :term:`traversal` protocol. - By default, set these to ``None`` to indicate that this is the :term:`root` object. + By default, these are set to ``None`` to indicate that this is the :term:`root` object. #. *Lines 8-12*. ``appmaker`` is used to return the *application root* object. It is called on *every request* to the :app:`Pyramid` application. It also performs bootstrapping by *creating* an application root (inside the ZODB root object) if one does not already exist. - It is used by the ``root_factory`` we've defined in our ``__init__.py``. + It is used by the ``root_factory`` we have defined in our ``__init__.py``. Bootstrapping is done by first seeing if the database has the persistent application root. - If not, we make an instance, store it, and commit the transaction. + If not, then we make an instance, store it, and commit the transaction. We then return the application root object. -- cgit v1.2.3 From 28f659844f0f3520a8bedf4d318970b039bf9734 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:42:18 -0800 Subject: Remove redundancy in appmaker narrative --- docs/tutorials/wiki/basiclayout.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index 7e6e86143..39e15bb58 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -174,12 +174,12 @@ Here is the source for ``models.py``: #. *Lines 8-12*. ``appmaker`` is used to return the *application root* object. - It is called on *every request* to the :app:`Pyramid` application. + It is called on *every request* to the :app:`Pyramid` application by virtue of the ``root_factory`` defined in our ``__init__.py``. It also performs bootstrapping by *creating* an application root (inside the ZODB root object) if one does not already exist. - It is used by the ``root_factory`` we have defined in our ``__init__.py``. - + Bootstrapping is done by first seeing if the database has the persistent application root. If not, then we make an instance, store it, and commit the transaction. + We then return the application root object. -- cgit v1.2.3 From 4ccf01a091485463bfae1129ed858546b6a93da6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:54:09 -0800 Subject: Add notfound_view function description and 404.pt template. --- docs/tutorials/wiki/basiclayout.rst | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index 39e15bb58..3f84f12c3 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -188,8 +188,8 @@ View declarations via the ``views`` package Our cookiecutter generated a default ``views`` package on our behalf. It contains a two views. -which is used to render the page shown when you visit the URL ``http://localhost:6543/``. +The first view is used to render the page shown when you visit the URL ``http://localhost:6543/``. Open ``tutorial/views/default.py`` in the ``views`` package. It should already contain the following: @@ -233,7 +233,7 @@ Let's try to understand the components in this module: The function returns the dictionary ``{'project': 'myproj'}``. This dictionary is used by the template named by the ``mytemplate.pt`` asset specification to fill in certain values on the page. -Now let us open the ``notfound.py`` module, and describe its function. +Let us open ``tutorial/views/default.py`` in the ``views`` package to look at the second view. .. literalinclude:: src/basiclayout/tutorial/views/notfound.py :linenos: @@ -241,7 +241,16 @@ Now let us open the ``notfound.py`` module, and describe its function. Without repeating ourselves, we will point out the differences between this view and the previous. -#. +#. *Line 4*. + The ``notfound_view`` function is decorated with ``@notfound_view_config``. + This decorator registers a :term:`Not Found View` using :meth:`pyramid.config.Configurator.add_notfound_view`. + + The ``renderer`` argument names an :term:`asset specification` of ``templates/404.pt``. + +#. *Lines 5-7*. + A :term:`view callable` named ``notfound_view`` is defined, which is decorated in the step above. + It sets the HTTP response status code to ``404``. + The function returns an empty dictionary to the template ``404.pt``, which accepts no parameters anyway. Configuration in ``development.ini`` -- cgit v1.2.3 From d42b654b1dda5e0e80c25c2cb8b8836ad538d60c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 18:57:26 -0800 Subject: Clean up configuration for development.ini --- docs/tutorials/wiki/basiclayout.rst | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index 3f84f12c3..ab9b7df5c 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -256,15 +256,11 @@ Without repeating ourselves, we will point out the differences between this view 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 -Note the existence of a ``[app:main]`` section which specifies our WSGI -application. Our ZODB database settings are specified as the -``zodbconn.uri`` setting within this section. This value, and the other -values within this section, are passed as ``**settings`` to the ``main`` -function we defined in ``__init__.py`` when the server is started via -``pserve``. +Note the existence of a ``[app:main]`` section which specifies our WSGI application. +Our ZODB database settings are specified as the ``zodbconn.uri`` setting within this section. +When the server is started via ``pserve``, the values within this section are passed as ``**settings`` to the ``main`` function defined in ``__init__.py``. -- cgit v1.2.3 From 3a06b648ca0fe2bb29b9c2ca167e95560f19a742 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 23 Nov 2018 19:05:17 -0800 Subject: Clean up introduction and delete the database sections of definingmodels.rst --- docs/tutorials/wiki/definingmodels.rst | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst index e973cfdfe..3f1cdf007 100644 --- a/docs/tutorials/wiki/definingmodels.rst +++ b/docs/tutorials/wiki/definingmodels.rst @@ -4,30 +4,26 @@ Defining the Domain Model ========================= -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. +Let's make changes to our stock cookiecutter-generated application. +We will 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 will do this inside our ``models.py`` file. -Because we're using :term:`ZODB` to represent our -:term:`resource tree`, each of these resource constructors represents a -:term:`domain model` object, so we'll call these constructors "model -constructors". Both our Page and Wiki constructors will be class objects. A -single instance of the "Wiki" class will serve as a container for "Page" -objects, which will be instances of the "Page" class. +Because we are using :term:`ZODB` to represent our :term:`resource tree`, each of these resource constructors represents a :term:`domain model` object. +We will call these constructors "model constructors". +Both our Page and Wiki constructors will be class objects. +A single instance of the "Wiki" class will serve as a container for "Page" objects, which will be instances of the "Page" class. Delete the database ------------------- -In the next step, we're going to remove the ``MyModel`` Python model -class from our ``models.py`` file. Since this class is referred to within -our persistent storage (represented on disk as a file named ``Data.fs``), -we'll have strange things happen the next time we want to visit the -application in a browser. Remove the ``Data.fs`` from the ``tutorial`` -directory before proceeding any further. It's always fine to do this as long -as you don't care about the content of the database; the database itself will -be recreated as necessary. +In the next step, we will remove the ``MyModel`` Python model class from our ``models`` package. +Since this class is referred to within our persistent storage (represented on disk as a file named ``Data.fs``), we will have strange things happen the next time we want to visit the application in a browser. + +Remove the ``Data.fs`` from the ``tutorial`` directory before proceeding any further. +It is always fine to do this as long as you don't care about the content of the database. +The database itself will be recreated as necessary. + Edit ``models.py`` ------------------ -- cgit v1.2.3 From 2296426292ad92e7a56ded4cef55a15b7cefdb7d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 04:09:25 -0800 Subject: Synch up src/models files --- docs/tutorials/wiki/src/models/MANIFEST.in | 2 +- docs/tutorials/wiki/src/models/pytest.ini | 2 +- docs/tutorials/wiki/src/models/setup.py | 4 +- .../tutorials/wiki/src/models/tutorial/__init__.py | 8 +-- docs/tutorials/wiki/src/models/tutorial/models.py | 20 ------- .../wiki/src/models/tutorial/models/__init__.py | 20 +++++++ docs/tutorials/wiki/src/models/tutorial/pshell.py | 1 + docs/tutorials/wiki/src/models/tutorial/routes.py | 2 + .../wiki/src/models/tutorial/templates/404.pt | 10 ++++ .../wiki/src/models/tutorial/templates/layout.pt | 62 +++++++++++++++++++ .../src/models/tutorial/templates/mytemplate.pt | 70 +++------------------- docs/tutorials/wiki/src/models/tutorial/tests.py | 3 +- docs/tutorials/wiki/src/models/tutorial/views.py | 7 --- .../wiki/src/models/tutorial/views/__init__.py | 0 .../wiki/src/models/tutorial/views/default.py | 8 +++ .../wiki/src/models/tutorial/views/notfound.py | 7 +++ 16 files changed, 128 insertions(+), 98 deletions(-) delete mode 100644 docs/tutorials/wiki/src/models/tutorial/models.py create mode 100644 docs/tutorials/wiki/src/models/tutorial/models/__init__.py create mode 100644 docs/tutorials/wiki/src/models/tutorial/routes.py create mode 100644 docs/tutorials/wiki/src/models/tutorial/templates/404.pt create mode 100644 docs/tutorials/wiki/src/models/tutorial/templates/layout.pt delete mode 100644 docs/tutorials/wiki/src/models/tutorial/views.py create mode 100644 docs/tutorials/wiki/src/models/tutorial/views/__init__.py create mode 100644 docs/tutorials/wiki/src/models/tutorial/views/default.py create mode 100644 docs/tutorials/wiki/src/models/tutorial/views/notfound.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/models/MANIFEST.in b/docs/tutorials/wiki/src/models/MANIFEST.in index 81beba1b1..05cc195d9 100644 --- a/docs/tutorials/wiki/src/models/MANIFEST.in +++ b/docs/tutorials/wiki/src/models/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.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/wiki/src/models/pytest.ini b/docs/tutorials/wiki/src/models/pytest.ini index 8b76bc410..a3489cdf8 100644 --- a/docs/tutorials/wiki/src/models/pytest.ini +++ b/docs/tutorials/wiki/src/models/pytest.ini @@ -1,3 +1,3 @@ [pytest] testpaths = tutorial -python_files = *.py +python_files = test*.py diff --git a/docs/tutorials/wiki/src/models/setup.py b/docs/tutorials/wiki/src/models/setup.py index a4f143d24..d6d488ed2 100644 --- a/docs/tutorials/wiki/src/models/setup.py +++ b/docs/tutorials/wiki/src/models/setup.py @@ -10,15 +10,15 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'plaster_pastedeploy', - 'pyramid >= 1.9a', + 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'waitress', 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', 'ZODB3', - 'waitress', ] tests_require = [ diff --git a/docs/tutorials/wiki/src/models/tutorial/__init__.py b/docs/tutorials/wiki/src/models/tutorial/__init__.py index f2b3c9568..bd0c71f5b 100644 --- a/docs/tutorials/wiki/src/models/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/models/tutorial/__init__.py @@ -11,13 +11,13 @@ def root_factory(request): def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' with Configurator(settings=settings) as config: - config.include('pyramid_chameleon') + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') config.set_root_factory(root_factory) - config.add_static_view('static', 'static', cache_max_age=3600) + config.include('pyramid_chameleon') + config.include('.routes') config.scan() - return config.make_wsgi_app() + return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/models/tutorial/models.py b/docs/tutorials/wiki/src/models/tutorial/models.py deleted file mode 100644 index 7c6597afa..000000000 --- a/docs/tutorials/wiki/src/models/tutorial/models.py +++ /dev/null @@ -1,20 +0,0 @@ -from persistent import Persistent -from persistent.mapping import PersistentMapping - -class Wiki(PersistentMapping): - __name__ = None - __parent__ = None - -class Page(Persistent): - def __init__(self, data): - self.data = data - -def appmaker(zodb_root): - if 'app_root' not in zodb_root: - app_root = Wiki() - frontpage = Page('This is the front page') - app_root['FrontPage'] = frontpage - frontpage.__name__ = 'FrontPage' - frontpage.__parent__ = app_root - zodb_root['app_root'] = app_root - return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/models/tutorial/models/__init__.py b/docs/tutorials/wiki/src/models/tutorial/models/__init__.py new file mode 100644 index 000000000..7c6597afa --- /dev/null +++ b/docs/tutorials/wiki/src/models/tutorial/models/__init__.py @@ -0,0 +1,20 @@ +from persistent import Persistent +from persistent.mapping import PersistentMapping + +class Wiki(PersistentMapping): + __name__ = None + __parent__ = None + +class Page(Persistent): + def __init__(self, data): + self.data = data + +def appmaker(zodb_root): + if 'app_root' not in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/models/tutorial/pshell.py b/docs/tutorials/wiki/src/models/tutorial/pshell.py index 3d026291b..a7cfa6a27 100644 --- a/docs/tutorials/wiki/src/models/tutorial/pshell.py +++ b/docs/tutorials/wiki/src/models/tutorial/pshell.py @@ -1,5 +1,6 @@ from . import models + def setup(env): request = env['request'] diff --git a/docs/tutorials/wiki/src/models/tutorial/routes.py b/docs/tutorials/wiki/src/models/tutorial/routes.py new file mode 100644 index 000000000..3c0a37992 --- /dev/null +++ b/docs/tutorials/wiki/src/models/tutorial/routes.py @@ -0,0 +1,2 @@ +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/404.pt b/docs/tutorials/wiki/src/models/tutorial/templates/404.pt new file mode 100644 index 000000000..07298940c --- /dev/null +++ b/docs/tutorials/wiki/src/models/tutorial/templates/404.pt @@ -0,0 +1,10 @@ +
+
+ +
+

Pyramid Starter project

+

404 Page Not Found

+
+ +
+
diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/models/tutorial/templates/layout.pt new file mode 100644 index 000000000..9fdaef00f --- /dev/null +++ b/docs/tutorials/wiki/src/models/tutorial/templates/layout.pt @@ -0,0 +1,62 @@ + + + + + + + + + + + Cookiecutter Starter project for the Pyramid Web Framework + + + + + + + + + + + + + +
+
+
+
+ +
+
+
No content
+
+
+ +
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt index d63ea8c45..adac4fe35 100644 --- a/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt +++ b/docs/tutorials/wiki/src/models/tutorial/templates/mytemplate.pt @@ -1,65 +1,11 @@ - - - - - - - - - +
+
- Cookiecutter ZODB project for the Pyramid Web Framework - - - - - - - - - - - - - -
-
-
-
- -
-
-
-

Pyramid ZODB Project

-

Welcome to ${project}, a Pyramid application generated by
Cookiecutter.

-
-
+
+

Pyramid Starter project

+

Welcome to ${project}, a Pyramid + application generated by
Cookiecutter.

- -
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/models/tutorial/tests.py b/docs/tutorials/wiki/src/models/tutorial/tests.py index ca7a47279..6279d9f66 100644 --- a/docs/tutorials/wiki/src/models/tutorial/tests.py +++ b/docs/tutorials/wiki/src/models/tutorial/tests.py @@ -11,7 +11,8 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from .views import my_view + from .views.default import my_view request = testing.DummyRequest() info = my_view(request) 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 deleted file mode 100644 index c1878bdd0..000000000 --- a/docs/tutorials/wiki/src/models/tutorial/views.py +++ /dev/null @@ -1,7 +0,0 @@ -from pyramid.view import view_config -from .models import MyModel - - -@view_config(context=MyModel, renderer='templates/mytemplate.pt') -def my_view(request): - return {'project': 'myproj'} diff --git a/docs/tutorials/wiki/src/models/tutorial/views/__init__.py b/docs/tutorials/wiki/src/models/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/wiki/src/models/tutorial/views/default.py b/docs/tutorials/wiki/src/models/tutorial/views/default.py new file mode 100644 index 000000000..5d708d15c --- /dev/null +++ b/docs/tutorials/wiki/src/models/tutorial/views/default.py @@ -0,0 +1,8 @@ +from pyramid.view import view_config + +from ..models import MyModel + + +@view_config(context=MyModel, renderer='../templates/mytemplate.pt') +def my_view(request): + return {'project': 'myproj'} diff --git a/docs/tutorials/wiki/src/models/tutorial/views/notfound.py b/docs/tutorials/wiki/src/models/tutorial/views/notfound.py new file mode 100644 index 000000000..728791d0a --- /dev/null +++ b/docs/tutorials/wiki/src/models/tutorial/views/notfound.py @@ -0,0 +1,7 @@ +from pyramid.view import notfound_view_config + + +@notfound_view_config(renderer='../templates/404.pt') +def notfound_view(request): + request.response.status = 404 + return {} -- cgit v1.2.3 From 3f6ea7a313943ff69b4b66210ed299ed01bac3ed Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 04:09:56 -0800 Subject: Update models and view application sections --- docs/tutorials/wiki/definingmodels.rst | 114 +++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 47 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst index 3f1cdf007..81dd25862 100644 --- a/docs/tutorials/wiki/definingmodels.rst +++ b/docs/tutorials/wiki/definingmodels.rst @@ -25,65 +25,85 @@ It is always fine to do this as long as you don't care about the content of the The database itself will be recreated as necessary. -Edit ``models.py`` ------------------- +Edit ``models`` package +----------------------- .. note:: - There is nothing special about the filename ``models.py``. A - project may have many models throughout its codebase in arbitrarily named - files. Files implementing models often have ``model`` in their filenames - or they may live in a Python subpackage of your application package named - ``models``, but this is only by convention. + There is nothing special about the package name ``models``. + A project may have many models throughout its codebase in arbitrarily named files and directories. + Files that implement models often have ``model`` in their names, or they may live in a Python subpackage of your application package named ``models``, but this is only by convention. -Open ``tutorial/models.py`` file and edit it to look like the following: +Open ``tutorial/models/__init__.py`` file and edit it to look like the following: -.. literalinclude:: src/models/tutorial/models.py +.. literalinclude:: src/models/tutorial/models/__init__.py :linenos: :language: python -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 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. - -Our ``Wiki`` class should have two attributes set to ``None`` at -class scope: ``__parent__`` and ``__name__``. If a model has a -``__parent__`` attribute of ``None`` in a traversal-based :app:`Pyramid` -application, it means that it's the :term:`root` model. The ``__name__`` -of the root model is also always ``None``. - -Then we'll add a ``Page`` class. This class should inherit from the -:class:`persistent.Persistent` class. We'll also give it an ``__init__`` -method that accepts a single parameter named ``data``. This parameter will -contain the :term:`reStructuredText` body representing the wiki page content. -Note that ``Page`` objects don't have an initial ``__name__`` or -``__parent__`` attribute. All objects in a traversal graph must have a -``__name__`` and a ``__parent__`` attribute. We don't specify these here -because both ``__name__`` and ``__parent__`` will be set by a :term:`view` -function when a Page is added to our Wiki mapping. - -As a last step, we want to change the ``appmaker`` function in our -``models.py`` file so that the :term:`root` :term:`resource` of our -application is a Wiki instance. We'll also slot a single page object (the -front page) into the Wiki within the ``appmaker``. This will provide -:term:`traversal` a :term:`resource tree` to work against when it attempts to -resolve URLs to resources. +Remove the ``MyModel`` class from the generated ``models/__init__.py`` file. +The ``MyModel`` class is only a sample and we're not going to use it. + +Next we add an import at the top for the :class:`persistent.Persistent` class. +We will use this for a new ``Page`` class in a moment. + +.. literalinclude:: src/models/tutorial/models/__init__.py + :lines: 1-2 + :lineno-match: + :emphasize-lines: 1 + :language: py + +Then we add a ``Wiki`` class. + +.. literalinclude:: src/models/tutorial/models/__init__.py + :lines: 4-6 + :lineno-match: + :language: py + +We want it to inherit from the :class:`persistent.mapping.PersistentMapping` class because it provides mapping behavior. +It also makes sure that our ``Wiki`` page is stored as a "first-class" persistent object in our ZODB database. + +Our ``Wiki`` class should have two attributes set to ``None`` at class scope: ``__parent__`` and ``__name__``. +If a model has a ``__parent__`` attribute of ``None`` in a traversal-based :app:`Pyramid` application, it means that it is the :term:`root` model. +The ``__name__`` of the root model is also always ``None``. + +Now we add a ``Page`` class. + +.. literalinclude:: src/models/tutorial/models/__init__.py + :lines: 8-10 + :lineno-match: + :language: py + +This class should inherit from the :class:`persistent.Persistent` class. +We will give it an ``__init__`` method that accepts a single parameter named ``data``. +This parameter will contain the :term:`reStructuredText` body representing the wiki page content. + +Note that ``Page`` objects don't have an initial ``__name__`` or ``__parent__`` attribute. +All objects in a traversal graph must have a ``__name__`` and a ``__parent__`` attribute. +We do not specify these here. +Instead both ``__name__`` and ``__parent__`` will be set by a :term:`view` function when a ``Page`` is added to our ``Wiki`` mapping. +We will create this function in the next chapter. + +As a last step, edit the ``appmaker`` function. + +.. literalinclude:: src/models/tutorial/models/__init__.py + :lines: 12-20 + :lineno-match: + :emphasize-lines: 4-8 + :language: py + +The :term:`root` :term:`resource` of our application is a Wiki instance. + +We will also slot a single page object (the front page) into the Wiki within the ``appmaker``. +This will provide :term:`traversal` a :term:`resource tree` to work against when it attempts to resolve URLs to resources. + 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 -application successfully. If you try to start the application (See -:ref:`wiki-start-the-application`), you'll wind -up with a Python traceback on your console that ends with this exception: +We cannot. +At this point, our system is in a "non-runnable" state +We will need to change view-related files in the next chapter to be able to start the application successfully. +If you try to start the application (See :ref:`wiki-start-the-application`), you will wind up with a Python traceback on your console that ends with this exception: .. code-block:: text -- cgit v1.2.3 From 19553330cccff6f81a7f4db766525a0bacf9a76c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 04:17:18 -0800 Subject: rewrap introduction, spell out contractions --- docs/tutorials/wiki/definingviews.rst | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index d584a1b41..9bafa87c7 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -4,31 +4,22 @@ Defining Views ============== -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. +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. .. note:: - A :app:`Pyramid` view can also be defined as callable - which accepts *only* a :term:`request` argument. You'll see - 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, - 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 - it represents the persistent storage of our application. For - this reason, in this tutorial we define views as callables that - accept ``context`` in the callable argument list. If you do - need the ``context`` within a view function that only takes - the request as a single argument, you can obtain it via - ``request.context``. - -We're going to define several :term:`view callable` functions, then wire them -into :app:`Pyramid` using some :term:`view configuration`. + A :app:`Pyramid` view can also be defined as callable which accepts *only* a :term:`request` argument. + You will see 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, URLs are mapped to a context :term:`resource`. + Since our :term:`resource tree` also represents our application's "domain model", we are often interested in the context because it represents the persistent storage of our application. + For this reason, in this tutorial we define views as callables that accept ``context`` in the callable argument list. + If you do need the ``context`` within a view function that only takes the request as a single argument, you can obtain it via ``request.context``. + +We will define several :term:`view callable` functions, then wire them into :app:`Pyramid` using some :term:`view configuration`. Declaring Dependencies in Our ``setup.py`` File -- cgit v1.2.3 From 5a2a68d508c3c433dcb6a8ed5824bd99a0b6d8d4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 04:18:14 -0800 Subject: Synch non-view and non-template src/views files --- docs/tutorials/wiki/src/views/MANIFEST.in | 2 +- docs/tutorials/wiki/src/views/pytest.ini | 2 +- docs/tutorials/wiki/src/views/setup.py | 4 ++-- docs/tutorials/wiki/src/views/tutorial/__init__.py | 8 ++++---- docs/tutorials/wiki/src/views/tutorial/models.py | 20 -------------------- .../wiki/src/views/tutorial/models/__init__.py | 20 ++++++++++++++++++++ docs/tutorials/wiki/src/views/tutorial/pshell.py | 1 + docs/tutorials/wiki/src/views/tutorial/routes.py | 2 ++ docs/tutorials/wiki/src/views/tutorial/tests.py | 3 ++- 9 files changed, 33 insertions(+), 29 deletions(-) delete mode 100644 docs/tutorials/wiki/src/views/tutorial/models.py create mode 100644 docs/tutorials/wiki/src/views/tutorial/models/__init__.py create mode 100644 docs/tutorials/wiki/src/views/tutorial/routes.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/views/MANIFEST.in b/docs/tutorials/wiki/src/views/MANIFEST.in index 81beba1b1..05cc195d9 100644 --- a/docs/tutorials/wiki/src/views/MANIFEST.in +++ b/docs/tutorials/wiki/src/views/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.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/wiki/src/views/pytest.ini b/docs/tutorials/wiki/src/views/pytest.ini index 8b76bc410..a3489cdf8 100644 --- a/docs/tutorials/wiki/src/views/pytest.ini +++ b/docs/tutorials/wiki/src/views/pytest.ini @@ -1,3 +1,3 @@ [pytest] testpaths = tutorial -python_files = *.py +python_files = test*.py diff --git a/docs/tutorials/wiki/src/views/setup.py b/docs/tutorials/wiki/src/views/setup.py index 3c19db7b9..6f3cae397 100644 --- a/docs/tutorials/wiki/src/views/setup.py +++ b/docs/tutorials/wiki/src/views/setup.py @@ -10,15 +10,15 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'plaster_pastedeploy', - 'pyramid >= 1.9a', + 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'waitress', 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', 'ZODB3', - 'waitress', 'docutils', ] diff --git a/docs/tutorials/wiki/src/views/tutorial/__init__.py b/docs/tutorials/wiki/src/views/tutorial/__init__.py index f2b3c9568..bd0c71f5b 100644 --- a/docs/tutorials/wiki/src/views/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/views/tutorial/__init__.py @@ -11,13 +11,13 @@ def root_factory(request): def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' with Configurator(settings=settings) as config: - config.include('pyramid_chameleon') + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') config.set_root_factory(root_factory) - config.add_static_view('static', 'static', cache_max_age=3600) + config.include('pyramid_chameleon') + config.include('.routes') config.scan() - return config.make_wsgi_app() + return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/views/tutorial/models.py b/docs/tutorials/wiki/src/views/tutorial/models.py deleted file mode 100644 index 7c6597afa..000000000 --- a/docs/tutorials/wiki/src/views/tutorial/models.py +++ /dev/null @@ -1,20 +0,0 @@ -from persistent import Persistent -from persistent.mapping import PersistentMapping - -class Wiki(PersistentMapping): - __name__ = None - __parent__ = None - -class Page(Persistent): - def __init__(self, data): - self.data = data - -def appmaker(zodb_root): - if 'app_root' not in zodb_root: - app_root = Wiki() - frontpage = Page('This is the front page') - app_root['FrontPage'] = frontpage - frontpage.__name__ = 'FrontPage' - frontpage.__parent__ = app_root - zodb_root['app_root'] = app_root - return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/views/tutorial/models/__init__.py b/docs/tutorials/wiki/src/views/tutorial/models/__init__.py new file mode 100644 index 000000000..7c6597afa --- /dev/null +++ b/docs/tutorials/wiki/src/views/tutorial/models/__init__.py @@ -0,0 +1,20 @@ +from persistent import Persistent +from persistent.mapping import PersistentMapping + +class Wiki(PersistentMapping): + __name__ = None + __parent__ = None + +class Page(Persistent): + def __init__(self, data): + self.data = data + +def appmaker(zodb_root): + if 'app_root' not in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/views/tutorial/pshell.py b/docs/tutorials/wiki/src/views/tutorial/pshell.py index 3d026291b..a7cfa6a27 100644 --- a/docs/tutorials/wiki/src/views/tutorial/pshell.py +++ b/docs/tutorials/wiki/src/views/tutorial/pshell.py @@ -1,5 +1,6 @@ from . import models + def setup(env): request = env['request'] diff --git a/docs/tutorials/wiki/src/views/tutorial/routes.py b/docs/tutorials/wiki/src/views/tutorial/routes.py new file mode 100644 index 000000000..3c0a37992 --- /dev/null +++ b/docs/tutorials/wiki/src/views/tutorial/routes.py @@ -0,0 +1,2 @@ +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) diff --git a/docs/tutorials/wiki/src/views/tutorial/tests.py b/docs/tutorials/wiki/src/views/tutorial/tests.py index ca7a47279..6279d9f66 100644 --- a/docs/tutorials/wiki/src/views/tutorial/tests.py +++ b/docs/tutorials/wiki/src/views/tutorial/tests.py @@ -11,7 +11,8 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from .views import my_view + from .views.default import my_view request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], 'myproj') + -- cgit v1.2.3 From dc97176989ab06d260f1561e89681b607c1b9fc9 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 04:31:43 -0800 Subject: Clean up introduction to views, synch views files --- docs/tutorials/wiki/definingviews.rst | 49 ++++++++---------- .../wiki/src/views/tutorial/views/__init__.py | 0 .../wiki/src/views/tutorial/views/default.py | 60 ++++++++++++++++++++++ .../wiki/src/views/tutorial/views/notfound.py | 7 +++ 4 files changed, 87 insertions(+), 29 deletions(-) create mode 100644 docs/tutorials/wiki/src/views/tutorial/views/__init__.py create mode 100644 docs/tutorials/wiki/src/views/tutorial/views/default.py create mode 100644 docs/tutorials/wiki/src/views/tutorial/views/notfound.py (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 9bafa87c7..7773fbe0f 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -25,14 +25,11 @@ We will define several :term:`view callable` functions, then wire them into :app 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 cookiecutter; it doesn't know -about our custom application requirements. +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 cookiecutter. +It does not know about our custom application requirements. -We need to add a dependency on the ``docutils`` package to our ``tutorial`` -package's ``setup.py`` file by assigning this dependency to the ``requires`` -parameter in the ``setup()`` function. +We need to add a dependency on the ``docutils`` 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: @@ -43,17 +40,15 @@ 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 .`` ============================ -Since a new software dependency was added, you will need to run ``pip install --e .`` again inside the root of the ``tutorial`` package to obtain and register -the newly added dependency distribution. +Since a new software dependency was added, you need to run ``pip install -e .`` again inside the root of the ``tutorial`` package to obtain and register the newly added dependency distribution. -Make sure your current working directory is the root of the project (the -directory in which ``setup.py`` lives) and execute the following command. +Make sure your current working directory is the root of the project (the directory in which ``setup.py`` lives) and execute the following command. On Unix: @@ -69,47 +64,43 @@ On Windows: cd tutorial %VENV%\Scripts\pip install -e . -Success executing this command will end with a line to the console something -like: +Success executing this command will end with a line to the console similar to the following: .. code-block:: text - Successfully installed docutils-0.13.1 tutorial + Successfully installed docutils-0.14 tutorial Adding view functions in ``views.py`` ===================================== -It's time for a major change. Open ``tutorial/views.py`` and edit it to look -like the following: +It is time for a major change. +Open ``tutorial/views/default.py`` and edit it to look like the following: -.. literalinclude:: src/views/tutorial/views.py +.. literalinclude:: src/views/tutorial/views/default.py :linenos: :language: python 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 originally rendered after we selected the ``zodb`` backend option in the -cookiecutter. It was only an example and isn't relevant to our application. +We got rid of the ``my_view`` view function and its decorator that was added when originally rendered after we selected the ``zodb`` backend option in the cookiecutter. +It was only an example and is not relevant to our application. -Then we added four :term:`view callable` functions to our ``views.py`` -module: +Then we added four :term:`view callable` functions to our ``views.py`` module: * ``view_wiki()`` - Displays the wiki itself. It will answer on the root URL. * ``view_page()`` - Displays an individual page. * ``add_page()`` - Allows the user to add a page. * ``edit_page()`` - Allows the user to edit a page. -We'll describe each one briefly in the following sections. +We will describe each one briefly in the following sections. .. note:: - There is nothing special about the filename ``views.py``. A project may - have many view callables throughout its codebase in arbitrarily named - files. Files implementing view callables often have ``view`` in their - filenames (or may live in a Python subpackage of your application package - named ``views``), but this is only by convention. + There is nothing special about the filename ``views.py``. + A project may have many view callables throughout its codebase in arbitrarily named files. + Files that implement view callables often have ``view`` in their names (or may live in a Python subpackage of your application package named ``views``), but this is only by convention. + The ``view_wiki`` view function ------------------------------- diff --git a/docs/tutorials/wiki/src/views/tutorial/views/__init__.py b/docs/tutorials/wiki/src/views/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/wiki/src/views/tutorial/views/default.py b/docs/tutorials/wiki/src/views/tutorial/views/default.py new file mode 100644 index 000000000..dfc42c96a --- /dev/null +++ b/docs/tutorials/wiki/src/views/tutorial/views/default.py @@ -0,0 +1,60 @@ +from docutils.core import publish_parts +import re + +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config + +from .models import Page + +# regular expression used to find WikiWords +wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") + +@view_config(context='.models.Wiki') +def view_wiki(context, request): + return HTTPFound(location=request.resource_url(context, 'FrontPage')) + +@view_config(context='.models.Page', renderer='templates/view.pt') +def view_page(context, request): + wiki = context.__parent__ + + def check(match): + word = match.group(1) + if word in wiki: + page = wiki[word] + view_url = request.resource_url(page) + return '%s' % (view_url, word) + else: + add_url = request.application_url + '/add_page/' + word + return '%s' % (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) + +@view_config(name='add_page', context='.models.Wiki', + renderer='templates/edit.pt') +def add_page(context, request): + pagename = request.subpath[0] + if 'form.submitted' in request.params: + body = request.params['body'] + page = Page(body) + page.__name__ = pagename + page.__parent__ = context + context[pagename] = 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) + +@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 dict(page=context, + save_url=request.resource_url(context, 'edit_page')) diff --git a/docs/tutorials/wiki/src/views/tutorial/views/notfound.py b/docs/tutorials/wiki/src/views/tutorial/views/notfound.py new file mode 100644 index 000000000..728791d0a --- /dev/null +++ b/docs/tutorials/wiki/src/views/tutorial/views/notfound.py @@ -0,0 +1,7 @@ +from pyramid.view import notfound_view_config + + +@notfound_view_config(renderer='../templates/404.pt') +def notfound_view(request): + request.response.status = 404 + return {} -- cgit v1.2.3 From af7c9c4a94aa26e910efb5177aa48bdf7e3c711c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 04:42:21 -0800 Subject: Update view_wiki narrative --- docs/tutorials/wiki/definingviews.rst | 55 +++++++++++++++-------------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 7773fbe0f..5a6b6c8e9 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -107,45 +107,38 @@ The ``view_wiki`` view function Following is the code for the ``view_wiki`` view function and its decorator: -.. literalinclude:: src/views/tutorial/views.py +.. literalinclude:: src/views/tutorial/views/default.py :lines: 12-14 :lineno-match: :language: python -.. note:: In our code, we use an *import* that is *relative* to our package - named ``tutorial``, meaning we can omit the name of the package in the - ``import`` and ``context`` statements. In our narrative, however, we refer - to a *class* and thus we use the *absolute* form, meaning that the name of - the package is included. - -``view_wiki()`` is the :term:`default view` that gets called when a request is -made to the root URL of our wiki. It always redirects to an URL which -represents the path to our "FrontPage". - -We provide it with a ``@view_config`` decorator which names the class -``tutorial.models.Wiki`` as its context. This means that when a Wiki resource -is the context and no :term:`view name` exists in the request, then this view -will be used. The view configuration associated with ``view_wiki`` does not -use a ``renderer`` because the view callable always returns a :term:`response` -object rather than a dictionary. No renderer is necessary when a view returns -a response object. - -The ``view_wiki`` view callable always redirects to the URL of a Page resource -named "FrontPage". To do so, it returns an instance of the -:class:`pyramid.httpexceptions.HTTPFound` class (instances of which implement -the :class:`pyramid.interfaces.IResponse` interface, like -:class:`pyramid.response.Response` does). It uses the -:meth:`pyramid.request.Request.route_url` API to construct an URL to the -``FrontPage`` page resource (i.e., ``http://localhost:6543/FrontPage``), and -uses it as the "location" of the ``HTTPFound`` response, forming an HTTP -redirect. +.. note:: + + In our code, we use an *import* that is *relative* to our package named ``tutorial``. + This means we can omit the name of the package in the ``import`` and ``context`` statements. + In our narrative, however, we refer to a *class* and thus we use the *absolute* form. + This means that the name of the package is included. + +``view_wiki()`` is the :term:`default view` that gets called when a request is made to the root URL of our wiki. +It always redirects to an URL which represents the path to our ``FrontPage``. + +We provide it with a ``@view_config`` decorator which names the class ``tutorial.models.Wiki`` as its context. +This means that when a ``Wiki`` resource is the context and no :term:`view name` exists in the request, then this view will be used. +The view configuration associated with ``view_wiki`` does not use a ``renderer`` because the view callable always returns a :term:`response` object rather than a dictionary. +No renderer is necessary when a view returns a response object. + +The ``view_wiki`` view callable always redirects to the URL of a ``Page`` resource named ``FrontPage``. +To do so, it returns an instance of the :class:`pyramid.httpexceptions.HTTPFound` class. +Instances of this class implement the :class:`pyramid.interfaces.IResponse` interface, similar to :class:`pyramid.response.Response`. +It uses the :meth:`pyramid.request.Request.route_url` API to construct an URL to the ``FrontPage`` page resource (in other words, ``http://localhost:6543/FrontPage``), and uses it as the ``location`` of the ``HTTPFound`` response, forming an HTTP redirect. + The ``view_page`` view function ------------------------------- Here is the code for the ``view_page`` view function and its decorator: -.. literalinclude:: src/views/tutorial/views.py +.. literalinclude:: src/views/tutorial/views/default.py :lines: 16-33 :lineno-match: :language: python @@ -198,7 +191,7 @@ The ``add_page`` view function Here is the code for the ``add_page`` view function and its decorator: -.. literalinclude:: src/views/tutorial/views.py +.. literalinclude:: src/views/tutorial/views/default.py :lines: 35-50 :lineno-match: :language: python @@ -252,7 +245,7 @@ The ``edit_page`` view function Here is the code for the ``edit_page`` view function and its decorator: -.. literalinclude:: src/views/tutorial/views.py +.. literalinclude:: src/views/tutorial/views/default.py :lines: 52-60 :lineno-match: :language: python -- cgit v1.2.3 From bed4277cdf2469709c078c6b0991a0975028f197 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 05:12:56 -0800 Subject: Add trailing slashes to intersphinx in hopes of fixing failed docs builds --- docs/conf.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'docs') diff --git a/docs/conf.py b/docs/conf.py index 15cffb1eb..3b7eb261a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -61,26 +61,26 @@ extensions = [ # Looks for objects in external projects intersphinx_mapping = { - 'colander': ('https://docs.pylonsproject.org/projects/colander/en/latest', None), + 'colander': ('https://docs.pylonsproject.org/projects/colander/en/latest/', None), 'cookbook': ('https://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/', None), 'cookiecutter': ('https://cookiecutter.readthedocs.io/en/latest/', None), - 'deform': ('https://docs.pylonsproject.org/projects/deform/en/latest', None), + 'deform': ('https://docs.pylonsproject.org/projects/deform/en/latest/', None), 'jinja2': ('https://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/', None), 'plaster': ('https://docs.pylonsproject.org/projects/plaster/en/latest/', None), 'pylonswebframework': ('https://docs.pylonsproject.org/projects/pylons-webframework/en/latest/', None), - 'python': ('https://docs.python.org/3', None), + 'python': ('https://docs.python.org/3/', None), 'pytest': ('https://docs.pytest.org/en/latest/', None), - 'sphinx': ('http://www.sphinx-doc.org/en/latest', None), - 'sqla': ('https://docs.sqlalchemy.org/en/latest', None), + 'sphinx': ('http://www.sphinx-doc.org/en/latest/', None), + 'sqla': ('https://docs.sqlalchemy.org/en/latest/', None), 'tm': ('https://docs.pylonsproject.org/projects/pyramid-tm/en/latest/', None), - 'toolbar': ('https://docs.pylonsproject.org/projects/pyramid-debugtoolbar/en/latest', None), - 'tstring': ('https://docs.pylonsproject.org/projects/translationstring/en/latest', None), + 'toolbar': ('https://docs.pylonsproject.org/projects/pyramid-debugtoolbar/en/latest/', None), + 'tstring': ('https://docs.pylonsproject.org/projects/translationstring/en/latest/', None), 'tutorials': ('https://docs.pylonsproject.org/projects/pyramid-tutorials/en/latest/', None), - 'venusian': ('https://docs.pylonsproject.org/projects/venusian/en/latest', None), + 'venusian': ('https://docs.pylonsproject.org/projects/venusian/en/latest/', None), 'webob': ('https://docs.pylonsproject.org/projects/webob/en/latest/', None), 'webtest': ('https://docs.pylonsproject.org/projects/webtest/en/latest/', None), - 'who': ('https://repozewho.readthedocs.io/en/latest', None), - 'zcml': ('https://docs.pylonsproject.org/projects/pyramid-zcml/en/latest', None), + 'who': ('https://repozewho.readthedocs.io/en/latest/', None), + 'zcml': ('https://docs.pylonsproject.org/projects/pyramid-zcml/en/latest/', None), 'zcomponent': ('https://zopecomponent.readthedocs.io/en/latest/', None), 'zinterface': ('https://zopeinterface.readthedocs.io/en/latest/', None), } -- cgit v1.2.3 From 90036b6778992f896ccf4aa52c241fafb1c82f24 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 05:30:47 -0800 Subject: Revise view_page narrative --- docs/tutorials/wiki/definingviews.rst | 70 ++++++++++++++--------------------- 1 file changed, 28 insertions(+), 42 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 5a6b6c8e9..03bdd1080 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -143,48 +143,34 @@ Here is the code for the ``view_page`` view function and its decorator: :lineno-match: :language: python -The ``view_page`` function is configured to respond as the default view -of a Page resource. We provide it with a ``@view_config`` decorator which -names the class ``tutorial.models.Page`` as its context. This means that -when a Page resource is the context, and no :term:`view name` exists in the -request, this view will be used. We inform :app:`Pyramid` this view will use -the ``templates/view.pt`` template file as a ``renderer``. - -The ``view_page`` function generates the :term:`reStructuredText` body of a -page (stored as the ``data`` attribute of the context passed to the view; the -context will be a ``Page`` resource) as HTML. Then it substitutes an HTML -anchor for each *WikiWord* reference in the rendered HTML using a compiled -regular expression. - -The curried function named ``check`` is used as the first argument to -``wikiwords.sub``, indicating that it should be called to provide a value for -each WikiWord match found in the content. If the wiki (our page's -``__parent__``) already contains a page with the matched WikiWord name, the -``check`` function generates a view link to be used as the substitution value -and returns it. If the wiki does not already contain a page with the -matched WikiWord name, the function generates an "add" link as the -substitution value and returns it. - -As a result, the ``content`` variable is now a fully formed bit of HTML -containing various view and add links for WikiWords based on the content of -our current page resource. - -We then generate an edit URL because it's easier to do here than in the -template, and we wrap up a number of arguments in a dictionary and return -it. - -The arguments we wrap into a dictionary include ``page``, ``content``, and -``edit_url``. As a result, the *template* associated with this view callable -(via ``renderer=`` in its configuration) will be able to use these names to -perform various rendering tasks. The template associated with this view -callable will be a template which lives in ``templates/view.pt``. - -Note the contrast between this view callable and the ``view_wiki`` view -callable. In the ``view_wiki`` view callable, we unconditionally return a -:term:`response` object. In the ``view_page`` view callable, we return a -*dictionary*. It is *always* fine to return a :term:`response` object from a -:app:`Pyramid` view. Returning a dictionary is allowed only when there is a -:term:`renderer` associated with the view callable in the view configuration. +The ``view_page`` function is configured to respond as the default view of a ``Page`` resource. +We provide it with a ``@view_config`` decorator which names the class ``tutorial.models.Page`` as its context. +This means that when a ``Page`` resource is the context, and no :term:`view name` exists in the request, this view will be used. +We inform :app:`Pyramid` this view will use the ``templates/view.pt`` template file as a ``renderer``. + +The ``view_page`` function generates the :term:`reStructuredText` body of a page as HTML. +The body is stored as the ``data`` attribute of the context passed to the view. +The context will be a ``Page`` resource. +Then it substitutes an HTML anchor for each *WikiWord* reference in the rendered HTML using a compiled regular expression. + +The curried function named ``check`` is used as the first argument to ``wikiwords.sub``, indicating that it should be called to provide a value for each WikiWord match found in the content. +If the wiki (our page's ``__parent__``) already contains a page with the matched WikiWord name, the ``check`` function generates a view link to be used as the substitution value and returns it. +If the wiki does not already contain a page with the matched WikiWord name, the function generates an "add" link as the substitution value and returns it. + +As a result, the ``content`` variable is now a fully formed bit of HTML containing various view and add links for WikiWords based on the content of our current page resource. + +We then generate an edit URL because it is easier to do here than in the template. +Finally we wrap up a number of arguments in a dictionary and return it. + +The arguments we wrap into a dictionary include ``page``, ``content``, and ``edit_url``. +As a result, the *template* associated with this view callable (via ``renderer=`` in its configuration) will be able to use these names to perform various rendering tasks. +The template associated with this view callable will be a template which lives in ``templates/view.pt``. + +Note the contrast between this view callable and the ``view_wiki`` view callable. +In the ``view_wiki`` view callable, we unconditionally return a :term:`response` object. +In the ``view_page`` view callable, we return a *dictionary*. It is *always* fine to return a :term:`response` object from a :app:`Pyramid` view. +Returning a dictionary is allowed only when there is a :term:`renderer` associated with the view callable in the view configuration. + The ``add_page`` view function ------------------------------ -- cgit v1.2.3 From 3d77f50790bdd5a63513c82b53d677dfe31c6494 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 11:44:28 -0800 Subject: Add a note for resources and traversal chapters. --- docs/tutorials/wiki/definingmodels.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst index 81dd25862..2ea81b005 100644 --- a/docs/tutorials/wiki/definingmodels.rst +++ b/docs/tutorials/wiki/definingmodels.rst @@ -10,9 +10,14 @@ We will do this inside our ``models.py`` file. Because we are using :term:`ZODB` to represent our :term:`resource tree`, each of these resource constructors represents a :term:`domain model` object. We will call these constructors "model constructors". -Both our Page and Wiki constructors will be class objects. +Both our ``Page`` and ``Wiki`` constructors will be class objects. A single instance of the "Wiki" class will serve as a container for "Page" objects, which will be instances of the "Page" class. +.. note:: + + We will introduce a lot of concepts throughout the remainder of this tutorial. + See also the chapter :ref:`resources_chapter` for a complete description of resources and the chapter :ref:`traversal_chapter` for the technical details of how traversal works in Pyramid. + Delete the database ------------------- -- cgit v1.2.3 From abba3f32fa3a0e91b2780724123e63b0ce38adc6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 11:46:04 -0800 Subject: Update models and view application sections --- docs/tutorials/wiki/definingviews.rst | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 03bdd1080..625716de9 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -21,6 +21,11 @@ A view callable is assumed to return a :term:`response` object. We will define several :term:`view callable` functions, then wire them into :app:`Pyramid` using some :term:`view configuration`. +.. note:: + + This chapter will introduce more concepts, as did the previous. + See also the chapter :ref:`resources_chapter` for a complete description of resources and the chapter :ref:`traversal_chapter` for the technical details of how traversal works in Pyramid. + Declaring Dependencies in Our ``setup.py`` File =============================================== -- cgit v1.2.3 From af62fedf04d9f7e3c5eec98bc018da6ad2b7d88b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 11:46:52 -0800 Subject: Use double backticks on objects --- docs/tutorials/wiki/definingviews.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 625716de9..d7575e815 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -158,11 +158,11 @@ The body is stored as the ``data`` attribute of the context passed to the view. The context will be a ``Page`` resource. Then it substitutes an HTML anchor for each *WikiWord* reference in the rendered HTML using a compiled regular expression. -The curried function named ``check`` is used as the first argument to ``wikiwords.sub``, indicating that it should be called to provide a value for each WikiWord match found in the content. -If the wiki (our page's ``__parent__``) already contains a page with the matched WikiWord name, the ``check`` function generates a view link to be used as the substitution value and returns it. -If the wiki does not already contain a page with the matched WikiWord name, the function generates an "add" link as the substitution value and returns it. +The curried function named ``check`` is used as the first argument to ``wikiwords.sub``, indicating that it should be called to provide a value for each ``WikiWord`` match found in the content. +If the wiki (our page's ``__parent__``) already contains a page with the matched ``WikiWord`` name, the ``check`` function generates a view link to be used as the substitution value and returns it. +If the wiki does not already contain a page with the matched ``WikiWord`` name, the function generates an "add" link as the substitution value and returns it. -As a result, the ``content`` variable is now a fully formed bit of HTML containing various view and add links for WikiWords based on the content of our current page resource. +As a result, the ``content`` variable is now a fully formed bit of HTML containing various view and add links for ``WikiWord``s based on the content of our current page resource. We then generate an edit URL because it is easier to do here than in the template. Finally we wrap up a number of arguments in a dictionary and return it. @@ -242,11 +242,11 @@ Here is the code for the ``edit_page`` view function and its decorator: :language: python The ``edit_page`` function is configured to respond when the context is -a Page resource and the :term:`view name` is ``edit_page``. We provide it +a ``Page`` resource and the :term:`view name` is ``edit_page``. We provide it with a ``@view_config`` decorator which names the string ``edit_page`` as its :term:`view name` (via ``name=``), the class ``tutorial.models.Page`` as its context, and the renderer named ``templates/edit.pt``. This means that when -a Page resource is the context, and a :term:`view name` exists as the result +a ``Page`` resource is the context, and a :term:`view name` exists as the result of traversal named ``edit_page``, this view will be used. We inform :app:`Pyramid` this view will use the ``templates/edit.pt`` template file as a ``renderer``. @@ -254,7 +254,7 @@ a ``renderer``. The ``edit_page`` function will be invoked when a user clicks the "Edit this Page" button on the view form. It renders an edit form but it also acts as the form post view callable for the form it renders. The ``context`` of the -``edit_page`` view will *always* be a Page resource (never a Wiki resource). +``edit_page`` view will *always* be a ``Page`` resource (never a ``Wiki`` resource). If the view execution is *not* a result of a form submission (if the expression ``'form.submitted' in request.params`` is ``False``), the view @@ -345,16 +345,16 @@ We can finally examine our application in a browser (See each of the following URLs, checking that the result is as expected: - http://localhost:6543/ invokes the ``view_wiki`` view. This always - redirects to the ``view_page`` view of the ``FrontPage`` Page resource. + redirects to the ``view_page`` view of the ``FrontPage`` ``Page`` resource. - http://localhost:6543/FrontPage/ invokes the ``view_page`` view of the front page resource. This is because it's the :term:`default view` (a view - without a ``name``) for Page resources. + without a ``name``) for ``Page`` resources. - http://localhost:6543/FrontPage/edit_page invokes the edit view for the - ``FrontPage`` Page resource. + ``FrontPage`` ``Page`` resource. -- http://localhost:6543/add_page/SomePageName invokes the add view for a Page. +- 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 ``IndexError: tuple index out of range`` error. You'll see an -- cgit v1.2.3 From b33a1777e5347677d1ee0dcec2a5da277ee7d094 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 11:51:38 -0800 Subject: Revise the add_page view section narrative --- docs/tutorials/wiki/definingviews.rst | 80 ++++++++++++++++------------------- 1 file changed, 37 insertions(+), 43 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index d7575e815..449b9d9c2 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -187,49 +187,43 @@ Here is the code for the ``add_page`` view function and its decorator: :lineno-match: :language: python -The ``add_page`` function is configured to respond when the context resource -is a Wiki and the :term:`view name` is ``add_page``. We provide it with a -``@view_config`` decorator which names the string ``add_page`` as its -:term:`view name` (via ``name=``), the class ``tutorial.models.Wiki`` as its -context, and the renderer named ``templates/edit.pt``. This means that when a -Wiki resource is the context, and a :term:`view name` named ``add_page`` -exists as the result of traversal, this view will be used. We inform -:app:`Pyramid` this view will use the ``templates/edit.pt`` template file as a -``renderer``. We share the same template between add and edit views, thus -``edit.pt`` instead of ``add.pt``. - -The ``add_page`` function will be invoked when a user clicks on a WikiWord -which isn't yet represented as a page in the system. The ``check`` function -within the ``view_page`` view generates URLs to this view. It also acts as a -handler for the form that is generated when we want to add a page resource. -The ``context`` of the ``add_page`` view is always a Wiki resource (*not* a -Page resource). - -The request :term:`subpath` in :app:`Pyramid` is the sequence of names that -are found *after* the :term:`view name` in the URL segments given in the -``PATH_INFO`` of the WSGI request as the result of :term:`traversal`. If our -add view is invoked via, e.g., ``http://localhost:6543/add_page/SomeName``, -the :term:`subpath` will be a tuple: ``('SomeName',)``. - -The add view takes the 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. - -If the view rendering is *not* a result of a form submission (if the -expression ``'form.submitted' in request.params`` is ``False``), the view -renders a template. To do so, it generates a "save url" which the template -uses as the form post URL during rendering. We're lazy here, so we're trying -to use the same template (``templates/edit.pt``) for the add view as well as -the page edit view. To do so, we create a dummy Page resource object in -order to satisfy the edit form's desire to have *some* page object exposed as -``page``, and we'll render the template to a response. - -If the view rendering *is* a result of a form submission (if the expression -``'form.submitted' in request.params`` is ``True``), we grab the page body -from the form data, create a Page object using the name in the subpath and -the page body, and save it into "our context" (the Wiki) using the -``__setitem__`` method of the context. We then redirect back to the -``view_page`` view (the default view for a page) for the newly created page. +The ``add_page`` function is configured to respond when the context resource is a ``Wiki`` and the :term:`view name` is ``add_page``. +We provide it with a ``@view_config`` decorator which names the string ``add_page`` as its :term:`view name` (via ``name=``), the class ``tutorial.models.Wiki`` as its context, and the renderer named ``templates/edit.pt``. +This means that when a ``Wiki`` resource is the context, and a :term:`view name` named ``add_page`` exists as the result of traversal, then this view will be used. +We inform :app:`Pyramid` this view will use the ``templates/edit.pt`` template file as a ``renderer``. +We share the same template between add and edit views, thus ``edit.pt`` instead of ``add.pt``. + +The ``add_page`` function will be invoked when a user clicks on a ``WikiWord`` that is not yet represented as a page in the system. +The ``check`` function within the ``view_page`` view generates URLs to this view. +It also acts as a handler for the form that is generated when we want to add a page resource. +The ``context`` of the ``add_page`` view is always a ``Wiki`` resource (*not* a ``Page`` resource). + +The request :term:`subpath` in :app:`Pyramid` is the sequence of names that are found *after* the :term:`view name` in the URL segments given in the ``PATH_INFO`` of the WSGI request as the result of :term:`traversal`. +If our add view is invoked via, for example, ``http://localhost:6543/add_page/SomeName``, then the :term:`subpath` will be a tuple ``('SomeName',)``. + +The add view takes the zero\ :sup:`th` element of the subpath (the wiki page name), then aliases it to the name attribute to know the name of the page we are trying to add. + +If the view rendering is *not* a result of a form submission (if the expression ``'form.submitted' in request.params`` is ``False``), then the view renders a template. +To do so, it generates a ``save_url`` which the template uses as the form post URL during rendering. +We are lazy here, so we try to use the same template (``templates/edit.pt``) for both the add and edit views. +To do so, we create a dummy ``Page`` resource object to satisfy the edit form's desire to have *some* page object exposed as ``page``. +We then set the ``Page`` object's ``__name__`` and ``__parent__``. +Then we will render the template to a response. + +If the view rendering *is* a result of a form submission (if the expression ``'form.submitted' in request.params`` is ``True``), then do the following: + +- Grab the page body from the form data as ``body``. +- Create a ``Page`` object using the name in the subpath and the page body as ``page``. +- Set the ``Page`` object's ``__name__`` and ``__parent__``. +- Save it into "our context" (the ``Wiki``) using the ``__setitem__`` method of the context. +- We then redirect back to the ``view_page`` view (the default view for a page) for the newly created page. + +.. seealso:: + + In the :ref:`previous chapter `, we mentioned that all objects in a traversal graph must have a ``__name__`` and a ``__parent__`` attribute. + That provides location awareness for resources. + See also the section on :ref:`location-aware-resources` in the :ref:`resources_chapter` chapter for a complete discussion. + The ``edit_page`` view function ------------------------------- -- cgit v1.2.3 From 07c5639c50814320e572d1bb478854bc4fcd33cc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 24 Nov 2018 11:56:30 -0800 Subject: Use proper reST syntax and directives --- docs/tutorials/wiki/definingmodels.rst | 2 +- docs/tutorials/wiki/definingviews.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst index 2ea81b005..3a340e6f7 100644 --- a/docs/tutorials/wiki/definingmodels.rst +++ b/docs/tutorials/wiki/definingmodels.rst @@ -13,7 +13,7 @@ We will call these constructors "model constructors". Both our ``Page`` and ``Wiki`` constructors will be class objects. A single instance of the "Wiki" class will serve as a container for "Page" objects, which will be instances of the "Page" class. -.. note:: +.. seealso:: We will introduce a lot of concepts throughout the remainder of this tutorial. See also the chapter :ref:`resources_chapter` for a complete description of resources and the chapter :ref:`traversal_chapter` for the technical details of how traversal works in Pyramid. diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 449b9d9c2..8d291a5e7 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -21,7 +21,7 @@ A view callable is assumed to return a :term:`response` object. We will define several :term:`view callable` functions, then wire them into :app:`Pyramid` using some :term:`view configuration`. -.. note:: +.. seealso:: This chapter will introduce more concepts, as did the previous. See also the chapter :ref:`resources_chapter` for a complete description of resources and the chapter :ref:`traversal_chapter` for the technical details of how traversal works in Pyramid. @@ -162,7 +162,7 @@ The curried function named ``check`` is used as the first argument to ``wikiword If the wiki (our page's ``__parent__``) already contains a page with the matched ``WikiWord`` name, the ``check`` function generates a view link to be used as the substitution value and returns it. If the wiki does not already contain a page with the matched ``WikiWord`` name, the function generates an "add" link as the substitution value and returns it. -As a result, the ``content`` variable is now a fully formed bit of HTML containing various view and add links for ``WikiWord``s based on the content of our current page resource. +As a result, the ``content`` variable is now a fully formed bit of HTML containing various view and add links for ``WikiWord``\s based on the content of our current page resource. We then generate an edit URL because it is easier to do here than in the template. Finally we wrap up a number of arguments in a dictionary and return it. @@ -222,7 +222,7 @@ If the view rendering *is* a result of a form submission (if the expression ``'f In the :ref:`previous chapter `, we mentioned that all objects in a traversal graph must have a ``__name__`` and a ``__parent__`` attribute. That provides location awareness for resources. - See also the section on :ref:`location-aware-resources` in the :ref:`resources_chapter` chapter for a complete discussion. + See also the section on :ref:`location_aware` in the :ref:`resources_chapter` chapter for a complete discussion. The ``edit_page`` view function -- cgit v1.2.3 From b4c32b1763e53d5fba939f6abd0111c81561a3c7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 01:36:54 -0800 Subject: Rewrap edit_page view section --- docs/tutorials/wiki/definingviews.rst | 40 +++++++++++++---------------------- 1 file changed, 15 insertions(+), 25 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 8d291a5e7..164bc4326 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -235,31 +235,21 @@ Here is the code for the ``edit_page`` view function and its decorator: :lineno-match: :language: python -The ``edit_page`` function is configured to respond when the context is -a ``Page`` resource and the :term:`view name` is ``edit_page``. We provide it -with a ``@view_config`` decorator which names the string ``edit_page`` as its -:term:`view name` (via ``name=``), the class ``tutorial.models.Page`` as its -context, and the renderer named ``templates/edit.pt``. This means that when -a ``Page`` resource is the context, and a :term:`view name` exists as the result -of traversal named ``edit_page``, this view will be used. We inform -:app:`Pyramid` this view will use the ``templates/edit.pt`` template file as -a ``renderer``. - -The ``edit_page`` function will be invoked when a user clicks the "Edit this -Page" button on the view form. It renders an edit form but it also acts as -the form post view callable for the form it renders. The ``context`` of the -``edit_page`` view will *always* be a ``Page`` resource (never a ``Wiki`` resource). - -If the view execution is *not* a result of a form submission (if the -expression ``'form.submitted' in request.params`` is ``False``), the view -simply renders the edit form, passing the page resource, and a ``save_url`` -which will be used as the action of the generated form. - -If the view execution *is* a result of a form submission (if the expression -``'form.submitted' in request.params`` is ``True``), the view grabs the -``body`` element of the request parameter and sets it as the ``data`` -attribute of the page context. It then redirects to the default view of the -context (the page), which will always be the ``view_page`` view. +The ``edit_page`` function is configured to respond when the context is a ``Page`` resource and the :term:`view name` is ``edit_page``. +We provide it with a ``@view_config`` decorator which names the string ``edit_page`` as its :term:`view name` (via ``name=``), the class ``tutorial.models.Page`` as its context, and the renderer named ``templates/edit.pt``. +This means that when a ``Page`` resource is the context, and a :term:`view name` exists as the result of traversal named ``edit_page``, this view will be used. +We inform :app:`Pyramid` this view will use the ``templates/edit.pt`` template file as a ``renderer``. + +The ``edit_page`` function will be invoked when a user clicks the "Edit this Page" button on the view form. +It renders an edit form. +It also acts as the form post view callable for the form it renders. +The ``context`` of the ``edit_page`` view will *always* be a ``Page`` resource (never a ``Wiki`` resource). + +If the view execution is *not* a result of a form submission (if the expression ``'form.submitted' in request.params`` is ``False``), then the view renders the edit form, passing the page resource, and a ``save_url`` which will be used as the action of the generated form. + +If the view execution *is* a result of a form submission (if the expression ``'form.submitted' in request.params`` is ``True``), the view grabs the ``body`` element of the request parameter and sets it as the ``data`` attribute of the page context. +It then redirects to the default view of the context (the page), which will always be the ``view_page`` view. + Adding templates ================ -- cgit v1.2.3 From faa25d660effa044c0324aded75a37b225299a9b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:30:08 -0800 Subject: Clean up templates narrative. --- docs/tutorials/wiki/definingviews.rst | 120 +++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 51 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 164bc4326..7d3c65e58 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -76,8 +76,8 @@ Success executing this command will end with a line to the console similar to th Successfully installed docutils-0.14 tutorial -Adding view functions in ``views.py`` -===================================== +Adding view functions in the ``views`` package +============================================== It is time for a major change. Open ``tutorial/views/default.py`` and edit it to look like the following: @@ -162,12 +162,12 @@ The curried function named ``check`` is used as the first argument to ``wikiword If the wiki (our page's ``__parent__``) already contains a page with the matched ``WikiWord`` name, the ``check`` function generates a view link to be used as the substitution value and returns it. If the wiki does not already contain a page with the matched ``WikiWord`` name, the function generates an "add" link as the substitution value and returns it. -As a result, the ``content`` variable is now a fully formed bit of HTML containing various view and add links for ``WikiWord``\s based on the content of our current page resource. +As a result, the ``page_text`` variable is now a fully formed bit of HTML containing various view and add links for ``WikiWord``\s based on the content of our current page resource. We then generate an edit URL because it is easier to do here than in the template. Finally we wrap up a number of arguments in a dictionary and return it. -The arguments we wrap into a dictionary include ``page``, ``content``, and ``edit_url``. +The arguments we wrap into a dictionary include ``page``, ``page_text``, and ``edit_url``. As a result, the *template* associated with this view callable (via ``renderer=`` in its configuration) will be able to use these names to perform various rendering tasks. The template associated with this view callable will be a template which lives in ``templates/view.pt``. @@ -254,11 +254,36 @@ It then redirects to the default view of the context (the page), which will alwa Adding templates ================ -The ``view_page``, ``add_page`` and ``edit_page`` views that we've added -reference a :term:`template`. Each template is a :term:`Chameleon` -:term:`ZPT` template. These templates will live in the ``templates`` -directory of our tutorial package. Chameleon templates must have a ``.pt`` -extension to be recognized as such. +The ``view_page``, ``add_page``, and ``edit_page`` views that we added reference a :term:`template`. +Each template is a :term:`Chameleon` :term:`ZPT` template. +These templates will live in the ``templates`` directory of our tutorial package. +Chameleon templates must have a ``.pt`` extension to be recognized as such. + + +The ``layout.pt`` template +-------------------------- + +Update ``tutorial/templates/layout.pt`` with the following content, as indicated by the emphasized lines: + +.. literalinclude:: src/views/tutorial/templates/layout.pt + :linenos: + :emphasize-lines: 11-12 + :language: html + +Since we are using a templating engine, we can factor common boilerplate out of our page templates into reusable components. +We can do this via :term:`METAL` macros and slots. + +- The cookiecutter defined a macro named ``layout`` (Line 1). + This macro consists of the entire document. +- The cookiecutter defined a macro customization point or `slot` (Line 36). + This slot is inside the macro ``layout``. + Therefore it can be replaced by content, customizing the macro. +- We removed the row of icons and links from the original cookiecutter. + +.. seealso:: + + Please refer to the Chameleon documentation for more information about using `METAL `_ for defining and using macros and slots. + The ``view.pt`` template ------------------------ @@ -268,16 +293,19 @@ Rename ``tutorial/templates/mytemplate.pt`` to ``tutorial/templates/view.pt`` an .. literalinclude:: src/views/tutorial/templates/view.pt :linenos: :language: html - :emphasize-lines: 11-12,37-52 + :emphasize-lines: 5-19 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 37-39). ``content`` contains HTML, so the ``structure`` - keyword is used to prevent escaping it (i.e., changing ">" to ">", etc.) -- A link that points at the "edit" URL which invokes the ``edit_page`` view - for the page being viewed (lines 41-43). +- The use of a macro to load the entire template ``layout.pt``. +- The template fills the slot named ``content`` (line 2) with a ``div`` element. +- A ``div`` element that is replaced with the ``page_text`` value provided by the view (line 5). + ``page_text`` contains HTML, so the ``structure`` keyword is used to prevent escaping HTML entities, such as changing ``>`` to ``>``. +- A link that points at the "edit" URL, which invokes the ``edit_page`` view for the page being viewed (lines 9-11). +- A ``span`` whose content is replaced by the name of the page, if present. +- A link to the FrontPage. + The ``edit.pt`` template ------------------------ @@ -288,58 +316,48 @@ Copy ``tutorial/templates/view.pt`` to ``tutorial/templates/edit.pt`` and edit t :linenos: :language: html -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: +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 (lines 14-15). +- A submit button that has the name ``form.submitted`` (line 18). -- 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). +When submitted, the form sends a POST request to the ``save_url`` argument supplied by the view (line 12). +The view will use the ``body`` and ``form.submitted`` values. -The form POSTs back to the ``save_url`` argument supplied by the view (line -44). The view will use the ``body`` and ``form.submitted`` values. +.. note:: -.. note:: Our templates use a ``request`` object that none of our tutorial - views return in their dictionary. ``request`` is one of several names that - are available "by default" in a template when a template renderer is used. - See :ref:`renderer_system_values` for information about other names that - are available by default when a template is used as a renderer. + Our templates use a ``request`` object that none of our tutorial views return in their dictionary. + ``request`` is one of several names that are available "by default" in a template when a template renderer is used. + See :ref:`renderer_system_values` for information about other names that are available by default when a template is used as a renderer. 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 -were provided at the time we created the project. +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 were provided by the cookiecutter at the time we created the project. -As an example, the CSS file will be accessed via -``http://localhost:6543/static/theme.css`` by virtue of the call to the -``add_static_view`` directive we've made in the ``__init__.py`` file. Any -number and type of static assets can be placed in this directory (or -subdirectories) and are just referred to by URL or by using the convenience -method ``static_url``, e.g., -``request.static_url(':static/foo.css')`` within templates. +As an example, the CSS file will be accessed via ``http://localhost:6543/static/theme.css`` by virtue of the call to the ``add_static_view`` directive in the ``routes.py`` file. +Any number and type of static assets can be placed in this directory (or subdirectories) +They are referred to by either URL or using the convenience method ``static_url``, for example ``request.static_url(':static/foo.css')``, within templates. Viewing the application in a browser ==================================== -We can finally examine our application in a browser (See -:ref:`wiki-start-the-application`). Launch a browser and visit -each of the following URLs, checking that the result is as expected: +We can finally examine our application in a browser (See :ref:`wiki-start-the-application`). +Launch a browser and visit each of the following URLs, checking that the result is as expected: -- http://localhost:6543/ invokes the ``view_wiki`` view. This always - redirects to the ``view_page`` view of the ``FrontPage`` ``Page`` resource. +- http://localhost:6543/ invokes the ``view_wiki`` view. + This always redirects to the ``view_page`` view of the ``FrontPage`` ``Page`` resource. -- http://localhost:6543/FrontPage/ invokes the ``view_page`` view of the front - page resource. This is because it's the :term:`default view` (a view - without a ``name``) for ``Page`` resources. +- http://localhost:6543/FrontPage/ invokes the ``view_page`` view of the front page resource. + This is because it is the :term:`default view` (a view without a ``name``) for ``Page`` resources. -- http://localhost:6543/FrontPage/edit_page invokes the edit view for the - ``FrontPage`` ``Page`` resource. +- http://localhost:6543/FrontPage/edit_page invokes the edit view for the ``FrontPage`` ``Page`` resource. -- http://localhost:6543/add_page/SomePageName invokes the add view for a ``Page``. +- 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 ``IndexError: tuple index out of range`` error. You'll see an - interactive traceback facility provided by :term:`pyramid_debugtoolbar`. +- To generate an error, visit http://localhost:6543/add_page which will generate an ``IndexError: tuple index out of range`` error. + You will see an interactive traceback facility provided by :term:`pyramid_debugtoolbar`. -- cgit v1.2.3 From 9161c6a4a2e5b96043a4b4f9171a6cd2fc7ec337 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:35:54 -0800 Subject: Fix imports, contexts, paths to templates, and refactor `content` to `page_text` (there's too many "content" already and is confusing) --- .../wiki/src/views/tutorial/views/default.py | 24 +++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/views/tutorial/views/default.py b/docs/tutorials/wiki/src/views/tutorial/views/default.py index dfc42c96a..b4b65a49b 100644 --- a/docs/tutorials/wiki/src/views/tutorial/views/default.py +++ b/docs/tutorials/wiki/src/views/tutorial/views/default.py @@ -4,16 +4,18 @@ import re from pyramid.httpexceptions import HTTPFound from pyramid.view import view_config -from .models import Page +from ..models import Page # regular expression used to find WikiWords wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") -@view_config(context='.models.Wiki') + +@view_config(context='..models.Wiki') def view_wiki(context, request): return HTTPFound(location=request.resource_url(context, 'FrontPage')) -@view_config(context='.models.Page', renderer='templates/view.pt') + +@view_config(context='..models.Page', renderer='../templates/view.pt') def view_page(context, request): wiki = context.__parent__ @@ -27,13 +29,14 @@ def view_page(context, request): add_url = request.application_url + '/add_page/' + word return '%s' % (add_url, word) - content = publish_parts(context.data, writer_name='html')['html_body'] - content = wikiwords.sub(check, content) + page_text = publish_parts(context.data, writer_name='html')['html_body'] + page_text = wikiwords.sub(check, page_text) edit_url = request.resource_url(context, 'edit_page') - return dict(page=context, content=content, edit_url=edit_url) + return dict(page=context, page_text=page_text, edit_url=edit_url) -@view_config(name='add_page', context='.models.Wiki', - renderer='templates/edit.pt') + +@view_config(name='add_page', context='..models.Wiki', + renderer='../templates/edit.pt') def add_page(context, request): pagename = request.subpath[0] if 'form.submitted' in request.params: @@ -49,8 +52,9 @@ def add_page(context, request): page.__parent__ = context return dict(page=page, save_url=save_url) -@view_config(name='edit_page', context='.models.Page', - renderer='templates/edit.pt') + +@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'] -- cgit v1.2.3 From db221574993ace9ab0773fe746ff7ae35b474d41 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:36:11 -0800 Subject: Delete obsolete views.py --- docs/tutorials/wiki/src/views/tutorial/views.py | 60 ------------------------- 1 file changed, 60 deletions(-) delete mode 100644 docs/tutorials/wiki/src/views/tutorial/views.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/views/tutorial/views.py b/docs/tutorials/wiki/src/views/tutorial/views.py deleted file mode 100644 index fd2b0edc1..000000000 --- a/docs/tutorials/wiki/src/views/tutorial/views.py +++ /dev/null @@ -1,60 +0,0 @@ -from docutils.core import publish_parts -import re - -from pyramid.httpexceptions import HTTPFound -from pyramid.view import view_config - -from .models import Page - -# regular expression used to find WikiWords -wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") - -@view_config(context='.models.Wiki') -def view_wiki(context, request): - return HTTPFound(location=request.resource_url(context, 'FrontPage')) - -@view_config(context='.models.Page', renderer='templates/view.pt') -def view_page(context, request): - wiki = context.__parent__ - - def check(match): - word = match.group(1) - if word in wiki: - page = wiki[word] - view_url = request.resource_url(page) - return '%s' % (view_url, word) - else: - add_url = request.application_url + '/add_page/' + word - return '%s' % (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) - -@view_config(name='add_page', context='.models.Wiki', - renderer='templates/edit.pt') -def add_page(context, request): - pagename = request.subpath[0] - if 'form.submitted' in request.params: - body = request.params['body'] - page = Page(body) - page.__name__ = pagename - page.__parent__ = context - context[pagename] = 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) - -@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 dict(page=context, - save_url=request.resource_url(context, 'edit_page')) \ No newline at end of file -- cgit v1.2.3 From 047394ea8ee37fb9161e8dad7693e82112f40d31 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:36:51 -0800 Subject: Add import and return a Page object for the notfound view --- docs/tutorials/wiki/src/views/tutorial/views/notfound.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/views/tutorial/views/notfound.py b/docs/tutorials/wiki/src/views/tutorial/views/notfound.py index 728791d0a..214ec810e 100644 --- a/docs/tutorials/wiki/src/views/tutorial/views/notfound.py +++ b/docs/tutorials/wiki/src/views/tutorial/views/notfound.py @@ -1,7 +1,12 @@ from pyramid.view import notfound_view_config +from ..models import Page + @notfound_view_config(renderer='../templates/404.pt') def notfound_view(request): request.response.status = 404 - return {} + pagename = request.subpath + page = Page(pagename) + page.__name__ = pagename + return dict(page=page) -- cgit v1.2.3 From 3176aa197371a912f4fd9a90a4645074bccabfda Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:37:29 -0800 Subject: Align line numbers with src in views --- docs/tutorials/wiki/definingviews.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 7d3c65e58..0435a70d2 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -113,7 +113,7 @@ The ``view_wiki`` view function Following is the code for the ``view_wiki`` view function and its decorator: .. literalinclude:: src/views/tutorial/views/default.py - :lines: 12-14 + :lines: 13-15 :lineno-match: :language: python @@ -144,7 +144,7 @@ The ``view_page`` view function Here is the code for the ``view_page`` view function and its decorator: .. literalinclude:: src/views/tutorial/views/default.py - :lines: 16-33 + :lines: 18-35 :lineno-match: :language: python @@ -183,7 +183,7 @@ The ``add_page`` view function Here is the code for the ``add_page`` view function and its decorator: .. literalinclude:: src/views/tutorial/views/default.py - :lines: 35-50 + :lines: 38-53 :lineno-match: :language: python @@ -231,7 +231,7 @@ The ``edit_page`` view function Here is the code for the ``edit_page`` view function and its decorator: .. literalinclude:: src/views/tutorial/views/default.py - :lines: 52-60 + :lines: 56-64 :lineno-match: :language: python -- cgit v1.2.3 From 8af7634939d18c0fc1d2118ce46d9848dfe514bf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:39:01 -0800 Subject: Fix up templates to inherit from layout.pt --- .../wiki/src/views/tutorial/templates/404.pt | 10 +++ .../wiki/src/views/tutorial/templates/edit.pt | 76 ++++----------------- .../wiki/src/views/tutorial/templates/layout.pt | 59 ++++++++++++++++ .../wiki/src/views/tutorial/templates/view.pt | 78 ++++------------------ 4 files changed, 97 insertions(+), 126 deletions(-) create mode 100644 docs/tutorials/wiki/src/views/tutorial/templates/404.pt create mode 100644 docs/tutorials/wiki/src/views/tutorial/templates/layout.pt (limited to 'docs') diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/404.pt b/docs/tutorials/wiki/src/views/tutorial/templates/404.pt new file mode 100644 index 000000000..07298940c --- /dev/null +++ b/docs/tutorials/wiki/src/views/tutorial/templates/404.pt @@ -0,0 +1,10 @@ +
+
+ +
+

Pyramid Starter project

+

404 Page Not Found

+
+ +
+
diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt index 2db3ca79c..620fcbfb7 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt @@ -1,69 +1,21 @@ - - - - - - - - - +
+
- ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - -
-
-
-
- -
-
-
-

- Editing - Page Name Goes Here -

-

You can return to the - FrontPage. -

- +
+

+ Editing + Page Name Goes Here +

+
- +
- +
- -
-
+
-
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt new file mode 100644 index 000000000..ba40fd6f4 --- /dev/null +++ b/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt @@ -0,0 +1,59 @@ + + + + + + + + + + + ${page.__name__} - Pyramid tutorial wiki (based on + TurboGears 20-Minute Wiki) + + + + + + + + + + + + + +
+
+
+
+ +
+
+
No content
+
+

You can return to the + FrontPage. +

+
+
+
+
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt index 1feeab5ef..b8a6fbbaf 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/view.pt @@ -1,70 +1,20 @@ - - - - - - - - - +
+
- ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - - -
-
-
-
- -
-
-
-
- Page text goes here. -
-

+

+
+ Page text goes here. +
+

Edit this page -

-

- Viewing - Page Name Goes Here -

-

You can return to the - FrontPage. -

-
-
-
-
- +

+

+ Viewing + Page Name Goes Here +

-
-
- - - - - - - +
+
-- cgit v1.2.3 From 57d8d1fd670b156439ac522fe17988116754d42c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:53:25 -0800 Subject: Fix up template for display on docs --- docs/tutorials/wiki/src/views/tutorial/templates/edit.pt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt index 620fcbfb7..488e7a6af 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/edit.pt @@ -9,10 +9,13 @@
+ class="form-control" name="body" + rows="10" cols="60">
- +
-- cgit v1.2.3 From 890ecc61836cc2caddd9c5aeacd8e99880ec0237 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 03:53:50 -0800 Subject: Fix up line numbers, add a not found error check --- docs/tutorials/wiki/definingviews.rst | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 0435a70d2..3194d2df7 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -267,17 +267,19 @@ Update ``tutorial/templates/layout.pt`` with the following content, as indicated .. literalinclude:: src/views/tutorial/templates/layout.pt :linenos: - :emphasize-lines: 11-12 + :emphasize-lines: 11-12, 37-41 :language: html Since we are using a templating engine, we can factor common boilerplate out of our page templates into reusable components. We can do this via :term:`METAL` macros and slots. -- The cookiecutter defined a macro named ``layout`` (Line 1). - This macro consists of the entire document. -- The cookiecutter defined a macro customization point or `slot` (Line 36). +- The cookiecutter defined a macro named ``layout`` (line 1). + This macro consists of the entire template. +- We changed the ``title`` tag to use the ``name`` attribute of a ``page`` object (lines 11-12). +- The cookiecutter defined a macro customization point or `slot` (line 36). This slot is inside the macro ``layout``. Therefore it can be replaced by content, customizing the macro. +- We added a ``div`` element with a link to allow the user to return to the front page (lines 37-41). - We removed the row of icons and links from the original cookiecutter. .. seealso:: @@ -293,7 +295,7 @@ Rename ``tutorial/templates/mytemplate.pt`` to ``tutorial/templates/view.pt`` an .. literalinclude:: src/views/tutorial/templates/view.pt :linenos: :language: html - :emphasize-lines: 5-19 + :emphasize-lines: 5-16 This template is used by ``view_page()`` for displaying a single wiki page. It includes: @@ -304,7 +306,6 @@ wiki page. It includes: ``page_text`` contains HTML, so the ``structure`` keyword is used to prevent escaping HTML entities, such as changing ``>`` to ``>``. - A link that points at the "edit" URL, which invokes the ``edit_page`` view for the page being viewed (lines 9-11). - A ``span`` whose content is replaced by the name of the page, if present. -- A link to the FrontPage. The ``edit.pt`` template @@ -315,14 +316,15 @@ Copy ``tutorial/templates/view.pt`` to ``tutorial/templates/edit.pt`` and edit t .. literalinclude:: src/views/tutorial/templates/edit.pt :linenos: :language: html + :emphasize-lines: 5-20 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 (lines 14-15). -- A submit button that has the name ``form.submitted`` (line 18). +- A 10-row by 60-column ``textarea`` field named ``body`` that is filled with any existing page data when it is rendered (lines 11-13). +- A submit button that has the name ``form.submitted`` (lines 16-18). -When submitted, the form sends a POST request to the ``save_url`` argument supplied by the view (line 12). +When submitted, the form sends a POST request to the ``save_url`` argument supplied by the view (line 9). The view will use the ``body`` and ``form.submitted`` values. .. note:: @@ -361,3 +363,5 @@ Launch a browser and visit each of the following URLs, checking that the result - To generate an error, visit http://localhost:6543/add_page which will generate an ``IndexError: tuple index out of range`` error. You will see an interactive traceback facility provided by :term:`pyramid_debugtoolbar`. + +- To generate a not found error, visit http://localhost:6543/wakawaka which will invoke the ``notfound_view`` view provided by the cookiecutter. -- cgit v1.2.3 From 51c36cffdf86f22a3a50549f459fe4b8e500db94 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 04:02:00 -0800 Subject: Add section for notfound --- docs/tutorials/wiki/definingviews.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 3194d2df7..81ef4f5c4 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -251,6 +251,21 @@ If the view execution *is* a result of a form submission (if the expression ``'f It then redirects to the default view of the context (the page), which will always be the ``view_page`` view. +Modifying the ``notfound_view`` in ``notfound.py`` +-------------------------------------------------- + +We have one more view to modify. +Open ``tutorial/views/notfound.py`` and make the changes shown by the emphasized lines. + +.. literalinclude:: src/views/tutorial/views/notfound.py + :linenos: + :language: python + :emphasize-lines: 3-4, 9-12 + +We need to import the ``Page`` from our models. +We eventually return a ``Page`` object as ``page`` into the template ``layout.pt`` to display its name in the title tag. + + Adding templates ================ -- cgit v1.2.3 From 65deab3b3aa370217d504c2a64e9cf0b7b3d84f3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 04:06:32 -0800 Subject: Rewrap intro and add dependencies to authorization --- docs/tutorials/wiki/authorization.rst | 47 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index b7eeb19ae..f224a072a 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -4,36 +4,30 @@ Adding authorization ==================== -:app:`Pyramid` provides facilities for :term:`authentication` and -:term:`authorization`. We'll make use of both features to provide security to -our application. Our application currently allows anyone with access to the -server to view, edit, and add pages to our wiki. We'll change that to allow -only people who are members of a *group* named ``group:editors`` to add and -edit wiki pages, but we'll continue allowing anyone with access to the server -to view pages. - -We will also add a login page and a logout link on all the pages. The login -page will be shown when a user is denied access to any of the views that +:app:`Pyramid` provides facilities for :term:`authentication` and :term:`authorization`. +We will make use of both features to provide security to our application. +Our application currently allows anyone with access to the server to view, edit, and add pages to our wiki. +We will change that to allow only people who are members of a *group* named ``group:editors`` to add and edit wiki pages. +We will continue to allow anyone with access to the server to view pages. + +We will also add a login page and a logout link on all the pages. +The login page will be shown when a user is denied access to any of the views that 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` - (``__init__.py``). -* Add :term:`permission` declarations to the ``edit_page`` and ``add_page`` - views (``views.py``). +- 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` (``__init__.py``). +- Add :term:`permission` declarations to the ``edit_page`` and ``add_page`` views (``views.py``). Then we will add the login and logout features: -* Add ``login`` and ``logout`` views (``views.py``). -* Add a login template (``login.pt``). -* Make the existing views return a ``logged_in`` flag to the renderer - (``views.py``). -* Add a "Logout" link to be shown when logged in and viewing or editing a page - (``view.pt``, ``edit.pt``). +- Add ``login`` and ``logout`` views (``views.py``). +- Add a login template (``login.pt``). +- Make the existing views return a ``logged_in`` flag to the renderer (``views.py``). +- Add a "Logout" link to be shown when logged in and viewing or editing a page (``view.pt``, ``edit.pt``). Access control @@ -43,7 +37,8 @@ Access control Add dependencies ~~~~~~~~~~~~~~~~ -Just like in :ref:`wiki_defining_views`, we need a new dependency. We need to add the `bcrypt `_ package, to our tutorial package's ``setup.py`` file by assigning this dependency to the ``requires`` parameter in the ``setup()`` function. +Just like in :ref:`wiki_defining_views`, we need a new dependency. +We need to add the `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: @@ -58,7 +53,9 @@ Do not forget to run ``pip install -e .`` just like in :ref:`wiki-running-pip-in .. 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. + 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 is an algorithm approved for storing passwords versus a generic one-way hash. Add users and groups -- cgit v1.2.3 From ef5bbad0b84c4abeda5ad6bd9b6e2295c19e7c80 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 04:07:31 -0800 Subject: We're adding both authn and authz --- docs/tutorials/wiki/authorization.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index f224a072a..beea1b804 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -1,8 +1,8 @@ .. _wiki_adding_authorization: -==================== -Adding authorization -==================== +======================================= +Adding authorization and authentication +======================================= :app:`Pyramid` provides facilities for :term:`authentication` and :term:`authorization`. We will make use of both features to provide security to our application. -- cgit v1.2.3 From c54405f9ebeadf339912f226beb13daa3d653e32 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 04:13:27 -0800 Subject: rewrap users and groups section, shorter sentences, fix grammar --- docs/tutorials/wiki/authorization.rst | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index beea1b804..f027617ec 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -67,34 +67,34 @@ Create a new ``tutorial/security.py`` module with the following content: :linenos: :language: python -The ``groupfinder`` function accepts a userid and a request and -returns one of these values: +The ``groupfinder`` function accepts a ``userid`` and a ``request`` +It returns one of these values: -- 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``. +- If ``userid`` exists in the system, it will return either a sequence of group identifiers, or an empty sequence if the user is not a member of any groups. +- If the userid *does not* exist in the system, it will return ``None``. -For example, ``groupfinder('editor', request )`` returns ``['group:editor']``, -``groupfinder('viewer', request)`` returns ``[]``, and ``groupfinder('admin', -request)`` returns ``None``. We will use ``groupfinder()`` as an -:term:`authentication policy` "callback" that will provide the -:term:`principal` or principals for a user. +For example: + +- ``groupfinder('editor', request )`` returns ``['group:editor']``. +- ``groupfinder('viewer', request)`` returns ``[]``. +- ``groupfinder('admin', request)`` returns ``None``. + +We will use ``groupfinder()`` as an :term:`authentication policy` "callback" that will provide the :term:`principal` or principals for a user. 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. +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. +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. +database. +Here we use "dummy" data to represent user and groups sources. + Add an ACL ~~~~~~~~~~ -- cgit v1.2.3 From 9548bae2badbb6333f7bfd855ce3f2f393cd3420 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 04:56:56 -0800 Subject: rewrap add an ACL section, shorter sentences, fix grammar --- docs/tutorials/wiki/authorization.rst | 74 +++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index f027617ec..93d7fb21f 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -43,9 +43,9 @@ We need to add the `bcrypt `_ package to our t Open ``setup.py`` and edit it to look like the following: .. literalinclude:: src/authorization/setup.py - :linenos: - :emphasize-lines: 23 - :language: python + :linenos: + :emphasize-lines: 23 + :language: python Only the highlighted line needs to be added. @@ -64,8 +64,8 @@ Add users and groups Create a new ``tutorial/security.py`` module with the following content: .. literalinclude:: src/authorization/tutorial/security.py - :linenos: - :language: python + :linenos: + :language: python The ``groupfinder`` function accepts a ``userid`` and a ``request`` It returns one of these values: @@ -99,43 +99,43 @@ Here we use "dummy" data to represent user and groups sources. Add an ACL ~~~~~~~~~~ -Open ``tutorial/models.py`` and add the following import -statement near the top: +Open ``tutorial/models.py`` and add the following import statement near the top: -.. literalinclude:: src/authorization/tutorial/models.py - :lines: 4-8 - :lineno-match: - :language: python +.. literalinclude:: src/authorization/tutorial/models/__init__.py + :lines: 4-8 + :lineno-match: + :language: python Add the following lines to the ``Wiki`` class: -.. literalinclude:: src/authorization/tutorial/models.py - :lines: 9-13 - :lineno-match: - :emphasize-lines: 4-5 - :language: python +.. literalinclude:: src/authorization/tutorial/models/__init__.py + :lines: 9-13 + :lineno-match: + :emphasize-lines: 4-5 + :language: python + +We import :data:`~pyramid.security.Allow`, an action which means that +permission is allowed. +We also import :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 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. + +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 provided to each view in the :term:`context` of the request as the ``context`` attribute. + +It is only happenstance that we assigned this ACL at class scope. +An ACL can be attached to an object *instance* too. +This is how "row level security" can be achieved in :app:`Pyramid` applications. +We actually need only *one* ACL for the entire system, however, because our security requirements are simple, so this feature is not demonstrated. + +.. seealso:: + + See :ref:`assigning_acls` for more information about what an :term:`ACL` represents. -We import :data:`~pyramid.security.Allow`, an action that means that -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 -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. - -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 -provided to each view in the :term:`context` of the request as the ``context`` -attribute. - -It's only happenstance that we're assigning this ACL at class scope. An ACL -can be attached to an object *instance* too; this is how "row level security" -can be achieved in :app:`Pyramid` applications. We actually need only *one* -ACL for the entire system, however, because our security requirements are -simple, so this feature is not demonstrated. See :ref:`assigning_acls` for -more information about what an :term:`ACL` represents. Add authentication and authorization policies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 99d91941cdabb2bee707f740f763465e588a4f49 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 05:09:56 -0800 Subject: rewrap policies and permissions sections, shorter sentences, fix grammar --- docs/tutorials/wiki/authorization.rst | 46 ++++++++++++++++------------------- 1 file changed, 21 insertions(+), 25 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 93d7fb21f..2d9d73d46 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -152,44 +152,40 @@ statements: Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 18-25 + :lines: 15-25 :lineno-match: - :emphasize-lines: 2-4,6-7 + :emphasize-lines: 4-6,9-10 :language: python Only the highlighted lines need to be added. -We are enabling an ``AuthTktAuthenticationPolicy``, which is based in an auth -ticket that may be included in the request. We are also enabling an -``ACLAuthorizationPolicy``, which uses an ACL to determine the *allow* or -*deny* outcome for a view. +We enabled an ``AuthTktAuthenticationPolicy`` which is based in an auth ticket that may be included in the request. +We also enabled an ``ACLAuthorizationPolicy`` which uses an ACL to determine the *allow* or *deny* outcome for a view. + +Note that the :class:`pyramid.authentication.AuthTktAuthenticationPolicy` constructor accepts two arguments: ``secret`` and ``callback``. +``secret`` is a string representing an encryption key used by the "authentication ticket" machinery represented by this policy. +It is required. +The ``callback`` is the ``groupfinder()`` function that we created earlier. -Note that the :class:`pyramid.authentication.AuthTktAuthenticationPolicy` -constructor accepts two arguments: ``secret`` and ``callback``. ``secret`` is -a string representing an encryption key used by the "authentication ticket" -machinery represented by this policy: it is required. The ``callback`` is the -``groupfinder()`` function that we created before. Add permission declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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 +Open ``tutorial/views/default.py`` and add a ``permission='edit'`` parameter to the ``@view_config`` decorators for ``add_page()`` and ``edit_page()``: + +.. literalinclude:: src/authorization/tutorial/views/default.py :lines: 49-51 :emphasize-lines: 2-3 :language: python -.. literalinclude:: src/authorization/tutorial/views.py +.. literalinclude:: src/authorization/tutorial/views/default.py :lines: 68-70 :emphasize-lines: 2-3 :language: python -Only the highlighted lines, along with their preceding commas, need to be -edited and added. +Only the highlighted lines, along with their preceding commas, need to be edited and added. -The result is that only users who possess the ``edit`` permission at the time -of the request may invoke those two views. +The result is that only users who possess the ``edit`` permission at the time of the request may invoke those two views. Add a ``permission='view'`` parameter to the ``@view_config`` decorator for ``view_wiki()`` and ``view_page()`` as follows: @@ -204,22 +200,22 @@ Add a ``permission='view'`` parameter to the ``@view_config`` decorator for :emphasize-lines: 1-2 :language: python -Only the highlighted lines, along with their preceding commas, need to be -edited and added. +Only the highlighted lines, along with their preceding commas, need to be edited and added. This allows anyone to invoke these two views. -We are done with the changes needed to control access. The changes that -follow will add the login and logout feature. +We are done with the changes needed to control access. +The changes that follow will add the login and logout feature. + Login, logout ------------- + Add login and logout views ~~~~~~~~~~~~~~~~~~~~~~~~~~ -We'll add a ``login`` view which renders a login form and processes the post -from the login form, checking credentials. +We will add a ``login`` view which renders a login form and processes the post from the login form, checking credentials. We'll also add a ``logout`` view callable to our application and provide a link to it. This view will clear the credentials of the logged in user and -- cgit v1.2.3 From 097381f8e8fa112bfb859fcf4938611b94a498bf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 11:47:03 -0800 Subject: indent literalincludes, add login.pt template and view --- docs/tutorials/wiki/authorization.rst | 147 ++++++++++++++++------------------ 1 file changed, 71 insertions(+), 76 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 2d9d73d46..60c83c871 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -144,18 +144,18 @@ Open ``tutorial/__init__.py`` and add the highlighted import statements: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 1-8 - :linenos: - :emphasize-lines: 3-6,8 - :language: python + :lines: 1-8 + :linenos: + :emphasize-lines: 3-6,8 + :language: python Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py - :lines: 15-25 - :lineno-match: - :emphasize-lines: 4-6,9-10 - :language: python + :lines: 15-25 + :lineno-match: + :emphasize-lines: 4-6,9-10 + :language: python Only the highlighted lines need to be added. @@ -174,14 +174,14 @@ Add permission declarations Open ``tutorial/views/default.py`` and add a ``permission='edit'`` parameter to the ``@view_config`` decorators for ``add_page()`` and ``edit_page()``: .. literalinclude:: src/authorization/tutorial/views/default.py - :lines: 49-51 - :emphasize-lines: 2-3 - :language: python + :lines: 49-51 + :emphasize-lines: 2-3 + :language: python .. literalinclude:: src/authorization/tutorial/views/default.py - :lines: 68-70 - :emphasize-lines: 2-3 - :language: python + :lines: 68-70 + :emphasize-lines: 2-3 + :language: python Only the highlighted lines, along with their preceding commas, need to be edited and added. @@ -191,14 +191,14 @@ Add a ``permission='view'`` parameter to the ``@view_config`` decorator for ``view_wiki()`` and ``view_page()`` as follows: .. literalinclude:: src/authorization/tutorial/views.py - :lines: 23-24 - :emphasize-lines: 1-2 - :language: python + :lines: 23-24 + :emphasize-lines: 1-2 + :language: python .. literalinclude:: src/authorization/tutorial/views.py - :lines: 28-29 - :emphasize-lines: 1-2 - :language: python + :lines: 28-29 + :emphasize-lines: 1-2 + :language: python Only the highlighted lines, along with their preceding commas, need to be edited and added. @@ -217,46 +217,41 @@ Add login and logout views We will add a ``login`` view which renders a login form and processes the post from the login form, checking credentials. -We'll also add a ``logout`` view callable to our application and provide a -link to it. This view will clear the credentials of the logged in user and -redirect back to the front page. +We will also add a ``logout`` view callable to our application and provide a link to it. +This view will clear the credentials of the logged in user and redirect back to the front page. -Add the following import statements to the head of -``tutorial/views.py``: +Add the following import statements to the head of ``tutorial/views/default.py``: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 6-17 - :emphasize-lines: 1-12 - :language: python +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 4-15 + :emphasize-lines: 2-10,12 + :lineno-match: + :language: python All the highlighted lines need to be added or edited. -:meth:`~pyramid.view.forbidden_view_config` will be used to customize the -default 403 Forbidden page. :meth:`~pyramid.security.remember` and -:meth:`~pyramid.security.forget` help to create and expire an auth ticket -cookie. +:meth:`~pyramid.view.forbidden_view_config` will be used to customize the default 403 Forbidden page. +:meth:`~pyramid.security.remember` and :meth:`~pyramid.security.forget` help to create and expire an auth ticket cookie. Now add the ``login`` and ``logout`` views at the end of the file: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 80- - :lineno-match: - :language: python +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 78- + :lineno-match: + :language: python ``login()`` has two decorators: -- a ``@view_config`` decorator which associates it with the ``login`` route - and makes it visible when we visit ``/login``, -- a ``@forbidden_view_config`` decorator which turns it into a - :term:`forbidden view`. ``login()`` will be invoked when a user tries to - execute a view callable for which they lack authorization. For example, if - a user has not logged in and tries to add or edit a Wiki page, they will be - shown the login form before being allowed to continue. +- A ``@view_config`` decorator which associates it with the ``login`` route and makes it visible when we visit ``/login``. +- A ``@forbidden_view_config`` decorator which turns it into a :term:`forbidden view`. + ``login()`` will be invoked when a user tries to execute a view callable for which they lack authorization. + For example, if a user has not logged in and tries to add or edit a Wiki page, then they will be shown the login form before being allowed to continue. The order of these two :term:`view configuration` decorators is unimportant. -``logout()`` is decorated with a ``@view_config`` decorator which associates -it with the ``logout`` route. It will be invoked when we visit ``/logout``. +``logout()`` is decorated with a ``@view_config`` decorator which associates it with the ``logout`` route. +It will be invoked when we visit ``/logout``. + Add the ``login.pt`` Template ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -264,10 +259,10 @@ Add the ``login.pt`` Template Create ``tutorial/templates/login.pt`` with the following content: .. literalinclude:: src/authorization/tutorial/templates/login.pt - :language: html + :language: html + +The above template is referenced in the login view that we just added in ``views.py``. -The above template is referenced in the login view that we just added in -``views.py``. Return a ``logged_in`` flag to the renderer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -277,19 +272,19 @@ the return value of ``view_page()``, ``add_page()``, and ``edit_page()`` as follows: .. literalinclude:: src/authorization/tutorial/views.py - :lines: 46-47 - :emphasize-lines: 1-2 - :language: python + :lines: 46-47 + :emphasize-lines: 1-2 + :language: python .. literalinclude:: src/authorization/tutorial/views.py - :lines: 65-66 - :emphasize-lines: 1-2 - :language: python + :lines: 65-66 + :emphasize-lines: 1-2 + :language: python .. literalinclude:: src/authorization/tutorial/views.py - :lines: 76-78 - :emphasize-lines: 2-3 - :language: python + :lines: 76-78 + :emphasize-lines: 2-3 + :language: python Only the highlighted lines need to be added or edited. @@ -304,9 +299,9 @@ Open ``tutorial/templates/edit.pt`` and indicated by the highlighted lines. .. literalinclude:: src/authorization/tutorial/templates/edit.pt - :lines: 35-39 - :emphasize-lines: 2-4 - :language: html + :lines: 35-39 + :emphasize-lines: 2-4 + :language: html The attribute ``tal:condition="logged_in"`` will make the element be included when ``logged_in`` is any user id. The link will invoke the logout view. The @@ -319,27 +314,27 @@ Reviewing our changes Our ``tutorial/__init__.py`` will look like this when we're done: .. literalinclude:: src/authorization/tutorial/__init__.py - :linenos: - :emphasize-lines: 4-5,8,19-21,23-24 - :language: python + :linenos: + :emphasize-lines: 4-5,8,19-21,23-24 + :language: python Only the highlighted lines need to be added or edited. Our ``tutorial/models.py`` will look like this when we're done: .. literalinclude:: src/authorization/tutorial/models.py - :linenos: - :emphasize-lines: 4-7,12-13 - :language: python + :linenos: + :emphasize-lines: 4-7,12-13 + :language: python Only the highlighted lines need to be added or edited. 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,47,51,66,70,78,80- - :language: python + :linenos: + :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. @@ -347,9 +342,9 @@ Our ``tutorial/templates/edit.pt`` template will look like this when we're done: .. literalinclude:: src/authorization/tutorial/templates/edit.pt - :linenos: - :emphasize-lines: 36-38 - :language: html + :linenos: + :emphasize-lines: 36-38 + :language: html Only the highlighted lines need to be added or edited. @@ -357,9 +352,9 @@ Our ``tutorial/templates/view.pt`` template will look like this when we're done: .. literalinclude:: src/authorization/tutorial/templates/view.pt - :linenos: - :emphasize-lines: 36-38 - :language: html + :linenos: + :emphasize-lines: 36-38 + :language: html Only the highlighted lines need to be added or edited. -- cgit v1.2.3 From 622a98df9f46805617481c573073901493e601c4 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 12:26:58 -0800 Subject: Use path for pagename, not subpath --- docs/tutorials/wiki/src/views/tutorial/views/notfound.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/views/tutorial/views/notfound.py b/docs/tutorials/wiki/src/views/tutorial/views/notfound.py index 214ec810e..d44b4d0e6 100644 --- a/docs/tutorials/wiki/src/views/tutorial/views/notfound.py +++ b/docs/tutorials/wiki/src/views/tutorial/views/notfound.py @@ -6,7 +6,7 @@ from ..models import Page @notfound_view_config(renderer='../templates/404.pt') def notfound_view(request): request.response.status = 404 - pagename = request.subpath + pagename = request.path page = Page(pagename) page.__name__ = pagename return dict(page=page) -- cgit v1.2.3 From 7672298e3877e36f12832cc6d6099aefa6173160 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 13:19:22 -0800 Subject: Update theme.css to display text in inputs - See #3431 --- docs/tutorials/wiki/src/basiclayout/tutorial/static/theme.css | 3 +++ docs/tutorials/wiki/src/installation/tutorial/static/theme.css | 3 +++ docs/tutorials/wiki/src/models/tutorial/static/theme.css | 3 +++ docs/tutorials/wiki/src/views/tutorial/static/theme.css | 3 +++ 4 files changed, 12 insertions(+) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/static/theme.css b/docs/tutorials/wiki/src/basiclayout/tutorial/static/theme.css index 0f4b1a4d4..a70ee557a 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/static/theme.css +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/static/theme.css @@ -17,6 +17,9 @@ h6 { p { font-weight: 300; } +button, input, optgroup, select, textarea { + color: black; +} .font-normal { font-weight: 400; } diff --git a/docs/tutorials/wiki/src/installation/tutorial/static/theme.css b/docs/tutorials/wiki/src/installation/tutorial/static/theme.css index 0f4b1a4d4..a70ee557a 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/static/theme.css +++ b/docs/tutorials/wiki/src/installation/tutorial/static/theme.css @@ -17,6 +17,9 @@ h6 { p { font-weight: 300; } +button, input, optgroup, select, textarea { + color: black; +} .font-normal { font-weight: 400; } diff --git a/docs/tutorials/wiki/src/models/tutorial/static/theme.css b/docs/tutorials/wiki/src/models/tutorial/static/theme.css index 0f4b1a4d4..a70ee557a 100644 --- a/docs/tutorials/wiki/src/models/tutorial/static/theme.css +++ b/docs/tutorials/wiki/src/models/tutorial/static/theme.css @@ -17,6 +17,9 @@ h6 { p { font-weight: 300; } +button, input, optgroup, select, textarea { + color: black; +} .font-normal { font-weight: 400; } diff --git a/docs/tutorials/wiki/src/views/tutorial/static/theme.css b/docs/tutorials/wiki/src/views/tutorial/static/theme.css index 0f4b1a4d4..a70ee557a 100644 --- a/docs/tutorials/wiki/src/views/tutorial/static/theme.css +++ b/docs/tutorials/wiki/src/views/tutorial/static/theme.css @@ -17,6 +17,9 @@ h6 { p { font-weight: 300; } +button, input, optgroup, select, textarea { + color: black; +} .font-normal { font-weight: 400; } -- cgit v1.2.3 From 6f16b8f8f8a2747115cc6e2b3633b841cf2c17dc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 13:20:16 -0800 Subject: rewrap review, shorter sentences, fix grammar. align line numbers with code. --- docs/tutorials/wiki/authorization.rst | 118 ++++++++++++++++------------------ 1 file changed, 55 insertions(+), 63 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 60c83c871..207b19d10 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -190,12 +190,12 @@ The result is that only users who possess the ``edit`` permission at the time of Add a ``permission='view'`` parameter to the ``@view_config`` decorator for ``view_wiki()`` and ``view_page()`` as follows: -.. literalinclude:: src/authorization/tutorial/views.py +.. literalinclude:: src/authorization/tutorial/views/default.py :lines: 23-24 :emphasize-lines: 1-2 :language: python -.. literalinclude:: src/authorization/tutorial/views.py +.. literalinclude:: src/authorization/tutorial/views/default.py :lines: 28-29 :emphasize-lines: 1-2 :language: python @@ -225,7 +225,6 @@ Add the following import statements to the head of ``tutorial/views/default.py`` .. literalinclude:: src/authorization/tutorial/views/default.py :lines: 4-15 :emphasize-lines: 2-10,12 - :lineno-match: :language: python All the highlighted lines need to be added or edited. @@ -267,93 +266,90 @@ The above template is referenced in the login view that we just added in ``views Return a ``logged_in`` flag to the renderer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Open ``tutorial/views.py`` again. Add a ``logged_in`` parameter to -the return value of ``view_page()``, ``add_page()``, and ``edit_page()`` as -follows: +Open ``tutorial/views/default.py`` again. +Add a ``logged_in`` parameter to the return value of ``view_page()``, ``add_page()``, and ``edit_page()`` as follows: -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 46-47 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 45-46 :emphasize-lines: 1-2 :language: python -.. literalinclude:: src/authorization/tutorial/views.py +.. literalinclude:: src/authorization/tutorial/views/default.py :lines: 65-66 :emphasize-lines: 1-2 :language: python -.. literalinclude:: src/authorization/tutorial/views.py - :lines: 76-78 +.. literalinclude:: src/authorization/tutorial/views/default.py + :lines: 77-79 :emphasize-lines: 2-3 :language: python Only the highlighted lines need to be added or edited. -The :meth:`pyramid.request.Request.authenticated_userid` will be ``None`` if -the user is not authenticated, or a userid if the user is authenticated. +The :meth:`pyramid.request.Request.authenticated_userid` will be ``None`` if the user is not authenticated, or a ``userid`` if the user is authenticated. + Add a "Logout" link when logged in ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Open ``tutorial/templates/edit.pt`` and -``tutorial/templates/view.pt`` and add the following code as -indicated by the highlighted lines. +Open ``tutorial/templates/edit.pt`` and ``tutorial/templates/view.pt``. +Add the following code as indicated by the highlighted lines. .. literalinclude:: src/authorization/tutorial/templates/edit.pt - :lines: 35-39 + :lines: 4-8 :emphasize-lines: 2-4 :language: html -The attribute ``tal:condition="logged_in"`` will make the element be included -when ``logged_in`` is any user id. The link will invoke the logout view. The -above element will not be included if ``logged_in`` is ``None``, such as when +The attribute ``tal:condition="logged_in"`` will make the element be included when ``logged_in`` is any user id. +The link will invoke the logout view. +The above element will not be included if ``logged_in`` is ``None``, such as when a user is not authenticated. + Reviewing our changes --------------------- -Our ``tutorial/__init__.py`` will look like this when we're done: +Our ``tutorial/__init__.py`` will look like this when we are done: .. literalinclude:: src/authorization/tutorial/__init__.py :linenos: - :emphasize-lines: 4-5,8,19-21,23-24 + :emphasize-lines: 3-6,8,18-20,23-24 :language: python Only the highlighted lines need to be added or edited. -Our ``tutorial/models.py`` will look like this when we're done: +Our ``tutorial/models.py`` will look like this when we are done: -.. literalinclude:: src/authorization/tutorial/models.py +.. literalinclude:: src/authorization/tutorial/models/__init__.py :linenos: - :emphasize-lines: 4-7,12-13 + :emphasize-lines: 4-8,12-13 :language: python Only the highlighted lines need to be added or edited. -Our ``tutorial/views.py`` will look like this when we're done: +Our ``tutorial/views/default.py`` will look like this when we are done: -.. literalinclude:: src/authorization/tutorial/views.py +.. literalinclude:: src/authorization/tutorial/views/default.py :linenos: - :emphasize-lines: 8,11-15,17,24,29,47,51,66,70,78,80- + :emphasize-lines: 5-12,15,21-22,27-28,45-46,50-51,65-66,70-71,78- :language: python Only the highlighted lines need to be added or edited. -Our ``tutorial/templates/edit.pt`` template will look like this when -we're done: +Our ``tutorial/templates/edit.pt`` template will look like this when we are done: .. literalinclude:: src/authorization/tutorial/templates/edit.pt :linenos: - :emphasize-lines: 36-38 + :emphasize-lines: 5-7 :language: html Only the highlighted lines need to be added or edited. -Our ``tutorial/templates/view.pt`` template will look like this when -we're done: +Our ``tutorial/templates/view.pt`` template will look like this when we are done: .. literalinclude:: src/authorization/tutorial/templates/view.pt :linenos: - :emphasize-lines: 36-38 + :emphasize-lines: 5-7 :language: html Only the highlighted lines need to be added or edited. @@ -361,32 +357,28 @@ Only the highlighted lines need to be added or edited. Viewing the application in a browser ------------------------------------ -We can finally examine our application in a browser (See -:ref:`wiki-start-the-application`). Launch a browser and visit each of the -following URLs, checking that the result is as expected: - -- http://localhost:6543/ invokes the ``view_wiki`` view. This always - redirects to the ``view_page`` view of the ``FrontPage`` Page resource. It - is executable by any user. - -- http://localhost:6543/FrontPage invokes the ``view_page`` view of the - ``FrontPage`` Page resource. This is because it's the :term:`default view` - (a view without a ``name``) for ``Page`` resources. It is executable by any - user. - -- http://localhost:6543/FrontPage/edit_page invokes the edit view for the - FrontPage object. It is executable by only the ``editor`` user. If a - different user (or the anonymous user) invokes it, a login form will be - displayed. Supplying the credentials with the username ``editor``, password - ``editor`` will display the edit page form. - -- http://localhost:6543/add_page/SomePageName invokes the add view for a page. - It is executable by only the ``editor`` user. If a different user (or the - anonymous user) invokes it, a login form will be displayed. Supplying the - credentials with the username ``editor``, password ``editor`` will display - the edit page form. - -- After logging in (as a result of hitting an edit or add page and submitting - the login form with the ``editor`` credentials), we'll see a Logout link in - the upper right hand corner. When we click it, we're logged out, and - redirected back to the front page. +We can finally examine our application in a browser (See :ref:`wiki-start-the-application`). +Launch a browser and visit each of the following URLs, checking that the result is as expected: + +- http://localhost:6543/ invokes the ``view_wiki`` view. + This always redirects to the ``view_page`` view of the ``FrontPage`` Page resource. + It is executable by any user. + +- http://localhost:6543/FrontPage invokes the ``view_page`` view of the ``FrontPage`` Page resource. + This is because it is the :term:`default view` (a view without a ``name``) for ``Page`` resources. + It is executable by any user. + +- http://localhost:6543/FrontPage/edit_page invokes the edit view for the FrontPage object. + It is executable by only the ``editor`` user. + If a different user (or the anonymous user) invokes it, then a login form will be displayed. + Supplying the credentials with the username ``editor`` and password ``editor`` will display the edit page form. + +- http://localhost:6543/add_page/SomePageName invokes the add view for a page. + It is executable by only the ``editor`` user. + If a different user (or the anonymous user) invokes it, a login form will be displayed. + Supplying the credentials with the username ``editor``, password ``editor`` will display the edit page form. + +- After logging in (as a result of hitting an edit or add page and submitting the login form with the ``editor`` credentials), we will see a Logout link in the upper right hand corner. + When we click it, we are logged out, and redirected back to the front page. + +- To generate a not found error, visit http://localhost:6543/wakawaka which will invoke the ``notfound_view`` view provided by the cookiecutter. -- cgit v1.2.3 From 9495e5d7e65b138b0b209635efd00ae02c2afd27 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 13:21:11 -0800 Subject: synch up src/authorization files --- docs/tutorials/wiki/src/authorization/MANIFEST.in | 2 +- docs/tutorials/wiki/src/authorization/pytest.ini | 2 +- docs/tutorials/wiki/src/authorization/setup.py | 4 +- .../wiki/src/authorization/tutorial/__init__.py | 8 +- .../wiki/src/authorization/tutorial/models.py | 27 ----- .../src/authorization/tutorial/models/__init__.py | 27 +++++ .../wiki/src/authorization/tutorial/pshell.py | 1 + .../wiki/src/authorization/tutorial/routes.py | 2 + .../src/authorization/tutorial/static/theme.css | 3 + .../src/authorization/tutorial/templates/404.pt | 10 ++ .../src/authorization/tutorial/templates/edit.pt | 83 ++++----------- .../src/authorization/tutorial/templates/layout.pt | 59 +++++++++++ .../src/authorization/tutorial/templates/login.pt | 57 +--------- .../src/authorization/tutorial/templates/view.pt | 81 +++----------- .../wiki/src/authorization/tutorial/tests.py | 3 +- .../wiki/src/authorization/tutorial/views.py | 114 -------------------- .../src/authorization/tutorial/views/__init__.py | 0 .../src/authorization/tutorial/views/default.py | 116 +++++++++++++++++++++ .../src/authorization/tutorial/views/notfound.py | 12 +++ 19 files changed, 280 insertions(+), 331 deletions(-) delete mode 100644 docs/tutorials/wiki/src/authorization/tutorial/models.py create mode 100644 docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py create mode 100644 docs/tutorials/wiki/src/authorization/tutorial/routes.py create mode 100644 docs/tutorials/wiki/src/authorization/tutorial/templates/404.pt create mode 100644 docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt delete mode 100644 docs/tutorials/wiki/src/authorization/tutorial/views.py create mode 100644 docs/tutorials/wiki/src/authorization/tutorial/views/__init__.py create mode 100644 docs/tutorials/wiki/src/authorization/tutorial/views/default.py create mode 100644 docs/tutorials/wiki/src/authorization/tutorial/views/notfound.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/authorization/MANIFEST.in b/docs/tutorials/wiki/src/authorization/MANIFEST.in index 81beba1b1..05cc195d9 100644 --- a/docs/tutorials/wiki/src/authorization/MANIFEST.in +++ b/docs/tutorials/wiki/src/authorization/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.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/wiki/src/authorization/pytest.ini b/docs/tutorials/wiki/src/authorization/pytest.ini index 8b76bc410..a3489cdf8 100644 --- a/docs/tutorials/wiki/src/authorization/pytest.ini +++ b/docs/tutorials/wiki/src/authorization/pytest.ini @@ -1,3 +1,3 @@ [pytest] testpaths = tutorial -python_files = *.py +python_files = test*.py diff --git a/docs/tutorials/wiki/src/authorization/setup.py b/docs/tutorials/wiki/src/authorization/setup.py index 7b405745e..fa5948acb 100644 --- a/docs/tutorials/wiki/src/authorization/setup.py +++ b/docs/tutorials/wiki/src/authorization/setup.py @@ -10,15 +10,15 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'plaster_pastedeploy', - 'pyramid >= 1.9a', + 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'waitress', 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', 'ZODB3', - 'waitress', 'docutils', 'bcrypt', ] diff --git a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py index 58635ea74..196c0f311 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py @@ -15,18 +15,18 @@ def root_factory(request): def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' authn_policy = AuthTktAuthenticationPolicy( 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() with Configurator(settings=settings) as config: + settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) - config.include('pyramid_chameleon') config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') config.set_root_factory(root_factory) - config.add_static_view('static', 'static', cache_max_age=3600) + config.include('pyramid_chameleon') + config.include('.routes') config.scan() - return config.make_wsgi_app() + return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/authorization/tutorial/models.py b/docs/tutorials/wiki/src/authorization/tutorial/models.py deleted file mode 100644 index ebd70e912..000000000 --- a/docs/tutorials/wiki/src/authorization/tutorial/models.py +++ /dev/null @@ -1,27 +0,0 @@ -from persistent import Persistent -from persistent.mapping import PersistentMapping - -from pyramid.security import ( - Allow, - Everyone, - ) - -class Wiki(PersistentMapping): - __name__ = None - __parent__ = None - __acl__ = [ (Allow, Everyone, 'view'), - (Allow, 'group:editors', 'edit') ] - -class Page(Persistent): - def __init__(self, data): - self.data = data - -def appmaker(zodb_root): - if 'app_root' not in zodb_root: - app_root = Wiki() - frontpage = Page('This is the front page') - app_root['FrontPage'] = frontpage - frontpage.__name__ = 'FrontPage' - frontpage.__parent__ = app_root - zodb_root['app_root'] = app_root - return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py new file mode 100644 index 000000000..ebd70e912 --- /dev/null +++ b/docs/tutorials/wiki/src/authorization/tutorial/models/__init__.py @@ -0,0 +1,27 @@ +from persistent import Persistent +from persistent.mapping import PersistentMapping + +from pyramid.security import ( + Allow, + Everyone, + ) + +class Wiki(PersistentMapping): + __name__ = None + __parent__ = None + __acl__ = [ (Allow, Everyone, 'view'), + (Allow, 'group:editors', 'edit') ] + +class Page(Persistent): + def __init__(self, data): + self.data = data + +def appmaker(zodb_root): + if 'app_root' not in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/authorization/tutorial/pshell.py b/docs/tutorials/wiki/src/authorization/tutorial/pshell.py index 3d026291b..a7cfa6a27 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/pshell.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/pshell.py @@ -1,5 +1,6 @@ from . import models + def setup(env): request = env['request'] diff --git a/docs/tutorials/wiki/src/authorization/tutorial/routes.py b/docs/tutorials/wiki/src/authorization/tutorial/routes.py new file mode 100644 index 000000000..3c0a37992 --- /dev/null +++ b/docs/tutorials/wiki/src/authorization/tutorial/routes.py @@ -0,0 +1,2 @@ +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) diff --git a/docs/tutorials/wiki/src/authorization/tutorial/static/theme.css b/docs/tutorials/wiki/src/authorization/tutorial/static/theme.css index 0f4b1a4d4..a70ee557a 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/static/theme.css +++ b/docs/tutorials/wiki/src/authorization/tutorial/static/theme.css @@ -17,6 +17,9 @@ h6 { p { font-weight: 300; } +button, input, optgroup, select, textarea { + color: black; +} .font-normal { font-weight: 400; } diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/404.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/404.pt new file mode 100644 index 000000000..07298940c --- /dev/null +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/404.pt @@ -0,0 +1,10 @@ +
+
+ +
+

Pyramid Starter project

+

404 Page Not Found

+
+ +
+
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt index eedb83da4..6438b1569 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/edit.pt @@ -1,72 +1,27 @@ - - - - - - - - - +
+
- ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - -
-
-
-
- -
-
-
-

+

+

Logout -

-

- Editing - Page Name Goes Here -

-

You can return to the - FrontPage. -

-
+

+

+ Editing + Page Name Goes Here +

+
- +
- +
-
-
-
+
-
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt new file mode 100644 index 000000000..ba40fd6f4 --- /dev/null +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt @@ -0,0 +1,59 @@ + + + + + + + + + + + ${page.__name__} - Pyramid tutorial wiki (based on + TurboGears 20-Minute Wiki) + + + + + + + + + + + + + +
+
+
+
+ +
+
+
No content
+
+

You can return to the + FrontPage. +

+
+
+
+
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt index 626db6637..acc4876cf 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/login.pt @@ -1,39 +1,7 @@ - - - - - - - - - +
+
- Login - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - - -
-
-
-
- -
-
-
+

Login @@ -54,22 +22,7 @@

-
-
-
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt index f2a9249ef..911ab0c99 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/view.pt @@ -1,72 +1,23 @@ - - - - - - - - - +
+
- ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - -
-
-
-
- -
-
-
-

+

+

Logout -

-
- Page text goes here. -
-

+

+
+ Page text goes here. +
+

Edit this page -

-

- Viewing - Page Name Goes Here -

-

You can return to the - FrontPage. -

-
-
-
-
- +

+

+ Viewing + Page Name Goes Here +

-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/authorization/tutorial/tests.py b/docs/tutorials/wiki/src/authorization/tutorial/tests.py index ca7a47279..6279d9f66 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/tests.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/tests.py @@ -11,7 +11,8 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from .views import my_view + from .views.default import my_view request = testing.DummyRequest() info = my_view(request) 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 deleted file mode 100644 index ea2da01af..000000000 --- a/docs/tutorials/wiki/src/authorization/tutorial/views.py +++ /dev/null @@ -1,114 +0,0 @@ -from docutils.core import publish_parts -import re - -from pyramid.httpexceptions import HTTPFound - -from pyramid.view import ( - view_config, - forbidden_view_config, - ) - -from pyramid.security import ( - remember, - forget, - ) - - -from .security import USERS, check_password -from .models import Page - -# regular expression used to find WikiWords -wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") - -@view_config(context='.models.Wiki', - permission='view') -def view_wiki(context, request): - return HTTPFound(location=request.resource_url(context, 'FrontPage')) - -@view_config(context='.models.Page', renderer='templates/view.pt', - permission='view') -def view_page(context, request): - wiki = context.__parent__ - - def check(match): - word = match.group(1) - if word in wiki: - page = wiki[word] - view_url = request.resource_url(page) - return '%s' % (view_url, word) - else: - add_url = request.application_url + '/add_page/' + word - return '%s' % (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, - logged_in=request.authenticated_userid) - -@view_config(name='add_page', context='.models.Wiki', - renderer='templates/edit.pt', - permission='edit') -def add_page(context, request): - pagename = request.subpath[0] - if 'form.submitted' in request.params: - body = request.params['body'] - page = Page(body) - page.__name__ = pagename - page.__parent__ = context - context[pagename] = 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, - logged_in=request.authenticated_userid) - -@view_config(name='edit_page', context='.models.Page', - renderer='templates/edit.pt', - permission='edit') -def edit_page(context, request): - if 'form.submitted' in request.params: - context.data = request.params['body'] - return HTTPFound(location=request.resource_url(context)) - - return dict(page=context, - save_url=request.resource_url(context, 'edit_page'), - logged_in=request.authenticated_userid) - -@view_config(context='.models.Wiki', name='login', - renderer='templates/login.pt') -@forbidden_view_config(renderer='templates/login.pt') -def login(request): - login_url = request.resource_url(request.context, 'login') - referrer = request.url - if referrer == login_url: - referrer = '/' # never use the login form itself as came_from - came_from = request.params.get('came_from', referrer) - message = '' - login = '' - password = '' - if 'form.submitted' in request.params: - login = request.params['login'] - password = request.params['password'] - if check_password(USERS.get(login), password): - headers = remember(request, login) - return HTTPFound(location=came_from, - headers=headers) - message = 'Failed login' - - return dict( - message=message, - url=request.application_url + '/login', - came_from=came_from, - login=login, - password=password, - ) - - -@view_config(context='.models.Wiki', name='logout') -def logout(request): - headers = forget(request) - return HTTPFound(location=request.resource_url(request.context), - headers=headers) diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views/default.py b/docs/tutorials/wiki/src/authorization/tutorial/views/default.py new file mode 100644 index 000000000..a44aca786 --- /dev/null +++ b/docs/tutorials/wiki/src/authorization/tutorial/views/default.py @@ -0,0 +1,116 @@ +from docutils.core import publish_parts +import re + +from pyramid.httpexceptions import HTTPFound +from pyramid.security import ( + forget, + remember, +) +from pyramid.view import ( + forbidden_view_config, + view_config, + ) + +from ..models import Page +from ..security import check_password, USERS + +# regular expression used to find WikiWords +wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") + + +@view_config(context='..models.Wiki', + permission='view') +def view_wiki(context, request): + return HTTPFound(location=request.resource_url(context, 'FrontPage')) + + +@view_config(context='..models.Page', renderer='../templates/view.pt', + permission='view') +def view_page(context, request): + wiki = context.__parent__ + + def check(match): + word = match.group(1) + if word in wiki: + page = wiki[word] + view_url = request.resource_url(page) + return '%s' % (view_url, word) + else: + add_url = request.application_url + '/add_page/' + word + return '%s' % (add_url, word) + + page_text = publish_parts(context.data, writer_name='html')['html_body'] + page_text = wikiwords.sub(check, page_text) + edit_url = request.resource_url(context, 'edit_page') + return dict(page=context, page_text=page_text, edit_url=edit_url, + logged_in=request.authenticated_userid) + + +@view_config(name='add_page', context='..models.Wiki', + renderer='../templates/edit.pt', + permission='edit') +def add_page(context, request): + pagename = request.subpath[0] + if 'form.submitted' in request.params: + body = request.params['body'] + page = Page(body) + page.__name__ = pagename + page.__parent__ = context + context[pagename] = 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, + logged_in=request.authenticated_userid) + + +@view_config(name='edit_page', context='..models.Page', + renderer='../templates/edit.pt', + permission='edit') +def edit_page(context, request): + if 'form.submitted' in request.params: + context.data = request.params['body'] + return HTTPFound(location=request.resource_url(context)) + + return dict(page=context, + save_url=request.resource_url(context, 'edit_page'), + logged_in=request.authenticated_userid) + + +@view_config(context='..models.Wiki', name='login', + renderer='templates/login.pt') +@forbidden_view_config(renderer='../templates/login.pt') +def login(request): + login_url = request.resource_url(request.context, 'login') + referrer = request.url + if referrer == login_url: + referrer = '/' # never use the login form itself as came_from + came_from = request.params.get('came_from', referrer) + message = '' + login = '' + password = '' + if 'form.submitted' in request.params: + login = request.params['login'] + password = request.params['password'] + if check_password(USERS.get(login), password): + headers = remember(request, login) + return HTTPFound(location=came_from, + headers=headers) + message = 'Failed login' + + return dict( + message=message, + url=request.application_url + '/login', + came_from=came_from, + login=login, + password=password, + ) + + +@view_config(context='..models.Wiki', name='logout') +def logout(request): + headers = forget(request) + return HTTPFound(location=request.resource_url(request.context), + headers=headers) diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views/notfound.py b/docs/tutorials/wiki/src/authorization/tutorial/views/notfound.py new file mode 100644 index 000000000..d44b4d0e6 --- /dev/null +++ b/docs/tutorials/wiki/src/authorization/tutorial/views/notfound.py @@ -0,0 +1,12 @@ +from pyramid.view import notfound_view_config + +from ..models import Page + + +@notfound_view_config(renderer='../templates/404.pt') +def notfound_view(request): + request.response.status = 404 + pagename = request.path + page = Page(pagename) + page.__name__ = pagename + return dict(page=page) -- cgit v1.2.3 From f5355df850ff5abb2e184f74f3acc1bd193d5d72 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 13:29:31 -0800 Subject: Fix template to include either the page name or a title for the title tag --- docs/tutorials/wiki/definingviews.rst | 2 +- docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt | 2 +- docs/tutorials/wiki/src/authorization/tutorial/views/default.py | 1 + docs/tutorials/wiki/src/views/tutorial/templates/layout.pt | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst index 81ef4f5c4..bd8dc6ecf 100644 --- a/docs/tutorials/wiki/definingviews.rst +++ b/docs/tutorials/wiki/definingviews.rst @@ -290,7 +290,7 @@ We can do this via :term:`METAL` macros and slots. - The cookiecutter defined a macro named ``layout`` (line 1). This macro consists of the entire template. -- We changed the ``title`` tag to use the ``name`` attribute of a ``page`` object (lines 11-12). +- We changed the ``title`` tag to use the ``name`` attribute of a ``page`` object, or if it does not exist then the page title (lines 11-12). - The cookiecutter defined a macro customization point or `slot` (line 36). This slot is inside the macro ``layout``. Therefore it can be replaced by content, customizing the macro. diff --git a/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt index ba40fd6f4..b606e8dad 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/authorization/tutorial/templates/layout.pt @@ -8,7 +8,7 @@ - ${page.__name__} - Pyramid tutorial wiki (based on + <title><span tal:replace="page.__name__ | title"></span> - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views/default.py b/docs/tutorials/wiki/src/authorization/tutorial/views/default.py index a44aca786..0725f7660 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/views/default.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/views/default.py @@ -106,6 +106,7 @@ def login(request): came_from=came_from, login=login, password=password, + title='Login', ) diff --git a/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt index ba40fd6f4..b606e8dad 100644 --- a/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt +++ b/docs/tutorials/wiki/src/views/tutorial/templates/layout.pt @@ -8,7 +8,7 @@ - ${page.__name__} - Pyramid tutorial wiki (based on + <title><span tal:replace="page.__name__ | title"></span> - Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki) -- cgit v1.2.3 From 248d92e49510206b82397e954de3af93c239891b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 13:37:45 -0800 Subject: Fix path to template --- docs/tutorials/wiki/src/authorization/tutorial/views/default.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/authorization/tutorial/views/default.py b/docs/tutorials/wiki/src/authorization/tutorial/views/default.py index 0725f7660..3a3b170e2 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/views/default.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/views/default.py @@ -80,7 +80,7 @@ def edit_page(context, request): @view_config(context='..models.Wiki', name='login', - renderer='templates/login.pt') + renderer='../templates/login.pt') @forbidden_view_config(renderer='../templates/login.pt') def login(request): login_url = request.resource_url(request.context, 'login') -- cgit v1.2.3 From 9a47083da48d6967e329ff7e1730854760e66ca6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 23:31:05 -0800 Subject: Remove settings for tm.manager_hook from __init__.py --- docs/tutorials/wiki/src/authorization/tutorial/__init__.py | 1 - docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py | 1 - docs/tutorials/wiki/src/installation/tutorial/__init__.py | 1 - docs/tutorials/wiki/src/models/tutorial/__init__.py | 1 - docs/tutorials/wiki/src/views/tutorial/__init__.py | 1 - 5 files changed, 5 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py index 196c0f311..935a5d6d2 100644 --- a/docs/tutorials/wiki/src/authorization/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/authorization/tutorial/__init__.py @@ -19,7 +19,6 @@ def main(global_config, **settings): 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() with Configurator(settings=settings) as config: - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config.include('pyramid_tm') diff --git a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py index bd0c71f5b..830a607f3 100644 --- a/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/basiclayout/tutorial/__init__.py @@ -12,7 +12,6 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ with Configurator(settings=settings) as config: - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') diff --git a/docs/tutorials/wiki/src/installation/tutorial/__init__.py b/docs/tutorials/wiki/src/installation/tutorial/__init__.py index bd0c71f5b..830a607f3 100644 --- a/docs/tutorials/wiki/src/installation/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/installation/tutorial/__init__.py @@ -12,7 +12,6 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ with Configurator(settings=settings) as config: - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') diff --git a/docs/tutorials/wiki/src/models/tutorial/__init__.py b/docs/tutorials/wiki/src/models/tutorial/__init__.py index bd0c71f5b..830a607f3 100644 --- a/docs/tutorials/wiki/src/models/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/models/tutorial/__init__.py @@ -12,7 +12,6 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ with Configurator(settings=settings) as config: - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') diff --git a/docs/tutorials/wiki/src/views/tutorial/__init__.py b/docs/tutorials/wiki/src/views/tutorial/__init__.py index bd0c71f5b..830a607f3 100644 --- a/docs/tutorials/wiki/src/views/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/views/tutorial/__init__.py @@ -12,7 +12,6 @@ def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ with Configurator(settings=settings) as config: - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') -- cgit v1.2.3 From c2092ff372f49efb73a923d97d641b0561594b3f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 23:37:10 -0800 Subject: Align line numbers with code - See https://github.com/Pylons/pyramid-cookiecutter-starter/pull/66 --- docs/tutorials/wiki/authorization.rst | 4 ++-- docs/tutorials/wiki/basiclayout.rst | 24 ++++++++---------------- 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst index 207b19d10..ef914cab5 100644 --- a/docs/tutorials/wiki/authorization.rst +++ b/docs/tutorials/wiki/authorization.rst @@ -154,7 +154,7 @@ Now add those policies to the configuration: .. literalinclude:: src/authorization/tutorial/__init__.py :lines: 15-25 :lineno-match: - :emphasize-lines: 4-6,9-10 + :emphasize-lines: 4-6,8-9 :language: python Only the highlighted lines need to be added. @@ -313,7 +313,7 @@ Our ``tutorial/__init__.py`` will look like this when we are done: .. literalinclude:: src/authorization/tutorial/__init__.py :linenos: - :emphasize-lines: 3-6,8,18-20,23-24 + :emphasize-lines: 3-6,8,18-20,22-23 :language: python Only the highlighted lines need to be added or edited. diff --git a/docs/tutorials/wiki/basiclayout.rst b/docs/tutorials/wiki/basiclayout.rst index ab9b7df5c..52d3f4670 100644 --- a/docs/tutorials/wiki/basiclayout.rst +++ b/docs/tutorials/wiki/basiclayout.rst @@ -65,53 +65,45 @@ See also :term:`Deployment settings`. This will be a dictionary of settings parsed from the ``.ini`` file, which contains deployment-related values, such as ``pyramid.reload_templates``, ``zodbconn.uri``, and so on. -Next use an explicit transaction manager for our application. -This prevents new transactions from being implicitly created when touching the manager outside of the ``pyramid_tm`` lifecycle. - -.. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 15 - :lineno-match: - :language: py - Next include support for ``pyramid_tm``, allowing Pyramid requests to join the active transaction as provided by the `transaction `_ package. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 16 + :lines: 15 :lineno-match: :language: py Next include support for ``pyramid_retry`` to retry a request when transient exceptions occur. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 17 + :lines: 16 :lineno-match: :language: py Next include support for ``pyramid_zodbconn``, providing integration between :term:`ZODB` and a Pyramid application. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 18 + :lines: 17 :lineno-match: :language: py Next set a root factory using our function named ``root_factory``. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 19 + :lines: 18 :lineno-match: :language: py Next include support for the :term:`Chameleon` template rendering bindings, allowing us to use the ``.pt`` templates. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 20 + :lines: 19 :lineno-match: :language: py Next include routes from the ``.routes`` module. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 21 + :lines: 20 :lineno-match: :language: py @@ -132,7 +124,7 @@ The third argument is an optional ``cache_max_age`` which specifies the number o Next perform a :term:`scan`. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 22 + :lines: 21 :lineno-match: :language: py @@ -144,7 +136,7 @@ The cookiecutter could have equivalently said ``config.scan('tutorial')``, but i Finally use the :meth:`pyramid.config.Configurator.make_wsgi_app` method to return a :term:`WSGI` application. .. literalinclude:: src/basiclayout/tutorial/__init__.py - :lines: 23 + :lines: 22 :lineno-match: :language: py -- cgit v1.2.3 From b2c7fc1bcf8bd12c24314f4fb09d194a28489a7d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 23:54:08 -0800 Subject: Synch src files between auth and tests --- docs/tutorials/wiki/src/tests/MANIFEST.in | 2 +- docs/tutorials/wiki/src/tests/pytest.ini | 2 +- docs/tutorials/wiki/src/tests/setup.py | 4 +- docs/tutorials/wiki/src/tests/tutorial/__init__.py | 7 +- docs/tutorials/wiki/src/tests/tutorial/models.py | 27 ----- .../wiki/src/tests/tutorial/models/__init__.py | 27 +++++ docs/tutorials/wiki/src/tests/tutorial/pshell.py | 1 + docs/tutorials/wiki/src/tests/tutorial/routes.py | 2 + .../wiki/src/tests/tutorial/static/theme.css | 3 + .../wiki/src/tests/tutorial/templates/404.pt | 10 ++ .../wiki/src/tests/tutorial/templates/edit.pt | 83 ++++----------- .../wiki/src/tests/tutorial/templates/layout.pt | 59 +++++++++++ .../wiki/src/tests/tutorial/templates/login.pt | 57 +--------- .../wiki/src/tests/tutorial/templates/view.pt | 81 +++----------- docs/tutorials/wiki/src/tests/tutorial/views.py | 114 -------------------- .../wiki/src/tests/tutorial/views/__init__.py | 0 .../wiki/src/tests/tutorial/views/default.py | 117 +++++++++++++++++++++ .../wiki/src/tests/tutorial/views/notfound.py | 12 +++ 18 files changed, 278 insertions(+), 330 deletions(-) delete mode 100644 docs/tutorials/wiki/src/tests/tutorial/models.py create mode 100644 docs/tutorials/wiki/src/tests/tutorial/models/__init__.py create mode 100644 docs/tutorials/wiki/src/tests/tutorial/routes.py create mode 100644 docs/tutorials/wiki/src/tests/tutorial/templates/404.pt create mode 100644 docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt delete mode 100644 docs/tutorials/wiki/src/tests/tutorial/views.py create mode 100644 docs/tutorials/wiki/src/tests/tutorial/views/__init__.py create mode 100644 docs/tutorials/wiki/src/tests/tutorial/views/default.py create mode 100644 docs/tutorials/wiki/src/tests/tutorial/views/notfound.py (limited to 'docs') diff --git a/docs/tutorials/wiki/src/tests/MANIFEST.in b/docs/tutorials/wiki/src/tests/MANIFEST.in index 81beba1b1..05cc195d9 100644 --- a/docs/tutorials/wiki/src/tests/MANIFEST.in +++ b/docs/tutorials/wiki/src/tests/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include tutorial *.ico *.png *.css *.gif *.jpg *.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/wiki/src/tests/pytest.ini b/docs/tutorials/wiki/src/tests/pytest.ini index 8b76bc410..a3489cdf8 100644 --- a/docs/tutorials/wiki/src/tests/pytest.ini +++ b/docs/tutorials/wiki/src/tests/pytest.ini @@ -1,3 +1,3 @@ [pytest] testpaths = tutorial -python_files = *.py +python_files = test*.py diff --git a/docs/tutorials/wiki/src/tests/setup.py b/docs/tutorials/wiki/src/tests/setup.py index 7b405745e..fa5948acb 100644 --- a/docs/tutorials/wiki/src/tests/setup.py +++ b/docs/tutorials/wiki/src/tests/setup.py @@ -10,15 +10,15 @@ with open(os.path.join(here, 'CHANGES.txt')) as f: requires = [ 'plaster_pastedeploy', - 'pyramid >= 1.9a', + 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', + 'waitress', 'pyramid_retry', 'pyramid_tm', 'pyramid_zodbconn', 'transaction', 'ZODB3', - 'waitress', 'docutils', 'bcrypt', ] diff --git a/docs/tutorials/wiki/src/tests/tutorial/__init__.py b/docs/tutorials/wiki/src/tests/tutorial/__init__.py index 58635ea74..935a5d6d2 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/__init__.py +++ b/docs/tutorials/wiki/src/tests/tutorial/__init__.py @@ -15,18 +15,17 @@ def root_factory(request): def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' authn_policy = AuthTktAuthenticationPolicy( 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() with Configurator(settings=settings) as config: config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) - config.include('pyramid_chameleon') config.include('pyramid_tm') config.include('pyramid_retry') config.include('pyramid_zodbconn') config.set_root_factory(root_factory) - config.add_static_view('static', 'static', cache_max_age=3600) + config.include('pyramid_chameleon') + config.include('.routes') config.scan() - return config.make_wsgi_app() + return config.make_wsgi_app() diff --git a/docs/tutorials/wiki/src/tests/tutorial/models.py b/docs/tutorials/wiki/src/tests/tutorial/models.py deleted file mode 100644 index ebd70e912..000000000 --- a/docs/tutorials/wiki/src/tests/tutorial/models.py +++ /dev/null @@ -1,27 +0,0 @@ -from persistent import Persistent -from persistent.mapping import PersistentMapping - -from pyramid.security import ( - Allow, - Everyone, - ) - -class Wiki(PersistentMapping): - __name__ = None - __parent__ = None - __acl__ = [ (Allow, Everyone, 'view'), - (Allow, 'group:editors', 'edit') ] - -class Page(Persistent): - def __init__(self, data): - self.data = data - -def appmaker(zodb_root): - if 'app_root' not in zodb_root: - app_root = Wiki() - frontpage = Page('This is the front page') - app_root['FrontPage'] = frontpage - frontpage.__name__ = 'FrontPage' - frontpage.__parent__ = app_root - zodb_root['app_root'] = app_root - return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/tests/tutorial/models/__init__.py b/docs/tutorials/wiki/src/tests/tutorial/models/__init__.py new file mode 100644 index 000000000..ebd70e912 --- /dev/null +++ b/docs/tutorials/wiki/src/tests/tutorial/models/__init__.py @@ -0,0 +1,27 @@ +from persistent import Persistent +from persistent.mapping import PersistentMapping + +from pyramid.security import ( + Allow, + Everyone, + ) + +class Wiki(PersistentMapping): + __name__ = None + __parent__ = None + __acl__ = [ (Allow, Everyone, 'view'), + (Allow, 'group:editors', 'edit') ] + +class Page(Persistent): + def __init__(self, data): + self.data = data + +def appmaker(zodb_root): + if 'app_root' not in zodb_root: + app_root = Wiki() + frontpage = Page('This is the front page') + app_root['FrontPage'] = frontpage + frontpage.__name__ = 'FrontPage' + frontpage.__parent__ = app_root + zodb_root['app_root'] = app_root + return zodb_root['app_root'] diff --git a/docs/tutorials/wiki/src/tests/tutorial/pshell.py b/docs/tutorials/wiki/src/tests/tutorial/pshell.py index 3d026291b..a7cfa6a27 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/pshell.py +++ b/docs/tutorials/wiki/src/tests/tutorial/pshell.py @@ -1,5 +1,6 @@ from . import models + def setup(env): request = env['request'] diff --git a/docs/tutorials/wiki/src/tests/tutorial/routes.py b/docs/tutorials/wiki/src/tests/tutorial/routes.py new file mode 100644 index 000000000..3c0a37992 --- /dev/null +++ b/docs/tutorials/wiki/src/tests/tutorial/routes.py @@ -0,0 +1,2 @@ +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) diff --git a/docs/tutorials/wiki/src/tests/tutorial/static/theme.css b/docs/tutorials/wiki/src/tests/tutorial/static/theme.css index 0f4b1a4d4..a70ee557a 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/static/theme.css +++ b/docs/tutorials/wiki/src/tests/tutorial/static/theme.css @@ -17,6 +17,9 @@ h6 { p { font-weight: 300; } +button, input, optgroup, select, textarea { + color: black; +} .font-normal { font-weight: 400; } diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/404.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/404.pt new file mode 100644 index 000000000..07298940c --- /dev/null +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/404.pt @@ -0,0 +1,10 @@ +
+
+ +
+

Pyramid Starter project

+

404 Page Not Found

+
+ +
+
diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt index eedb83da4..6438b1569 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/edit.pt @@ -1,72 +1,27 @@ - - - - - - - - - +
+
- ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - -
-
-
-
- -
-
-
-

+

+

Logout -

-

- Editing - Page Name Goes Here -

-

You can return to the - FrontPage. -

-
+

+

+ Editing + Page Name Goes Here +

+
- +
- +
-
-
-
+
-
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt new file mode 100644 index 000000000..b606e8dad --- /dev/null +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/layout.pt @@ -0,0 +1,59 @@ + + + + + + + + + + + <span tal:replace="page.__name__ | title"></span> - Pyramid tutorial wiki (based on + TurboGears 20-Minute Wiki) + + + + + + + + + + + + + +
+
+
+
+ +
+
+
No content
+
+

You can return to the + FrontPage. +

+
+
+
+
+ +
+
+
+ + + + + + + + diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt index 626db6637..acc4876cf 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/login.pt @@ -1,39 +1,7 @@ - - - - - - - - - +
+
- Login - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - - -
-
-
-
- -
-
-
+

Login @@ -54,22 +22,7 @@

-
-
-
- -
-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt index f2a9249ef..911ab0c99 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt +++ b/docs/tutorials/wiki/src/tests/tutorial/templates/view.pt @@ -1,72 +1,23 @@ - - - - - - - - - +
+
- ${page.__name__} - Pyramid tutorial wiki (based on - TurboGears 20-Minute Wiki) - - - - - - - - - - - - -
-
-
-
- -
-
-
-

+

+

Logout -

-
- Page text goes here. -
-

+

+
+ Page text goes here. +
+

Edit this page -

-

- Viewing - Page Name Goes Here -

-

You can return to the - FrontPage. -

-
-
-
-
- +

+

+ Viewing + Page Name Goes Here +

-
-
- - - - - - - +
+
diff --git a/docs/tutorials/wiki/src/tests/tutorial/views.py b/docs/tutorials/wiki/src/tests/tutorial/views.py deleted file mode 100644 index ea2da01af..000000000 --- a/docs/tutorials/wiki/src/tests/tutorial/views.py +++ /dev/null @@ -1,114 +0,0 @@ -from docutils.core import publish_parts -import re - -from pyramid.httpexceptions import HTTPFound - -from pyramid.view import ( - view_config, - forbidden_view_config, - ) - -from pyramid.security import ( - remember, - forget, - ) - - -from .security import USERS, check_password -from .models import Page - -# regular expression used to find WikiWords -wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") - -@view_config(context='.models.Wiki', - permission='view') -def view_wiki(context, request): - return HTTPFound(location=request.resource_url(context, 'FrontPage')) - -@view_config(context='.models.Page', renderer='templates/view.pt', - permission='view') -def view_page(context, request): - wiki = context.__parent__ - - def check(match): - word = match.group(1) - if word in wiki: - page = wiki[word] - view_url = request.resource_url(page) - return '%s' % (view_url, word) - else: - add_url = request.application_url + '/add_page/' + word - return '%s' % (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, - logged_in=request.authenticated_userid) - -@view_config(name='add_page', context='.models.Wiki', - renderer='templates/edit.pt', - permission='edit') -def add_page(context, request): - pagename = request.subpath[0] - if 'form.submitted' in request.params: - body = request.params['body'] - page = Page(body) - page.__name__ = pagename - page.__parent__ = context - context[pagename] = 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, - logged_in=request.authenticated_userid) - -@view_config(name='edit_page', context='.models.Page', - renderer='templates/edit.pt', - permission='edit') -def edit_page(context, request): - if 'form.submitted' in request.params: - context.data = request.params['body'] - return HTTPFound(location=request.resource_url(context)) - - return dict(page=context, - save_url=request.resource_url(context, 'edit_page'), - logged_in=request.authenticated_userid) - -@view_config(context='.models.Wiki', name='login', - renderer='templates/login.pt') -@forbidden_view_config(renderer='templates/login.pt') -def login(request): - login_url = request.resource_url(request.context, 'login') - referrer = request.url - if referrer == login_url: - referrer = '/' # never use the login form itself as came_from - came_from = request.params.get('came_from', referrer) - message = '' - login = '' - password = '' - if 'form.submitted' in request.params: - login = request.params['login'] - password = request.params['password'] - if check_password(USERS.get(login), password): - headers = remember(request, login) - return HTTPFound(location=came_from, - headers=headers) - message = 'Failed login' - - return dict( - message=message, - url=request.application_url + '/login', - came_from=came_from, - login=login, - password=password, - ) - - -@view_config(context='.models.Wiki', name='logout') -def logout(request): - headers = forget(request) - return HTTPFound(location=request.resource_url(request.context), - headers=headers) diff --git a/docs/tutorials/wiki/src/tests/tutorial/views/__init__.py b/docs/tutorials/wiki/src/tests/tutorial/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/wiki/src/tests/tutorial/views/default.py b/docs/tutorials/wiki/src/tests/tutorial/views/default.py new file mode 100644 index 000000000..3a3b170e2 --- /dev/null +++ b/docs/tutorials/wiki/src/tests/tutorial/views/default.py @@ -0,0 +1,117 @@ +from docutils.core import publish_parts +import re + +from pyramid.httpexceptions import HTTPFound +from pyramid.security import ( + forget, + remember, +) +from pyramid.view import ( + forbidden_view_config, + view_config, + ) + +from ..models import Page +from ..security import check_password, USERS + +# regular expression used to find WikiWords +wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") + + +@view_config(context='..models.Wiki', + permission='view') +def view_wiki(context, request): + return HTTPFound(location=request.resource_url(context, 'FrontPage')) + + +@view_config(context='..models.Page', renderer='../templates/view.pt', + permission='view') +def view_page(context, request): + wiki = context.__parent__ + + def check(match): + word = match.group(1) + if word in wiki: + page = wiki[word] + view_url = request.resource_url(page) + return '%s' % (view_url, word) + else: + add_url = request.application_url + '/add_page/' + word + return '%s' % (add_url, word) + + page_text = publish_parts(context.data, writer_name='html')['html_body'] + page_text = wikiwords.sub(check, page_text) + edit_url = request.resource_url(context, 'edit_page') + return dict(page=context, page_text=page_text, edit_url=edit_url, + logged_in=request.authenticated_userid) + + +@view_config(name='add_page', context='..models.Wiki', + renderer='../templates/edit.pt', + permission='edit') +def add_page(context, request): + pagename = request.subpath[0] + if 'form.submitted' in request.params: + body = request.params['body'] + page = Page(body) + page.__name__ = pagename + page.__parent__ = context + context[pagename] = 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, + logged_in=request.authenticated_userid) + + +@view_config(name='edit_page', context='..models.Page', + renderer='../templates/edit.pt', + permission='edit') +def edit_page(context, request): + if 'form.submitted' in request.params: + context.data = request.params['body'] + return HTTPFound(location=request.resource_url(context)) + + return dict(page=context, + save_url=request.resource_url(context, 'edit_page'), + logged_in=request.authenticated_userid) + + +@view_config(context='..models.Wiki', name='login', + renderer='../templates/login.pt') +@forbidden_view_config(renderer='../templates/login.pt') +def login(request): + login_url = request.resource_url(request.context, 'login') + referrer = request.url + if referrer == login_url: + referrer = '/' # never use the login form itself as came_from + came_from = request.params.get('came_from', referrer) + message = '' + login = '' + password = '' + if 'form.submitted' in request.params: + login = request.params['login'] + password = request.params['password'] + if check_password(USERS.get(login), password): + headers = remember(request, login) + return HTTPFound(location=came_from, + headers=headers) + message = 'Failed login' + + return dict( + message=message, + url=request.application_url + '/login', + came_from=came_from, + login=login, + password=password, + title='Login', + ) + + +@view_config(context='..models.Wiki', name='logout') +def logout(request): + headers = forget(request) + return HTTPFound(location=request.resource_url(request.context), + headers=headers) diff --git a/docs/tutorials/wiki/src/tests/tutorial/views/notfound.py b/docs/tutorials/wiki/src/tests/tutorial/views/notfound.py new file mode 100644 index 000000000..d44b4d0e6 --- /dev/null +++ b/docs/tutorials/wiki/src/tests/tutorial/views/notfound.py @@ -0,0 +1,12 @@ +from pyramid.view import notfound_view_config + +from ..models import Page + + +@notfound_view_config(renderer='../templates/404.pt') +def notfound_view(request): + request.response.status = 404 + pagename = request.path + page = Page(pagename) + page.__name__ = pagename + return dict(page=page) -- cgit v1.2.3 From 2e1da5700d30519d5e9f0a6feaaefabcfd145249 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sun, 25 Nov 2018 23:54:33 -0800 Subject: rewrap narrative, adjust grammar --- docs/tutorials/wiki/tests.rst | 52 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 27 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst index fdd218add..9dacc5f96 100644 --- a/docs/tutorials/wiki/tests.rst +++ b/docs/tutorials/wiki/tests.rst @@ -4,58 +4,56 @@ Adding Tests ============ -We will now add tests for the models and the views and a few functional tests -in ``tests.py``. Tests ensure that an application works, and that it -continues to work when changes are made in the future. +We will now add tests for the models and the views and a few functional tests in ``tests.py``. +Tests ensure that an application works, and that it continues to work when changes are made in the future. + Test the models =============== -We write tests for the ``model`` classes and the ``appmaker``. Changing -``tests.py``, we'll write a separate test class for each ``model`` class, and -we'll write a test class for the ``appmaker``. +We write tests for the ``model`` classes and the ``appmaker``. +Changing ``tests.py``, we will write a separate test class for each ``model`` class +We will also write a test class for the ``appmaker``. + +To do so, we will retain the ``tutorial.tests.ViewTests`` class that was generated from choosing the ``zodb`` backend option. +We will add three test classes, one for each of the following: + +- the ``Page`` model named ``PageModelTests`` +- the ``Wiki`` model named ``WikiModelTests`` +- the appmaker named ``AppmakerTests`` -To do so, we'll retain the ``tutorial.tests.ViewTests`` class that was -generated from choosing the ``zodb`` backend option. 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``. 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`` backend option 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. +We will modify our ``tests.py`` file, adding tests for each view function that we added previously. +As a result, we will delete the ``ViewTests`` class that the ``zodb`` backend option 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. + Functional tests ================ -We'll test the whole application, covering security aspects that are not -tested in the unit tests, like logging in, logging out, checking that -the ``viewer`` user cannot add or edit pages, but the ``editor`` user -can, and so on. +We will test the whole application, covering security aspects that are not tested in the unit tests, such as logging in, logging out, checking that the ``viewer`` user cannot add or edit pages, but the ``editor`` user can, and so on. + View the results of all our edits to ``tests.py`` ================================================= -Open the ``tutorial/tests.py`` module, and edit it such that it appears as -follows: +Open the ``tutorial/tests.py`` module, and edit it such that it appears as follows: .. literalinclude:: src/tests/tutorial/tests.py :linenos: :language: python + Running the tests ================= -We can run these tests by using ``pytest`` similarly to how we did in -:ref:`running_tests`. Courtesy of the cookiecutter, our testing dependencies have -already been satisfied and ``pytest`` and coverage have already been -configured, so we can jump right to running tests. +We can run these tests by using ``pytest`` similarly to how we did in :ref:`running_tests`. +Courtesy of the cookiecutter, our testing dependencies have already been satisfied. +``pytest`` and coverage have already been configured. +We can jump right to running tests. On Unix: -- cgit v1.2.3 From 971e764b0d8cfbd544d6a2adfa91100ddb68f752 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 26 Nov 2018 00:50:50 -0800 Subject: Add note about docutils deprecation warnings. Submitted a PR to fix the warnings in WebTest https://github.com/Pylons/webtest/pull/207, which usually gets reviewed and merged rapidly, so didn't bother to include a warning for it. --- docs/tutorials/wiki/tests.rst | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs') diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst index 9dacc5f96..a0872e605 100644 --- a/docs/tutorials/wiki/tests.rst +++ b/docs/tutorials/wiki/tests.rst @@ -73,3 +73,6 @@ The expected result should look like the following: ......................... 25 passed in 6.87 seconds + +If you use Python 3.7, you may see deprecation warnings from the docutils 0.14 package. +You can apply a [patch](https://sourceforge.net/p/docutils/patches/144/) to fix the issue, or ignore it and wait for the next release of docutils. -- cgit v1.2.3 From 766bdda32a1db5940e637c29ef91b3ba89ffe484 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 26 Nov 2018 00:52:12 -0800 Subject: Fix imports. Change info key from content to page_text. --- docs/tutorials/wiki/src/tests/tutorial/tests.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/src/tests/tutorial/tests.py b/docs/tutorials/wiki/src/tests/tutorial/tests.py index d713d3fdd..ff1c07b7c 100644 --- a/docs/tutorials/wiki/src/tests/tutorial/tests.py +++ b/docs/tutorials/wiki/src/tests/tutorial/tests.py @@ -43,7 +43,7 @@ class AppmakerTests(unittest.TestCase): class ViewWikiTests(unittest.TestCase): def test_it(self): - from .views import view_wiki + from .views.default import view_wiki context = testing.DummyResource() request = testing.DummyRequest() response = view_wiki(context, request) @@ -51,7 +51,7 @@ class ViewWikiTests(unittest.TestCase): class ViewPageTests(unittest.TestCase): def _callFUT(self, context, request): - from .views import view_page + from .views.default import view_page return view_page(context, request) def test_it(self): @@ -64,7 +64,7 @@ class ViewPageTests(unittest.TestCase): info = self._callFUT(context, request) self.assertEqual(info['page'], context) self.assertEqual( - info['content'], + info['page_text'], '
\n' '

Hello ' 'CruelWorld ' @@ -77,7 +77,7 @@ class ViewPageTests(unittest.TestCase): class AddPageTests(unittest.TestCase): def _callFUT(self, context, request): - from .views import add_page + from .views.default import add_page return add_page(context, request) def test_it_notsubmitted(self): @@ -103,7 +103,7 @@ class AddPageTests(unittest.TestCase): class EditPageTests(unittest.TestCase): def _callFUT(self, context, request): - from .views import edit_page + from .views.default import edit_page return edit_page(context, request) def test_it_notsubmitted(self): -- cgit v1.2.3 From 05292fb519ad33c74663221e7bd6da68eedceb72 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 26 Nov 2018 00:57:22 -0800 Subject: Update distributing with terms, rewrap --- docs/tutorials/wiki/distributing.rst | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'docs') diff --git a/docs/tutorials/wiki/distributing.rst b/docs/tutorials/wiki/distributing.rst index 36d00adb4..c23f79b5a 100644 --- a/docs/tutorials/wiki/distributing.rst +++ b/docs/tutorials/wiki/distributing.rst @@ -4,10 +4,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 contains the ``tutorial`` package and the -``setup.py`` file. +Once your application works properly, you can create a :term:`distribution` from it by using the ``setup.py sdist`` command. +The following commands assume your current working directory contains the ``tutorial`` package and the ``setup.py`` file. On Unix: @@ -31,10 +29,8 @@ The output of such a command will be something like: Creating tar archive removing 'tutorial-0.0' (and everything under it) -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 -`_ 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. +This command creates a subdirectory named ``dist``. +Inside that is a tarball named ``tutorial-0.0.tar.gz``, which is the :term:`distribution` of your application. +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 `_ 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. -- cgit v1.2.3