From 1220ce51e492caad3d361c9fd32dc79065b16f92 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 15 Apr 2016 02:27:01 -0700 Subject: rewrap 79-col --- docs/quick_tutorial/index.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/index.rst b/docs/quick_tutorial/index.rst index 9373fe38a..29b4d8fb7 100644 --- a/docs/quick_tutorial/index.rst +++ b/docs/quick_tutorial/index.rst @@ -4,12 +4,12 @@ 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 2 and 3. This tutorial gives a Python +3/2-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 experts of the Pyramid web framework. +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 +experts of the Pyramid web framework. Contents ======== -- cgit v1.2.3 From b61a8ba298a7e474d4d209967791a0b13bc5d77d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 02:39:17 -0700 Subject: quick_tutorial cleanup - replace nose and coverage with pytest and pytest-cov - update glossary and terms - use doscon lexer for Windows commands - refer to Pyramid Installation and put an end to copy-pasta - fix directory tree --- docs/glossary.rst | 20 ++++-- docs/quick_tutorial/requirements.rst | 115 +++++++++++++----------------- docs/quick_tutorial/tutorial_approach.rst | 66 ++++++++--------- 3 files changed, 96 insertions(+), 105 deletions(-) (limited to 'docs') diff --git a/docs/glossary.rst b/docs/glossary.rst index 486e94848..1d97bffe8 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -1108,14 +1108,15 @@ Glossary ``f``, ``false``, ``n``, ``no``, ``off`` and ``0``. pip - The `Python Packaging Authority's `_ recommended - tool for installing Python packages. + The :term:`Python Packaging Authority`'s recommended tool for installing + Python packages. pyvenv - The Python Packaging Authority formerly recommended using this command - for `creating virtual environments on Python 3.4 and 3.5 + The :term:`Python Packaging Authority` formerly recommended using the + ``pyvenv`` command for `creating virtual environments on Python 3.4 and + 3.5 `_, - but it is deprecated in 3.6 in favor of ``python3 -m venv`` on UNIX or + but it was deprecated in 3.6 in favor of ``python3 -m venv`` on UNIX or ``python -m venv`` on Windows, which is backward compatible on Python 3.3 and greater. @@ -1124,9 +1125,14 @@ Glossary use by a particular application, rather than being installed system wide. venv - The `Python Packaging Authority's `_ recommended - tool for creating virtual environments on Python 3.3 and greater. + The :term:`Python Packaging Authority`'s recommended tool for creating + virtual environments on Python 3.3 and greater. Note: whenever you encounter commands prefixed with ``$VENV`` (Unix) or ``%VENV`` (Windows), know that that is the environment variable whose value is the root of the virtual environment in question. + + Python Packaging Authority + The `Python Packaging Authority (PyPA) `_ + is a working group that maintains many of the relevant projects in Python + packaging. \ No newline at end of file diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index 9e10e3ebe..76af2c8ab 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -6,41 +6,44 @@ Requirements Let's get our tutorial environment set up. Most of the set up work is in standard Python development practices (install Python and make an isolated -environment.) +virtual environment.) .. note:: - Pyramid encourages standard Python development practices with - packaging tools, virtual environments, logging, and so on. There - are many variations, implementations, and opinions across the Python - community. For consistency, ease of documentation maintenance, - and to minimize confusion, the Pyramid *documentation* has adopted - specific conventions. + Pyramid encourages standard Python development practices with packaging + tools, virtual environments, logging, and so on. There are many variations, + implementations, and opinions across the Python community. For consistency, + ease of documentation maintenance, and to minimize confusion, the Pyramid + *documentation* has adopted specific conventions that are consistent with the + :term:`Python Packaging Authority`. This *Quick Tutorial* is based on: -* **Python 3.5**. Pyramid fully supports Python 3.3+ and Python 2.6+. This +* **Python 3.5**. Pyramid fully supports Python 3.3+ and Python 2.7+. This tutorial uses **Python 3.5** but runs fine under Python 2.7. * **venv**. We believe in virtual environments. For this tutorial, we use - Python 3.5's built-in solution ``venv``. For Python 2.7, you can install - ``virtualenv``. + Python 3.5's built-in solution :term:`venv`. For Python 2.7, you can install + :term:`virtualenv`. -* **pip**. We use ``pip`` for package management. +* **pip**. We use :term:`pip` for package management. -* **Workspaces, projects, and packages.** Our home directory - will contain a *tutorial workspace* with our Python virtual - environment(s) and *Python projects* (a directory with packaging - information and *Python packages* of working code.) +* **Workspaces, projects, and packages.** Our home directory will contain a + *tutorial workspace* with our Python virtual environment and *Python + projects* (a directory with packaging information and *Python packages* of + working code.) -* **Unix commands**. Commands in this tutorial use UNIX syntax and - paths. Windows users should adjust commands accordingly. +* **Unix commands**. Commands in this tutorial use UNIX syntax and paths. + Windows users should adjust commands accordingly. .. note:: - Pyramid was one of the first web frameworks to fully support Python 3 in October 2011. +.. note:: + Windows commands use the plain old MSDOS shell. For PowerShell command + syntax, see its documentation. + Steps ===== @@ -56,27 +59,12 @@ Steps Install Python 3 ---------------- -Windows and Mac OS X users can download and run an installer. - -Download the latest standard Python 3 release (not development release) from -`python.org `_. +See the detailed recommendation for your operating system described under +:ref:`installing_chapter`. -Windows users should also install the `Python for Windows extensions -`_. Carefully read the -``README.txt`` file at the end of the list of builds, and follow its -directions. Make sure you get the proper 32- or 64-bit build and Python -version. - -Linux users can either use their package manager to install Python 3 -or may `build Python 3 from source -`_. - -.. seealso:: See also :ref:`For Mac OS X Users `, :ref:`If - You Don't Yet Have a Python Interpreter (UNIX) - `, and :ref:`If You Don't - Yet Have a Python Interpreter (Windows) - `. +- :ref:`for-mac-os-x-users` +- :ref:`if-you-don-t-yet-have-a-python-interpreter-unix` +- :ref:`if-you-don-t-yet-have-a-python-interpreter-windows` .. _create-a-project-directory-structure: @@ -84,11 +72,10 @@ method>`_. Create a project directory structure ------------------------------------ -We will arrive at a directory structure of -``workspace->project->package``, with our workspace named -``quick_tutorial``. The following tree diagram shows how this will be -structured and where our virtual environment will reside as we proceed through -the tutorial: +We will arrive at a directory structure of ``workspace -> project -> package``, +where our workspace is named ``quick_tutorial``. The following tree diagram +shows how this will be structured, and where our :term:`virtual environment` +will reside as we proceed through the tutorial: .. code-block:: text @@ -113,43 +100,41 @@ For Linux, the commands to do so are as follows: For Windows: -.. code-block:: ps1con +.. code-block:: doscon # Windows c:\> cd \ c:\> mkdir projects\quick_tutorial c:\> cd projects\quick_tutorial -In the above figure, your user home directory is represented by ``~``. In -your home directory, all of your projects are in the ``projects`` directory. -This is a general convention not specific to Pyramid that many developers use. -Windows users will do well to use ``c:\`` as the location for ``projects`` in -order to avoid spaces in any of the path names. +In the above figure, your user home directory is represented by ``~``. In your +home directory, all of your projects are in the ``projects`` directory. This is +a general convention not specific to Pyramid that many developers use. Windows +users will do well to use ``c:\`` as the location for ``projects`` in order to +avoid spaces in any of the path names. Next within ``projects`` is your workspace directory, here named ``quick_tutorial``. A workspace is a common term used by integrated -development environments (IDE) like PyCharm and PyDev that stores -isolated Python environments (virtual environments) and specific project files -and repositories. +development environments (IDE), like PyCharm and PyDev, where virtual +environments, specific project files, and repositories are stored. .. _set-an-environment-variable: -Set an Environment Variable +Set an environment variable --------------------------- -This tutorial will refer frequently to the location of the virtual -environment. We set an environment variable to save typing later. +This tutorial will refer frequently to the location of the :term:`virtual +environment`. We set an environment variable to save typing later. .. code-block:: bash # Mac and Linux $ export VENV=~/projects/quick_tutorial/env -.. code-block:: ps1con +.. code-block:: doscon # Windows - # TODO: This command does not work c:\> set VENV=c:\projects\quick_tutorial\env @@ -168,7 +153,7 @@ environment variable. # Mac and Linux $ python3 -m venv $VENV -.. code-block:: ps1con +.. code-block:: doscon # Windows c:\> c:\Python35\python3 -m venv %VENV% @@ -195,18 +180,16 @@ part is pretty easy: Our Python virtual environment now has the Pyramid software available. -You can optionally install some of the extra Python packages used -during this tutorial: +You can optionally install some of the extra Python packages used in this +tutorial: .. code-block:: bash # Mac and Linux - $ $VENV/bin/pip install nose webtest deform sqlalchemy \ - pyramid_chameleon pyramid_debugtoolbar waitress \ - pyramid_tm zope.sqlalchemy + $ $VENV/bin/pip install webtest deform sqlalchemy pyramid_chameleon \ + pyramid_debugtoolbar waitress pyramid_tm zope.sqlalchemy -.. code-block:: ps1con +.. code-block:: doscon # Windows - c:\> %VENV%\Scripts\pip install nose webtest deform sqlalchemy pyramid_chameleon pyramid_debugtoolbar waitress pyramid_tm zope.sqlalchemy - + c:\> %VENV%\Scripts\pip install webtest deform sqlalchemy pyramid_chameleon pyramid_debugtoolbar waitress pyramid_tm zope.sqlalchemy diff --git a/docs/quick_tutorial/tutorial_approach.rst b/docs/quick_tutorial/tutorial_approach.rst index 8298a4710..09e0217c6 100644 --- a/docs/quick_tutorial/tutorial_approach.rst +++ b/docs/quick_tutorial/tutorial_approach.rst @@ -2,44 +2,46 @@ Tutorial Approach ================= -This tutorial uses conventions to keep the introduction focused and -concise. Details, references, and deeper discussions are mentioned in -"See also" notes. +This tutorial uses conventions to keep the introduction focused and concise. +Details, references, and deeper discussions are mentioned in "See also" notes. .. seealso:: This is an example "See also" note. -This "Getting Started" tutorial is broken into independent steps, -starting with the smallest possible "single file WSGI app" example. -Each of these steps introduce a topic and a very small set of concepts -via working code. The steps each correspond to a directory in this -repo, where each step/topic/directory is a Python package. +This "Getting Started" tutorial is broken into independent steps, starting with +the smallest possible "single file WSGI app" example. Each of these steps +introduce a topic and a very small set of concepts via working code. The steps +each correspond to a directory in this repo, where each step/topic/directory is +a Python package. -To successfully run each step:: +To successfully run each step: - $ cd request_response - $ $VENV/bin/pip install -e . +.. code-block:: bash -...and repeat for each step you would like to work on. In most cases we -will start with the results of an earlier step. + $ cd request_response + $ $VENV/bin/pip install -e . -Directory Tree +...and repeat for each step you would like to work on. In most cases we will +start with the results of an earlier step. + +Directory tree ============== -As we develop our tutorial our directory tree will resemble the -structure below:: - - quicktutorial/ - request_response/ - development.ini - setup.py - tutorial/ - __init__.py - home.pt - tests.py - views.py - -Each of the first-level directories (e.g. ``request_response``) is a -*Python project* (except, as noted, the ``hello_world`` step.) The -``tutorial`` directory is a *Python package*. At the end of each step, -we copy a previous directory into a new directory to use as a starting -point. +As we develop our tutorial, our directory tree will resemble the structure +below: + +.. code-block:: text + + quick_tutorial + ├── env + └── request_response + ├── tutorial + │ ├── __init__.py + │ ├── tests.py + │ └── views.py + ├── development.ini + └── setup.py + +Each of the first-level directories (e.g., ``request_response``) is a *Python +project* (except as noted for the ``hello_world`` step). The``tutorial`` +directory is a *Python package*. At the end of each step, we copy a previous +directory into a new directory to use as a starting point. -- cgit v1.2.3 From 789a9059a1190b3f1e748dda4b3755d1b26d43fa Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 03:03:10 -0700 Subject: quick_tutorial cleanup - update pip and setuptools - moar cleanup --- docs/quick_tutorial/requirements.rst | 24 +++++++++++++++++++++--- docs/quick_tutorial/tutorial_approach.rst | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index 76af2c8ab..9174ea657 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -140,7 +140,7 @@ environment`. We set an environment variable to save typing later. .. _create-a-virtual-environment: -Create a Virtual Environment +Create a virtual environment ---------------------------- ``venv`` is a tool to create isolated Python 3 environments, each with its own @@ -162,13 +162,31 @@ environment variable. 2's `virtualenv `_ package. +Update packaging tools in the virtual environment +------------------------------------------------- + +It's always a good idea to update to the very latest version of packaging tools +because the installed Python bundles only the version that was available at the +time of its release. + +.. code-block:: bash + + # Mac and Linux + $VENV/bin/pip install --upgrade pip setuptools + +.. code-block:: doscon + + # Windows + c:\> %VENV%\Scripts\pip install --upgrade pip setuptools + + .. _install-pyramid: Install Pyramid --------------- We have our Python standard prerequisites out of the way. The Pyramid -part is pretty easy: +part is pretty easy. .. parsed-literal:: @@ -181,7 +199,7 @@ part is pretty easy: Our Python virtual environment now has the Pyramid software available. You can optionally install some of the extra Python packages used in this -tutorial: +tutorial. .. code-block:: bash diff --git a/docs/quick_tutorial/tutorial_approach.rst b/docs/quick_tutorial/tutorial_approach.rst index 09e0217c6..6d534fe13 100644 --- a/docs/quick_tutorial/tutorial_approach.rst +++ b/docs/quick_tutorial/tutorial_approach.rst @@ -42,6 +42,6 @@ below: └── setup.py Each of the first-level directories (e.g., ``request_response``) is a *Python -project* (except as noted for the ``hello_world`` step). The``tutorial`` +project* (except as noted for the ``hello_world`` step). The ``tutorial`` directory is a *Python package*. At the end of each step, we copy a previous directory into a new directory to use as a starting point. -- cgit v1.2.3 From 878d1aa1ea7a9208d70cf3092d0a3dcd11775a74 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 03:39:51 -0700 Subject: quick_tutorial cleanup - cleanup hello_world.rst --- docs/quick_tutorial/hello_world.rst | 81 ++++++++++++++++++------------------ docs/quick_tutorial/requirements.rst | 5 ++- docs/quick_tutorial/scaffolds.rst | 48 ++++++++++----------- 3 files changed, 67 insertions(+), 67 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/hello_world.rst b/docs/quick_tutorial/hello_world.rst index fb661e9c5..4e35da7bb 100644 --- a/docs/quick_tutorial/hello_world.rst +++ b/docs/quick_tutorial/hello_world.rst @@ -4,40 +4,40 @@ 01: Single-File Web Applications ================================ -What's the simplest way to get started in Pyramid? A single-file module. -No Python packages, no ``pip install -e .``, no other machinery. +What's the simplest way to get started in Pyramid? A single-file module. No +Python packages, no ``pip install -e .``, no other machinery. + Background ========== -Microframeworks are all the rage these days. "Microframework" is a -marketing term, not a technical one. They have a low mental overhead: -they do so little, the only things you have to worry about are *your -things*. +Microframeworks are all the rage these days. "Microframework" is a marketing +term, not a technical one. They have a low mental overhead: they do so little, +the only things you have to worry about are *your things*. + +Pyramid is special because it can act as a single-file module microframework. +You can have a single Python file that can be executed directly by Python. But +Pyramid also provides facilities to scale to the largest of applications. -Pyramid is special because it can act as a single-file module -microframework. You can have a single Python file that can be executed -directly by Python. But Pyramid also provides facilities to scale to -the largest of applications. +Python has a standard called :term:`WSGI` that defines how Python web +applications plug into standard servers, getting passed incoming requests, and +returning responses. Most modern Python web frameworks obey an "MVC" +(model-view-controller) application pattern, where the data in the model has a +view that mediates interaction with outside systems. -Python has a standard called :term:`WSGI` that defines how -Python web applications plug into standard servers, getting passed -incoming requests and returning responses. Most modern Python web -frameworks obey an "MVC" (model-view-controller) application pattern, -where the data in the model has a view that mediates interaction with -outside systems. +In this step we'll see a brief glimpse of WSGI servers, WSGI applications, +requests, responses, and views. -In this step we'll see a brief glimpse of WSGI servers, WSGI -applications, requests, responses, and views. Objectives ========== -- Get a running Pyramid web application, as simply as possible +- Get a running Pyramid web application, as simply as possible. + +- Use that as a well-understood base for adding each unit of complexity. -- Use that as a well-understood base for adding each unit of complexity +- Initial exposure to WSGI apps, requests, views, and responses. -- Initial exposure to WSGI apps, requests, views, and responses Steps ===== @@ -64,30 +64,29 @@ Steps #. Open http://localhost:6543/ in your browser. + Analysis ======== -New to Python web programming? If so, some lines in module merit +New to Python web programming? If so, some lines in the module merit explanation: -#. *Line 11*. The ``if __name__ == '__main__':`` is Python's way of - saying "Start here when running from the command line", rather than - when this module is imported. +#. *Line 11*. The ``if __name__ == '__main__':`` is Python's way of saying, + "Start here when running from the command line", rather than when this + module is imported. + +#. *Lines 12-14*. Use Pyramid's :term:`configurator` to connect :term:`view` + code to a particular URL :term:`route`. -#. *Lines 12-14*. Use Pyramid's :term:`configurator` to connect - :term:`view` code to a particular URL :term:`route`. +#. *Lines 6-8*. Implement the view code that generates the :term:`response`. -#. *Lines 6-8*. Implement the view code that generates the - :term:`response`. +#. *Lines 15-17*. Publish a :term:`WSGI` app using an HTTP server. -#. *Lines 15-17*. Publish a :term:`WSGI` app using an HTTP - server. +As shown in this example, the :term:`configurator` plays a central role in +Pyramid development. Building an application from loosely-coupled parts via +:ref:`configuration_narr` is a central idea in Pyramid, one that we will +revisit regularly in this *Quick Tutorial*. -As shown in this example, the :term:`configurator` plays a -central role in Pyramid development. Building an application from -loosely-coupled parts via :ref:`configuration_narr` is a -central idea in Pyramid, one that we will revisit regularly in this -*Quick Tour*. Extra Credit ============ @@ -106,9 +105,9 @@ Extra Credit #. What happens if you return a string of HTML? A sequence of integers? -#. Put something invalid, such as ``print xyz``, in the view function. - Kill your ``python app.py`` with ``cntrl-c`` and restart, - then reload your browser. See the exception in the console? +#. Put something invalid, such as ``print xyz``, in the view function. Kill + your ``python app.py`` with ``ctrl-C`` and restart, then reload your + browser. See the exception in the console? -#. The ``GI`` in ``WSGI`` stands for "Gateway Interface". What web - standard is this modelled after? +#. The ``GI`` in ``WSGI`` stands for "Gateway Interface". What web standard is + this modelled after? diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index 9174ea657..f4c1e70ac 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -204,8 +204,9 @@ tutorial. .. code-block:: bash # Mac and Linux - $ $VENV/bin/pip install webtest deform sqlalchemy pyramid_chameleon \ - pyramid_debugtoolbar waitress pyramid_tm zope.sqlalchemy + $ $VENV/bin/pip install webtest pytest pytest-cov deform sqlalchemy \ + pyramid_chameleon pyramid_debugtoolbar waitress pyramid_tm \ + zope.sqlalchemy .. code-block:: doscon diff --git a/docs/quick_tutorial/scaffolds.rst b/docs/quick_tutorial/scaffolds.rst index 319eb9d90..7845f2b71 100644 --- a/docs/quick_tutorial/scaffolds.rst +++ b/docs/quick_tutorial/scaffolds.rst @@ -4,29 +4,30 @@ Prelude: Quick Project Startup with Scaffolds ============================================= -To ease the process of getting started, Pyramid provides *scaffolds* -that generate sample projects from templates in Pyramid and Pyramid -add-ons. +To ease the process of getting started, Pyramid provides *scaffolds* that +generate sample projects from templates in Pyramid and Pyramid add-ons. + Background ========== -We're going to cover a lot in this tutorial, focusing on one topic at a -time and writing everything from scratch. As a warm up, though, -it sure would be nice to see some pixels on a screen. +We're going to cover a lot in this tutorial, focusing on one topic at a time +and writing everything from scratch. As a warm up, though, it sure would be +nice to see some pixels on a screen. + +Like other web development frameworks, Pyramid provides a number of "scaffolds" +that generate working Python, template, and CSS code for sample applications. +In this step we'll use a built-in scaffold to let us preview a Pyramid +application, before starting from scratch on Step 1. -Like other web development frameworks, Pyramid provides a number of -"scaffolds" that generate working Python, template, and CSS code for -sample applications. In this step we'll use a built-in scaffold to let -us preview a Pyramid application, before starting from scratch on Step 1. Objectives ========== -- Use Pyramid's ``pcreate`` command to list scaffolds and make a new - project +- Use Pyramid's ``pcreate`` command to list scaffolds and make a new project. + +- Start up a Pyramid application and visit it in a web browser. -- Start up a Pyramid application and visit it in a web browser Steps ===== @@ -55,8 +56,8 @@ Steps $ cd scaffolds $ $VENV/bin/pip install -e . -#. Start up the application by pointing Pyramid's ``pserve`` command at - the project's (generated) configuration file: +#. Start up the application by pointing Pyramid's ``pserve`` command at the + project's (generated) configuration file: .. code-block:: bash @@ -75,13 +76,12 @@ Steps Analysis ======== -Rather than starting from scratch, ``pcreate`` can make getting a -Python project containing a Pyramid application a quick matter. -Pyramid ships with a few scaffolds. But installing a Pyramid add-on can -give you new scaffolds from that add-on. +Rather than starting from scratch, ``pcreate`` can make getting a Python +project containing a Pyramid application a quick matter. Pyramid ships with a +few scaffolds. But installing a Pyramid add-on can give you new scaffolds from +that add-on. -``pserve`` is Pyramid's application runner, separating operational -details from your code. When you install Pyramid, a small command -program called ``pserve`` is written to your ``bin`` directory. This -program is an executable Python module. It is passed a configuration -file (in this case, ``development.ini``.) +``pserve`` is Pyramid's application runner, separating operational details from +your code. When you install Pyramid, a small command program called ``pserve`` +is written to your ``bin`` directory. This program is an executable Python +module. It is passed a configuration file (in this case, ``development.ini``). -- cgit v1.2.3 From 4e34c51b1e7c1ffa836cef81ee7b31cfdbdf69df Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 03:57:50 -0700 Subject: quick_tutorial cleanup - cleanup package.rst --- docs/quick_tutorial/package.rst | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/package.rst b/docs/quick_tutorial/package.rst index 6a379032e..94cb39fc9 100644 --- a/docs/quick_tutorial/package.rst +++ b/docs/quick_tutorial/package.rst @@ -3,16 +3,17 @@ ============================================ Most modern Python development is done using Python packages, an approach -Pyramid puts to good use. In this step we redo "Hello World" as a -minimum Python package inside a minimum Python project. +Pyramid puts to good use. In this step we redo "Hello World" as a minimal +Python package inside a minimal Python project. + Background ========== Python developers can organize a collection of modules and files into a -namespaced unit called a :ref:`package `. If a -directory is on ``sys.path`` and has a special file named -``__init__.py``, it is treated as a Python package. +namespaced unit called a :ref:`package `. If a directory +is on ``sys.path`` and has a special file named ``__init__.py``, it is treated +as a Python package. Packages can be bundled up, made available for installation, and installed through a toolchain oriented around a ``setup.py`` file. For this tutorial, @@ -34,6 +35,7 @@ In summary: - That package will be part of a *project*. + Objectives ========== @@ -43,6 +45,7 @@ Objectives - Install our ``tutorial`` project in development mode. + Steps ===== @@ -56,8 +59,8 @@ Steps .. literalinclude:: package/setup.py -#. Make the new project installed for development then make a directory - for the actual code: +#. Make the new project installed for development then make a directory for the + actual code: .. code-block:: bash @@ -80,26 +83,27 @@ Steps #. Open http://localhost:6543/ in your browser. + Analysis ======== -Python packages give us an organized unit of project development. -Python projects, via ``setup.py``, gives us special features when -our package is installed (in this case, in local development mode.) +Python packages give us an organized unit of project development. Python +projects, via ``setup.py``, give us special features when our package is +installed (in this case, in local development mode, also called local editable +mode as indicated by ``-e .``). -In this step we have a Python package called ``tutorial``. We use the -same name in each step of the tutorial, to avoid unnecessary retyping. +In this step we have a Python package called ``tutorial``. We use the same name +in each step of the tutorial, to avoid unnecessary retyping. -Above this ``tutorial`` directory we have the files that handle the -packaging of this project. At the moment, all we need is a -bare-bones ``setup.py``. +Above this ``tutorial`` directory we have the files that handle the packaging +of this project. At the moment, all we need is a bare-bones ``setup.py``. -Everything else is the same about our application. We simply made a -Python package with a ``setup.py`` and installed it in development mode. +Everything else is the same about our application. We simply made a Python +package with a ``setup.py`` and installed it in development mode. Note that the way we're running the app (``python tutorial/app.py``) is a bit of an odd duck. We would never do this unless we were writing a tutorial that -tries to capture how this stuff works a step at a time. It's generally a bad +tries to capture how this stuff works one step at a time. It's generally a bad idea to run a Python module inside a package directly as a script. .. seealso:: :ref:`Python Packages ` and `Working in -- cgit v1.2.3 From 8e6520bd91d9b873b5e367176b7c303d7cac429a Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 04:17:36 -0700 Subject: quick_tutorial cleanup - cleanup ini.rst --- docs/quick_tutorial/ini.rst | 92 ++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/ini.rst b/docs/quick_tutorial/ini.rst index 0aed304df..fba5ce29e 100644 --- a/docs/quick_tutorial/ini.rst +++ b/docs/quick_tutorial/ini.rst @@ -7,28 +7,30 @@ Use Pyramid's ``pserve`` command with a ``.ini`` configuration file for simpler, better application running. + Background ========== -Pyramid has a first-class concept of -:ref:`configuration ` distinct from code. -This approach is optional, but its presence makes it distinct from -other Python web frameworks. It taps into Python's ``setuptools`` -library, which establishes conventions for installing and providing -"entry points" for Python projects. Pyramid uses an entry point to -let a Pyramid application know where to find the WSGI app. +Pyramid has a first-class concept of :ref:`configuration ` +distinct from code. This approach is optional, but its presence makes it +distinct from other Python web frameworks. It taps into Python's ``setuptools`` +library, which establishes conventions for installing and providing "entry +points" for Python projects. Pyramid uses an entry point to let a Pyramid +application know where to find the WSGI app. + Objectives ========== -- Modify our ``setup.py`` to have an entry point telling Pyramid the - location of the WSGI app +- Modify our ``setup.py`` to have an entry point telling Pyramid the location + of the WSGI app. + +- Create an application driven by an ``.ini`` file. -- Create an application driven by a ``.ini`` file +- Start the application with Pyramid's ``pserve`` command. -- Startup the application with Pyramid's ``pserve`` command +- Move code into the package's ``__init__.py``. -- Move code into the package's ``__init__.py`` Steps ===== @@ -39,14 +41,14 @@ Steps $ cd ..; cp -r package ini; cd ini -#. Our ``ini/setup.py`` needs a setuptools "entry point" in the - ``setup()`` function: +#. Our ``ini/setup.py`` needs a setuptools "entry point" in the ``setup()`` + function: .. literalinclude:: ini/setup.py :linenos: -#. We can now install our project, thus generating (or re-generating) an - "egg" at ``ini/tutorial.egg-info``: +#. We can now install our project, thus generating (or re-generating) an "egg" + at ``ini/tutorial.egg-info``: .. code-block:: bash @@ -58,8 +60,8 @@ Steps :language: ini :linenos: -#. We can refactor our startup code from the previous step's ``app.py`` - into ``ini/tutorial/__init__.py``: +#. We can refactor our startup code from the previous step's ``app.py`` into + ``ini/tutorial/__init__.py``: .. literalinclude:: ini/tutorial/__init__.py :linenos: @@ -81,27 +83,26 @@ Steps Analysis ======== -Our ``development.ini`` file is read by ``pserve`` and serves to -bootstrap our application. Processing then proceeds as described in -the Pyramid chapter on +Our ``development.ini`` file is read by ``pserve`` and serves to bootstrap our +application. Processing then proceeds as described in the Pyramid chapter on :ref:`application startup `: -- ``pserve`` looks for ``[app:main]`` and finds ``use = egg:tutorial`` +- ``pserve`` looks for ``[app:main]`` and finds ``use = egg:tutorial``. -- The projects's ``setup.py`` has defined an "entry point" (lines 9-12) - for the project "main" entry point of ``tutorial:main`` +- The projects's ``setup.py`` has defined an "entry point" (lines 9-12) for the + project's "main" entry point of ``tutorial:main``. -- The ``tutorial`` package's ``__init__`` has a ``main`` function +- The ``tutorial`` package's ``__init__`` has a ``main`` function. -- This function is invoked, with the values from certain ``.ini`` - sections passed in +- This function is invoked, with the values from certain ``.ini`` sections + passed in. The ``.ini`` file is also used for two other functions: -- *Configuring the WSGI server*. ``[server:main]`` wires up the choice of - which WSGI *server* for your WSGI *application*. In this case, we are using - ``wsgiref`` bundled in the Python library. It also wires up the *port - number*: ``port = 6543`` tells ``wsgiref`` to listen on port 6543. +- *Configuring the WSGI server*. ``[server:main]`` wires up the choice of which + WSGI *server* for your WSGI *application*. In this case, we are using + ``wsgiref`` bundled in the Python library. It also wires up the *port + number*: ``port = 6543`` tells ``wsgiref`` to listen on port 6543. - *Configuring Python logging*. Pyramid uses Python standard logging, which needs a number of configuration values. The ``.ini`` serves this function. @@ -109,27 +110,27 @@ The ``.ini`` file is also used for two other functions: request. We moved our startup code from ``app.py`` to the package's -``tutorial/__init__.py``. This isn't necessary, -but it is a common style in Pyramid to take the WSGI app bootstrapping -out of your module's code and put it in the package's ``__init__.py``. +``tutorial/__init__.py``. This isn't necessary, but it is a common style in +Pyramid to take the WSGI app bootstrapping out of your module's code and put it +in the package's ``__init__.py``. + +The ``pserve`` application runner has a number of command-line arguments and +options. We are using ``--reload`` which tells ``pserve`` to watch the +filesystem for changes to relevant code (Python files, the INI file, etc.) and, +when something changes, restart the application. Very handy during development. -The ``pserve`` application runner has a number of command-line arguments -and options. We are using ``--reload`` which tells ``pserve`` to watch -the filesystem for changes to relevant code (Python files, the INI file, -etc.) and, when something changes, restart the application. Very handy -during development. Extra Credit ============ -#. If you don't like configuration and/or ``.ini`` files, - could you do this yourself in Python code? +#. If you don't like configuration and/or ``.ini`` files, could you do this + yourself in Python code? -#. Can we have multiple ``.ini`` configuration files for a project? Why - might you want to do that? +#. Can we have multiple ``.ini`` configuration files for a project? Why might + you want to do that? -#. The entry point in ``setup.py`` didn't mention ``__init__.py`` when - it declared ``tutorial:main`` function. Why not? +#. The entry point in ``setup.py`` didn't mention ``__init__.py`` when it + declared ``tutorial:main`` function. Why not? #. What is the purpose of ``**settings``? What does the ``**`` signify? @@ -139,4 +140,3 @@ Extra Credit :ref:`what_is_this_pserve_thing`, :ref:`environment_chapter`, :ref:`paste_chapter` - -- cgit v1.2.3 From 823ef1d9c931106de11e7d383856fcc2fc99c3fa Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 04:26:05 -0700 Subject: quick_tutorial cleanup - cleanup debugtoolbar.rst --- docs/quick_tutorial/debugtoolbar.rst | 53 ++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/debugtoolbar.rst b/docs/quick_tutorial/debugtoolbar.rst index 1f89cd319..aaf904390 100644 --- a/docs/quick_tutorial/debugtoolbar.rst +++ b/docs/quick_tutorial/debugtoolbar.rst @@ -6,31 +6,34 @@ Error handling and introspection using the ``pyramid_debugtoolbar`` add-on. + Background ========== -As we introduce the basics we also want to show how to be productive in -development and debugging. For example, we just discussed template -reloading and earlier we showed ``--reload`` for application reloading. +As we introduce the basics, we also want to show how to be productive in +development and debugging. For example, we just discussed template reloading, +and earlier we showed ``--reload`` for application reloading. + +``pyramid_debugtoolbar`` is a popular Pyramid add-on which makes several tools +available in your browser. Adding it to your project illustrates several points +about configuration. -``pyramid_debugtoolbar`` is a popular Pyramid add-on which makes -several tools available in your browser. Adding it to your project -illustrates several points about configuration. Objectives ========== -- Install and enable the toolbar to help during development +- Install and enable the toolbar to help during development. + +- Explain Pyramid add-ons. -- Explain Pyramid add-ons +- Show how an add-on gets configured into your application. -- Show how an add-on gets configured into your application Steps ===== -#. First we copy the results of the previous step, as well as install - the ``pyramid_debugtoolbar`` package: +#. First we copy the results of the previous step, as well as install the + ``pyramid_debugtoolbar`` package: .. code-block:: bash @@ -54,6 +57,7 @@ Steps #. Open http://localhost:6543/ in your browser. See the handy toolbar on the right. + Analysis ======== @@ -66,16 +70,16 @@ The ``pyramid_debugtoolbar`` Python package is also a Pyramid add-on, which means we need to include its add-on configuration into our web application. We could do this with imperative configuration in ``tutorial/__init__.py`` by using ``config.include``. Pyramid also supports wiring in add-on configuration -via our ``development.ini`` using ``pyramid.includes``. We use this to load -the configuration for the debugtoolbar. +via our ``development.ini`` using ``pyramid.includes``. We use this to load the +configuration for the debugtoolbar. You'll now see an attractive button on the right side of your browser, which -you may click to provide introspective access to debugging information in a -new browser tab. Even better, if your web application generates an error, you -will see a nice traceback on the screen. When you want to disable this -toolbar, there's no need to change code: you can remove it from -``pyramid.includes`` in the relevant ``.ini`` configuration file (thus showing -why configuration files are handy.) +you may click to provide introspective access to debugging information in a new +rowser tab. Even better, if your web application generates an error, you will +see a nice traceback on the screen. When you want to disable this toolbar, +there's no need to change code: you can remove it from ``pyramid.includes`` in +the relevant ``.ini`` configuration file (thus showing why configuration files +are handy). Note that the toolbar injects a small amount of HTML/CSS into your app just before the closing ```` tag in order to display itself. If you start to @@ -85,13 +89,14 @@ temporarily. .. seealso:: See also :ref:`pyramid_debugtoolbar `. + Extra Credit ============ #. Why don't we add ``pyramid_debugtoolbar`` to the list of ``install_requires`` dependencies in ``debugtoolbar/setup.py``? -#. Introduce a bug into your application: Change: +#. Introduce a bug into your application. Change: .. code-block:: python @@ -105,7 +110,7 @@ Extra Credit def hello_world(request): return xResponse('

