diff options
Diffstat (limited to 'docs/narr/project.rst')
| -rw-r--r-- | docs/narr/project.rst | 1284 |
1 files changed, 711 insertions, 573 deletions
diff --git a/docs/narr/project.rst b/docs/narr/project.rst index 0ada1a379..725263407 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -1,115 +1,146 @@ .. _project_narr: Creating a :app:`Pyramid` Project -==================================== +================================= -As we saw in :ref:`firstapp_chapter`, it's possible to create a -:app:`Pyramid` application completely manually. However, it's usually more -convenient to use a :term:`scaffold` to generate a basic :app:`Pyramid` -:term:`project`. +As we saw in :ref:`firstapp_chapter`, it's possible to create a :app:`Pyramid` +application completely manually. However, it's usually more convenient to use +our :term:`cookiecutter` to generate a basic :app:`Pyramid` :term:`project`. A project is a directory that contains at least one Python :term:`package`. -You'll use a scaffold to create a project, and you'll create your application -logic within a package that lives inside the project. Even if your -application is extremely simple, it is useful to place code that drives the -application within a package, because: 1) a package is more easily extended -with new code and 2) an application that lives inside a package can also be -distributed more easily than one which does not live within a package. +You'll use the :app:`Pyramid` cookiecutter to create a project, and you'll +create your application logic within a package that lives inside the project. +Even if your application is extremely simple, it is useful to place code that +drives the application within a package, because (1) a package is more easily +extended with new code, and (2) an application that lives inside a package can +also be distributed more easily than one which does not live within a package. -:app:`Pyramid` comes with a variety of scaffolds that you can use to generate -a project. Each scaffold makes different configuration assumptions about -what type of application you're trying to construct. +The Pylons Project provides a :app:`Pyramid` cookiecutter that you can use to +generate a project. Our cookiecutter allows several configuration options +to generate the type of application you're trying to construct. + +This cookiecutter is rendered using the ``cookiecutter`` command that you may install. + +.. seealso:: + + See also `Cookiecutter Installation <https://cookiecutter.readthedocs.io/en/latest/installation.html>`_. -These scaffolds are rendered using the ``pcreate`` command that is installed -as part of Pyramid. .. index:: - single: scaffolds - single: starter scaffold - single: zodb scaffold - single: alchemy scaffold + single: cookiecutters + single: pyramid-cookiecutter-starter + +.. _additional_cookiecutters: + +:app:`Pyramid` cookiecutters +---------------------------- -.. _additional_paster_scaffolds: +The Pyramid cookiecutter released under the Pylons Project offers the following configuration options: -Scaffolds Included with :app:`Pyramid` ------------------------------------------------- +- templating libraries (:term:`Jinja2`, :term:`Chameleon`, or :term:`Mako`) -The convenience scaffolds included with :app:`Pyramid` differ from -each other on a number of axes: +- the persistence mechanism (no persistence mechanism, :term:`SQLAlchemy` with SQLite, or :term:`ZODB`) -- the persistence mechanism they offer (no persistence mechanism, - :term:`ZODB`, or :term:`SQLAlchemy`). +- the mechanism of mapping URLs to code (:term:`URL dispatch` or :term:`traversal`) -- the mechanism they use to map URLs to code (:term:`traversal` or :term:`URL - dispatch`). +* `pyramid-cookiecutter-starter <https://github.com/Pylons/pyramid-cookiecutter-starter>`_ -The included scaffolds are these: +All configuration options offer a choice of templating language. -``starter`` - URL mapping via :term:`URL dispatch` and no persistence mechanism. +The configuration of mapping URLs to code (routing) depends on the backend option selected, with additional variations as follows. + +``none`` + :term:`URL dispatch` for routing + +``sqlalchemy`` + SQLite for persistent storage, :term:`SQLAlchemy` for an ORM, :term:`URL dispatch` for routing, and :term:`Alembic` for database migrations ``zodb`` - URL mapping via :term:`traversal` and persistence via :term:`ZODB`. + :term:`ZODB` for persistent storage and :term:`traversal` for routing -``alchemy`` - URL mapping via :term:`URL dispatch` and persistence via - :term:`SQLAlchemy` .. index:: single: creating a project single: project + single: cookiecutter .. _creating_a_project: Creating the Project -------------------- -In :ref:`installing_chapter`, you created a virtual Python environment via -the ``virtualenv`` command. To start a :app:`Pyramid` :term:`project`, use -the ``pcreate`` command installed within the virtualenv. We'll choose the -``starter`` scaffold for this purpose. When we invoke ``pcreate``, it will -create a directory that represents our project. +In :ref:`installing_chapter`, you created a virtual Python environment via the +``venv`` command. We called the virtual environment directory +``env`` and set an environment variable ``VENV`` to its path. -In :ref:`installing_chapter` we called the virtualenv directory ``env``; the -following commands assume that our current working directory is the ``env`` -directory. +We assume that you :ref:`previously installed cookiecutter <cookiecutters>`, following its installation instructions. -The below example uses the ``pcreate`` command to create a project with the -``starter`` scaffold. +When we invoke ``cookiecutter``, it will create a directory that represents our project. -On UNIX: +We assume our current working directory is the value of ``VENV``. -.. code-block:: text +On all platforms, generate a project using cookiecutter. - $ $VENV/bin/pcreate -s starter MyProject +.. code-block:: bash -Or on Windows: + cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout master + +If prompted for the first item, accept the default ``yes`` by hitting return. .. code-block:: text - > %VENV%\Scripts\pcreate -s starter MyProject - + You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before. + Is it okay to delete and re-clone it? [yes]: yes + project_name [Pyramid Scaffold]: myproject + repo_name [myproject]: myproject + Select template_language: + 1 - jinja2 + 2 - chameleon + 3 - mako + Choose from 1, 2, 3 [1]: 1 + Select backend: + 1 - none + 2 - sqlalchemy + 3 - zodb + Choose from 1, 2, 3 [1]: 1 + +We then run through the following commands. + +On Unix: + +.. code-block:: bash + + # Reset our environment variable for a new virtual environment. + export VENV=~/env/myproject/env + # Change directory into your newly created project. + cd myproject + # Create a new virtual environment... + python3 -m venv $VENV + # ...where we upgrade packaging tools. + env/bin/pip install --upgrade pip setuptools -Here's sample output from a run of ``pcreate`` on UNIX for a project we name -``MyProject``: +Or on Windows: -.. code-block:: text +.. code-block:: doscon - $ $VENV/bin/pcreate -s starter MyProject - Creating template pyramid - Creating directory ./MyProject - # ... more output ... - Running /Users/chrism/projects/pyramid/bin/python setup.py egg_info + # Reset our environment variable for a new virtual environment. + set VENV=c:\env\myproject\env + # Change directory into your newly created project. + cd myproject + # Create a new virtual environment... + python -m venv %VENV% + # ...where we upgrade packaging tools. + %VENV%\Scripts\pip install --upgrade pip setuptools -As a result of invoking the ``pcreate`` command, a directory named -``MyProject`` is created. That directory is a :term:`project` directory. -The ``setup.py`` file in that directory can be used to distribute your -application, or install your application for deployment or development. +As a result of invoking the ``cookiecutter`` command, a directory named +``myproject`` is created. That directory is a :term:`project` directory. The +``setup.py`` file in that directory can be used to distribute your application, +or install your application for deployment or development. -A ``.ini`` file named ``development.ini`` will be created in the project -directory. You will use this ``.ini`` file to configure a server, to run -your application, and to debug your application. It contains configuration -that enables an interactive debugger and settings optimized for development. +An ``.ini`` file named ``development.ini`` will be created in the project +directory. You will use this ``.ini`` file to configure a server, to run your +application, and to debug your application. It contains configuration that +enables an interactive debugger and settings optimized for development. Another ``.ini`` file named ``production.ini`` will also be created in the project directory. It contains configuration that disables any interactive @@ -117,29 +148,29 @@ debugger (to prevent inappropriate access and disclosure), and turns off a number of debugging settings. You can use this file to put your application into production. -The ``MyProject`` project directory contains an additional subdirectory named -``myproject`` (note the case difference) representing a Python -:term:`package` which holds very simple :app:`Pyramid` sample code. This is -where you'll edit your application's Python code and templates. - -We created this project within an ``env`` virtualenv directory. However, -note that this is not mandatory. The project directory can go more or less -anywhere on your filesystem. You don't need to put it in a special "web -server" directory, and you don't need to put it within a virtualenv -directory. The author uses Linux mainly, and tends to put project -directories which he creates within his ``~/projects`` directory. On -Windows, it's a good idea to put project directories within a directory that -contains no space characters, so it's wise to *avoid* a path that contains -i.e. ``My Documents``. As a result, the author, when he uses Windows, just -puts his projects in ``C:\projects``. +The ``myproject`` project directory contains an additional subdirectory named +``myproject`` (note the case difference) representing a Python :term:`package` +which holds very simple :app:`Pyramid` sample code. This is where you'll edit +your application's Python code and templates. + +We created this project in a directory next to its virtual environment directory. +However, note that this is not mandatory. The project directory can go more or +less anywhere on your filesystem. You don't need to put it in a special "web +server" directory. You could put it within a virtual environment +directory. The author uses Linux mainly, and tends to put project directories +which he creates within his ``~/projects`` directory. On Windows, it's a good +idea to put project directories within a directory that contains no space +characters, so it's wise to *avoid* a path that contains, i.e., ``My +Documents``. As a result, the author, when he uses Windows, just puts his +projects in ``C:\projects``. .. warning:: - You'll need to avoid using ``pcreate`` to create a project with the same + You'll need to avoid using ``cookiecutter`` to create a project with the same name as a Python standard library component. In particular, this means you - should avoid using the names ``site`` or ``test``, both of which - conflict with Python standard library packages. You should also avoid - using the name ``pyramid``, which will conflict with Pyramid itself. + should avoid using the names ``site`` or ``test``, both of which conflict + with Python standard library packages. You should also avoid using the name + ``pyramid``, which will conflict with Pyramid itself. .. index:: single: setup.py develop @@ -150,97 +181,117 @@ Installing your Newly Created Project for Development To install a newly created project for development, you should ``cd`` to the newly created project directory and use the Python interpreter from the -:term:`virtualenv` you created during :ref:`installing_chapter` to invoke the -command ``python setup.py develop`` +:term:`virtual environment` you created during :ref:`installing_chapter` to +invoke the command ``pip install -e .``, which installs the project in +development mode (``-e`` is for "editable") into the current directory (``.``). -The file named ``setup.py`` will be in the root of the pcreate-generated -project directory. The ``python`` you're invoking should be the one that -lives in the ``bin`` (or ``Scripts`` on Windows) directory of your virtual -Python environment. Your terminal's current working directory *must* be the -newly created project directory. +The file named ``setup.py`` will be in the root of the cookiecutter-generated +project directory. The ``python`` you're invoking should be the one that lives +in the ``bin`` (or ``Scripts`` on Windows) directory of your virtual Python +environment. Your terminal's current working directory *must* be the newly +created project directory. -On UNIX: +On Unix: -.. code-block:: text +.. code-block:: bash - $ cd MyProject - $ $VENV/bin/python setup.py develop + $VENV/bin/pip install -e . Or on Windows: -.. code-block:: text +.. code-block:: doscon - > cd MyProject - > %VENV%\Scripts\python.exe setup.py develop + %VENV%\Scripts\pip install -e . -Elided output from a run of this command on UNIX is shown below: +Elided output from a run of this command on Unix is shown below: -.. code-block:: text +.. code-block:: bash - $ cd MyProject - $ $VENV/bin/python setup.py develop - ... - Finished processing dependencies for MyProject==0.0 + Running setup.py develop for myproject + Successfully installed Jinja2-2.8 Mako-1.0.6 MarkupSafe-0.23 \ + PasteDeploy-1.5.2 Pygments-2.1.3 WebOb-1.7.0 myproject pyramid-1.7.3 \ + pyramid-debugtoolbar-3.0.5 pyramid-jinja2-2.7 pyramid-mako-1.0.2 \ + repoze.lru-0.6 translationstring-1.3 venusian-1.0 waitress-1.0.1 \ + zope.deprecation-4.2.0 zope.interface-4.3.3 -This will install a :term:`distribution` representing your project -into the virtual environment interpreter's library set so it can be -found by ``import`` statements and by other console scripts such as -``pserve``, ``pshell``, ``proutes`` and ``pviews``. +This will install a :term:`distribution` representing your project into the +virtual environment interpreter's library set so it can be found by ``import`` +statements and by other console scripts such as ``pserve``, ``pshell``, +``proutes``, and ``pviews``. .. index:: single: running tests single: tests (running) -Running The Tests For Your Application +Running the Tests for Your Application -------------------------------------- -To run unit tests for your application, you should invoke them using the -Python interpreter from the :term:`virtualenv` you created during -:ref:`installing_chapter` (the ``python`` command that lives in the ``bin`` -directory of your virtualenv). +To run unit tests for your application, you must first install the testing +dependencies. -On UNIX: +On Unix: -.. code-block:: text +.. code-block:: bash - $ $VENV/bin/python setup.py test -q + $VENV/bin/pip install -e ".[testing]" -Or on Windows: +On Windows: -.. code-block:: text +.. code-block:: doscon - > %VENV%\Scripts\python.exe setup.py test -q + %VENV%\Scripts\pip install -e ".[testing]" -Here's sample output from a test run on UNIX: +Once the testing requirements are installed, then you can run the tests using +the ``pytest`` command that was just installed in the ``bin`` directory of +your virtual environment. -.. code-block:: text +On Unix: + +.. code-block:: bash + + $VENV/bin/pytest -q + +On Windows: + +.. code-block:: doscon + + %VENV%\Scripts\pytest -q - $ $VENV/bin/python setup.py test -q - running test - running egg_info - writing requirements to MyProject.egg-info/requires.txt - writing MyProject.egg-info/PKG-INFO - writing top-level names to MyProject.egg-info/top_level.txt - writing dependency_links to MyProject.egg-info/dependency_links.txt - writing entry points to MyProject.egg-info/entry_points.txt - reading manifest file 'MyProject.egg-info/SOURCES.txt' - writing manifest file 'MyProject.egg-info/SOURCES.txt' - running build_ext - .. - ---------------------------------------------------------------------- - Ran 1 test in 0.108s - - OK - -The tests themselves are found in the ``tests.py`` module in your ``pcreate`` -generated project. Within a project generated by the ``starter`` scaffold, a -single sample test exists. +Here's sample output from a test run on Unix: + +.. code-block:: bash + + $VENV/bin/pytest -q + .. + 2 passed in 0.47 seconds + +The tests themselves are found in the ``tests.py`` module in your ``cookiecutter``-generated project. Within a project generated by the ``pyramid-cookiecutter-starter`` cookiecutter, only two sample tests exist. .. note:: - The ``-q`` option is passed to the ``setup.py test`` command to limit the - output to a stream of dots. If you don't pass ``-q``, you'll see more - verbose test result output (which normally isn't very useful). + The ``-q`` option is passed to the ``pytest`` command to limit the output + to a stream of dots. If you don't pass ``-q``, you'll see verbose test + result output (which normally isn't very useful). + +Alternatively, if you'd like to see test coverage, pass the ``--cov`` option +to ``pytest``: + +.. code-block:: bash + + $VENV/bin/pytest --cov -q + +Cookiecutters include configuration defaults for ``pytest`` and test coverage. +These configuration files are ``pytest.ini`` and ``.coveragerc``, located at +the root of your package. Without these defaults, we would need to specify the +path to the module on which we want to run tests and coverage. + +.. code-block:: bash + + $VENV/bin/pytest --cov=myproject myproject/tests.py -q + +.. seealso:: See ``pytest``'s documentation for :ref:`pytest:usage` or invoke + ``pytest -h`` to see its full set of options. + .. index:: single: running an application @@ -250,83 +301,85 @@ single sample test exists. .. _running_the_project_application: -Running The Project Application +Running the Project Application ------------------------------- +.. seealso:: See also the output of :ref:`pserve --help <pserve_script>`. + Once a project is installed for development, you can run the application it represents using the ``pserve`` command against the generated configuration file. In our case, this file is named ``development.ini``. -On UNIX: +On Unix: -.. code-block:: text +.. code-block:: bash - $ $VENV/bin/pserve development.ini + $VENV/bin/pserve development.ini On Windows: -.. code-block:: text +.. code-block:: doscon - > %VENV%\Scripts\pserve development.ini + %VENV%\Scripts\pserve development.ini -Here's sample output from a run of ``pserve`` on UNIX: +Here's sample output from a run of ``pserve`` on Unix: -.. code-block:: text +.. code-block:: bash - $ $VENV/bin/pserve development.ini - Starting server in PID 16601. - serving on http://0.0.0.0:6543 - -When you use ``pserve`` to start the application implied by the default -rendering of a scaffold, it will respond to requests on *all* IP addresses -possessed by your system, not just requests to ``localhost``. This is what -the ``0.0.0.0`` in ``serving on http://0.0.0.0:6543`` means. The server will -respond to requests made to ``127.0.0.1`` and on any external IP address. -For example, your system might be configured to have an external IP address -``192.168.1.50``. If that's the case, if you use a browser running on the -same system as Pyramid, it will be able to access the application via -``http://127.0.0.1:6543/`` as well as via -``http://192.168.1.50:6543/``. However, *other people* on other computers on -the same network will also be able to visit your Pyramid application in their -browser by visiting ``http://192.168.1.50:6543/``. + $VENV/bin/pserve development.ini + Starting server in PID 77171. + Serving on http://localhost:6543 + Serving on http://localhost:6543 -If you want to restrict access such that only a browser running on the same -machine as Pyramid will be able to access your Pyramid application, edit the -``development.ini`` file, and replace the ``host`` value in the -``[server:main]`` section. Change it from ``0.0.0.0`` to ``127.0.0.1``. For -example: +Access is restricted such that only a browser running on the same machine as +Pyramid will be able to access your Pyramid application. However, if you want +to open access to other machines on the same network, then edit the +``development.ini`` file, and replace the ``listen`` value in the +``[server:main]`` section, changing it from ``localhost:6543`` to ``*:6543`` +(this is equivalent to ``0.0.0.0:6543 [::]:6543``). For example: .. code-block:: ini - [server:main] - use = egg:waitress#main - host = 127.0.0.1 - port = 6543 + [server:main] + use = egg:waitress#main + listen = *:6543 + +Now when you use ``pserve`` to start the application, it will respond to +requests on *all* IP addresses possessed by your system, not just requests to +``localhost``. This is what the ``0.0.0.0`` in +``serving on http://0.0.0.0:6543`` means. The server will respond to requests +made to ``127.0.0.1`` and on any external IP address. For example, your system +might be configured to have an external IP address ``192.168.1.50``. If that's +the case, if you use a browser running on the same system as Pyramid, it will +be able to access the application via ``http://127.0.0.1:6543/`` as well as via +``http://192.168.1.50:6543/``. However, *other people* on other computers on +the same network will also be able to visit your Pyramid application in their +browser by visiting ``http://192.168.1.50:6543/``. The same holds true if you use +IPv6. ``[::]`` means the same as ``0.0.0.0`` but for IPv6 protocol. You can change the port on which the server runs on by changing the same portion of the ``development.ini`` file. For example, you can change the -``port = 6543`` line in the ``development.ini`` file's ``[server:main]`` -section to ``port = 8080`` to run the server on port 8080 instead of -port 6543. +``listen = localhost:6543`` line in the ``development.ini`` file's ``[server:main]`` +section to ``listen = localhost:8080`` to run the server on port 8080 instead of port 6543. -You can shut down a server started this way by pressing ``Ctrl-C``. +You can shut down a server started this way by pressing ``Ctrl-C`` (or +``Ctrl-Break`` on Windows). The default server used to run your Pyramid application when a project is -created from a scaffold is named :term:`Waitress`. This server is what -prints the ``serving on...`` line when you run ``pserve``. It's a good idea -to use this server during development, because it's very simple. It can also -be used for light production. Setting your application up under a different -server is not advised until you've done some development work under the -default server, particularly if you're not yet experienced with Python web -development. Python web server setup can be complex, and you should get some -confidence that your application works in a default environment before trying -to optimize it or make it "more like production". It's awfully easy to get -sidetracked trying to set up a nondefault server for hours without actually -starting to do any development. One of the nice things about Python web -servers is that they're largely interchangeable, so if your application works -under the default server, it will almost certainly work under any other -server in production if you eventually choose to use a different one. Don't -worry about it right now. +created from a cookiecutter is named :term:`Waitress`. This server is what prints +the ``Serving on...`` line when you run ``pserve``. It's a good idea to use +this server during development because it's very simple. It can also be used +for light production. Setting your application up under a different server is +not advised until you've done some development work under the default server, +particularly if you're not yet experienced with Python web development. Python +web server setup can be complex, and you should get some confidence that your +application works in a default environment before trying to optimize it or make +it "more like production". It's awfully easy to get sidetracked trying to set +up a non-default server for hours without actually starting to do any +development. One of the nice things about Python web servers is that they're +largely interchangeable, so if your application works under the default server, +it will almost certainly work under any other server in production if you +eventually choose to use a different one. Don't worry about it right now. For more detailed information about the startup process, see :ref:`startup_chapter`. For more information about environment variables and @@ -338,36 +391,38 @@ configuration file settings that influence startup and runtime behavior, see Reloading Code ~~~~~~~~~~~~~~ -During development, it's often useful to run ``pserve`` using its -``--reload`` option. When ``--reload`` is passed to ``pserve``, changes to -any Python module your project uses will cause the server to restart. This -typically makes development easier, as changes to Python code made within a +During development, it's often useful to run ``pserve`` using its ``--reload`` +option. When ``--reload`` is passed to ``pserve``, changes to any Python +module your project uses will cause the server to restart. This typically +makes development easier, as changes to Python code made within a :app:`Pyramid` application is not put into effect until the server restarts. -For example, on UNIX: +For example, on Unix: .. code-block:: text - $ $VENV/bin/pserve development.ini --reload - Starting subprocess with file monitor - Starting server in PID 16601. - serving on http://0.0.0.0:6543 + $VENV/bin/pserve development.ini --reload + Starting subprocess with file monitor + Starting server in PID 16601. + Serving on http://localhost:6543 + Serving on http://localhost:6543 Now if you make a change to any of your project's ``.py`` files or ``.ini`` files, you'll see the server restart automatically: .. code-block:: text - development.ini changed; reloading... - -------------------- Restarting -------------------- - Starting server in PID 16602. - serving on http://0.0.0.0:6543 + development.ini changed; reloading... + -------------------- Restarting -------------------- + Starting server in PID 16602. + Serving on http://localhost:6543 + Serving on http://localhost:6543 Changes to template files (such as ``.pt`` or ``.mak`` files) won't cause the -server to restart. Changes to template files don't require a server restart -as long as the ``pyramid.reload_templates`` setting in the -``development.ini`` file is ``true``. Changes made to template files when -this setting is true will take effect immediately without a server restart. +server to restart. Changes to template files don't require a server restart as +long as the ``pyramid.reload_templates`` setting in the ``development.ini`` +file is ``true``. Changes made to template files when this setting is ``true`` +will take effect immediately without a server restart. .. index:: single: WSGI @@ -381,8 +436,8 @@ browser like what is displayed in the following image: .. image:: project.png -This is the page shown by default when you visit an unmodified ``pcreate`` -generated ``starter`` application in a browser. +This is the page shown by default when you visit an unmodified ``cookiecutter`` +generated ``pyramid-cookiecutter-starter`` application in a browser. .. index:: single: debug toolbar @@ -392,71 +447,70 @@ generated ``starter`` application in a browser. The Debug Toolbar ~~~~~~~~~~~~~~~~~ -If you click on the image shown at the right hand top of the page ("^DT"), -you'll be presented with a debug toolbar that provides various niceties while -you're developing. This image will float above every HTML page served by -:app:`Pyramid` while you develop an application, and allows you show the -toolbar as necessary. Click on ``Hide`` to hide the toolbar and show the -image again. +.. image:: project-show-toolbar.png + +If you click on the :app:`Pyramid` logo at the top right of the page, a new +target window will open to present a debug toolbar that provides various +niceties while you're developing. This logo will float above every HTML page +served by :app:`Pyramid` while you develop an application, and allows you to +show the toolbar as necessary. .. image:: project-debug.png -If you don't see the debug toolbar image on the right hand top of the page, -it means you're browsing from a system that does not have debugging access. -By default, for security reasons, only a browser originating from -``localhost`` (``127.0.0.1``) can see the debug toolbar. To allow your -browser on a remote system to access the server, add a line within the -``[app:main]`` section of the ``development.ini`` file in the form -``debugtoolbar.hosts = X.X.X.X``. For example, if your Pyramid application -is running on a remote system, and you're browsing from a host with the IP -address ``192.168.1.1``, you'd add something like this to enable the toolbar -when your system contacts Pyramid: +If you don't see the Pyramid logo on the top right of the page, it means you're +browsing from a system that does not have debugging access. By default, for +security reasons, only a browser originating from ``localhost`` (``127.0.0.1``) +can see the debug toolbar. To allow your browser on a remote system to access +the server, add a line within the ``[app:main]`` section of the +``development.ini`` file in the form ``debugtoolbar.hosts = X .X.X.X``. For +example, if your Pyramid application is running on a remote system, and you're +browsing from a host with the IP address ``192.168.1.1``, you'd add something +like this to enable the toolbar when your system contacts Pyramid: .. code-block:: ini - [app:main] - # .. other settings ... - debugtoolbar.hosts = 192.168.1.1 + [app:main] + # .. other settings ... + debugtoolbar.hosts = 192.168.1.1 -For more information about what the debug toolbar allows you to do, see `the -documentation for pyramid_debugtoolbar -<http://docs.pylonsproject.org/projects/pyramid_debugtoolbar/en/latest/>`_. +For more information about what the debug toolbar allows you to do, see the +:ref:`documentation for pyramid_debugtoolbar <toolbar:overview>`. -The debug toolbar will not be shown (and all debugging will be turned off) -when you use the ``production.ini`` file instead of the ``development.ini`` -ini file to run the application. +The debug toolbar will not be shown (and all debugging will be turned off) when +you use the ``production.ini`` file instead of the ``development.ini`` ini file +to run the application. You can also turn the debug toolbar off by editing ``development.ini`` and commenting out a line. For example, instead of: .. code-block:: ini - :linenos: + :linenos: - [app:main] - ... - pyramid.includes = - pyramid_debugtoolbar + [app:main] + # ... elided configuration + pyramid.includes = + pyramid_debugtoolbar Put a hash mark at the beginning of the ``pyramid_debugtoolbar`` line: .. code-block:: ini - :linenos: + :linenos: - [app:main] - ... - pyramid.includes = - # pyramid_debugtoolbar + [app:main] + # ... elided configuration + pyramid.includes = + # pyramid_debugtoolbar Then restart the application to see that the toolbar has been turned off. Note that if you comment out the ``pyramid_debugtoolbar`` line, the ``#`` -*must* be in the first column. If you put it anywhere else, -and then attempt to restart the application, -you'll receive an error that ends something like this: +*must* be in the first column. If you put it anywhere else, and then attempt +to restart the application, you'll receive an error that ends something like +this: .. code-block:: text - ImportError: No module named #pyramid_debugtoolbar + ImportError: No module named #pyramid_debugtoolbar .. index:: single: project structure @@ -464,168 +518,178 @@ you'll receive an error that ends something like this: The Project Structure --------------------- -The ``starter`` scaffold generated a :term:`project` (named ``MyProject``), +The ``pyramid-cookiecutter-starter`` cookiecutter generated a :term:`project` (named ``myproject``), which contains a Python :term:`package`. The package is *also* named -``myproject``, but it's lowercased; the scaffold generates a project which -contains a package that shares its name except for case. +``myproject``; the cookiecutter generates a project which +contains a package that shares its name. -All :app:`Pyramid` ``pcreate`` -generated projects share a similar structure. -The ``MyProject`` project we've generated has the following directory -structure: +All :app:`Pyramid` ``cookiecutter``-generated projects share a similar structure. +The ``myproject`` project we've generated has the following directory structure: .. code-block:: text - MyProject/ - |-- CHANGES.txt - |-- development.ini - |-- MANIFEST.in - |-- myproject - | |-- __init__.py - | |-- static - | | |-- pyramid-16x16.png - | | |-- pyramid.png - | | |-- theme.css - | | `-- theme.min.css - | |-- templates - | | `-- mytemplate.pt - | |-- tests.py - | `-- views.py - |-- production.ini - |-- README.txt - `-- setup.py - -The ``MyProject`` :term:`Project` + 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 + │ ├── __init__.py + │ ├── default.py + │ └── notfound.py + ├── README.txt + ├── development.ini + ├── production.ini + ├── pytest.ini + └── setup.py + + +The ``myproject`` :term:`Project` --------------------------------- -The ``MyProject`` :term:`project` directory is the distribution and -deployment wrapper for your application. It contains both the ``myproject`` +The ``myproject`` :term:`project` directory is the distribution and deployment +wrapper for your application. It contains both the ``myproject`` :term:`package` representing your application as well as files used to describe, run, and test your application. -#. ``CHANGES.txt`` describes the changes you've made to the application. It - is conventionally written in :term:`ReStructuredText` format. - -#. ``README.txt`` describes the application in general. It is conventionally - written in :term:`ReStructuredText` format. +#. ``.coveragerc`` configures coverage when running tests. -#. ``development.ini`` is a :term:`PasteDeploy` configuration file that can - be used to execute your application during development. +#. ``.gitignore`` tells git which files and directories to ignore from source code version control. -#. ``production.ini`` is a :term:`PasteDeploy` configuration file that can - be used to execute your application in a production configuration. +#. ``CHANGES.txt`` describes the changes you've made to the application. It is + conventionally written in :term:`reStructuredText` format. #. ``MANIFEST.in`` is a :term:`distutils` "manifest" file, naming which files should be included in a source distribution of the package when ``python setup.py sdist`` is run. -#. ``setup.py`` is the file you'll use to test and distribute your - application. It is a standard :term:`setuptools` ``setup.py`` file. +#. ``README.txt`` describes the application in general. It is conventionally + written in :term:`reStructuredText` format. + +#. ``development.ini`` is a :term:`PasteDeploy` configuration file that can be + used to execute your application during development. + +#. ``production.ini`` is a :term:`PasteDeploy` configuration file that can be + used to execute your application in a production configuration. + +#. ``pytest.ini`` is a configuration file for running tests. + +#. ``setup.py`` is the file you'll use to test and distribute your application. + It is a standard :term:`Setuptools` ``setup.py`` file. .. index:: single: PasteDeploy single: ini file -.. _MyProject_ini: +.. _myproject_ini: ``development.ini`` ~~~~~~~~~~~~~~~~~~~ -The ``development.ini`` file is a :term:`PasteDeploy` configuration file. -Its purpose is to specify an application to run when you invoke ``pserve``, -as well as the deployment settings provided to that application. +The ``development.ini`` file is a :term:`PasteDeploy` configuration file. Its +purpose is to specify an application to run when you invoke ``pserve``, as well +as the deployment settings provided to that application. The generated ``development.ini`` file looks like so: -.. literalinclude:: MyProject/development.ini +.. literalinclude:: myproject/development.ini :language: ini :linenos: This file contains several sections including ``[app:main]``, -``[server:main]`` and several other sections related to logging -configuration. +``[server:main]``, and several other sections related to logging configuration. The ``[app:main]`` section represents configuration for your :app:`Pyramid` -application. The ``use`` setting is the only setting required to be present -in the ``[app:main]`` section. Its default value, ``egg:MyProject``, -indicates that our MyProject project contains the application that should be -served. Other settings added to this section are passed as keyword arguments -to the function named ``main`` in our package's ``__init__.py`` module. You -can provide startup-time configuration parameters to your application by -adding more settings to this section. +application. The ``use`` setting is the only setting required to be present in +the ``[app:main]`` section. Its default value, ``egg:myproject``, indicates +that our myproject project contains the application that should be served. +Other settings added to this section are passed as keyword arguments to the +function named ``main`` in our package's ``__init__.py`` module. You can +provide startup-time configuration parameters to your application by adding +more settings to this section. -.. note:: See :ref:`pastedeploy_entry_points` for more information about the - meaning of the ``use = egg:MyProject`` value in this section. +.. seealso:: See :ref:`pastedeploy_entry_points` for more information about the + meaning of the ``use = egg:myproject`` value in this section. The ``pyramid.reload_templates`` setting in the ``[app:main]`` section is a -:app:`Pyramid` -specific setting which is passed into the framework. If it -exists, and its value is ``true``, supported template changes will not -require an application restart to be detected. See -:ref:`reload_templates_section` for more information. +:app:`Pyramid`-specific setting which is passed into the framework. If it +exists, and its value is ``true``, supported template changes will not require +an application restart to be detected. See :ref:`reload_templates_section` for +more information. .. warning:: The ``pyramid.reload_templates`` option should be turned off for production applications, as template rendering is slowed when it is turned on. -The ``pyramid.includes`` setting in the ``[app:main]`` section tells Pyramid -to "include" configuration from another package. In this case, the line +The ``pyramid.includes`` setting in the ``[app:main]`` section tells Pyramid to +"include" configuration from another package. In this case, the line ``pyramid.includes = pyramid_debugtoolbar`` tells Pyramid to include configuration from the ``pyramid_debugtoolbar`` package. This turns on a -debugging panel in development mode which will be shown on the right hand -side of the screen. Including the debug toolbar will also make it possible -to interactively debug exceptions when an error occurs. +debugging panel in development mode which can be opened by clicking on the +:app:`Pyramid` logo on the top right of the screen. Including the debug +toolbar will also make it possible to interactively debug exceptions when an +error occurs. -Various other settings may exist in this section having to do with debugging -or influencing runtime behavior of a :app:`Pyramid` application. See +Various other settings may exist in this section having to do with debugging or +influencing runtime behavior of a :app:`Pyramid` application. See :ref:`environment_chapter` for more information about these settings. The name ``main`` in ``[app:main]`` signifies that this is the default application run by ``pserve`` when it is invoked against this configuration -file. The name ``main`` is a convention used by PasteDeploy signifying that -it is the default application. +file. The name ``main`` is a convention used by PasteDeploy signifying that it +is the default application. The ``[server:main]`` section of the configuration file configures a WSGI -server which listens on TCP port 6543. It is configured to listen on all -interfaces (``0.0.0.0``). This means that any remote system which has TCP -access to your system can see your Pyramid application. - -.. _MyProject_ini_logging: - -The sections that live between the markers ``# Begin logging configuration`` -and ``# End logging configuration`` represent Python's standard library -:mod:`logging` module configuration for your application. The sections -between these two markers are passed to the `logging module's config file -configuration engine -<http://docs.python.org/howto/logging.html#configuring-logging>`_ when the -``pserve`` or ``pshell`` commands are executed. The default -configuration sends application logging output to the standard error output -of your terminal. For more information about logging configuration, see -:ref:`logging_chapter`. +server which listens on TCP port 6543. It is configured to listen on localhost +only (``127.0.0.1``). + +.. _myproject_ini_logging: + +The sections after ``# logging configuration`` represent Python's standard +library :mod:`logging` module configuration for your application. These +sections are passed to the `logging module's config file configuration engine +<https://docs.python.org/2/howto/logging.html#configuring-logging>`_ when the +``pserve`` or ``pshell`` commands are executed. The default configuration +sends application logging output to the standard error output of your terminal. +For more information about logging configuration, see :ref:`logging_chapter`. See the :term:`PasteDeploy` documentation for more information about other types of things you can put into this ``.ini`` file, such as other -applications, :term:`middleware` and alternate :term:`WSGI` server +applications, :term:`middleware`, and alternate :term:`WSGI` server implementations. .. index:: single: production.ini ``production.ini`` -~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~ -The ``production.ini`` file is a :term:`PasteDeploy` configuration file with -a purpose much like that of ``development.ini``. However, it disables the -debug toolbar, and filters all log messages except those above the WARN -level. It also turns off template development options such that templates -are not automatically reloaded when changed, and turns off all debugging -options. This file is appropriate to use instead of ``development.ini`` when -you put your application into production. +The ``production.ini`` file is a :term:`PasteDeploy` configuration file with a +purpose much like that of ``development.ini``. However, it disables the debug +toolbar, and filters all log messages except those above the WARN level. It +also turns off template development options such that templates are not +automatically reloaded when changed, and turns off all debugging options. This +file is appropriate to use instead of ``development.ini`` when you put your +application into production. It's important to use ``production.ini`` (and *not* ``development.ini``) to benchmark your application and put it into production. ``development.ini`` configures your system with a debug toolbar that helps development, but the inclusion of this toolbar slows down page rendering times by over an order of -magnitude. The debug toolbar is also a potential security risk if you have -it configured incorrectly. +magnitude. The debug toolbar is also a potential security risk if you have it +configured incorrectly. .. index:: single: MANIFEST.in @@ -637,42 +701,40 @@ The ``MANIFEST.in`` file is a :term:`distutils` configuration file which specifies the non-Python files that should be included when a :term:`distribution` of your Pyramid project is created when you run ``python setup.py sdist``. Due to the information contained in the default -``MANIFEST.in``, an sdist of your Pyramid project will include ``.txt`` -files, ``.ini`` files, ``.rst`` files, graphics files, and template files, as -well as ``.py`` files. See -http://docs.python.org/distutils/sourcedist.html#the-manifest-in-template for -more information about the syntax and usage of ``MANIFEST.in``. - -Without the presence of a ``MANIFEST.in`` file or without checking your -source code into a version control repository, ``setup.py sdist`` places only -*Python source files* (files ending with a ``.py`` extension) into tarballs -generated by ``python setup.py sdist``. This means, for example, if your -project was not checked into a setuptools-compatible source control system, -and your project directory didn't contain a ``MANIFEST.in`` file that told -the ``sdist`` machinery to include ``*.pt`` files, the -``myproject/templates/mytemplate.pt`` file would not be included in the -generated tarball. - -Projects generated by Pyramid scaffolds include a default ``MANIFEST.in`` -file. The ``MANIFEST.in`` file contains declarations which tell it to -include files like ``*.pt``, ``*.css`` and ``*.js`` in the generated tarball. -If you include files with extensions other than the files named in the -project's ``MANIFEST.in`` and you don't make use of a setuptools-compatible -version control system, you'll need to edit the ``MANIFEST.in`` file and -include the statements necessary to include your new files. See -http://docs.python.org/distutils/sourcedist.html#principle for more +``MANIFEST.in``, an sdist of your Pyramid project will include ``.txt`` files, +``.ini`` files, ``.rst`` files, graphics files, and template files, as well as +``.py`` files. See +https://docs.python.org/2/distutils/sourcedist.html#the-manifest-in-template +for more information about the syntax and usage of ``MANIFEST.in``. + +Without the presence of a ``MANIFEST.in`` file or without checking your source +code into a version control repository, ``setup.py sdist`` places only *Python +source files* (files ending with a ``.py`` extension) into tarballs generated +by ``python setup.py sdist``. This means, for example, if your project was not +checked into a Setuptools-compatible source control system, and your project +directory didn't contain a ``MANIFEST.in`` file that told the ``sdist`` +machinery to include ``*.pt`` files, the ``myproject/templates/mytemplate.pt`` +file would not be included in the generated tarball. + +Projects generated by Pyramid cookiecutters include a default ``MANIFEST.in`` file. +The ``MANIFEST.in`` file contains declarations which tell it to include files +like ``*.pt``, ``*.css`` and ``*.js`` in the generated tarball. If you include +files with extensions other than the files named in the project's +``MANIFEST.in`` and you don't make use of a Setuptools-compatible version +control system, you'll need to edit the ``MANIFEST.in`` file and include the +statements necessary to include your new files. See +https://docs.python.org/2/distutils/sourcedist.html#principle for more information about how to do this. -You can also delete ``MANIFEST.in`` from your project and rely on a -setuptools feature which simply causes all files checked into a version -control system to be put into the generated tarball. To allow this to -happen, check all the files that you'd like to be distributed along with your -application's Python files into Subversion. After you do this, when you -rerun ``setup.py sdist``, all files checked into the version control system -will be included in the tarball. If you don't use Subversion, and instead -use a different version control system, you may need to install a setuptools -add-on such as ``setuptools-git`` or ``setuptools-hg`` for this behavior to -work properly. +You can also delete ``MANIFEST.in`` from your project and rely on a :term:`Setuptools` +feature which simply causes all files checked into a version control system to +be put into the generated tarball. To allow this to happen, check all the +files that you'd like to be distributed along with your application's Python +files into Subversion. After you do this, when you rerun ``setup.py sdist``, +all files checked into the version control system will be included in the +tarball. If you don't use Subversion, and instead use a different version +control system, you may need to install a :term:`Setuptools` add-on such as +``setuptools-git`` or ``setuptools-hg`` for this behavior to work properly. .. index:: single: setup.py @@ -680,66 +742,65 @@ work properly. ``setup.py`` ~~~~~~~~~~~~ -The ``setup.py`` file is a :term:`setuptools` setup file. It is meant to be -run directly from the command line to perform a variety of functions, such as -testing, packaging, and distributing your application. +The ``setup.py`` file is a :term:`Setuptools` setup file. It is meant to be +used to define requirements for installing dependencies for your package and +testing, as well as distributing your application. .. note:: - ``setup.py`` is the de facto standard which Python developers use to - distribute their reusable code. You can read more about ``setup.py`` files - and their usage in the `Setuptools documentation - <http://peak.telecommunity.com/DevCenter/setuptools>`_ and `The - Hitchhiker's Guide to Packaging <http://guide.python-distribute.org/>`_. + ``setup.py`` is the de facto standard which Python developers use to + distribute their reusable code. You can read more about ``setup.py`` files + and their usage in the `Python Packaging User Guide + <https://packaging.python.org/>`_ and `Setuptools documentation + <https://setuptools.readthedocs.io/en/latest/>`_. Our generated ``setup.py`` looks like this: -.. literalinclude:: MyProject/setup.py +.. literalinclude:: myproject/setup.py :language: python :linenos: -The ``setup.py`` file calls the setuptools ``setup`` function, which does -various things depending on the arguments passed to ``setup.py`` on the -command line. +The ``setup.py`` file calls the :term:`Setuptools` ``setup`` function, which does +various things depending on the arguments passed to ``pip`` on the command +line. -Within the arguments to this function call, information about your -application is kept. While it's beyond the scope of this documentation to -explain everything about setuptools setup files, we'll provide a whirlwind -tour of what exists in this file in this section. +Within the arguments to this function call, information about your application +is kept. While it's beyond the scope of this documentation to explain +everything about :term:`Setuptools` setup files, we'll provide a whirlwind tour of what +exists in this file in this section. Your application's name can be any string; it is specified in the ``name`` field. The version number is specified in the ``version`` value. A short -description is provided in the ``description`` field. The -``long_description`` is conventionally the content of the README and CHANGES -file appended together. The ``classifiers`` field is a list of `Trove -<http://pypi.python.org/pypi?%3Aaction=list_classifiers>`_ classifiers -describing your application. ``author`` and ``author_email`` are text fields -which probably don't need any description. ``url`` is a field that should -point at your application project's URL (if any). -``packages=find_packages()`` causes all packages within the project to be -found when packaging the application. ``include_package_data`` will include -non-Python files when the application is packaged if those files are checked -into version control. ``zip_safe`` indicates that this package is not safe -to use as a zipped egg; instead it will always unpack as a directory, which -is more convenient. ``install_requires`` and ``tests_require`` indicate that -this package depends on the ``pyramid`` package. ``test_suite`` points at -the package for our application, which means all tests found in the package -will be run when ``setup.py test`` is invoked. We examined ``entry_points`` -in our discussion of the ``development.ini`` file; this file defines the -``main`` entry point that represents our project's application. - -Usually you only need to think about the contents of the ``setup.py`` file -when distributing your application to other people, when adding Python -package dependencies, or when versioning your application for your own use. -For fun, you can try this command now: +description is provided in the ``description`` field. The ``long_description`` +is conventionally the content of the ``README`` and ``CHANGES`` files appended +together. The ``classifiers`` field is a list of `Trove classifiers +<https://pypi.org/pypi?%3Aaction=list_classifiers>`_ describing your +application. ``author`` and ``author_email`` are text fields which probably +don't need any description. ``url`` is a field that should point at your +application project's URL (if any). ``packages=find_packages()`` causes all +packages within the project to be found when packaging the application. +``include_package_data`` will include non-Python files when the application is +packaged if those files are checked into version control. ``zip_safe=False`` +indicates that this package is not safe to use as a zipped egg; instead it will +always unpack as a directory, which is more convenient. ``install_requires`` +indicates that this package depends on the ``pyramid`` package. +``extras_require`` is a Python dictionary that defines what is required to be +installed for running tests. We examined ``entry_points`` in our discussion of +the ``development.ini`` file; this file defines the ``main`` entry point that +represents our project's application. + +Usually you only need to think about the contents of the ``setup.py`` file when +distributing your application to other people, when adding Python package +dependencies, or when versioning your application for your own use. For fun, +you can try this command now: .. code-block:: text - $ python setup.py sdist + $VENV/bin/python setup.py sdist -This will create a tarball of your application in a ``dist`` subdirectory -named ``MyProject-0.1.tar.gz``. You can send this tarball to other people -who want to install and use your application. +This will create a tarball of your application in a ``dist`` subdirectory named +``myproject-0.0.tar.gz``. You can send this tarball to other people who want +to install and use your application. .. index:: single: package @@ -747,28 +808,29 @@ who want to install and use your application. The ``myproject`` :term:`Package` --------------------------------- -The ``myproject`` :term:`package` lives inside the ``MyProject`` +The ``myproject`` :term:`package` lives inside the ``myproject`` :term:`project`. It contains: -#. An ``__init__.py`` file signifies that this is a Python :term:`package`. - It also contains code that helps users run the application, including a +#. An ``__init__.py`` file signifies that this is a Python :term:`package`. It + also contains code that helps users run the application, including a ``main`` function which is used as a entry point for commands such as ``pserve``, ``pshell``, ``pviews``, and others. -#. A ``templates`` directory, which contains :term:`Chameleon` (or - other types of) templates. +#. A ``templates`` directory, which contains :term:`Jinja2` (or other types + of) templates. + +#. A ``tests.py`` module, which contains unit test code for the application. + +#. A ``routes.py`` module, which contains routing code for the application. -#. A ``tests.py`` module, which contains unit test code for the - application. +#. A ``views`` package, which contains view code for the application. -#. A ``views.py`` module, 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 scaffold: -:app:`Pyramid` doesn't insist that you name things in any particular way. -However, it's generally a good idea to follow Pyramid standards for naming, -so that other Pyramid developers can get up to speed quickly on your code -when you need help. +These are purely conventions established by the cookiecutter. :app:`Pyramid` +doesn't insist that you name things in any particular way. However, it's +generally a good idea to follow Pyramid standards for naming, so that other +Pyramid developers can get up to speed quickly on your code when you need help. .. index:: single: __init__.py @@ -783,7 +845,7 @@ advertises an entry point for use by our :term:`PasteDeploy` ``.ini`` file. This is the file named ``__init__.py``. The presence of an ``__init__.py`` also informs Python that the directory which contains it is a *package*. -.. literalinclude:: MyProject/myproject/__init__.py +.. literalinclude:: myproject/myproject/__init__.py :language: python :linenos: @@ -796,90 +858,120 @@ also informs Python that the directory which contains it is a *package*. Within this function, application configuration is performed. - Line 7 creates an instance of a :term:`Configurator`. + Line 7 opens a context manager with an instance of a :term:`Configurator`. - Line 8 adds support for Chameleon templating bindings, allowing us to - specify renderers with the ``.pt`` extension. + 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`. +application developer; it is a bit of code which accepts a :term:`request` and +which returns a :term:`response`. + +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. -.. literalinclude:: MyProject/myproject/views.py +We have two view modules in the ``views`` package. +Let's look at ``default.py``. + +.. literalinclude:: myproject/myproject/views/default.py :language: python :linenos: 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 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 a :term:`asset -specification` that specifies the ``mytemplate.pt`` 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 -optional. The template file pointed to is a :term:`Chameleon` ZPT -template file (``templates/my_template.pt``). +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 ``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.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.jinja2``; the leading package name and colon is +optional. The template file pointed to is a :term:`Jinja2` template +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`` class representing the browser's request to our server. +:term:`request`. The *request* is an instance of the :term:`WebOb` ``Request`` +class representing the browser's request to our server. This view is configured to invoke a :term:`renderer` on a template. The dictionary the view returns (on line 6) provides the value the renderer -substitutes into the template when generating HTML. The renderer then -returns the HTML in a :term:`response`. +substitutes into the template when generating HTML. The renderer then returns +the HTML in a :term:`response`. .. note:: Dictionaries provide values to :term:`template`\s. -.. note:: When the application is run with the scaffold's :ref:`default - development.ini <MyProject_ini>` configuration :ref:`logging is set up - <MyProject_ini_logging>` to aid debugging. If an exception is raised, +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 <myproject_ini>` configuration, :ref:`logging is set up + <myproject_ini_logging>` to aid debugging. If an exception is raised, uncaught tracebacks are displayed after the startup messages on :ref:`the console running the server <running_the_project_application>`. Also - ``print()`` statements may be inserted into the application for debugging - to send output to this console. + ``print()`` statements may be inserted into the application for debugging to + send output to this console. .. note:: ``development.ini`` has a setting that controls how templates are reloaded, ``pyramid.reload_templates``. - - When set to ``True`` (as in the scaffold ``development.ini``) changed + - When set to ``True`` (as in the cookiecutter ``development.ini``), changed templates automatically reload without a server restart. This is convenient while developing, but slows template rendering speed. - - When set to ``False`` (the default value), changing templates requires - a server restart to reload them. Production applications should use + - When set to ``False`` (the default value), changing templates requires a + server restart to reload them. Production applications should use ``pyramid.reload_templates = False``. .. seealso:: - See also :ref:`views_which_use_a_renderer` for more information - about how views, renderers, and templates relate and cooperate. + See also :ref:`views_which_use_a_renderer` for more information about how + views, renderers, and templates relate and cooperate. .. seealso:: @@ -899,38 +991,65 @@ returns the HTML in a :term:`response`. ``static`` ~~~~~~~~~~ -This directory contains static assets which support the ``mytemplate.pt`` +This directory contains static assets which support the ``layout.jinja2`` template. It includes CSS and images. -``templates/mytemplate.pt`` + +``templates/layout.jinja2`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The single :term:`Chameleon` template that exists in the project. Its -contents are too long to show here, but it displays a default page when -rendered. It is referenced by the call to ``@view_config`` as the -``renderer`` of the ``my_view`` view callable in the ``views.py`` file. See -:ref:`views_which_use_a_renderer` for more information about renderers. +This is the base layout content. It contains a single marker for content block. Other templates inherit its content, providing layout for the web application. Its contents are too long to show here, but here is an excerpt: + +.. literalinclude:: myproject/myproject/templates/layout.jinja2 + :language: jinja + :lines: 34-38 + :lineno-match: + + +``templates/mytemplate.jinja2`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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/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 + :language: jinja + :linenos: Templates are accessed and used by view configurations and sometimes by view 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 ``tests.py`` ~~~~~~~~~~~~ -The ``tests.py`` module includes unit tests for your application. +The ``tests.py`` module includes tests for your application. -.. literalinclude:: MyProject/myproject/tests.py +.. literalinclude:: myproject/myproject/tests.py :language: python :linenos: -This sample ``tests.py`` file has a single unit test defined within it. This -test is executed when you run ``python setup.py test``. You may add more -tests here as you build your application. You are not required to write -tests to use :app:`Pyramid`, this file is simply provided as convenience and +This sample ``tests.py`` file has one unit test and one functional test defined +within it. These tests are executed when you run ``pytest -q``. You may add +more tests here as you build your application. You are not required to write +tests to use :app:`Pyramid`. This file is simply provided for convenience and example. See :ref:`testing_chapter` for more information about writing :app:`Pyramid` @@ -942,107 +1061,126 @@ unit tests. .. _modifying_package_structure: Modifying Package Structure ----------------------------- +--------------------------- It is best practice for your application's code layout to not stray too much -from accepted Pyramid scaffold defaults. If you refrain from changing -things very much, other Pyramid coders will be able to more quickly -understand your application. However, the code layout choices made for you -by a scaffold are in no way magical or required. Despite the choices -made for you by any scaffold, you can decide to lay your code out any -way you see fit. +from accepted Pyramid cookiecutter defaults. If you refrain from changing things +very much, other Pyramid coders will be able to more quickly understand your +application. However, the code layout choices made for you by a cookiecutter are +in no way magical or required. Despite the choices made for you by any +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`` scaffold 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: - -- 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 to register views in conjunction with -``config.scan()`` they will be picked up automatically when the application -is restarted. +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. Using the Interactive Shell --------------------------- It is possible to use the ``pshell`` command to load a Python interpreter -prompt with a similar configuration as would be loaded if you were running -your Pyramid application via ``pserve``. This can be a useful debugging tool. -See :ref:`interactive_shell` for more details. +prompt with a similar configuration as would be loaded if you were running your +Pyramid application via ``pserve``. This can be a useful debugging tool. See +:ref:`interactive_shell` for more details. .. _what_is_this_pserve_thing: What Is This ``pserve`` Thing ----------------------------- -The code generated by an :app:`Pyramid` scaffold assumes that you will be -using the ``pserve`` command to start your application while you do -development. ``pserve`` is a command that reads a :term:`PasteDeploy` -``.ini`` file (e.g. ``development.ini``) and configures a server to serve a -Pyramid application based on the data in the file. +The code generated by a :app:`Pyramid` cookiecutter assumes that you will be using +the ``pserve`` command to start your application while you do development. +``pserve`` is a command that reads a :term:`PasteDeploy` ``.ini`` file (e.g., +``development.ini``), and configures a server to serve a :app:`Pyramid` +application based on the data in the file. ``pserve`` is by no means the only way to start up and serve a :app:`Pyramid` application. As we saw in :ref:`firstapp_chapter`, ``pserve`` needn't be invoked at all to run a :app:`Pyramid` application. The use of ``pserve`` to -run a :app:`Pyramid` application is purely conventional based on the output -of its scaffolding. But we strongly recommend using ``pserve`` while -developing your application, because many other convenience introspection -commands (such as ``pviews``, ``prequest``, ``proutes`` and others) are also -implemented in terms of configuration availability of this ``.ini`` file -format. It also configures Pyramid logging and provides the ``--reload`` -switch for convenient restarting of the server when code changes. +run a :app:`Pyramid` application is purely conventional based on the output of +its cookiecutter. But we strongly recommend using ``pserve`` while developing +your application because many other convenience introspection commands (such as +``pviews``, ``prequest``, ``proutes``, and others) are also implemented in +terms of configuration availability of this ``.ini`` file format. It also +configures Pyramid logging and provides the ``--reload`` switch for convenient +restarting of the server when code changes. .. _alternate_wsgi_server: Using an Alternate WSGI Server ------------------------------ -Pyramid scaffolds generate projects which use the :term:`Waitress` WSGI -server. Waitress is a server that is suited for development and light -production usage. It's not the fastest nor the most featureful WSGI server. -Instead, its main feature is that it works on all platforms that Pyramid -needs to run on, making it a good choice as a default server from the -perspective of Pyramid's developers. +Pyramid cookiecutters generate projects which use the :term:`Waitress` WSGI server. +Waitress is a server that is suited for development and light production +usage. It's not the fastest nor the most featureful WSGI server. Instead, its +main feature is that it works on all platforms that Pyramid needs to run on, +making it a good choice as a default server from the perspective of Pyramid's +developers. Any WSGI server is capable of running a :app:`Pyramid` application. But we -suggest you stick with the default server for development, and that you wait -to investigate other server options until you're ready to deploy your -application to production. Unless for some reason you need to develop on a -non-local system, investigating alternate server options is usually a -distraction until you're ready to deploy. But we recommend developing using -the default configuration on a local system that you have complete control -over; it will provide the best development experience. +suggest you stick with the default server for development, and that you wait to +investigate other server options until you're ready to deploy your application +to production. Unless for some reason you need to develop on a non-local +system, investigating alternate server options is usually a distraction until +you're ready to deploy. But we recommend developing using the default +configuration on a local system that you have complete control over; it will +provide the best development experience. One popular production alternative to the default Waitress server is -:term:`mod_wsgi`. You can use mod_wsgi to serve your :app:`Pyramid` -application using the Apache web server rather than any "pure-Python" server -like Waitress. It is fast and featureful. See :ref:`modwsgi_tutorial` for -details. +:term:`mod_wsgi`. You can use ``mod_wsgi`` to serve your :app:`Pyramid` application +using the Apache web server rather than any "pure-Python" server like Waitress. +It is fast and featureful. See :ref:`modwsgi_tutorial` for details. Another good production alternative is :term:`Green Unicorn` (aka -``gunicorn``). It's faster than Waitress and slightly easier to configure -than mod_wsgi, although it depends, in its default configuration, on having a -buffering HTTP proxy in front of it. It does not, as of this writing, work -on Windows. +``gunicorn``). It's faster than Waitress and slightly easier to configure than +``mod_wsgi``, although it depends, in its default configuration, on having a +buffering HTTP proxy in front of it. It does not, as of this writing, work on +Windows. + +Automatically Reloading Your Code +--------------------------------- + +During development, it can be really useful to automatically have the +webserver restart when you make changes. ``pserve`` has a ``--reload`` switch +to enable this. It uses the +`hupper <https://docs.pylonsproject.org/projects/hupper/en/latest/>`_ package +to enable this behavior. When your code crashes, ``hupper`` will wait for +another change or the ``SIGHUP`` signal before restarting again. + +inotify support +~~~~~~~~~~~~~~~ + +By default ``hupper`` will poll the filesystem for changes to all Python +code. This can be pretty inefficient in larger projects. To be nicer to your +hard drive, you should install the +`watchdog <https://pythonhosted.org/watchdog/>`_ package in development. +``hupper`` will automatically use ``watchdog`` to more efficiently poll the +filesystem. + +Monitoring Custom Files +~~~~~~~~~~~~~~~~~~~~~~~ + +By default, ``pserve --reload`` will monitor all imported Python code +(everything in ``sys.modules``) as well as the config file passed to +``pserve`` (e.g., ``development.ini``). You can instruct ``pserve`` to watch +other files for changes as well by defining a ``[pserve]`` section in your +configuration file. For example, let's say your application loads the +``favicon.ico`` file at startup and stores it in memory to efficiently +serve it many times. When you change it, you want ``pserve`` to restart: + +.. code-block:: ini + + [pserve] + watch_files = + myproject/static/favicon.ico + +Paths may be absolute or relative to the configuration file. They may also +be an :term:`asset specification`. These paths are passed to ``hupper``, which +has some basic support for globbing. Acceptable glob patterns depend on the +version of Python being used. |
