From a155b4be97de8955ba753220984287e82853e35f Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 27 Aug 2018 14:38:02 -0700 Subject: Improve instructions of how to run p-scripts - add link in each script usage to the instructions --- docs/narr/commandline.rst | 165 ++++++++++++++++++++++++++++++---------------- 1 file changed, 110 insertions(+), 55 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index 9e0310c29..107f35914 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -6,6 +6,63 @@ Command-Line Pyramid Your :app:`Pyramid` application can be controlled and inspected using a variety of command-line utilities. These utilities are documented in this chapter. +We commonly refer to this collection of utilities as "p-scripts", which is short for "Pyramid console scripts". + +Each p-script's command line usage details is available in the :ref:`pscripts_documentation`. + + +.. index:: + single: running p-scripts + pair: running; p-scripts + +.. _running-pscripts: + +Running p-scripts +----------------- + +All of the Pyramid console scripts may be run either: + +* by its name +* through a Python interpreter + + +.. index:: + single: running p-script by name + triple: p-script; running; name + +.. _running-pscripts-by-name: + +Running by ``p*`` script name +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each of Pyramid's console scripts may be run by its name. For example: + +.. code-block:: bash + + $VENV/bin/pserve development.ini --reload + +.. note:: ``$VENV/bin/`` represents the ``bin`` directory in a virtual environment, where ``$VENV`` is an environment variable representing its path. + + +.. index:: + single: running p-scripts via Python + triple: p-script; running; Python + +.. _custom-arguments-to-python: + +Using Custom Arguments to Python when Running ``p*`` Scripts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.5 + +Each of Pyramid's console scripts (``pserve``, ``pviews``, etc.) can be run +using ``python3 -m``, allowing custom arguments to be sent to the +Python interpreter at runtime. For example: + +.. code-block:: bash + + python3 -m pyramid.scripts.pserve development.ini --reload + .. index:: pair: matching views; printing @@ -13,8 +70,8 @@ of command-line utilities. These utilities are documented in this chapter. .. _displaying_matching_views: -Displaying Matching Views for a Given URL ------------------------------------------ +``pviews``: Displaying Matching Views for a Given URL +----------------------------------------------------- .. seealso:: See also the output of :ref:`pviews --help `. @@ -31,7 +88,7 @@ to be ``main``. Here is an example for a simple view configuration using :term:`traversal`: -.. code-block:: text +.. code-block:: bash :linenos: $VENV/bin/pviews development.ini#tutorial /FrontPage @@ -54,7 +111,7 @@ permissions and predicates that are part of that view configuration. A more complex configuration might generate something like this: -.. code-block:: text +.. code-block:: bash :linenos: $VENV/bin/pviews development.ini#shootout /about @@ -114,8 +171,8 @@ found* message. .. _interactive_shell: -The Interactive Shell ---------------------- +``pshell``: The Interactive Shell +--------------------------------- .. seealso:: See also the output of :ref:`pshell --help `. @@ -144,7 +201,7 @@ have an ``[app:main]`` section that looks like so: If so, you can use the following command to invoke a debug shell using the name ``main`` as a section name: -.. code-block:: text +.. code-block:: bash $VENV/bin/pshell starter/development.ini#main Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32) @@ -178,7 +235,7 @@ default :term:`root factory`, ``registry``, and ``request`` will be available. You can also simply rely on the ``main`` default section name by omitting any hash after the filename: -.. code-block:: text +.. code-block:: bash $VENV/bin/pshell starter/development.ini @@ -252,7 +309,7 @@ By defining the ``setup`` callable, we will create the module ``myapp.lib.pshell When this ``.ini`` file is loaded, the extra variable ``models`` will be available for use immediately. Since a ``setup`` callable was also specified, it is executed and new variables ``testapp``, ``tm``, and ``dbsession`` are exposed, and the request is configured to generate URLs from the host ``http://www.example.com``. For example: -.. code-block:: text +.. code-block:: bash $VENV/bin/pshell starter/development.ini Python 2.6.5 (r265:79063, Apr 29 2010, 00:31:32) @@ -296,13 +353,13 @@ installed such as ``pyramid_ipython`` it will normally be auto-selected and used. You may also specifically invoke your choice with the ``-p choice`` or ``--python-shell choice`` option. -.. code-block:: text +.. code-block:: bash $VENV/bin/pshell -p ipython development.ini#MyProject You may use the ``--list-shells`` option to see the available shells. -.. code-block:: text +.. code-block:: bash $VENV/bin/pshell --list-shells Available shells: @@ -363,8 +420,8 @@ specify a list of preferred shells. .. _displaying_application_routes: -Displaying All Application Routes ---------------------------------- +``proutes``: Displaying All Application Routes +---------------------------------------------- .. seealso:: See also the output of :ref:`proutes --help `. @@ -378,7 +435,7 @@ the ``section_name`` is ``main`` and can be omitted. For example: -.. code-block:: text +.. code-block:: bash :linenos: $VENV/bin/proutes development.ini @@ -415,7 +472,7 @@ and use those as defaults. For example you may remove the request method and place the view first: -.. code-block:: text +.. code-block:: ini :linenos: [proutes] @@ -425,7 +482,7 @@ For example you may remove the request method and place the view first: You can also separate the formats with commas or spaces: -.. code-block:: text +.. code-block:: ini :linenos: [proutes] @@ -446,8 +503,8 @@ include. The current available formats are ``name``, ``pattern``, ``view``, and .. _displaying_tweens: -Displaying "Tweens" -------------------- +``ptweens``: Displaying "Tweens" +-------------------------------- .. seealso:: See also the output of :ref:`ptweens --help `. @@ -462,7 +519,7 @@ standard Python dotted name in the ``ptweens`` output. For example, here's the ``ptweens`` command run against a system configured without any explicit tweens: -.. code-block:: text +.. code-block:: bash :linenos: $VENV/bin/ptweens development.ini @@ -480,10 +537,10 @@ without any explicit tweens: Here's the ``ptweens`` command run against a system configured *with* explicit tweens defined in its ``development.ini`` file: -.. code-block:: text +.. code-block:: bash :linenos: - ptweens development.ini + $VENV/bin/ptweens development.ini "pyramid.tweens" config value set (explicitly ordered tweens used) Explicit Tween Chain (used) @@ -534,8 +591,8 @@ See :ref:`registering_tweens` for more information about tweens. .. _invoking_a_request: -Invoking a Request ------------------- +``prequest``: Invoking a Request +-------------------------------- .. seealso:: See also the output of :ref:`prequest --help `. @@ -553,9 +610,11 @@ There are two required arguments to ``prequest``: - The path: this should be the non-URL-quoted path element of the URL to the resource you'd like to be rendered on the server. For example, ``/``. -For example:: +For example: + +.. code-block:: bash - $ $VENV/bin/prequest development.ini / + $VENV/bin/prequest development.ini / This will print the body of the response to the console on which it was invoked. @@ -564,16 +623,20 @@ Several options are supported by ``prequest``. These should precede any config file name or URL. ``prequest`` has a ``-d`` (i.e., ``--display-headers``) option which prints the -status and headers returned by the server before the output:: +status and headers returned by the server before the output: + +.. code-block:: bash - $ $VENV/bin/prequest -d development.ini / + $VENV/bin/prequest -d development.ini / This will print the status, headers, and the body of the response to the console. -You can add request header values by using the ``--header`` option:: +You can add request header values by using the ``--header`` option: + +.. code-block:: bash - $ $VENV/bin/prequest --header=Host:example.com development.ini / + $VENV/bin/prequest --header=Host:example.com development.ini / Headers are added to the WSGI environment by converting them to their CGI/WSGI equivalents (e.g., ``Host=example.com`` will insert the ``HTTP_HOST`` header @@ -584,21 +647,11 @@ in the WSGI environment. By default, ``prequest`` sends a ``GET`` request. You can change this by using the ``-m`` (aka ``--method``) option. ``GET``, ``HEAD``, ``POST``, and ``DELETE`` are currently supported. When you use ``POST``, the standard input -of the ``prequest`` process is used as the ``POST`` body:: - - $ $VENV/bin/prequest -mPOST development.ini / < somefile - - -Using Custom Arguments to Python when Running ``p*`` Scripts ------------------------------------------------------------- - -.. versionadded:: 1.5 +of the ``prequest`` process is used as the ``POST`` body: -Each of Pyramid's console scripts (``pserve``, ``pviews``, etc.) can be run -directly using ``python3 -m``, allowing custom arguments to be sent to the -Python interpreter at runtime. For example:: +.. code-block:: bash - python3 -m pyramid.scripts.pserve development.ini + $VENV/bin/prequest -mPOST development.ini / < somefile .. index:: @@ -608,8 +661,8 @@ Python interpreter at runtime. For example:: .. _showing_distributions: -Showing All Installed Distributions and Their Versions ------------------------------------------------------- +``pdistreport``: Showing All Installed Distributions and Their Versions +----------------------------------------------------------------------- .. versionadded:: 1.5 @@ -618,17 +671,19 @@ Showing All Installed Distributions and Their Versions You can use the ``pdistreport`` command to show the :app:`Pyramid` version in use, the Python version in use, and all installed versions of Python -distributions in your Python environment:: - - $ $VENV/bin/pdistreport - Pyramid version: 1.5dev - Platform Linux-3.2.0-51-generic-x86_64-with-debian-wheezy-sid - Packages: - authapp 0.0 - /home/chrism/projects/foo/src/authapp - beautifulsoup4 4.1.3 - /home/chrism/projects/foo/lib/python2.7/site-packages/beautifulsoup4-4.1.3-py2.7.egg - ... more output ... +distributions in your Python environment: + +.. code-block:: bash + + $VENV/bin/pdistreport + Pyramid version: 1.5dev + Platform Linux-3.2.0-51-generic-x86_64-with-debian-wheezy-sid + Packages: + authapp 0.0 + /home/chrism/projects/foo/src/authapp + beautifulsoup4 4.1.3 + /home/chrism/projects/foo/lib/python2.7/site-packages/beautifulsoup4-4.1.3-py2.7.egg + # ... more output ... ``pdistreport`` takes no options. Its output is useful to paste into a pastebin when you are having problems and need someone with more familiarity -- cgit v1.2.3 From d7dfe77e5fa8f0aa1ae75ae076ce160661376172 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 27 Aug 2018 23:57:42 -0700 Subject: Use correct terminology for running p-scripts in Python --- docs/narr/commandline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index 107f35914..3cc7b9653 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -23,7 +23,7 @@ Running p-scripts All of the Pyramid console scripts may be run either: * by its name -* through a Python interpreter +* as a Python module .. index:: -- cgit v1.2.3 From cbab50f10ffcb12d094aafc0afacc5601838e56c Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 28 Aug 2018 13:47:24 -0700 Subject: Clarify $VENV convention with references. --- docs/narr/commandline.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index 3cc7b9653..53e4ee31c 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -41,7 +41,9 @@ Each of Pyramid's console scripts may be run by its name. For example: $VENV/bin/pserve development.ini --reload -.. note:: ``$VENV/bin/`` represents the ``bin`` directory in a virtual environment, where ``$VENV`` is an environment variable representing its path. +.. note:: ``$VENV/bin/`` is a convention we use to simplify Pyramid documentation. + It represents the ``bin`` directory in a virtual environment, where ``$VENV`` is an environment variable representing its path. + See :ref:`installing_unix` and :ref:`venv-bin-pip-vs-source-bin-activate` for more information. .. index:: -- cgit v1.2.3 From 8ffc520f8f49397861899599c3ec9edf3ba79853 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 28 Aug 2018 13:57:58 -0700 Subject: Add label to :ref: to make Sphinx happy --- docs/narr/commandline.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index 53e4ee31c..98e34fea2 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -43,7 +43,7 @@ Each of Pyramid's console scripts may be run by its name. For example: .. note:: ``$VENV/bin/`` is a convention we use to simplify Pyramid documentation. It represents the ``bin`` directory in a virtual environment, where ``$VENV`` is an environment variable representing its path. - See :ref:`installing_unix` and :ref:`venv-bin-pip-vs-source-bin-activate` for more information. + See :ref:`installing_unix` and :ref:`Why use $VENV/bin/pip instead of source bin/activate, then pip ` for more information. .. index:: -- cgit v1.2.3 From 7f5a799b0a5344d5460025c05dd33e360eb9a87e Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Aug 2018 04:50:53 -0700 Subject: Update narr/project.rst and /myproject starter cookiecutter source files --- docs/narr/myproject/.gitignore | 21 ++++ docs/narr/myproject/myproject/__init__.py | 9 +- docs/narr/myproject/myproject/routes.py | 3 + docs/narr/myproject/myproject/templates/404.jinja2 | 8 ++ docs/narr/myproject/myproject/tests.py | 2 +- docs/narr/myproject/myproject/views.py | 6 - docs/narr/myproject/myproject/views/__init__.py | 0 docs/narr/myproject/myproject/views/default.py | 6 + docs/narr/myproject/myproject/views/notfound.py | 7 ++ docs/narr/myproject/setup.py | 2 +- docs/narr/project.rst | 124 +++++++++++++-------- 11 files changed, 129 insertions(+), 59 deletions(-) create mode 100644 docs/narr/myproject/.gitignore create mode 100644 docs/narr/myproject/myproject/routes.py create mode 100644 docs/narr/myproject/myproject/templates/404.jinja2 delete mode 100644 docs/narr/myproject/myproject/views.py create mode 100644 docs/narr/myproject/myproject/views/__init__.py create mode 100644 docs/narr/myproject/myproject/views/default.py create mode 100644 docs/narr/myproject/myproject/views/notfound.py (limited to 'docs/narr') diff --git a/docs/narr/myproject/.gitignore b/docs/narr/myproject/.gitignore new file mode 100644 index 000000000..1853d983c --- /dev/null +++ b/docs/narr/myproject/.gitignore @@ -0,0 +1,21 @@ +*.egg +*.egg-info +*.pyc +*$py.class +*~ +.coverage +coverage.xml +build/ +dist/ +.tox/ +nosetests.xml +env*/ +tmp/ +Data.fs* +*.sublime-project +*.sublime-workspace +.*.sw? +.sw? +.DS_Store +coverage +test diff --git a/docs/narr/myproject/myproject/__init__.py b/docs/narr/myproject/myproject/__init__.py index 49dde36d4..a3d5a6469 100644 --- a/docs/narr/myproject/myproject/__init__.py +++ b/docs/narr/myproject/myproject/__init__.py @@ -4,9 +4,8 @@ from pyramid.config import Configurator def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ - config = Configurator(settings=settings) - config.include('pyramid_jinja2') - config.add_static_view('static', 'static', cache_max_age=3600) - config.add_route('home', '/') - config.scan() + with Configurator(settings=settings) as config: + config.include('pyramid_jinja2') + config.include('.routes') + config.scan() return config.make_wsgi_app() diff --git a/docs/narr/myproject/myproject/routes.py b/docs/narr/myproject/myproject/routes.py new file mode 100644 index 000000000..25504ad4d --- /dev/null +++ b/docs/narr/myproject/myproject/routes.py @@ -0,0 +1,3 @@ +def includeme(config): + config.add_static_view('static', 'static', cache_max_age=3600) + config.add_route('home', '/') diff --git a/docs/narr/myproject/myproject/templates/404.jinja2 b/docs/narr/myproject/myproject/templates/404.jinja2 new file mode 100644 index 000000000..aaf12413f --- /dev/null +++ b/docs/narr/myproject/myproject/templates/404.jinja2 @@ -0,0 +1,8 @@ +{% extends "layout.jinja2" %} + +{% block content %} +
+

Pyramid Starter project

+

404 Page Not Found

+
+{% endblock content %} diff --git a/docs/narr/myproject/myproject/tests.py b/docs/narr/myproject/myproject/tests.py index fd414cced..05ccadcfb 100644 --- a/docs/narr/myproject/myproject/tests.py +++ b/docs/narr/myproject/myproject/tests.py @@ -11,7 +11,7 @@ class ViewTests(unittest.TestCase): testing.tearDown() def test_my_view(self): - from .views import my_view + from .views.default import my_view request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], 'MyProject') diff --git a/docs/narr/myproject/myproject/views.py b/docs/narr/myproject/myproject/views.py deleted file mode 100644 index 9e9ec4320..000000000 --- a/docs/narr/myproject/myproject/views.py +++ /dev/null @@ -1,6 +0,0 @@ -from pyramid.view import view_config - - -@view_config(route_name='home', renderer='templates/mytemplate.jinja2') -def my_view(request): - return {'project': 'MyProject'} diff --git a/docs/narr/myproject/myproject/views/__init__.py b/docs/narr/myproject/myproject/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs/narr/myproject/myproject/views/default.py b/docs/narr/myproject/myproject/views/default.py new file mode 100644 index 000000000..8324cfe32 --- /dev/null +++ b/docs/narr/myproject/myproject/views/default.py @@ -0,0 +1,6 @@ +from pyramid.view import view_config + + +@view_config(route_name='home', renderer='../templates/mytemplate.jinja2') +def my_view(request): + return {'project': 'myproject'} diff --git a/docs/narr/myproject/myproject/views/notfound.py b/docs/narr/myproject/myproject/views/notfound.py new file mode 100644 index 000000000..69d6e2804 --- /dev/null +++ b/docs/narr/myproject/myproject/views/notfound.py @@ -0,0 +1,7 @@ +from pyramid.view import notfound_view_config + + +@notfound_view_config(renderer='../templates/404.jinja2') +def notfound_view(request): + request.response.status = 404 + return {} diff --git a/docs/narr/myproject/setup.py b/docs/narr/myproject/setup.py index 153a659ba..cf626880f 100644 --- a/docs/narr/myproject/setup.py +++ b/docs/narr/myproject/setup.py @@ -18,7 +18,7 @@ requires = [ tests_require = [ 'WebTest >= 1.3.1', # py3 compat - 'pytest', + 'pytest>=3.7.4', 'pytest-cov', ] diff --git a/docs/narr/project.rst b/docs/narr/project.rst index f41e155e7..fb5a241db 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -525,21 +525,27 @@ The ``myproject`` project we've generated has the following directory structure: .. code-block:: text - myproject/ + myproject ├── .coveragerc + ├── .gitignore ├── CHANGES.txt ├── MANIFEST.in ├── myproject │   ├── __init__.py + │   ├── routes.py │   ├── static │   │   ├── pyramid-16x16.png │   │   ├── pyramid.png │   │   └── theme.css │   ├── templates + │   │   ├── 404.jinja2 │   │   ├── layout.jinja2 │   │   └── mytemplate.jinja2 │   ├── tests.py - │   └── views.py + │   └── views + │   ├── __init__.py + │   ├── default.py + │   └── notfound.py ├── README.txt ├── development.ini ├── production.ini @@ -557,6 +563,8 @@ describe, run, and test your application. #. ``.coveragerc`` configures coverage when running tests. +#. ``.gitignore`` tells git which files and directories to ignore from source code version control. + #. ``CHANGES.txt`` describes the changes you've made to the application. It is conventionally written in :term:`reStructuredText` format. @@ -810,7 +818,9 @@ The ``myproject`` :term:`package` lives inside the ``myproject`` #. A ``tests.py`` module, which contains unit test code for the application. -#. A ``views.py`` module, which contains view code for the application. +#. A ``views`` package, which contains view code for the application. + +#. A ``static`` directory, which contains static files, including images and CSS. These are purely conventions established by the cookiecutter. :app:`Pyramid` doesn't insist that you name things in any particular way. However, it's @@ -848,31 +858,53 @@ also informs Python that the directory which contains it is a *package*. Line 8 adds support for Jinja2 templating bindings, allowing us to specify renderers with the ``.jinja2`` extension. - Line 9 registers a static view, which will serve up the files from the - ``myproject:static`` :term:`asset specification` (the ``static`` directory - of the ``myproject`` package). + Line 9 includes the ``routes.py`` module. - Line 10 adds a :term:`route` to the configuration. This route is later used - by a view in the ``views`` module. - - Line 11 calls ``config.scan()``, which picks up view registrations declared + Line 10 calls ``config.scan()``, which picks up view registrations declared elsewhere in the package (in this case, in the ``views.py`` module). - Line 12 returns a :term:`WSGI` application to the caller of the function + Line 11 returns a :term:`WSGI` application to the caller of the function (Pyramid's pserve). + +.. index:: + single: routes.py + +.. _routes_py: + +``routes.py`` +~~~~~~~~~~~~~ + +The ``routes.py`` module gets included by the ``main`` function in our ``__init__.py``. +It registers a view and a route. + +.. literalinclude:: myproject/myproject/routes.py + :language: python + :linenos: + +Line 2 registers a static view, which will serve up the files from the ``myproject:static`` :term:`asset specification` (the ``static`` directory of the ``myproject`` package). + +Line 3 adds a :term:`route` to the configuration. This route is later used by a view in the ``views`` module. + + .. index:: single: views.py -``views.py`` -~~~~~~~~~~~~ +``views`` package +~~~~~~~~~~~~~~~~~ Much of the heavy lifting in a :app:`Pyramid` application is done by *view callables*. A :term:`view callable` is the main tool of a :app:`Pyramid` web application developer; it is a bit of code which accepts a :term:`request` and which returns a :term:`response`. -.. literalinclude:: myproject/myproject/views.py +Our project has a ``views`` package by virtue of it being a directory containing an ``__init__.py`` file. +This ``__init__.py`` file happens to have no content, although it could as a project develops. + +We have two view modules in the ``views`` package. +Let's look at ``default.py``. + +.. literalinclude:: myproject/myproject/views/default.py :language: python :linenos: @@ -880,17 +912,17 @@ Lines 4-6 define and register a :term:`view callable` named ``my_view``. The function named ``my_view`` is decorated with a ``view_config`` decorator (which is processed by the ``config.scan()`` line in our ``__init__.py``). The view_config decorator asserts that this view be found when a :term:`route` -named ``home`` is matched. In our case, because our ``__init__.py`` maps the +named ``home`` is matched. In our case, because our ``routes.py`` maps the route named ``home`` to the URL pattern ``/``, this route will match when a visitor visits the root URL. The view_config decorator also names a ``renderer``, which in this case is a template that will be used to render the result of the view callable. This particular view declaration points at -``templates/mytemplate.pt``, which is an :term:`asset specification` that -specifies the ``mytemplate.pt`` file within the ``templates`` directory of the +``../templates/mytemplate.jinja2``, which is an :term:`asset specification` that +specifies the ``mytemplate.jinja2`` file within the ``templates`` directory of the ``myproject`` package. The asset specification could have also been specified -as ``myproject:templates/mytemplate.pt``; the leading package name and colon is +as ``myproject:templates/mytemplate.jinja2``; the leading package name and colon is optional. The template file pointed to is a :term:`Jinja2` template -file (``templates/my_template.jinja2``). +file (``templates/mytemplate.jinja2``). This view callable function is handed a single piece of information: the :term:`request`. The *request* is an instance of the :term:`WebOb` ``Request`` @@ -903,6 +935,15 @@ the HTML in a :term:`response`. .. note:: Dictionaries provide values to :term:`template`\s. +Now let's look at ``notfound.py``. + +.. literalinclude:: myproject/myproject/views/notfound.py + :language: python + :linenos: + +This file is similar to ``default.py``. +It merely returns a ``404`` response status and an empty dictionary to the template at ``../templates/404.jinja2``. + .. note:: When the application is run with the cookiecutter's :ref:`default development.ini ` configuration, :ref:`logging is set up ` to aid debugging. If an exception is raised, @@ -964,7 +1005,7 @@ This is the base layout content. It contains a single marker for content block. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the content :term:`Jinja2` template that exists in the project. It is referenced by the call to ``@view_config`` as the ``renderer`` -of the ``my_view`` view callable in the ``views.py`` file. See +of the ``my_view`` view callable in the ``views/default.py`` file. See :ref:`views_which_use_a_renderer` for more information about renderers. It inherits ("extends") the HTML provided by ``layout.jinja2``, replacing the content block with its own content. .. literalinclude:: myproject/myproject/templates/mytemplate.jinja2 @@ -976,6 +1017,18 @@ functions themselves. See :ref:`templates_used_directly` and :ref:`templates_used_as_renderers`. +``templates/404.jinja2`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +This template is similar to ``mytemplate.jinja2``, but with a few differences. +It is referenced by the call to ``@notfound_view_config`` as the ``renderer`` of the ``notfound_view`` view callable in the ``views/notfound.py`` file. +It inherits the HTML provided by ``layout.jinja2``, replacing the content block with its own content. + +.. literalinclude:: myproject/myproject/templates/404.jinja2 + :language: jinja + :linenos: + + .. index:: single: tests.py @@ -1015,32 +1068,11 @@ cookiecutter, you can decide to lay your code out any way you see fit. For example, the configuration method named :meth:`~pyramid.config.Configurator.add_view` requires you to pass a :term:`dotted Python name` or a direct object reference as the class or -function to be used as a view. By default, the ``starter`` cookiecutter would have -you add view functions to the ``views.py`` module in your package. However, you -might be more comfortable creating a ``views`` *directory*, and adding a single -file for each view. - -If your project package name was ``myproject`` and you wanted to arrange all -your views in a Python subpackage within the ``myproject`` :term:`package` -named ``views`` instead of within a single ``views.py`` file, you might do the -following. - -- Create a ``views`` directory inside your ``myproject`` package directory (the - same directory which holds ``views.py``). - -- Create a file within the new ``views`` directory named ``__init__.py``. (It - can be empty. This just tells Python that the ``views`` directory is a - *package*.) - -- *Move* the content from the existing ``views.py`` file to a file inside the - new ``views`` directory named, say, ``blog.py``. Because the ``templates`` - directory remains in the ``myproject`` package, the template :term:`asset - specification` values in ``blog.py`` must now be fully qualified with the - project's package name (``myproject:templates/blog.pt``). - -You can then continue to add view callable functions to the ``blog.py`` module, -but you can also add other ``.py`` files which contain view callable functions -to the ``views`` directory. As long as you use the ``@view_config`` directive +function to be used as a view. +By default, the ``starter`` cookiecutter would have you create a ``views`` directory, and add a single file for each view or collection of related views. +However, you might be more comfortable creating a single ``views.py`` module in your package and add view functions to it. + +Whatever structure you prefer, as long as you use the ``@view_config`` directive to register views in conjunction with ``config.scan()``, they will be picked up automatically when the application is restarted. -- cgit v1.2.3 From e604ce4350ccb6a70f632d5a4fdc5984a4218fd1 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 30 Aug 2018 04:54:02 -0700 Subject: Update narr/testing.rst to updated files in narr/myproject/ --- docs/narr/testing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index 8f4d806e6..ad4ba2186 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -396,10 +396,10 @@ As always, whenever you change your dependencies, make sure to run the correct $VENV/bin/pip install -e ".[testing]" In your ``MyPackage`` project, your :term:`package` is named ``myproject`` -which contains a ``views`` module, which in turn contains a :term:`view` +which contains a ``views`` package containing a ``default.py`` module, which in turn contains a :term:`view` function ``my_view`` that returns an HTML body when the root URL is invoked: - .. literalinclude:: myproject/myproject/views.py + .. literalinclude:: myproject/myproject/views/default.py :linenos: :language: python -- cgit v1.2.3 From 549412454ef49430daaba2fccac56619b2e0cb83 Mon Sep 17 00:00:00 2001 From: Stephen Martin Date: Tue, 4 Sep 2018 10:17:31 -0700 Subject: clarify session factory warnings --- docs/narr/sessions.rst | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 6c88dcec5..6f826fe23 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -57,18 +57,27 @@ using the :meth:`pyramid.config.Configurator.set_session_factory` method. .. warning:: By default the :func:`~pyramid.session.SignedCookieSessionFactory` - implementation is *unencrypted*. You should not use it when you keep - sensitive information in the session object, as the information can be - easily read by both users of your application and third parties who have - access to your users' network traffic. And, if you use this sessioning - implementation, and you inadvertently create a cross-site scripting - vulnerability in your application, because the session data is stored - unencrypted in a cookie, it will also be easier for evildoers to obtain the - current user's cross-site scripting token. In short, use a different - session factory implementation (preferably one which keeps session data on - the server) for anything but the most basic of applications where "session - security doesn't matter", and you are sure your application has no - cross-site scripting vulnerabilities. + implementation contains the following security concerns: + + - Session data is *unencrypted*. You should not use it when you keep + sensitive information in the session object, as the information can be + easily read by both users of your application and third parties who have + access to your users' network traffic. + + - If you use this sessioning implementation, and you inadvertently create a + cross-site scripting vulnerability in your application, because the + session data is stored unencrypted in a cookie, it will also be easier for + evildoers to obtain the current user's cross-site scripting token. + + - The default serialization method, while replacable with something like + JSON, is implemented using pickle which can lead to remote code execution + if your secret key is compromised. + + In short, use a different session factory implementation (preferably one + which keeps session data on the server) for anything but the most basic of + applications where "session security doesn't matter", you are sure your + application has no cross-site scripting vulnerabilities, and you are confident + your secret key will not be exposed. .. index:: single: session object -- cgit v1.2.3 From 91f381754177896bf481e27ab53d33cac33e2a0d Mon Sep 17 00:00:00 2001 From: Stephen Martin Date: Tue, 4 Sep 2018 12:36:39 -0700 Subject: fix spelling error --- docs/narr/sessions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 6f826fe23..2d80b1a63 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -69,7 +69,7 @@ using the :meth:`pyramid.config.Configurator.set_session_factory` method. session data is stored unencrypted in a cookie, it will also be easier for evildoers to obtain the current user's cross-site scripting token. - - The default serialization method, while replacable with something like + - The default serialization method, while replaceable with something like JSON, is implemented using pickle which can lead to remote code execution if your secret key is compromised. -- cgit v1.2.3 From c3188340e841633924e8ab7a055c1df0dffed9c1 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 16 Sep 2018 11:06:05 -0500 Subject: deprecate pickleable sessions, recommend json --- docs/narr/sessions.rst | 72 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 19 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 2d80b1a63..17e8291a0 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -59,25 +59,59 @@ using the :meth:`pyramid.config.Configurator.set_session_factory` method. By default the :func:`~pyramid.session.SignedCookieSessionFactory` implementation contains the following security concerns: - - Session data is *unencrypted*. You should not use it when you keep - sensitive information in the session object, as the information can be - easily read by both users of your application and third parties who have - access to your users' network traffic. - - - If you use this sessioning implementation, and you inadvertently create a - cross-site scripting vulnerability in your application, because the - session data is stored unencrypted in a cookie, it will also be easier for - evildoers to obtain the current user's cross-site scripting token. - - - The default serialization method, while replaceable with something like - JSON, is implemented using pickle which can lead to remote code execution - if your secret key is compromised. - - In short, use a different session factory implementation (preferably one - which keeps session data on the server) for anything but the most basic of - applications where "session security doesn't matter", you are sure your - application has no cross-site scripting vulnerabilities, and you are confident - your secret key will not be exposed. + - Session data is *unencrypted* (but it is signed / authenticated). + + This means an attacker cannot change the session data, but they can view it. + You should not use it when you keep sensitive information in the session object, as the information can be easily read by both users of your application and third parties who have access to your users' network traffic. + + At the very least, use TLS and set ``secure=True`` to avoid arbitrary users on the network from viewing the session contents. + + - If you use this sessioning implementation, and you inadvertently create a cross-site scripting vulnerability in your application, because the session data is stored unencrypted in a cookie, it will also be easier for evildoers to obtain the current user's cross-site scripting token. + + Set ``httponly=True`` to mitigate this vulnerability by hiding the cookie from client-side JavaScript. + + - The default serialization method, while replaceable with something like JSON, is implemented using pickle which can lead to remote code execution if your secret key is compromised. + + To mitigate this, set ``serializer=pyramid.session.JSONSerializer()`` to use :class:`pyramid.session.JSONSerializer`. This option will be the default in :app:`Pyramid` 2.0. + See :ref:`pickle_session_deprecation` for more information about this change. + + In short, use a different session factory implementation (preferably one which keeps session data on the server) for anything but the most basic of applications where "session security doesn't matter", you are sure your application has no cross-site scripting vulnerabilities, and you are confident your secret key will not be exposed. + +.. _pickle_session_deprecation: + +Upcoming Changes to ISession in Pyramid 2.0 +------------------------------------------- + +In :app:`Pyramid` 2.0 the :class:`pyramid.interfaces.ISession` interface will be changing to require that session implementations only need to support json-serializable data types. +This is a stricter contract than the current requirement that all objects be pickleable and it is being done for security purposes. +This is a backward-incompatible change. +Currently, if a client-side session implementation is compromised, it leaves the application vulnerable to remote code execution attacks using specially-crafted sessions that execute code when deserialized. + +For users with compatibility concerns, it's possible to craft a serializer that can handle both formats until you are satisfied that clients have had time to reasonably upgrade. +Remember that sessions should be short-lived and thus the number of clients affected should be small (no longer than an auth token, at a maximum). An example serializer: + +.. code-block:: python + :linenos: + + from pyramid.session import JSONSerializer + from pyramid.session import PickleSerializer + + class JSONSerializerWithPickleFallback(object): + def __init__(self): + self.json = JSONSerializer() + self.pickle = PickleSerializer() + + def dumps(self, value): + # maybe catch serialization errors here and keep using pickle + # while finding spots in your app that are not storing + # json-serializable objects, falling back to pickle + return self.json.dumps(value) + + def loads(self, value): + try: + return self.json.loads(value) + except ValueError: + return self.pickle.loads(value) .. index:: single: session object -- cgit v1.2.3 From 38bbea331f9c485d40892a17674272a8876a55a1 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 16 Sep 2018 15:43:43 -0500 Subject: tweak some docs --- docs/narr/sessions.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 17e8291a0..971b4502d 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -79,10 +79,13 @@ using the :meth:`pyramid.config.Configurator.set_session_factory` method. .. _pickle_session_deprecation: +.. index:: + triple: pickle deprecation; JSON-serializable; ISession interface + Upcoming Changes to ISession in Pyramid 2.0 ------------------------------------------- -In :app:`Pyramid` 2.0 the :class:`pyramid.interfaces.ISession` interface will be changing to require that session implementations only need to support json-serializable data types. +In :app:`Pyramid` 2.0 the :class:`pyramid.interfaces.ISession` interface will be changing to require that session implementations only need to support JSON-serializable data types. This is a stricter contract than the current requirement that all objects be pickleable and it is being done for security purposes. This is a backward-incompatible change. Currently, if a client-side session implementation is compromised, it leaves the application vulnerable to remote code execution attacks using specially-crafted sessions that execute code when deserialized. @@ -104,7 +107,7 @@ Remember that sessions should be short-lived and thus the number of clients affe def dumps(self, value): # maybe catch serialization errors here and keep using pickle # while finding spots in your app that are not storing - # json-serializable objects, falling back to pickle + # JSON-serializable objects, falling back to pickle return self.json.dumps(value) def loads(self, value): @@ -173,7 +176,7 @@ Some gotchas: that they are instances of basic types of objects, such as strings, lists, dictionaries, tuples, integers, etc. If you place an object in a session data key or value that is not pickleable, an error will be raised when the - session is serialized. + session is serialized. Please also see :ref:`pickle_session_deprecation`. - If you place a mutable value (for example, a list or a dictionary) in a session object, and you subsequently mutate that value, you must call the -- cgit v1.2.3 From 07207637818049d27abb90792d48d7ed8fdd2340 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 16 Sep 2018 22:45:05 -0500 Subject: ref after index apparently --- docs/narr/sessions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index 971b4502d..d4d3c1074 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -77,11 +77,11 @@ using the :meth:`pyramid.config.Configurator.set_session_factory` method. In short, use a different session factory implementation (preferably one which keeps session data on the server) for anything but the most basic of applications where "session security doesn't matter", you are sure your application has no cross-site scripting vulnerabilities, and you are confident your secret key will not be exposed. -.. _pickle_session_deprecation: - .. index:: triple: pickle deprecation; JSON-serializable; ISession interface +.. _pickle_session_deprecation: + Upcoming Changes to ISession in Pyramid 2.0 ------------------------------------------- -- cgit v1.2.3 From 0296259599809671df9a4bb3b14623c117c09344 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Sat, 22 Sep 2018 01:33:35 -0700 Subject: Update links to trypyramid.com, Grok, gunicorn --- docs/narr/introduction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/introduction.rst b/docs/narr/introduction.rst index 3ee6b5367..9293386f2 100644 --- a/docs/narr/introduction.rst +++ b/docs/narr/introduction.rst @@ -52,7 +52,7 @@ Modern Tested ~~~~~~ -Untested code is broken by design. The :app:`Pyramid` community has a strong testing culture and our framework reflects that. Every release of :app:`Pyramid` has 100% statement coverage (as measured by `coverage `_) and 95% decision/condition coverage. (as measured by `instrumental `_) It is automatically tested using `Travis `_ and `Jenkins `_ on supported versions of Python after each commit to its GitHub repository. `Official Pyramid add-ons `_ are held to a similar testing standard. +Untested code is broken by design. The :app:`Pyramid` community has a strong testing culture and our framework reflects that. Every release of :app:`Pyramid` has 100% statement coverage (as measured by `coverage `_) and 95% decision/condition coverage. (as measured by `instrumental `_) It is automatically tested using `Travis `_ and `Jenkins `_ on supported versions of Python after each commit to its GitHub repository. `Official Pyramid add-ons `_ are held to a similar testing standard. We still find bugs in :app:`Pyramid`, but we've noticed we find a lot fewer of them while working on projects with a solid testing regime. @@ -173,7 +173,7 @@ Supported :app:`Pyramid` add-ons are held to the same demanding standards as the .. seealso:: - See also https://trypyramid.com/resources-extending-pyramid.html + See also https://trypyramid.com/extending-pyramid.html Write your views, *your* way ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 97ee7f3aa8af74a01e51c0c14fda1c0a5a490663 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 25 Sep 2018 15:49:23 -0500 Subject: show how to use the serializer --- docs/narr/sessions.rst | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst index d4d3c1074..ded7e87e3 100644 --- a/docs/narr/sessions.rst +++ b/docs/narr/sessions.rst @@ -98,6 +98,7 @@ Remember that sessions should be short-lived and thus the number of clients affe from pyramid.session import JSONSerializer from pyramid.session import PickleSerializer + from pyramid.session import SignedCookieSessionFactory class JSONSerializerWithPickleFallback(object): def __init__(self): @@ -116,6 +117,11 @@ Remember that sessions should be short-lived and thus the number of clients affe except ValueError: return self.pickle.loads(value) + # somewhere in your configuration code + serializer = JSONSerializerWithPickleFallback() + session_factory = SignedCookieSessionFactory(..., serializer=serializer) + config.set_session_factory(session_factory) + .. index:: single: session object -- cgit v1.2.3