Hello World!

') - Save, and visit http://localhost:6543/ again. Notice the nice - traceback display. On the lowest line, click the "screen" icon to the - right, and try typing the variable names ``request`` and ``Response``. - What else can you discover? + Save, and visit http://localhost:6543/ again. Notice the nice traceback + display. On the lowest line, click the "screen" icon to the right, and try + typing the variable names ``request`` and ``Response``. What else can you + discover? -- cgit v1.2.3 From 86e187a734728611bc8bfd5792133502ffd59160 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 04:44:55 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup unit_testing.rst --- docs/conf.py | 1 + docs/quick_tutorial/unit_testing.rst | 114 +++++++++++++++++------------------ 2 files changed, 57 insertions(+), 58 deletions(-) (limited to 'docs') diff --git a/docs/conf.py b/docs/conf.py index 1600e1f5c..c40f1c875 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -67,6 +67,7 @@ intersphinx_mapping = { 'jinja2': ('http://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/', None), 'pylonswebframework': ('http://docs.pylonsproject.org/projects/pylons-webframework/en/latest/', None), 'python': ('https://docs.python.org/3', None), + 'pytest': ('http://pytest.org/latest/', None), 'sqla': ('http://docs.sqlalchemy.org/en/latest', None), 'tm': ('http://docs.pylonsproject.org/projects/pyramid-tm/en/latest/', None), 'toolbar': ('http://docs.pylonsproject.org/projects/pyramid-debugtoolbar/en/latest', None), diff --git a/docs/quick_tutorial/unit_testing.rst b/docs/quick_tutorial/unit_testing.rst index 58512d1cc..56fd2b297 100644 --- a/docs/quick_tutorial/unit_testing.rst +++ b/docs/quick_tutorial/unit_testing.rst @@ -1,55 +1,56 @@ .. _qtut_unit_testing: -=========================== -05: Unit Tests and ``nose`` -=========================== +============================= +05: Unit Tests and ``pytest`` +============================= Provide unit testing for our project's Python code. + Background ========== -As the mantra says, "Untested code is broken code." The Python -community has had a long culture of writing test scripts which ensure -that your code works correctly as you write it and maintain it in the -future. Pyramid has always had a deep commitment to testing, -with 100% test coverage from the earliest pre-releases. - -Python includes a -:ref:`unit testing framework ` in its -standard library. Over the years a number of Python projects, such as -`nose `_, have extended this -framework with alternative test runners that provide more convenience -and functionality. The Pyramid developers use ``nose``, which we'll thus -use in this tutorial. - -Don't worry, this tutorial won't be pedantic about "test-driven -development" (TDD). We'll do just enough to ensure that, in each step, -we haven't majorly broken the code. As you're writing your code you -might find this more convenient than changing to your browser -constantly and clicking reload. - -We'll also leave discussion of -`coverage `_ for another section. +As the mantra says, "Untested code is broken code." The Python community has +had a long culture of writing test scripts which ensure that your code works +correctly as you write it and maintain it in the future. Pyramid has always had +a deep commitment to testing, with 100% test coverage from the earliest +pre-releases. + +Python includes a :ref:`unit testing framework +` in its standard library. Over the years a +number of Python projects, such as :ref:`pytest `, have +extended this framework with alternative test runners that provide more +convenience and functionality. The Pyramid developers use ``pytest``, which +we'll use in this tutorial. + +Don't worry, this tutorial won't be pedantic about "test-driven development" +(TDD). We'll do just enough to ensure that, in each step, we haven't majorly +broken the code. As you're writing your code, you might find this more +convenient than changing to your browser constantly and clicking reload. + +We'll also leave discussion of `pytest-cov +`_ for another section. + Objectives ========== -- Write unit tests that ensure the quality of our code +- Write unit tests that ensure the quality of our code. + +- Install a Python package (``pytest``) which helps in our testing. -- Install a Python package (``nose``) which helps in our testing Steps ===== -#. First we copy the results of the previous step, as well as install - the ``nose`` package: +#. First we copy the results of the previous step, as well as install the + ``pytest`` package: .. code-block:: bash $ cd ..; cp -r debugtoolbar unit_testing; cd unit_testing $ $VENV/bin/pip install -e . - $ $VENV/bin/pip install nose + $ $VENV/bin/pip install pytest #. Now we write a simple unit test in ``unit_testing/tutorial/tests.py``: @@ -61,54 +62,51 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/py.test tutorial/tests.py -q . - ---------------------------------------------------------------------- - Ran 1 test in 0.141s + 1 passed in 0.14 seconds - OK Analysis ======== -Our ``tests.py`` imports the Python standard unit testing framework. To -make writing Pyramid-oriented tests more convenient, Pyramid supplies -some ``pyramid.testing`` helpers which we use in the test setup and -teardown. Our one test imports the view, makes a dummy request, and sees -if the view returns what we expected. +Our ``tests.py`` imports the Python standard unit testing framework. To make +writing Pyramid-oriented tests more convenient, Pyramid supplies some +``pyramid.testing`` helpers which we use in the test setup and teardown. Our +one test imports the view, makes a dummy request, and sees if the view returns +what we expect. -The ``tests.TutorialViewTests.test_hello_world`` test is a small -example of a unit test. First, we import the view inside each test. Why -not import at the top, like in normal Python code? Because imports can -cause effects that break a test. We'd like our tests to be in *units*, -hence the name *unit* testing. Each test should isolate itself to the -correct degree. +The ``tests.TutorialViewTests.test_hello_world`` test is a small example of a +unit test. First, we import the view inside each test. Why not import at the +top, like in normal Python code? Because imports can cause effects that break a +test. We'd like our tests to be in *units*, hence the name *unit* testing. Each +test should isolate itself to the correct degree. -Our test then makes a fake incoming web request, then calls our Pyramid -view. We test the HTTP status code on the response to make sure it -matches our expectations. +Our test then makes a fake incoming web request, then calls our Pyramid view. +We test the HTTP status code on the response to make sure it matches our +expectations. Note that our use of ``pyramid.testing.setUp()`` and ``pyramid.testing.tearDown()`` aren't actually necessary here; they are only necessary when your test needs to make use of the ``config`` object (it's a Configurator) to add stuff to the configuration state before calling the view. + Extra Credit ============ -#. Change the test to assert that the response status code should be - ``404`` (meaning, not found.) Run ``nosetests`` again. Read the - error report and see if you can decipher what it is telling you. +#. Change the test to assert that the response status code should be ``404`` + (meaning, not found). Run ``py.test`` again. Read the error report and see + if you can decipher what it is telling you. -#. As a more realistic example, put the ``tests.py`` back as you found - it and put an error in your view, such as a reference to a - non-existing variable. Run the tests and see how this is more - convenient than reloading your browser and going back to your code. +#. As a more realistic example, put the ``tests.py`` back as you found it, and + put an error in your view, such as a reference to a non-existing variable. + Run the tests and see how this is more convenient than reloading your + browser and going back to your code. #. Finally, for the most realistic test, read about Pyramid ``Response`` - objects and see how to change the response code. Run the tests and - see how testing confirms the "contract" that your code claims to - support. + objects and see how to change the response code. Run the tests and see how + testing confirms the "contract" that your code claims to support. #. How could we add a unit test assertion to test the HTML value of the response body? -- cgit v1.2.3 From ccf3974f81fa0e026fadd42ba5259c838aeab68b Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 04:50:39 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup functional_testing.rst --- docs/quick_tutorial/functional_testing.rst | 52 +++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/functional_testing.rst b/docs/quick_tutorial/functional_testing.rst index b8aa7e87d..33793578a 100644 --- a/docs/quick_tutorial/functional_testing.rst +++ b/docs/quick_tutorial/functional_testing.rst @@ -6,30 +6,33 @@ Write end-to-end full-stack testing using ``webtest``. + Background ========== -Unit tests are a common and popular approach to test-driven development -(TDD). In web applications, though, the templating and entire apparatus -of a web site are important parts of the delivered quality. We'd like a -way to test these. +Unit tests are a common and popular approach to test-driven development (TDD). +In web applications, though, the templating and entire apparatus of a web site +are important parts of the delivered quality. We'd like a way to test these. + +`WebTest `_ is a +Python package that does functional testing. With WebTest you can write tests +which simulate a full HTTP request against a WSGI application, then test the +information in the response. For speed purposes, WebTest skips the +setup/teardown of an actual HTTP server, providing tests that run fast enough +to be part of TDD. -WebTest is a Python package that does functional testing. With WebTest -you can write tests which simulate a full HTTP request against a WSGI -application, then test the information in the response. For speed -purposes, WebTest skips the setup/teardown of an actual HTTP server, -providing tests that run fast enough to be part of TDD. Objectives ========== -- Write a test which checks the contents of the returned HTML +- Write a test which checks the contents of the returned HTML. + Steps ===== -#. First we copy the results of the previous step, as well as install - the ``webtest`` package: +#. First we copy the results of the previous step, as well as install the + ``webtest`` package: .. code-block:: bash @@ -43,31 +46,28 @@ Steps .. literalinclude:: functional_testing/tutorial/tests.py :linenos: - Be sure this file is not executable, or ``nosetests`` may not - include your tests. + Be sure this file is not executable, or ``pytest`` may not include your + tests. #. Now run the tests: .. code-block:: bash + $ $VENV/bin/py.test tutorial/tests.py -q + .. + 2 passed in 0.25 seconds - $ $VENV/bin/nosetests tutorial - . - ---------------------------------------------------------------------- - Ran 2 tests in 0.141s - - OK Analysis ======== -We now have the end-to-end testing we were looking for. WebTest lets us -simply extend our existing ``nose``-based test approach with functional -tests that are reported in the same output. These new tests not only -cover our templating, but they didn't dramatically increase the -execution time of our tests. +We now have the end-to-end testing we were looking for. WebTest lets us simply +extend our existing ``pytest``-based test approach with functional tests that +are reported in the same output. These new tests not only cover our templating, +but they didn't dramatically increase the execution time of our tests. + -Extra Credit +Extra credit ============ #. Why do our functional tests use ``b''``? -- cgit v1.2.3 From 8083654303f0f0b3ce5e78979f6b51f7afd6980c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 04:58:00 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup views.rst --- docs/quick_tutorial/views.rst | 85 +++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 43 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/views.rst b/docs/quick_tutorial/views.rst index 5b6e2960b..edbe4b2ff 100644 --- a/docs/quick_tutorial/views.rst +++ b/docs/quick_tutorial/views.rst @@ -6,12 +6,12 @@ Organize a views module with decorators and multiple views. + Background ========== -For the examples so far, the ``hello_world`` function is a "view". In -Pyramid, views are the primary way to accept web requests and return -responses. +For the examples so far, the ``hello_world`` function is a "view". In Pyramid, +views are the primary way to accept web requests and return responses. So far our examples place everything in one file: @@ -23,22 +23,24 @@ So far our examples place everything in one file: - The WSGI application launcher -Let's move the views out to their own ``views.py`` module and change -our startup code to scan that module, looking for decorators that setup -the views. Let's also add a second view and update our tests. +Let's move the views out to their own ``views.py`` module and change our +startup code to scan that module, looking for decorators that set up the views. +Let's also add a second view and update our tests. + Objectives ========== -- Views in a module that is scanned by the configurator +- Move views into a module that is scanned by the configurator. + +- Create decorators that do declarative configuration. -- Decorators that do declarative configuration Steps ===== -#. Let's begin by using the previous package as a starting point for a - new distribution, then making it active: +#. Let's begin by using the previous package as a starting point for a new + distribution, then making it active: .. code-block:: bash @@ -66,12 +68,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial - . - ---------------------------------------------------------------------- - Ran 4 tests in 0.141s - - OK + $ $VENV/bin/py.test tutorial/tests.py -q + .... + 4 passed in 0.28 seconds #. Run your Pyramid application with: @@ -82,41 +81,41 @@ Steps #. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser. + Analysis ======== -We added some more URLs, but we also removed the view code from the -application startup code in ``tutorial/__init__.py``. -Our views, and their view registrations (via decorators) are now in a -module ``views.py`` which is scanned via ``config.scan('.views')``. - -We have 2 views, each leading to the other. If you start at -http://localhost:6543/, you get a response with a link to the next -view. The ``hello`` view (available at the URL ``/howdy``) has a link -back to the first view. - -This step also shows that the name appearing in the URL, -the name of the "route" that maps a URL to a view, -and the name of the view, can all be different. More on routes later. - -Earlier we saw ``config.add_view`` as one way to configure a view. This -section introduces ``@view_config``. Pyramid's configuration supports -:term:`imperative configuration`, such as the -``config.add_view`` in the previous example. You can also use -:term:`declarative configuration`, in which a Python -:term:`python:decorator` -is placed on the line above the view. Both approaches result in the -same final configuration, thus usually, it is simply a matter of taste. - -Extra Credit +We added some more URLs, but we also removed the view code from the application +startup code in ``tutorial/__init__.py``. Our views, and their view +registrations (via decorators) are now in a module ``views.py``, which is +scanned via ``config.scan('.views')``. + +We have two views, each leading to the other. If you start at +http://localhost:6543/, you get a response with a link to the next view. The +``hello`` view (available at the URL ``/howdy``) has a link back to the first +view. + +This step also shows that the name appearing in the URL, the name of the +"route" that maps a URL to a view, and the name of the view, can all be +different. More on routes later. + +Earlier we saw ``config.add_view`` as one way to configure a view. This section +introduces ``@view_config``. Pyramid's configuration supports :term:`imperative +configuration`, such as the ``config.add_view`` in the previous example. You +can also use :term:`declarative configuration`, in which a Python +:term:`python:decorator` is placed on the line above the view. Both approaches +result in the same final configuration, thus usually, it is simply a matter of +taste. + + +Extra credit ============ #. What does the dot in ``.views`` signify? -#. Why might ``assertIn`` be a better choice in testing the text in - responses than ``assertEqual``? +#. Why might ``assertIn`` be a better choice in testing the text in responses + than ``assertEqual``? .. seealso:: :ref:`views_chapter`, :ref:`view_config_chapter`, and :ref:`debugging_view_configuration` - -- cgit v1.2.3 From 3dece91a06679f1af98c864160fcd06ec3f15b8c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 05:02:30 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup templating.rst --- docs/quick_tutorial/templating.rst | 84 ++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 44 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/templating.rst b/docs/quick_tutorial/templating.rst index a975d9ec2..dbcf76a0a 100644 --- a/docs/quick_tutorial/templating.rst +++ b/docs/quick_tutorial/templating.rst @@ -4,50 +4,52 @@ 08: HTML Generation With Templating =================================== -Most web frameworks don't embed HTML in programming code. Instead, -they pass data into a templating system. In this step we look at the -basics of using HTML templates in Pyramid. +Most web frameworks don't embed HTML in programming code. Instead, they pass +data into a templating system. In this step we look at the basics of using HTML +templates in Pyramid. + Background ========== -Ouch. We have been making our own ``Response`` and filling the response -body with HTML. You usually won't embed an HTML string directly in -Python, but instead, will use a templating language. +Ouch. We have been making our own ``Response`` and filling the response body +with HTML. You usually won't embed an HTML string directly in Python, but +instead will use a templating language. + +Pyramid doesn't mandate a particular database system, form library, and so on. +It encourages replaceability. This applies equally to templating, which is +fortunate: developers have strong views about template languages. As of +Pyramid 1.5a2, Pyramid doesn't even bundle a template language! -Pyramid doesn't mandate a particular database system, form library, -etc. It encourages replaceability. This applies equally to templating, -which is fortunate: developers have strong views about template -languages. As of Pyramid 1.5a2, Pyramid doesn't even bundle a template -language! +It does, however, have strong ties to Jinja2, Mako, and Chameleon. In this step +we see how to add ``pyramid_chameleon`` to your project, then change your views +to use templating. -It does, however, have strong ties to Jinja2, Mako, and Chameleon. In -this step we see how to add ``pyramid_chameleon`` to your project, -then change your views to use templating. Objectives ========== -- Enable the ``pyramid_chameleon`` Pyramid add-on +- Enable the ``pyramid_chameleon`` Pyramid add-on. + +- Generate HTML from template files. -- Generate HTML from template files +- Connect the templates as "renderers" for view code. -- Connect the templates as "renderers" for view code +- Change the view code to simply return data. -- Change the view code to simply return data Steps ===== -#. Let's begin by using the previous package as a starting point for a - new project: +#. Let's begin by using the previous package as a starting point for a new + project: .. code-block:: bash $ cd ..; cp -r views templating; cd templating -#. This step depends on ``pyramid_chameleon``, so add it as a dependency - in ``templating/setup.py``: +#. This step depends on ``pyramid_chameleon``, so add it as a dependency in + ``templating/setup.py``: .. literalinclude:: templating/setup.py :linenos: @@ -58,8 +60,8 @@ Steps $ $VENV/bin/pip install -e . -#. We need to connect ``pyramid_chameleon`` as a renderer by making a - call in the setup of ``templating/tutorial/__init__.py``: +#. We need to connect ``pyramid_chameleon`` as a renderer by making a call in + the setup of ``templating/tutorial/__init__.py``: .. literalinclude:: templating/tutorial/__init__.py :linenos: @@ -74,14 +76,13 @@ Steps .. literalinclude:: templating/tutorial/home.pt :language: html -#. For convenience, change ``templating/development.ini`` to reload - templates automatically with ``pyramid.reload_templates``: +#. For convenience, change ``templating/development.ini`` to reload templates + automatically with ``pyramid.reload_templates``: .. literalinclude:: templating/development.ini :language: ini -#. Our unit tests in ``templating/tutorial/tests.py`` can focus on - data: +#. Our unit tests in ``templating/tutorial/tests.py`` can focus on data: .. literalinclude:: templating/tutorial/tests.py :linenos: @@ -90,13 +91,9 @@ Steps .. code-block:: bash - - $ $VENV/bin/nosetests tutorial - . - ---------------------------------------------------------------------- - Ran 4 tests in 0.141s - - OK + $ $VENV/bin/py.test tutorial/tests.py -q + .... + 4 passed in 0.46 seconds #. Run your Pyramid application with: @@ -104,20 +101,19 @@ Steps $ $VENV/bin/pserve development.ini --reload -#. Open http://localhost:6543/ and http://localhost:6543/howdy - in your browser. +#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser. + Analysis ======== -Ahh, that looks better. We have a view that is focused on Python code. -Our ``@view_config`` decorator specifies a :term:`renderer` that points -to our template file. Our view then simply returns data which is then -supplied to our template. Note that we used the same template for both -views. +Ahh, that looks better. We have a view that is focused on Python code. Our +``@view_config`` decorator specifies a :term:`renderer` that points to our +template file. Our view then simply returns data which is then supplied to our +template. Note that we used the same template for both views. -Note the effect on testing. We can focus on having a data-oriented -contract with our view code. +Note the effect on testing. We can focus on having a data-oriented contract +with our view code. .. seealso:: :ref:`templates_chapter`, :ref:`debugging_templates`, and :ref:`available_template_system_bindings`. -- cgit v1.2.3 From 842a4fa23a8948a31023af0983c874ef45cb1041 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 05:09:14 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup view_classes.rst --- docs/quick_tutorial/templating.rst | 5 +-- docs/quick_tutorial/view_classes.rst | 69 +++++++++++++++++------------------- 2 files changed, 36 insertions(+), 38 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/templating.rst b/docs/quick_tutorial/templating.rst index dbcf76a0a..ec6de98f8 100644 --- a/docs/quick_tutorial/templating.rst +++ b/docs/quick_tutorial/templating.rst @@ -22,8 +22,9 @@ fortunate: developers have strong views about template languages. As of Pyramid 1.5a2, Pyramid doesn't even bundle a template language! It does, however, have strong ties to Jinja2, Mako, and Chameleon. In this step -we see how to add ``pyramid_chameleon`` to your project, then change your views -to use templating. +we see how to add `pyramid_chameleon +`_ to your project, then change +your views to use templating. Objectives diff --git a/docs/quick_tutorial/view_classes.rst b/docs/quick_tutorial/view_classes.rst index cc5337493..05d97a9b1 100644 --- a/docs/quick_tutorial/view_classes.rst +++ b/docs/quick_tutorial/view_classes.rst @@ -4,8 +4,9 @@ 09: Organizing Views With View Classes ====================================== -Change our view functions to be methods on a view class, -then move some declarations to the class level. +Change our view functions to be methods on a view class, then move some +declarations to the class level. + Background ========== @@ -15,27 +16,27 @@ views are related to one another. They may be different ways to look at or work on the same data, or be a REST API that handles multiple operations. Grouping these views together as a :ref:`view class ` makes sense: -- Group views +- Group views. + +- Centralize some repetitive defaults. -- Centralize some repetitive defaults +- Share some state and helpers. -- Share some state and helpers +In this step we just do the absolute minimum to convert the existing views to a +view class. In a later tutorial step, we'll examine view classes in depth. -In this step we just do the absolute minimum to convert the existing -views to a view class. In a later tutorial step we'll examine view -classes in depth. Objectives ========== -- Group related views into a view class +- Group related views into a view class. + +- Centralize configuration with class-level ``@view_defaults``. -- Centralize configuration with class-level ``@view_defaults`` Steps ===== - #. First we copy the results of the previous step: .. code-block:: bash @@ -43,15 +44,15 @@ Steps $ cd ..; cp -r templating view_classes; cd view_classes $ $VENV/bin/pip install -e . -#. Our ``view_classes/tutorial/views.py`` now has a view class with - our two views: +#. Our ``view_classes/tutorial/views.py`` now has a view class with our two + views: .. literalinclude:: view_classes/tutorial/views.py :linenos: -#. Our unit tests in ``view_classes/tutorial/tests.py`` don't run, - so let's modify them to import the view class and make an instance - before getting a response: +#. Our unit tests in ``view_classes/tutorial/tests.py`` don't run, so let's + modify them to import the view class, and make an instance before getting a + response: .. literalinclude:: view_classes/tutorial/tests.py :linenos: @@ -61,12 +62,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial - . - ---------------------------------------------------------------------- - Ran 4 tests in 0.141s - - OK + $ $VENV/bin/py.test tutorial/tests.py -q + .... + 4 passed in 0.34 seconds #. Run your Pyramid application with: @@ -74,24 +72,23 @@ Steps $ $VENV/bin/pserve development.ini --reload -#. Open http://localhost:6543/ and http://localhost:6543/howdy - in your browser. +#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser. + Analysis ======== To ease the transition to view classes, we didn't introduce any new -functionality. We simply changed the view functions to methods on a -view class, then updated the tests. - -In our ``TutorialViews`` view class you can see that our two view -classes are logically grouped together as methods on a common class. -Since the two views shared the same template, we could move that to a -``@view_defaults`` decorator at the class level. - -The tests needed to change. Obviously we needed to import the view -class. But you can also see the pattern in the tests of instantiating -the view class with the dummy request first, then calling the view -method being tested. +functionality. We simply changed the view functions to methods on a view class, +then updated the tests. + +In our ``TutorialViews`` view class, you can see that our two view classes are +logically grouped together as methods on a common class. Since the two views +shared the same template, we could move that to a ``@view_defaults`` decorator +at the class level. + +The tests needed to change. Obviously we needed to import the view class. But +you can also see the pattern in the tests of instantiating the view class with +the dummy request first, then calling the view method being tested. .. seealso:: :ref:`class_as_view` -- cgit v1.2.3 From ff68f90859f01658b397e3559dd1eae0feb508f3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 05:17:04 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup request_response.rst --- docs/quick_tutorial/request_response.rst | 71 +++++++++++++++++--------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/request_response.rst b/docs/quick_tutorial/request_response.rst index f42423de8..0ac9b4f6d 100644 --- a/docs/quick_tutorial/request_response.rst +++ b/docs/quick_tutorial/request_response.rst @@ -5,33 +5,32 @@ ======================================= Web applications handle incoming requests and return outgoing responses. -Pyramid makes working with requests and responses convenient and -reliable. +Pyramid makes working with requests and responses convenient and reliable. + Objectives ========== -- Learn the background on Pyramid's choices for requests and responses +- Learn the background on Pyramid's choices for requests and responses. + +- Grab data out of the request. -- Grab data out of the request +- Change information in the response headers. -- Change information in the response headers Background ========== -Developing for the web means processing web requests. As this is a -critical part of a web application, web developers need a robust, -mature set of software for web requests and returning web -responses. +Developing for the web means processing web requests. As this is a critical +part of a web application, web developers need a robust, mature set of software +for web requests and returning web responses. + +Pyramid has always fit nicely into the existing world of Python web development +(virtual environments, packaging, scaffolding, first to embrace Python 3, and +so on). Pyramid turned to the well-regarded :term:`WebOb` Python library for +request and response handling. In our example above, Pyramid hands +``hello_world`` a ``request`` that is :ref:`based on WebOb `. -Pyramid has always fit nicely into the existing world of Python web -development (virtual environments, packaging, scaffolding, -first to embrace Python 3, etc.) For request handling, Pyramid turned -to the well-regarded :term:`WebOb` Python library for request and -response handling. In our example -above, Pyramid hands ``hello_world`` a ``request`` that is -:ref:`based on WebOb `. Steps ===== @@ -62,7 +61,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/py.test tutorial/tests.py -q + ..... + 5 passed in 0.30 seconds #. Run your Pyramid application with: @@ -70,37 +71,39 @@ Steps $ $VENV/bin/pserve development.ini --reload -#. Open http://localhost:6543/ in your browser. You will be - redirected to http://localhost:6543/plain +#. Open http://localhost:6543/ in your browser. You will be redirected to + http://localhost:6543/plain. #. Open http://localhost:6543/plain?name=alice in your browser. + Analysis ======== -In this view class we have two routes and two views, with the first -leading to the second by an HTTP redirect. Pyramid can -:ref:`generate redirects ` by returning a -special object from a view or raising a special exception. +In this view class, we have two routes and two views, with the first leading to +the second by an HTTP redirect. Pyramid can :ref:`generate redirects +` by returning a special object from a view or raising a special +exception. + +In this Pyramid view, we get the URL being visited from ``request.url``. Also, +if you visited http://localhost:6543/plain?name=alice, the name is included in +the body of the response: -In this Pyramid view, we get the URL being visited from ``request.url``. -Also, if you visited http://localhost:6543/plain?name=alice, -the name is included in the body of the response:: +.. code-block:: text URL http://localhost:6543/plain?name=alice with name: alice -Finally, we set the response's content type and body, then return the -Response. +Finally, we set the response's content type and body, then return the response. + +We updated the unit and functional tests to prove that our code does the +redirection, but also handles sending and not sending ``/plain?name``. -We updated the unit and functional tests to prove that our code -does the redirection, but also handles sending and not sending -``/plain?name``. -Extra Credit +Extra credit ============ -#. Could we also ``raise HTTPFound(location='/plain')`` instead of - returning it? If so, what's the difference? +#. Could we also ``raise HTTPFound(location='/plain')`` instead of returning + it? If so, what's the difference? .. seealso:: :ref:`webob_chapter`, :ref:`generate redirects ` -- cgit v1.2.3 From 72c2196bf0c2bc867e7c13ea93bb6f6ddacd83cb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 05:22:37 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup routing.rst --- docs/quick_tutorial/routing.rst | 53 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 25 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/routing.rst b/docs/quick_tutorial/routing.rst index 7b6d0904d..27c8c2c22 100644 --- a/docs/quick_tutorial/routing.rst +++ b/docs/quick_tutorial/routing.rst @@ -4,22 +4,23 @@ 11: Dispatching URLs To Views With Routing ========================================== -Routing matches incoming URL patterns to view code. Pyramid's routing -has a number of useful features. +Routing matches incoming URL patterns to view code. Pyramid's routing has a +number of useful features. + Background ========== -Writing web applications usually means sophisticated URL design. We -just saw some Pyramid machinery for requests and views. Let's look at -features that help in routing. +Writing web applications usually means sophisticated URL design. We just saw +some Pyramid machinery for requests and views. Let's look at features that help +in routing. Previously we saw the basics of routing URLs to views in Pyramid. -- Your project's "setup" code registers a route name to be used when - matching part of the URL +- Your project's "setup" code registers a route name to be used when matching + part of the URL -- Elsewhere, a view is configured to be called for that route name +- Elsewhere a view is configured to be called for that route name. .. note:: @@ -33,12 +34,14 @@ Previously we saw the basics of routing URLs to views in Pyramid. `_ if you're interested in doing so. + Objectives ========== -- Define a route that extracts part of the URL into a Python dictionary +- Define a route that extracts part of the URL into a Python dictionary. + +- Use that dictionary data in a view. -- Use that dictionary data in a view Steps ===== @@ -76,7 +79,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/$VENV/bin/py.test tutorial/tests.py -q + .. + 2 passed in 0.39 seconds #. Run your Pyramid application with: @@ -86,6 +91,7 @@ Steps #. Open http://localhost:6543/howdy/amy/smith in your browser. + Analysis ======== @@ -95,27 +101,24 @@ In ``__init__.py`` we see an important change in our route declaration: config.add_route('hello', '/howdy/{first}/{last}') -With this we tell the :term:`configurator` that our URL has -a "replacement pattern". With this, URLs such as ``/howdy/amy/smith`` -will assign ``amy`` to ``first`` and ``smith`` to ``last``. We can then -use this data in our view: +With this we tell the :term:`configurator` that our URL has a "replacement +pattern". With this, URLs such as ``/howdy/amy/smith`` will assign ``amy`` to +``first`` and ``smith`` to ``last``. We can then use this data in our view: .. code-block:: python self.request.matchdict['first'] self.request.matchdict['last'] -``request.matchdict`` contains values from the URL that match the -"replacement patterns" (the curly braces) in the route declaration. -This information can then be used anywhere in Pyramid that has access -to the request. +``request.matchdict`` contains values from the URL that match the "replacement +patterns" (the curly braces) in the route declaration. This information can +then be used anywhere in Pyramid that has access to the request. -Extra Credit +Extra credit ============ -#. What happens if you to go the URL - http://localhost:6543/howdy? Is this the result that you - expected? +#. What happens if you to go the URL http://localhost:6543/howdy? Is this the + result that you expected? -.. seealso:: `Weird Stuff You Can Do With URL - Dispatch `_ +.. seealso:: `Weird Stuff You Can Do With URL Dispatch + `_ -- cgit v1.2.3 From d5e6762315458de334896096923abcd3d51a31f5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 06:43:35 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup jinja2.rst - add pyramid_jinja2 to requirements.rst --- docs/quick_tutorial/jinja2.rst | 55 +++++++++++++++++++----------------- docs/quick_tutorial/requirements.rst | 6 ++-- 2 files changed, 32 insertions(+), 29 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/jinja2.rst b/docs/quick_tutorial/jinja2.rst index 6b9d5feba..2fc68827b 100644 --- a/docs/quick_tutorial/jinja2.rst +++ b/docs/quick_tutorial/jinja2.rst @@ -4,24 +4,26 @@ 12: Templating With ``jinja2`` ============================== -We just said Pyramid doesn't prefer one templating language over -another. Time to prove it. Jinja2 is a popular templating system, -used in Flask and modeled after Django's templates. Let's add -``pyramid_jinja2``, a Pyramid :term:`add-on` which enables Jinja2 as a -:term:`renderer` in our Pyramid applications. +We just said Pyramid doesn't prefer one templating language over another. Time +to prove it. Jinja2 is a popular templating system, used in Flask and modeled +after Django's templates. Let's add ``pyramid_jinja2``, a Pyramid +:term:`add-on` which enables Jinja2 as a :term:`renderer` in our Pyramid +applications. + Objectives ========== -- Show Pyramid's support for different templating systems +- Show Pyramid's support for different templating systems. + +- Learn about installing Pyramid add-ons. -- Learn about installing Pyramid add-ons Steps ===== -#. In this step let's start by copying the ``view_class`` step's - directory, and then installing the ``pyramid_jinja2`` add-on. +#. In this step let's start by copying the ``view_class`` step's directory, + and then installing the ``pyramid_jinja2`` add-on. .. code-block:: bash @@ -29,8 +31,7 @@ Steps $ $VENV/bin/pip install -e . $ $VENV/bin/pip install pyramid_jinja2 -#. We need to include ``pyramid_jinja2`` in - ``jinja2/tutorial/__init__.py``: +#. We need to include ``pyramid_jinja2`` in ``jinja2/tutorial/__init__.py``: .. literalinclude:: jinja2/tutorial/__init__.py :linenos: @@ -49,7 +50,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/py.test tutorial/tests.py -q + .... + 4 passed in 0.40 seconds #. Run your Pyramid application with: @@ -59,30 +62,30 @@ Steps #. Open http://localhost:6543/ in your browser. + Analysis ======== -Getting a Pyramid add-on into Pyramid is simple. First you use normal -Python package installation tools to install the add-on package into -your Python. You then tell Pyramid's configurator to run the setup code +Getting a Pyramid add-on into Pyramid is simple. First you use normal Python +package installation tools to install the add-on package into your Python +virtual environment. You then tell Pyramid's configurator to run the setup code in the add-on. In this case the setup code told Pyramid to make a new "renderer" available that looked for ``.jinja2`` file extensions. -Our view code stayed largely the same. We simply changed the file -extension on the renderer. For the template, the syntax for Chameleon -and Jinja2's basic variable insertion is very similar. +Our view code stayed largely the same. We simply changed the file extension on +the renderer. For the template, the syntax for Chameleon and Jinja2's basic +variable insertion is very similar. + -Extra Credit +Extra credit ============ -#. Our project now depends on ``pyramid_jinja2``. We installed that - dependency manually. What is another way we could have made the - association? +#. Our project now depends on ``pyramid_jinja2``. We installed that dependency + manually. What is another way we could have made the association? #. We used ``config.include`` which is an imperative configuration to get the - :term:`Configurator` to load ``pyramid_jinja2``'s configuration. - What is another way could include it into the config? + :term:`Configurator` to load ``pyramid_jinja2``'s configuration. What is + another way could include it into the config? -.. seealso:: `Jinja2 homepage `_, - and +.. seealso:: `Jinja2 homepage `_, and :ref:`pyramid_jinja2 Overview ` diff --git a/docs/quick_tutorial/requirements.rst b/docs/quick_tutorial/requirements.rst index f4c1e70ac..1f2b4da97 100644 --- a/docs/quick_tutorial/requirements.rst +++ b/docs/quick_tutorial/requirements.rst @@ -205,10 +205,10 @@ tutorial. # Mac and Linux $ $VENV/bin/pip install webtest pytest pytest-cov deform sqlalchemy \ - pyramid_chameleon pyramid_debugtoolbar waitress pyramid_tm \ - zope.sqlalchemy + pyramid_chameleon pyramid_debugtoolbar pyramid_jinja2 waitress \ + pyramid_tm zope.sqlalchemy .. code-block:: doscon # Windows - c:\> %VENV%\Scripts\pip install webtest deform sqlalchemy pyramid_chameleon pyramid_debugtoolbar waitress pyramid_tm zope.sqlalchemy + c:\> %VENV%\Scripts\pip install webtest deform sqlalchemy pyramid_chameleon pyramid_debugtoolbar pyramid_jinja2 waitress pyramid_tm zope.sqlalchemy -- cgit v1.2.3 From 41279dddbf5343488542f2629194c68dd3c2142d Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 06:57:21 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup static_assets.rst --- docs/quick_tutorial/static_assets.rst | 45 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/static_assets.rst b/docs/quick_tutorial/static_assets.rst index 61c5fbd50..65b34f8f9 100644 --- a/docs/quick_tutorial/static_assets.rst +++ b/docs/quick_tutorial/static_assets.rst @@ -4,16 +4,17 @@ 13: CSS/JS/Images Files With Static Assets ========================================== -Of course the Web is more than just markup. You need static assets: -CSS, JS, and images. Let's point our web app at a directory where -Pyramid will serve some static assets. +Of course the Web is more than just markup. You need static assets: CSS, JS, +and images. Let's point our web app at a directory where Pyramid will serve +some static assets. Objectives ========== -- Publish a directory of static assets at a URL +- Publish a directory of static assets at a URL. + +- Use Pyramid to help generate URLs to files in that directory. -- Use Pyramid to help generate URLs to files in that directory Steps ===== @@ -37,8 +38,7 @@ Steps .. literalinclude:: static_assets/tutorial/home.pt :language: html -#. Add a CSS file at - ``static_assets/tutorial/static/app.css``: +#. Add a CSS file at ``static_assets/tutorial/static/app.css``: .. literalinclude:: static_assets/tutorial/static/app.css :language: css @@ -47,7 +47,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/$VENV/bin/py.test tutorial/tests.py -q + .... + 4 passed in 0.50 seconds #. Run your Pyramid application with: @@ -57,30 +59,31 @@ Steps #. Open http://localhost:6543/ in your browser and note the new font. + Analysis ======== We changed our WSGI application to map requests under -http://localhost:6543/static/ to files and directories inside a -``static`` directory inside our ``tutorial`` package. This directory -contained ``app.css``. +http://localhost:6543/static/ to files and directories inside a ``static`` +directory inside our ``tutorial`` package. This directory contained +``app.css``. -We linked to the CSS in our template. We could have hard-coded this -link to ``/static/app.css``. But what if the site is later moved under -``/somesite/static/``? Or perhaps the web developer changes the -arrangement on disk? Pyramid gives a helper that provides flexibility -on URL generation: +We linked to the CSS in our template. We could have hard-coded this link to +``/static/app.css``. But what if the site is later moved under +``/somesite/static/``? Or perhaps the web developer changes the arrangement on +disk? Pyramid gives a helper that provides flexibility on URL generation: .. code-block:: html ${request.static_url('tutorial:static/app.css')} -This matches the ``path='tutorial:static'`` in our -``config.add_static_view`` registration. By using ``request.static_url`` -to generate the full URL to the static assets, you both ensure you stay -in sync with the configuration and gain refactoring flexibility later. +This matches the ``path='tutorial:static'`` in our ``config.add_static_view`` +registration. By using ``request.static_url`` to generate the full URL to the +static assets, you both ensure you stay in sync with the configuration and gain +refactoring flexibility later. + -Extra Credit +Extra credit ============ #. There is also a ``request.static_path`` API. How does this differ from -- cgit v1.2.3 From 353268e208451fc302cfd19454cea650b7498af3 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 07:06:17 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup json.rst --- docs/quick_tutorial/json.rst | 87 ++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 43 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/json.rst b/docs/quick_tutorial/json.rst index 49421829b..ff153d2b5 100644 --- a/docs/quick_tutorial/json.rst +++ b/docs/quick_tutorial/json.rst @@ -1,27 +1,28 @@ .. _qtut_json: ======================================== -14: Ajax Development With JSON Renderers +14: AJAX Development With JSON Renderers ======================================== -Modern web apps are more than rendered HTML. Dynamic pages now use -JavaScript to update the UI in the browser by requesting server data as -JSON. Pyramid supports this with a *JSON renderer*. +Modern web apps are more than rendered HTML. Dynamic pages now use JavaScript +to update the UI in the browser by requesting server data as JSON. Pyramid +supports this with a *JSON renderer*. + Background ========== -As we saw in :doc:`templating`, view declarations can specify a -renderer. Output from the view is then run through the renderer, -which generates and returns the ``Response``. We first used a Chameleon -renderer, then a Jinja2 renderer. +As we saw in :doc:`templating`, view declarations can specify a renderer. +Output from the view is then run through the renderer, which generates and +returns the response. We first used a Chameleon renderer, then a Jinja2 +renderer. + +Renderers aren't limited, however, to templates that generate HTML. Pyramid +supplies a JSON renderer which takes Python data, serializes it to JSON, and +performs some other functions such as setting the content type. In fact you can +write your own renderer (or extend a built-in renderer) containing custom logic +for your unique application. -Renderers aren't limited, however, to templates that generate HTML. -Pyramid supplies a JSON renderer which takes Python data, -serializes it to JSON, and performs some other functions such as -setting the content type. In fact, you can write your own renderer (or -extend a built-in renderer) containing custom logic for your unique -application. Steps ===== @@ -33,20 +34,18 @@ Steps $ cd ..; cp -r view_classes json; cd json $ $VENV/bin/pip install -e . -#. We add a new route for ``hello_json`` in - ``json/tutorial/__init__.py``: +#. We add a new route for ``hello_json`` in ``json/tutorial/__init__.py``: .. literalinclude:: json/tutorial/__init__.py :linenos: -#. Rather than implement a new view, we will "stack" another decorator - on the ``hello`` view in ``views.py``: +#. Rather than implement a new view, we will "stack" another decorator on the + ``hello`` view in ``views.py``: .. literalinclude:: json/tutorial/views.py :linenos: -#. We need a new functional test at the end of - ``json/tutorial/tests.py``: +#. We need a new functional test at the end of ``json/tutorial/tests.py``: .. literalinclude:: json/tutorial/tests.py :linenos: @@ -55,7 +54,10 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/py.test tutorial/tests.py -q + ..... + 5 passed in 0.47 seconds + #. Run your Pyramid application with: @@ -63,40 +65,39 @@ Steps $ $VENV/bin/pserve development.ini --reload -#. Open http://localhost:6543/howdy.json in your browser and you - will see the resulting JSON response. +#. Open http://localhost:6543/howdy.json in your browser and you will see the + resulting JSON response. + Analysis ======== -Earlier we changed our view functions and methods to return Python -data. This change to a data-oriented view layer made test writing -easier, decoupling the templating from the view logic. +Earlier we changed our view functions and methods to return Python data. This +change to a data-oriented view layer made test writing easier, decoupling the +templating from the view logic. -Since Pyramid has a JSON renderer as well as the templating renderers, -it is an easy step to return JSON. In this case we kept the exact same -view and arranged to return a JSON encoding of the view data. We did -this by: +Since Pyramid has a JSON renderer as well as the templating renderers, it is an +easy step to return JSON. In this case we kept the exact same view and arranged +to return a JSON encoding of the view data. We did this by: -- Adding a route to map ``/howdy.json`` to a route name +- Adding a route to map ``/howdy.json`` to a route name. -- Providing a ``@view_config`` that associated that route name with an - existing view +- Providing a ``@view_config`` that associated that route name with an existing + view. -- *overriding* the view defaults in the view config that mentions the - ``hello_json`` route, so that when the route is matched, we use the JSON +- *Overriding* the view defaults in the view config that mentions the + ``hello_json`` route, so that when the route is matched, we use the JSON renderer rather than the ``home.pt`` template renderer that would otherwise be used. -In fact, for pure Ajax-style web applications, we could re-use the existing -route by using Pyramid's view predicates to match on the -``Accepts:`` header sent by modern Ajax implementation. +In fact, for pure AJAX-style web applications, we could re-use the existing +route by using Pyramid's view predicates to match on the ``Accepts:`` header +sent by modern AJAX implementations. -Pyramid's JSON renderer uses the base Python JSON encoder, -thus inheriting its strengths and weaknesses. For example, -Python can't natively JSON encode DateTime objects. There are a number -of solutions for this in Pyramid, including extending the JSON renderer -with a custom renderer. +Pyramid's JSON renderer uses the base Python JSON encoder, thus inheriting its +strengths and weaknesses. For example, Python can't natively JSON encode +DateTime objects. There are a number of solutions for this in Pyramid, +including extending the JSON renderer with a custom renderer. .. seealso:: :ref:`views_which_use_a_renderer`, :ref:`json_renderer`, and -- cgit v1.2.3 From 0fa18e37b5a81a68d70807c1abd90a439dbdb4b7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 12:19:25 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup more_view_classes.rst --- docs/quick_tutorial/more_view_classes.rst | 131 +++++++++++++++--------------- 1 file changed, 65 insertions(+), 66 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/more_view_classes.rst b/docs/quick_tutorial/more_view_classes.rst index fb97cceb2..30234ea2e 100644 --- a/docs/quick_tutorial/more_view_classes.rst +++ b/docs/quick_tutorial/more_view_classes.rst @@ -6,48 +6,49 @@ Group views into a class, sharing configuration, state, and logic. + Background ========== -As part of its mission to help build more ambitious web applications, -Pyramid provides many more features for views and view classes. +As part of its mission to help build more ambitious web applications, Pyramid +provides many more features for views and view classes. + +The Pyramid documentation discusses views as a Python "callable". This callable +can be a function, an object with a ``__call__``, or a Python class. In this +last case, methods on the class can be decorated with ``@view_config`` to +register the class methods with the :term:`configurator` as a view. -The Pyramid documentation discusses views as a Python "callable". This -callable can be a function, an object with an ``__call__``, -or a Python class. In this last case, methods on the class can be -decorated with ``@view_config`` to register the class methods with the -:term:`configurator` as a view. +At first, our views were simple, free-standing functions. Many times your views +are related: different ways to look at or work on the same data, or a REST API +that handles multiple operations. Grouping these together as a :ref:`view class +` makes sense: -At first, our views were simple, free-standing functions. Many times -your views are related: different ways to look at or work on the same -data or a REST API that handles multiple operations. Grouping these -together as a :ref:`view class ` makes sense: +- Group views. -- Group views +- Centralize some repetitive defaults. -- Centralize some repetitive defaults +- Share some state and helpers. -- Share some state and helpers +Pyramid views have :ref:`view predicates ` that +determine which view is matched to a request, based on factors such as the +request method, the form parameters, and so on. These predicates provide many +axes of flexibility. -Pyramid views have :ref:`view predicates ` -that determine which view is matched to a request, based on factors -such as the request method, the form parameters, etc. These predicates -provide many axes of flexibility. +The following shows a simple example with four operations: view a home page +which leads to a form, save a change, and press the delete button. -The following shows a simple example with four operations: -view a home page which leads to a form, save a change, -and press the delete button. Objectives ========== -- Group related views into a view class +- Group related views into a view class. -- Centralize configuration with class-level ``@view_defaults`` +- Centralize configuration with class-level ``@view_defaults``. -- Dispatch one route/URL to multiple views based on request data +- Dispatch one route/URL to multiple views based on request data. + +- Share states and logic between views and templates via the view class. -- Share states and logic between views and templates via the view class Steps ===== @@ -71,8 +72,7 @@ Steps .. literalinclude:: more_view_classes/tutorial/views.py :linenos: -#. Our primary view needs a template at - ``more_view_classes/tutorial/home.pt``: +#. Our primary view needs a template at ``more_view_classes/tutorial/home.pt``: .. literalinclude:: more_view_classes/tutorial/home.pt :language: html @@ -105,12 +105,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial - . - ---------------------------------------------------------------------- - Ran 2 tests in 0.248s - - OK + $ $VENV/bin/py.test tutorial/tests.py -q + .. + 2 passed in 0.40 seconds #. Run your Pyramid application with: @@ -118,29 +115,27 @@ Steps $ $VENV/bin/pserve development.ini --reload -#. Open http://localhost:6543/howdy/jane/doe in your browser. Click - the ``Save`` and ``Delete`` buttons and watch the output in the - console window. +#. Open http://localhost:6543/howdy/jane/doe in your browser. Click the + ``Save`` and ``Delete`` buttons, and watch the output in the console window. + Analysis ======== -As you can see, the four views are logically grouped together. -Specifically: +As you can see, the four views are logically grouped together. Specifically: -- We have a ``home`` view available at http://localhost:6543/ with - a clickable link to the ``hello`` view. +- We have a ``home`` view available at http://localhost:6543/ with a clickable + link to the ``hello`` view. -- The second view is returned when you go to ``/howdy/jane/doe``. This - URL is +- The second view is returned when you go to ``/howdy/jane/doe``. This URL is mapped to the ``hello`` route that we centrally set using the optional ``@view_defaults``. -- The third view is returned when the form is submitted with a ``POST`` - method. This rule is specified in the ``@view_config`` for that view. +- The third view is returned when the form is submitted with a ``POST`` method. + This rule is specified in the ``@view_config`` for that view. -- The fourth view is returned when clicking on a button such - as ````. +- The fourth view is returned when clicking on a button such as ````. In this step we show, using the following information as criteria, how to decide which view to use: @@ -149,49 +144,53 @@ decide which view to use: - Parameter information in the request (submitted form field names) -We also centralize part of the view configuration to the class level -with ``@view_defaults``, then in one view, override that default just -for that one view. Finally, we put this commonality between views to -work in the view class by sharing: +We also centralize part of the view configuration to the class level with +``@view_defaults``, then in one view, override that default just for that one +view. Finally, we put this commonality between views to work in the view class +by sharing: - State assigned in ``TutorialViews.__init__`` - A computed value -These are then available both in the view methods but also in the -templates (e.g. ``${view.view_name}`` and ``${view.full_name}``. +These are then available both in the view methods and in the templates (e.g., +``${view.view_name}`` and ``${view.full_name}``). + +As a note, we made a switch in our templates on how we generate URLs. We +previously hardcoded the URLs, such as: -As a note, we made a switch in our templates on how we generate URLs. -We previously hardcode the URLs, such as:: +.. code-block:: html Howdy -In ``home.pt`` we switched to:: +In ``home.pt`` we switched to: + +.. code-block:: xml form -Pyramid has rich facilities to help generate URLs in a flexible, -non-error-prone fashion. +Pyramid has rich facilities to help generate URLs in a flexible, non-error +prone fashion. -Extra Credit +Extra credit ============ #. Why could our template do ``${view.full_name}`` and not have to do ``${view.full_name()}``? -#. The ``edit`` and ``delete`` views are both submitted to with - ``POST``. Why does the ``edit`` view configuration not catch the - ``POST`` used by ``delete``? +#. The ``edit`` and ``delete`` views are both receive ``POST`` requests. Why + does the ``edit`` view configuration not catch the ``POST`` used by + ``delete``? -#. We used Python ``@property`` on ``full_name``. If we reference this - many times in a template or view code, it would re-compute this - every time. Does Pyramid provide something that will cache the initial - computation on a property? +#. We used Python ``@property`` on ``full_name``. If we reference this many + times in a template or view code, it would re-compute this every time. Does + Pyramid provide something that will cache the initial computation on a + property? #. Can you associate more than one route with the same view? -#. There is also a ``request.route_path`` API. How does this differ from +#. There is also a ``request.route_path`` API. How does this differ from ``request.route_url``? .. seealso:: :ref:`class_as_view`, `Weird Stuff You Can Do With -- cgit v1.2.3 From e672bd40b861d763e664992ac0ef6b5b6f84c740 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 12:27:07 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup logging.rst --- docs/quick_tutorial/logging.rst | 52 +++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/logging.rst b/docs/quick_tutorial/logging.rst index 556a09bf0..cbbf7860e 100644 --- a/docs/quick_tutorial/logging.rst +++ b/docs/quick_tutorial/logging.rst @@ -4,28 +4,30 @@ 16: Collecting Application Info With Logging ============================================ -Capture debugging and error output from your web applications using -standard Python logging. +Capture debugging and error output from your web applications using standard +Python logging. + Background ========== -It's important to know what is going on inside our web application. -In development we might need to collect some output. In production, -we might need to detect problems when other people use the site. We -need *logging*. +It's important to know what is going on inside our web application. In +development we might need to collect some output. In production, we might need +to detect problems when other people use the site. We need *logging*. + +Fortunately Pyramid uses the normal Python approach to logging. The scaffold +generated in your ``development.ini`` has a number of lines that configure the +logging for you to some reasonable defaults. You then see messages sent by +Pyramid, for example, when a new request comes in. -Fortunately Pyramid uses the normal Python approach to logging. The -scaffold generated in your ``development.ini`` has a number of lines that -configure the logging for you to some reasonable defaults. You then see -messages sent by Pyramid, for example, when a new request comes in. Objectives ========== -- Inspect the configuration setup used for logging +- Inspect the configuration setup used for logging. + +- Add logging statements to your view code. -- Add logging statements to your view code Steps ===== @@ -42,8 +44,8 @@ Steps .. literalinclude:: logging/tutorial/views.py :linenos: -#. Finally let's edit ``development.ini`` configuration file - to enable logging for our Pyramid application: +#. Finally let's edit ``development.ini`` configuration file to enable logging + for our Pyramid application: .. literalinclude:: logging/development.ini :language: ini @@ -52,7 +54,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/py.test tutorial/tests.py -q + .... + 4 passed in 0.41 seconds #. Run your Pyramid application with: @@ -60,19 +64,21 @@ Steps $ $VENV/bin/pserve development.ini --reload -#. Open http://localhost:6543/ and http://localhost:6543/howdy - in your browser. Note, both in the console and in the debug - toolbar, the message that you logged. +#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser. + Note, both in the console and in the debug toolbar, the message that you + logged. + Analysis ======== -In our configuration file ``development.ini``, our ``tutorial`` Python -package is setup as a logger and configured to log messages at a -``DEBUG`` or higher level. When you visit http://localhost:6543 your -console will now show:: +In our configuration file ``development.ini``, our ``tutorial`` Python package +is set up as a logger and configured to log messages at a ``DEBUG`` or higher +level. When you visit http://localhost:6543, your console will now show: + +.. code-block:: text - 2013-08-09 10:42:42,968 DEBUG [tutorial.views][MainThread] In home view + 2013-08-09 10:42:42,968 DEBUG [tutorial.views][MainThread] In home view Also, if you have configured your Pyramid application to use the ``pyramid_debugtoolbar``, logging statements appear in one of its menus. -- cgit v1.2.3 From 3b064fbbd2b9d8c348337f0742899c948862abf6 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 12:33:44 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup sessions.rst --- docs/quick_tutorial/sessions.rst | 70 +++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 33 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/sessions.rst b/docs/quick_tutorial/sessions.rst index 06176f2b6..df4887a4b 100644 --- a/docs/quick_tutorial/sessions.rst +++ b/docs/quick_tutorial/sessions.rst @@ -6,25 +6,28 @@ Store and retrieve non-permanent data in Pyramid sessions. + Background ========== -When people use your web application, they frequently perform a task -that requires semi-permanent data to be saved. For example, a shopping -cart. This is called a :term:`session`. +When people use your web application, they frequently perform a task that +requires semi-permanent data to be saved. For example, a shopping cart. This is +called a :term:`session`. Pyramid has basic built-in support for sessions. Third party packages such as -``pyramid_redis_sessions`` provide richer session support. Or you can create -your own custom sessioning engine. Let's take a look at the -:doc:`built-in sessioning support <../narr/sessions>`. +`pyramid_redis_sessions +`_ provide richer +session support. Or you can create your own custom sessioning engine. Let's +take a look at the :doc:`built-in sessioning support <../narr/sessions>`. + Objectives ========== -- Make a session factory using a built-in, simple Pyramid sessioning - system +- Make a session factory using a built-in, simple Pyramid sessioning system. + +- Change our code to use a session. -- Change our code to use a session Steps ===== @@ -36,14 +39,13 @@ Steps $ cd ..; cp -r view_classes sessions; cd sessions $ $VENV/bin/pip install -e . -#. Our ``sessions/tutorial/__init__.py`` needs a choice of session - factory to get registered with the :term:`configurator`: +#. Our ``sessions/tutorial/__init__.py`` needs a choice of session factory to + get registered with the :term:`configurator`: .. literalinclude:: sessions/tutorial/__init__.py :linenos: -#. Our views in ``sessions/tutorial/views.py`` can now use - ``request.session``: +#. Our views in ``sessions/tutorial/views.py`` can now use ``request.session``: .. literalinclude:: sessions/tutorial/views.py :linenos: @@ -58,7 +60,9 @@ Steps .. code-block:: bash - $ $VENV/bin/nosetests tutorial + $ $VENV/bin/py.test tutorial/tests.py -q + .... + 4 passed in 0.42 seconds #. Run your Pyramid application with: @@ -66,33 +70,33 @@ Steps $ $VENV/bin/pserve development.ini --reload -#. Open http://localhost:6543/ and http://localhost:6543/howdy - in your browser. As you reload and switch between those URLs, note - that the counter increases and is *not* specific to the URL. +#. Open http://localhost:6543/ and http://localhost:6543/howdy in your browser. + As you reload and switch between those URLs, note that the counter increases + and is *not* specific to the URL. + +#. Restart the application and revisit the page. Note that counter still + increases from where it left off. -#. Restart the application and revisit the page. Note that counter - still increases from where it left off. Analysis ======== -Pyramid's :term:`request` object now has a ``session`` attribute -that we can use in our view code. It acts like a dictionary. +Pyramid's :term:`request` object now has a ``session`` attribute that we can +use in our view code. It acts like a dictionary. -Since all the views are using the same counter, we made the counter a -Python property at the view class level. With this, each reload will -increase the counter displayed in our template. +Since all the views are using the same counter, we made the counter a Python +property at the view class level. With this, each reload will increase the +counter displayed in our template. -In web development, "flash messages" are notes for the user that need -to appear on a screen after a future web request. For example, -when you add an item using a form ``POST``, the site usually issues a -second HTTP Redirect web request to view the new item. You might want a -message to appear after that second web request saying "Your item was -added." You can't just return it in the web response for the POST, -as it will be tossed out during the second web request. +In web development, "flash messages" are notes for the user that need to appear +on a screen after a future web request. For example, when you add an item using +a form ``POST``, the site usually issues a second HTTP Redirect web request to +view the new item. You might want a message to appear after that second web +request saying "Your item was added." You can't just return it in the web +response for the POST, as it will be tossed out during the second web request. -Flash messages are a technique where messages can be stored between -requests, using sessions, then removed when they finally get displayed. +Flash messages are a technique where messages can be stored between requests, +using sessions, then removed when they finally get displayed. .. seealso:: :ref:`sessions_chapter`, -- cgit v1.2.3 From 59c8fc7919730c3f3100ad84250a788e2d0a3bb0 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 12:55:28 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup forms.rst --- docs/quick_tutorial/forms.rst | 127 ++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 61 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/forms.rst b/docs/quick_tutorial/forms.rst index 023e7127f..6b29833bd 100644 --- a/docs/quick_tutorial/forms.rst +++ b/docs/quick_tutorial/forms.rst @@ -6,30 +6,30 @@ Schema-driven, autogenerated forms with validation. + Background ========== -Modern web applications deal extensively with forms. Developers, -though, have a wide range of philosophies about how frameworks should -help them with their forms. As such, Pyramid doesn't directly bundle -one particular form library. Instead there are a variety of form -libraries that are easy to use in Pyramid. +Modern web applications deal extensively with forms. Developers, though, have a +wide range of philosophies about how frameworks should help them with their +forms. As such, Pyramid doesn't directly bundle one particular form library. +Instead there are a variety of form libraries that are easy to use in Pyramid. -:ref:`Deform ` -is one such library. In this step, we introduce Deform for our -forms and validation. This also gives us :ref:`Colander ` +:ref:`Deform ` is one such library. In this step, we introduce +Deform for our forms. This also gives us :ref:`Colander ` for schemas and validation. -Deform is getting a facelift, with styling from Twitter Bootstrap and -advanced widgets from popular JavaScript projects. The work began in -``deform_bootstrap`` and is being merged into an update to Deform. +Deform uses styling from Twitter Bootstrap and advanced widgets from popular +JavaScript projects. + Objectives ========== -- Make a schema using Colander, the companion to Deform +- Make a schema using Colander, the companion to Deform. + +- Create a form with Deform and change our views to handle validation. -- Create a form with Deform and change our views to handle validation Steps ===== @@ -40,8 +40,8 @@ Steps $ cd ..; cp -r view_classes forms; cd forms -#. Let's edit ``forms/setup.py`` to declare a dependency on Deform - (which then pulls in Colander as a dependency: +#. Let's edit ``forms/setup.py`` to declare a dependency on Deform (which then + pulls in Colander as a dependency: .. literalinclude:: forms/setup.py :linenos: @@ -52,21 +52,19 @@ Steps $ $VENV/bin/pip install -e . -#. Register a static view in ``forms/tutorial/__init__.py`` for - Deform's CSS/JS etc. as well as our demo wikipage scenario's - views: +#. Register a static view in ``forms/tutorial/__init__.py`` for Deform's CSS, + JavaScript, etc., as well as our demo wiki page's views: .. literalinclude:: forms/tutorial/__init__.py :linenos: -#. Implement the new views, as well as the form schemas and some - dummy data, in ``forms/tutorial/views.py``: +#. Implement the new views, as well as the form schemas and some dummy data, in + ``forms/tutorial/views.py``: .. literalinclude:: forms/tutorial/views.py :linenos: -#. A template for the top of the "wiki" in - ``forms/tutorial/wiki_view.pt``: +#. A template for the top of the "wiki" in ``forms/tutorial/wiki_view.pt``: .. literalinclude:: forms/tutorial/wiki_view.pt :language: html @@ -79,13 +77,21 @@ Steps :language: html :linenos: -#. Finally, a template at ``forms/tutorial/wikipage_view.pt`` - for viewing a wiki page: +#. Finally, a template at ``forms/tutorial/wikipage_view.pt`` for viewing a + wiki page: .. literalinclude:: forms/tutorial/wikipage_view.pt :language: html :linenos: +#. Run the tests: + + .. code-block:: bash + + $ $VENV/bin/py.test tutorial/tests.py -q + .. + 2 passed in 0.45 seconds + #. Run your Pyramid application with: .. code-block:: bash @@ -98,51 +104,50 @@ Steps Analysis ======== -This step helps illustrate the utility of asset specifications for -static assets. We have an outside package called Deform with static -assets which need to be published. We don't have to know where on disk -it is located. We point at the package, then the path inside the package. - -We just need to include a call to ``add_static_view`` to make that -directory available at a URL. For Pyramid-specific packages, -Pyramid provides a facility (``config.include()``) which even makes -that unnecessary for consumers of a package. (Deform is not specific to -Pyramid.) - -Our forms have rich widgets which need the static CSS and JS just -mentioned. Deform has a :term:`resource registry` which allows widgets -to specify which JS and CSS are needed. Our ``wikipage_addedit.pt`` -template shows how we iterated over that data to generate markup that -includes the needed resources. - -Our add and edit views use a pattern called *self-posting forms*. -Meaning, the same URL is used to ``GET`` the form as is used to -``POST`` the form. The route, the view, and the template are the same -whether you are walking up to it the first time or you clicked a button. - -Inside the view we do ``if 'submit' in self.request.params:`` to see if -this form was a ``POST`` where the user clicked on a particular button +This step helps illustrate the utility of asset specifications for static +assets. We have an outside package called Deform with static assets which need +to be published. We don't have to know where on disk it is located. We point at +the package, then the path inside the package. + +We just need to include a call to ``add_static_view`` to make that directory +available at a URL. For Pyramid-specific packages, Pyramid provides a facility +(``config.include()``) which even makes that unnecessary for consumers of a +package. (Deform is not specific to Pyramid.) + +Our forms have rich widgets which need the static CSS and JavaScript just +mentioned. Deform has a :term:`resource registry` which allows widgets to +specify which JavaScript and CSS are needed. Our ``wikipage_addedit.pt`` +template shows how we iterated over that data to generate markup that includes +the needed resources. + +Our add and edit views use a pattern called *self-posting forms*. Meaning, the +same URL is used to ``GET`` the form as is used to ``POST`` the form. The +route, the view, and the template are the same URL whether you are walking up +to it for the first time or you clicked a button. + +Inside the view we do ``if 'submit' in self.request.params:`` to see if this +form was a ``POST`` where the user clicked on a particular button ````. The form controller then follows a typical pattern: -- If you are doing a GET, skip over and just return the form +- If you are doing a ``GET``, skip over and just return the form. + +- If you are doing a ``POST``, validate the form contents. -- If you are doing a POST, validate the form contents +- If the form is invalid, bail out by re-rendering the form with the supplied + ``POST`` data. -- If the form is invalid, bail out by re-rendering the form with the - supplied ``POST`` data +- If the validation succeeded, perform some action and issue a redirect via + ``HTTPFound``. -- If the validation succeeded, perform some action and issue a - redirect via ``HTTPFound``. +We are, in essence, writing our own form controller. Other Pyramid-based +systems, including ``pyramid_deform``, provide a form-centric view class which +automates much of this branching and routing. -We are, in essence, writing our own form controller. Other -Pyramid-based systems, including ``pyramid_deform``, provide a -form-centric view class which automates much of this branching and -routing. -Extra Credit +Extra credit ============ -#. Give a try at a button that goes to a delete view for a - particular wiki page. +#. Give a try at a button that goes to a delete view for a particular wiki + page. -- cgit v1.2.3 From 8bca48a37f5a0f79976d975aa3afd5760688a89c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 13:22:31 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup databases.rst --- docs/quick_tutorial/databases.rst | 186 +++++++++++------------ docs/quick_tutorial/databases/sqltutorial.sqlite | Bin 12288 -> 0 bytes 2 files changed, 92 insertions(+), 94 deletions(-) delete mode 100644 docs/quick_tutorial/databases/sqltutorial.sqlite (limited to 'docs') diff --git a/docs/quick_tutorial/databases.rst b/docs/quick_tutorial/databases.rst index f9f548585..c8d87c180 100644 --- a/docs/quick_tutorial/databases.rst +++ b/docs/quick_tutorial/databases.rst @@ -4,37 +4,39 @@ 19: Databases Using SQLAlchemy ============================== -Store/retrieve data using the SQLAlchemy ORM atop the SQLite database. +Store and retrieve data using the SQLAlchemy ORM atop the SQLite database. + Background ========== -Our Pyramid-based wiki application now needs database-backed storage of -pages. This frequently means a SQL database. The Pyramid community -strongly supports the -:ref:`SQLAlchemy ` project and its -:ref:`object-relational mapper (ORM) ` -as a convenient, Pythonic way to interface to databases. +Our Pyramid-based wiki application now needs database-backed storage of pages. +This frequently means an SQL database. The Pyramid community strongly supports +the :ref:`SQLAlchemy ` project and its +:ref:`object-relational mapper (ORM) ` as a +convenient, Pythonic way to interface to databases. -In this step we hook up SQLAlchemy to a SQLite database table, -providing storage and retrieval for the wikipages in the previous step. +In this step we hook up SQLAlchemy to a SQLite database table, providing +storage and retrieval for the wiki pages in the previous step. .. note:: - The ``alchemy`` scaffold is really helpful for getting a - SQLAlchemy project going, including generation of the console - script. Since we want to see all the decisions, we will forgo - convenience in this tutorial and wire it up ourselves. + The ``alchemy`` scaffold is really helpful for getting an SQLAlchemy + project going, including generation of the console script. Since we want to + see all the decisions, we will forgo convenience in this tutorial, and wire + it up ourselves. + Objectives ========== -- Store pages in SQLite by using SQLAlchemy models +- Store pages in SQLite by using SQLAlchemy models. -- Use SQLAlchemy queries to list/add/view/edit pages +- Use SQLAlchemy queries to list/add/view/edit pages. + +- Provide a database-initialize command by writing a Pyramid *console script* + which can be run from the command line. -- Provide a database-initialize command by writing a Pyramid *console - script* which can be run from the command line Steps ===== @@ -45,31 +47,31 @@ Steps $ cd ..; cp -r forms databases; cd databases -#. We need to add some dependencies in ``databases/setup.py`` as well - as an "entry point" for the command-line script: +#. We need to add some dependencies in ``databases/setup.py`` as well as an + "entry point" for the command-line script: .. literalinclude:: databases/setup.py :linenos: .. note:: - We aren't yet doing ``$VENV/bin/pip install -e .`` as we - will change it later. + We aren't yet doing ``$VENV/bin/pip install -e .`` as we will change it + later. -#. Our configuration file at ``databases/development.ini`` wires - together some new pieces: +#. Our configuration file at ``databases/development.ini`` wires together some + new pieces: .. literalinclude:: databases/development.ini :language: ini -#. This engine configuration now needs to be read into the application - through changes in ``databases/tutorial/__init__.py``: +#. This engine configuration now needs to be read into the application through + changes in ``databases/tutorial/__init__.py``: .. literalinclude:: databases/tutorial/__init__.py :linenos: -#. Make a command-line script at ``databases/tutorial/initialize_db.py`` - to initialize the database: +#. Make a command-line script at ``databases/tutorial/initialize_db.py`` to + initialize the database: .. literalinclude:: databases/tutorial/initialize_db.py :linenos: @@ -90,51 +92,49 @@ Steps .. code-block:: bash $ $VENV/bin/initialize_tutorial_db development.ini - 2015-06-01 11:22:52,650 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 - 2015-06-01 11:22:52,650 INFO [sqlalchemy.engine.base.Engine][MainThread] () - 2015-06-01 11:22:52,651 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 - 2015-06-01 11:22:52,651 INFO [sqlalchemy.engine.base.Engine][MainThread] () - 2015-06-01 11:22:52,652 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("wikipages") - 2015-06-01 11:22:52,652 INFO [sqlalchemy.engine.base.Engine][MainThread] () - 2015-06-01 11:22:52,653 INFO [sqlalchemy.engine.base.Engine][MainThread] + + 2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 + 2016-04-16 13:01:33,055 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.base.Engine][MainThread] SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 + 2016-04-16 13:01:33,056 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("wikipages") + 2016-04-16 13:01:33,057 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.base.Engine][MainThread] CREATE TABLE wikipages ( - uid INTEGER NOT NULL, - title TEXT, - body TEXT, - PRIMARY KEY (uid), - UNIQUE (title) + uid INTEGER NOT NULL, + title TEXT, + body TEXT, + PRIMARY KEY (uid), + UNIQUE (title) ) - 2015-06-01 11:22:52,653 INFO [sqlalchemy.engine.base.Engine][MainThread] () - 2015-06-01 11:22:52,655 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT - 2015-06-01 11:22:52,658 INFO [sqlalchemy.engine.base.Engine][MainThread] BEGIN (implicit) - 2015-06-01 11:22:52,659 INFO [sqlalchemy.engine.base.Engine][MainThread] INSERT INTO wikipages (title, body) VALUES (?, ?) - 2015-06-01 11:22:52,659 INFO [sqlalchemy.engine.base.Engine][MainThread] ('Root', '

Root

') - 2015-06-01 11:22:52,659 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT + 2016-04-16 13:01:33,058 INFO [sqlalchemy.engine.base.Engine][MainThread] () + 2016-04-16 13:01:33,059 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT + 2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.base.Engine][MainThread] BEGIN (implicit) + 2016-04-16 13:01:33,062 INFO [sqlalchemy.engine.base.Engine][MainThread] INSERT INTO wikipages (title, body) VALUES (?, ?) + 2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.base.Engine][MainThread] ('Root', '

Root

') + 2016-04-16 13:01:33,063 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT -#. With our data now driven by SQLAlchemy queries, we need to update - our ``databases/tutorial/views.py``: +#. With our data now driven by SQLAlchemy queries, we need to update our + ``databases/tutorial/views.py``: .. literalinclude:: databases/tutorial/views.py :linenos: -#. Our tests in ``databases/tutorial/tests.py`` changed to include - SQLAlchemy bootstrapping: +#. Our tests in ``databases/tutorial/tests.py`` changed to include SQLAlchemy + bootstrapping: .. literalinclude:: databases/tutorial/tests.py :linenos: -#. Run the tests in your package using ``nose``: +#. Run the tests in your package using ``py.test``: - .. code-block:: bash - - $ $VENV/bin/nosetests tutorial - .. - ----------------------------------------------------------------- - Ran 2 tests in 1.141s + .. code-block:: bash - OK + $ $VENV/bin/py.test tutorial/tests.py -q + .. + 2 passed in 1.41 seconds #. Run your Pyramid application with: @@ -144,57 +144,55 @@ Steps #. Open http://localhost:6543/ in a browser. + Analysis ======== -Let's start with the dependencies. We made the decision to use -``SQLAlchemy`` to talk to our database. We also, though, installed -``pyramid_tm`` and ``zope.sqlalchemy``. Why? +Let's start with the dependencies. We made the decision to use ``SQLAlchemy`` +to talk to our database. We also, though, installed ``pyramid_tm`` and +``zope.sqlalchemy``. Why? Pyramid has a strong orientation towards support for ``transactions``. -Specifically, you can install a transaction manager into your -application either as middleware or a Pyramid "tween". Then, -just before you return the response, all transaction-aware parts of -your application are executed. +Specifically, you can install a transaction manager into your application +either as middleware or a Pyramid "tween". Then, just before you return the +response, all transaction-aware parts of your application are executed. -This means Pyramid view code usually doesn't manage transactions. If -your view code or a template generates an error, the transaction manager -aborts the transaction. This is a very liberating way to write code. +This means Pyramid view code usually doesn't manage transactions. If your view +code or a template generates an error, the transaction manager aborts the +transaction. This is a very liberating way to write code. The ``pyramid_tm`` package provides a "tween" that is configured in the -``development.ini`` configuration file. That installs it. We then need -a package that makes SQLAlchemy, and thus the RDBMS transaction manager, -integrate with the Pyramid transaction manager. That's what -``zope.sqlalchemy`` does. +``development.ini`` configuration file. That installs it. We then need a +package that makes SQLAlchemy, and thus the RDBMS transaction manager, +integrate with the Pyramid transaction manager. That's what ``zope.sqlalchemy`` +does. Where do we point at the location on disk for the SQLite file? In the -configuration file. This lets consumers of our package change the -location in a safe (non-code) way. That is, in configuration. This -configuration-oriented approach isn't required in Pyramid; you can -still make such statements in your ``__init__.py`` or some companion -module. - -The ``initialize_tutorial_db`` is a nice example of framework support. -You point your setup at the location of some ``[console_scripts]`` and -these get generated into your virtual environment's ``bin`` directory. Our -console script follows the pattern of being fed a configuration file -with all the bootstrapping. It then opens SQLAlchemy and creates the -root of the wiki, which also makes the SQLite file. Note the -``with transaction.manager`` part that puts the work in the scope of a -transaction, as we aren't inside a web request where this is done -automatically. - -The ``models.py`` does a little bit extra work to hook up SQLAlchemy -into the Pyramid transaction manager. It then declares the model for a -``Page``. +configuration file. This lets consumers of our package change the location in a +safe (non-code) way. That is, in configuration. This configuration-oriented +approach isn't required in Pyramid; you can still make such statements in your +``__init__.py`` or some companion module. + +The ``initialize_tutorial_db`` is a nice example of framework support. You +point your setup at the location of some ``[console_scripts]``, and these get +generated into your virtual environment's ``bin`` directory. Our console script +follows the pattern of being fed a configuration file with all the +bootstrapping. It then opens SQLAlchemy and creates the root of the wiki, which +also makes the SQLite file. Note the ``with transaction.manager`` part that +puts the work in the scope of a transaction, as we aren't inside a web request +where this is done automatically. + +The ``models.py`` does a little bit of extra work to hook up SQLAlchemy into +the Pyramid transaction manager. It then declares the model for a ``Page``. Our views have changes primarily around replacing our dummy -dictionary-of-dictionaries data with proper database support: list the -rows, add a row, edit a row, and delete a row. +dictionary-of-dictionaries data with proper database support: list the rows, +add a row, edit a row, and delete a row. + -Extra Credit +Extra credit ============ -#. Why all this code? Why can't I just type 2 lines and have magic ensue? +#. Why all this code? Why can't I just type two lines and have magic ensue? #. Give a try at a button that deletes a wiki page. diff --git a/docs/quick_tutorial/databases/sqltutorial.sqlite b/docs/quick_tutorial/databases/sqltutorial.sqlite deleted file mode 100644 index b8bd856fd..000000000 Binary files a/docs/quick_tutorial/databases/sqltutorial.sqlite and /dev/null differ -- cgit v1.2.3 From b92a5f6f44df3490c61ab9436e51c043299e9097 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 13:50:02 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup authentication.rst --- docs/quick_tutorial/authentication.rst | 89 ++++++++++++++++------------------ 1 file changed, 42 insertions(+), 47 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/authentication.rst b/docs/quick_tutorial/authentication.rst index cb3839b08..acff97f3b 100644 --- a/docs/quick_tutorial/authentication.rst +++ b/docs/quick_tutorial/authentication.rst @@ -4,28 +4,27 @@ 20: Logins With Authentication ============================== -Login views that authenticate a username/password against a list of -users. +Login views that authenticate a username and password against a list of users. + Background ========== -Most web applications have URLs that allow people to add/edit/delete -content via a web browser. Time to add -:ref:`security ` -to the application. In this first step we introduce authentication. -That is, logging in and logging out using Pyramid's rich facilities for -pluggable user storages. +Most web applications have URLs that allow people to add/edit/delete content +via a web browser. Time to add :ref:`security ` to the +application. In this first step we introduce authentication. That is, logging +in and logging out, using Pyramid's rich facilities for pluggable user storage. + +In the next step we will introduce protection of resources with authorization +security statements. -In the next step we will introduce protection resources with -authorization security statements. Objectives ========== -- Introduce the Pyramid concepts of authentication +- Introduce the Pyramid concepts of authentication. -- Create login/logout views +- Create login and logout views. Steps ===== @@ -38,22 +37,20 @@ Steps $ $VENV/bin/pip install -e . #. Put the security hash in the ``authentication/development.ini`` - configuration file as ``tutorial.secret`` instead of putting it in - the code: + configuration file as ``tutorial.secret`` instead of putting it in the code: .. literalinclude:: authentication/development.ini :language: ini :linenos: -#. Get authentication (and for now, authorization policies) and login - route into the :term:`configurator` in - ``authentication/tutorial/__init__.py``: +#. Get authentication (and for now, authorization policies) and login route + into the :term:`configurator` in ``authentication/tutorial/__init__.py``: .. literalinclude:: authentication/tutorial/__init__.py :linenos: -#. Create a ``authentication/tutorial/security.py`` module that can find - our user information by providing an *authentication policy callback*: +#. Create an ``authentication/tutorial/security.py`` module that can find our + user information by providing an *authentication policy callback*: .. literalinclude:: authentication/tutorial/security.py :linenos: @@ -69,7 +66,7 @@ Steps :language: html :linenos: -#. Provide a login/logout box in ``authentication/tutorial/home.pt`` +#. Provide a login/logout box in ``authentication/tutorial/home.pt``: .. literalinclude:: authentication/tutorial/home.pt :language: html @@ -95,39 +92,37 @@ Steps Analysis ======== -Unlike many web frameworks, Pyramid includes a built-in but optional -security model for authentication and authorization. This security -system is intended to be flexible and support many needs. In this -security model, authentication (who are you) and authorization (what -are you allowed to do) are not just pluggable, but de-coupled. To learn -one step at a time, we provide a system that identifies users and lets -them log out. - -In this example we chose to use the bundled -:ref:`AuthTktAuthenticationPolicy ` -policy. We enabled it in our configuration and provided a -ticket-signing secret in our INI file. - -Our view class grew a login view. When you reached it via a GET, -it returned a login form. When reached via POST, it processed the -username and password against the "groupfinder" callable that we -registered in the configuration. - -In our template, we fetched the ``logged_in`` value from the view -class. We use this to calculate the logged-in user, -if any. In the template we can then choose to show a login link to -anonymous visitors or a logout link to logged-in users. - -Extra Credit +Unlike many web frameworks, Pyramid includes a built-in but optional security +model for authentication and authorization. This security system is intended to +be flexible and support many needs. In this security model, authentication (who +are you) and authorization (what are you allowed to do) are not just pluggable, +but de-coupled. To learn one step at a time, we provide a system that +identifies users and lets them log out. + +In this example we chose to use the bundled :ref:`AuthTktAuthenticationPolicy +` policy. We enabled it in our configuration and +provided a ticket-signing secret in our INI file. + +Our view class grew a login view. When you reached it via a ``GET`` request, it +returned a login form. When reached via ``POST``, it processed the submitted +username and password against the "groupfinder" callable that we registered in +the configuration. + +In our template, we fetched the ``logged_in`` value from the view class. We use +this to calculate the logged-in user, if any. In the template we can then +choose to show a login link to anonymous visitors or a logout link to logged-in +users. + + +Extra credit ============ #. What is the difference between a user and a principal? #. Can I use a database behind my ``groupfinder`` to look up principals? -#. Once I am logged in, does any user-centric information get jammed - onto each request? Use ``import pdb; pdb.set_trace()`` to answer - this. +#. Once I am logged in, does any user-centric information get jammed onto each + request? Use ``import pdb; pdb.set_trace()`` to answer this. .. seealso:: See also :ref:`security_chapter`, :ref:`AuthTktAuthenticationPolicy `. -- cgit v1.2.3 From a5e89f07e4c97849f0a36069d4272c6e2efe8539 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 16 Apr 2016 13:57:14 -0700 Subject: quick_tutorial cleanup - replace nose with pytest - cleanup authorization.rst --- docs/quick_tutorial/authorization.rst | 86 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'docs') diff --git a/docs/quick_tutorial/authorization.rst b/docs/quick_tutorial/authorization.rst index a4a12774b..58c1d2582 100644 --- a/docs/quick_tutorial/authorization.rst +++ b/docs/quick_tutorial/authorization.rst @@ -4,33 +4,35 @@ 21: Protecting Resources With Authorization =========================================== -Assign security statements to resources describing the permissions -required to perform an operation. +Assign security statements to resources describing the permissions required to +perform an operation. + Background ========== -Our application has URLs that allow people to add/edit/delete content -via a web browser. Time to add security to the application. Let's -protect our add/edit views to require a login (username of -``editor`` and password of ``editor``). We will allow the other views -to continue working without a password. +Our application has URLs that allow people to add/edit/delete content via a web +browser. Time to add security to the application. Let's protect our add/edit +views to require a login (username of ``editor`` and password of ``editor``). +We will allow the other views to continue working without a password. + Objectives ========== -- Introduce the Pyramid concepts of authentication, authorization, - permissions, and access control lists (ACLs) +- Introduce the Pyramid concepts of authentication, authorization, permissions, + and access control lists (ACLs). + +- Make a :term:`root factory` that returns an instance of our class for the top + of the application. -- Make a :term:`root factory` that returns an instance of our - class for the top of the application +- Assign security statements to our root resource. -- Assign security statements to our root resource +- Add a permissions predicate on a view. -- Add a permissions predicate on a view +- Provide a :term:`Forbidden view` to handle visiting a URL without adequate + permissions. -- Provide a :term:`Forbidden view` to handle visiting a URL without - adequate permissions Steps ===== @@ -42,14 +44,13 @@ Steps $ cd ..; cp -r authentication authorization; cd authorization $ $VENV/bin/pip install -e . -#. Start by changing ``authorization/tutorial/__init__.py`` to - specify a root factory to the :term:`configurator`: +#. Start by changing ``authorization/tutorial/__init__.py`` to specify a root + factory to the :term:`configurator`: .. literalinclude:: authorization/tutorial/__init__.py :linenos: -#. That means we need to implement - ``authorization/tutorial/resources.py`` +#. That means we need to implement ``authorization/tutorial/resources.py``: .. literalinclude:: authorization/tutorial/resources.py :linenos: @@ -70,48 +71,47 @@ Steps #. If you are still logged in, click the "Log Out" link. -#. Visit http://localhost:6543/howdy in a browser. You should be - asked to login. +#. Visit http://localhost:6543/howdy in a browser. You should be asked to + login. + Analysis ======== This simple tutorial step can be boiled down to the following: -- A view can require a *permission* (``edit``) +- A view can require a *permission* (``edit``). -- The context for our view (the ``Root``) has an access control list - (ACL) +- The context for our view (the ``Root``) has an access control list (ACL). -- This ACL says that the ``edit`` permission is available on ``Root`` - to the ``group:editors`` *principal* +- This ACL says that the ``edit`` permission is available on ``Root`` to the + ``group:editors`` *principal*. -- The registered ``groupfinder`` answers whether a particular user - (``editor``) has a particular group (``group:editors``) +- The registered ``groupfinder`` answers whether a particular user (``editor``) + has a particular group (``group:editors``). -In summary: ``hello`` wants ``edit`` permission, ``Root`` says +In summary, ``hello`` wants ``edit`` permission, ``Root`` says ``group:editors`` has ``edit`` permission. -Of course, this only applies on ``Root``. Some other part of the site -(a.k.a. *context*) might have a different ACL. +Of course, this only applies on ``Root``. Some other part of the site (a.k.a. +*context*) might have a different ACL. + +If you are not logged in and visit ``/howdy``, you need to get shown the login +screen. How does Pyramid know what is the login page to use? We explicitly told +Pyramid that the ``login`` view should be used by decorating the view with +``@forbidden_view_config``. -If you are not logged in and visit ``/howdy``, you need to get -shown the login screen. How does Pyramid know what is the login page to -use? We explicitly told Pyramid that the ``login`` view should be used -by decorating the view with ``@forbidden_view_config``. -Extra Credit +Extra credit ============ -#. Do I have to put a ``renderer`` in my ``@forbidden_view_config`` - decorator? +#. Do I have to put a ``renderer`` in my ``@forbidden_view_config`` decorator? #. Perhaps you would like the experience of not having enough permissions (forbidden) to be richer. How could you change this? -#. Perhaps we want to store security statements in a database and - allow editing via a browser. How might this be done? +#. Perhaps we want to store security statements in a database and allow editing + via a browser. How might this be done? -#. What if we want different security statements on different kinds of - objects? Or on the same kinds of objects, but in different parts of a - URL hierarchy? +#. What if we want different security statements on different kinds of objects? + Or on the same kinds of objects, but in different parts of a URL hierarchy? -- cgit v1.2.3