summaryrefslogtreecommitdiff
path: root/docs/narr/firstapp.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/narr/firstapp.rst')
-rw-r--r--docs/narr/firstapp.rst341
1 files changed, 133 insertions, 208 deletions
diff --git a/docs/narr/firstapp.rst b/docs/narr/firstapp.rst
index f5adad905..6a952dec9 100644
--- a/docs/narr/firstapp.rst
+++ b/docs/narr/firstapp.rst
@@ -1,111 +1,101 @@
+.. index::
+ single: hello world program
+
.. _firstapp_chapter:
Creating Your First :app:`Pyramid` Application
-=================================================
+==============================================
In this chapter, we will walk through the creation of a tiny :app:`Pyramid`
application. After we're finished creating the application, we'll explain in
-more detail how it works.
+more detail how it works. It assumes you already have :app:`Pyramid` installed.
+If you do not, head over to the :ref:`installing_chapter` section.
.. _helloworld_imperative:
-Hello World, Goodbye World
---------------------------
+Hello World
+-----------
-Here's one of the very simplest :app:`Pyramid` applications, configured
-imperatively:
+Here's one of the very simplest :app:`Pyramid` applications:
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
- from pyramid.config import Configurator
- from pyramid.response import Response
- from paste.httpserver import serve
+When this code is inserted into a Python script named ``helloworld.py`` and
+executed by a Python interpreter which has the :app:`Pyramid` software
+installed, an HTTP server is started on TCP port 8080.
- def hello_world(request):
- return Response('Hello world!')
+On UNIX:
- def goodbye_world(request):
- return Response('Goodbye world!')
+.. code-block:: text
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- config.add_view(goodbye_world, name='goodbye')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
+ $ $VENV/bin/python helloworld.py
-When this code is inserted into a Python script named ``helloworld.py`` and
-executed by a Python interpreter which has the :app:`Pyramid` software
-installed, an HTTP server is started on TCP port 8080:
+On Windows:
.. code-block:: text
- $ python helloworld.py
- serving on 0.0.0.0:8080 view at http://127.0.0.1:8080
+ C:\> %VENV%\Scripts\python.exe helloworld.py
+
+This command will not return and nothing will be printed to the console. When
+port 8080 is visited by a browser on the URL ``/hello/world``, the server will
+simply serve up the text "Hello world!". If your application is running on
+your local system, using `<http://localhost:8080/hello/world>`_ in a browser
+will show this result.
-When port 8080 is visited by a browser on the root URL (``/``), the server
-will simply serve up the text "Hello world!" When visited by a browser on
-the URL ``/goodbye``, the server will serve up the text "Goodbye world!"
+Each time you visit a URL served by the application in a browser, a logging
+line will be emitted to the console displaying the hostname, the date, the
+request method and path, and some additional information. This output is done
+by the wsgiref server we've used to serve this application. It logs an "access
+log" in Apache combined logging format to the console.
-Press ``Ctrl-C`` to stop the application.
+Press ``Ctrl-C`` (or ``Ctrl-Break`` on Windows) to stop the application.
Now that we have a rudimentary understanding of what the application does,
-let's examine it piece-by-piece.
+let's examine it piece by piece.
Imports
~~~~~~~
-The above ``helloworld.py`` script uses the following set of import
-statements:
+The above ``helloworld.py`` script uses the following set of import statements:
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
-
- from pyramid.config import Configurator
- from pyramid.response import Response
- from paste.httpserver import serve
+ :lines: 1-3
The script imports the :class:`~pyramid.config.Configurator` class from the
:mod:`pyramid.config` module. An instance of the
:class:`~pyramid.config.Configurator` class is later used to configure your
:app:`Pyramid` application.
-The script uses the :class:`pyramid.response.Response` class later in the
-script to create a :term:`response` object.
-
Like many other Python web frameworks, :app:`Pyramid` uses the :term:`WSGI`
protocol to connect an application and a web server together. The
-:mod:`paste.httpserver` server is used in this example as a WSGI server for
-convenience, as the ``paste`` package is a dependency of :app:`Pyramid`
-itself.
+:mod:`wsgiref` server is used in this example as a WSGI server for convenience,
+as it is shipped within the Python standard library.
+
+The script also imports the :class:`pyramid.response.Response` class for later
+use. An instance of this class will be used to create a web response.
View Callable Declarations
~~~~~~~~~~~~~~~~~~~~~~~~~~
-The above script, beneath its set of imports, defines two functions: one
-named ``hello_world`` and one named ``goodbye_world``.
+The above script, beneath its set of imports, defines a function named
+``hello_world``.
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
+ :pyobject: hello_world
- def hello_world(request):
- return Response('Hello world!')
+The function accepts a single argument (``request``) and it returns an instance
+of the :class:`pyramid.response.Response` class. The single argument to the
+class' constructor is a string computed from parameters matched from the URL.
+This value becomes the body of the response.
- def goodbye_world(request):
- return Response('Goodbye world!')
-
-These functions don't do anything very difficult. Both functions accept a
-single argument (``request``). The ``hello_world`` function does nothing but
-return a response instance with the body ``Hello world!``. The
-``goodbye_world`` function returns a response instance with the body
-``Goodbye world!``.
-
-Each of these functions is known as a :term:`view callable`. A view callable
-accepts a single argument, ``request``. It is expected to return a
-:term:`response` object. A view callable doesn't need to be a function; it
-can be represented via another type of object, like a class or an instance,
-but for our purposes here, a function serves us well.
+This function is known as a :term:`view callable`. A view callable accepts a
+single argument, ``request``. It is expected to return a :term:`response`
+object. A view callable doesn't need to be a function; it can be represented
+via another type of object, like a class or an instance, but for our purposes
+here, a function serves us well.
A view callable is always called with a :term:`request` object. A request
object is a representation of an HTTP request sent to :app:`Pyramid` via the
@@ -113,18 +103,11 @@ active :term:`WSGI` server.
A view callable is required to return a :term:`response` object because a
response object has all the information necessary to formulate an actual HTTP
-response; this object is then converted to text by the upstream :term:`WSGI`
-server and sent back to the requesting browser. To return a response, each
-view callable creates an instance of the :class:`~pyramid.response.Response`
-class. In the ``hello_world`` function, the string ``'Hello world!'`` is
-passed to the ``Response`` constructor as the *body* of the response. In the
-``goodbye_world`` function, the string ``'Goodbye world!'`` is passed.
-
-.. note:: As we'll see in later chapters, returning a literal
- :term:`response` object from a view callable is not always required; we
- can instead use a :term:`renderer` in our view configurations. If we use
- a renderer, our view callable is allowed to return a value that the
- renderer understands, and the renderer generates a response on our behalf.
+response; this object is then converted to text by the :term:`WSGI` server
+which called Pyramid and it is sent back to the requesting browser. To return
+a response, each view callable creates an instance of the
+:class:`~pyramid.response.Response` class. In the ``hello_world`` function, a
+string is passed as the body to the response.
.. index::
single: imperative configuration
@@ -136,114 +119,63 @@ passed to the ``Response`` constructor as the *body* of the response. In the
Application Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~
-In the above script, the following code represents the *configuration* of
-this simple application. The application is configured using the previously
-defined imports and function definitions, placed within the confines of an
-``if`` statement:
+In the above script, the following code represents the *configuration* of this
+simple application. The application is configured using the previously defined
+imports and function definitions, placed within the confines of an ``if``
+statement:
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
+ :lines: 9-15
- if __name__ == '__main__':
- config = Configurator()
- config.add_view(hello_world)
- config.add_view(goodbye_world, name='goodbye')
- app = config.make_wsgi_app()
- serve(app, host='0.0.0.0')
-
-Let's break this down this piece-by-piece.
+Let's break this down piece by piece.
Configurator Construction
~~~~~~~~~~~~~~~~~~~~~~~~~
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
-
- if __name__ == '__main__':
- config = Configurator()
+ :lines: 9-10
The ``if __name__ == '__main__':`` line in the code sample above represents a
Python idiom: the code inside this if clause is not invoked unless the script
-containing this code is run directly from the command line. For example, if
-the file named ``helloworld.py`` contains the entire script body, the code
-within the ``if`` statement will only be invoked when ``python
-helloworld.py`` is executed from the operating system command line.
-
-``helloworld.py`` in this case is a Python :term:`module`. Using the ``if``
-clause is necessary -- or at least best practice -- because code in any
-Python module may be imported by another Python module. By using this idiom,
-the script is indicating that it does not want the code within the ``if``
-statement to execute if this module is imported; the code within the ``if``
-block should only be run during a direct script execution.
+containing this code is run directly from the operating system command line.
+For example, if the file named ``helloworld.py`` contains the entire script
+body, the code within the ``if`` statement will only be invoked when ``python
+helloworld.py`` is executed from the command line.
+
+Using the ``if`` clause is necessary—or at least best practice—because code in
+a Python ``.py`` file may be eventually imported via the Python ``import``
+statement by another ``.py`` file. ``.py`` files that are imported by other
+``.py`` files are referred to as *modules*. By using the ``if __name__ ==
+'__main__':`` idiom, the script above is indicating that it does not want the
+code within the ``if`` statement to execute if this module is imported from
+another; the code within the ``if`` block should only be run during a direct
+script execution.
The ``config = Configurator()`` line above creates an instance of the
:class:`~pyramid.config.Configurator` class. The resulting ``config`` object
represents an API which the script uses to configure this particular
:app:`Pyramid` application. Methods called on the Configurator will cause
-registrations to be made in a :term:`application registry` associated with
-the application.
+registrations to be made in an :term:`application registry` associated with the
+application.
.. _adding_configuration:
Adding Configuration
~~~~~~~~~~~~~~~~~~~~
-.. ignore-next-block
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
+ :lines: 11-12
+
+The first line above calls the :meth:`pyramid.config.Configurator.add_route`
+method, which registers a :term:`route` to match any URL path that begins with
+``/hello/`` followed by a string.
- config.add_view(hello_world)
- config.add_view(goodbye_world, name='goodbye')
-
-Each of these lines calls the :meth:`pyramid.config.Configurator.add_view`
-method. The ``add_view`` method of a configurator registers a :term:`view
-configuration` within the :term:`application registry`. A :term:`view
-configuration` represents a set of circumstances related to the
-:term:`request` that will cause a specific :term:`view callable` to be
-invoked. This "set of circumstances" is provided as one or more keyword
-arguments to the ``add_view`` method. Each of these keyword arguments is
-known as a view configuration :term:`predicate`.
-
-The line ``config.add_view(hello_world)`` registers the ``hello_world``
-function as a view callable. The ``add_view`` method of a Configurator must
-be called with a view callable object or a :term:`dotted Python name` as its
-first argument, so the first argument passed is the ``hello_world`` function.
-This line calls ``add_view`` with a *default* value for the :term:`predicate`
-argument, named ``name``. The ``name`` predicate defaults to a value
-equalling the empty string (``''``). This means that we're instructing
-:app:`Pyramid` to invoke the ``hello_world`` view callable when the
-:term:`view name` is the empty string. We'll learn in later chapters what a
-:term:`view name` is, and under which circumstances a request will have a
-view name that is the empty string; in this particular application, it means
-that the ``hello_world`` view callable will be invoked when the root URL
-``/`` is visited by a browser.
-
-The line ``config.add_view(goodbye_world, name='goodbye')`` registers the
-``goodbye_world`` function as a view callable. The line calls ``add_view``
-with the view callable as the first required positional argument, and a
-:term:`predicate` keyword argument ``name`` with the value ``'goodbye'``.
-The ``name`` argument supplied in this :term:`view configuration` implies
-that only a request that has a :term:`view name` of ``goodbye`` should cause
-the ``goodbye_world`` view callable to be invoked. In this particular
-application, this means that the ``goodbye_world`` view callable will be
-invoked when the URL ``/goodbye`` is visited by a browser.
-
-Each invocation of the ``add_view`` method registers a :term:`view
-configuration`. Each :term:`predicate` provided as a keyword argument to the
-``add_view`` method narrows the set of circumstances which would cause the
-view configuration's callable to be invoked. In general, a greater number of
-predicates supplied along with a view configuration will more strictly limit
-the applicability of its associated view callable. When :app:`Pyramid`
-processes a request, the view callable with the *most specific* view
-configuration (the view configuration that matches the most specific set of
-predicates) is always invoked.
-
-In this application, :app:`Pyramid` chooses the most specific view callable
-based only on view :term:`predicate` applicability. The ordering of calls to
-:meth:`~pyramid.config.Configurator.add_view` is never very important. We can
-register ``goodbye_world`` first and ``hello_world`` second; :app:`Pyramid`
-will still give us the most specific callable when a request is dispatched to
-it.
+The second line registers the ``hello_world`` function as a :term:`view
+callable` and makes sure that it will be called when the ``hello`` route is
+matched.
.. index::
single: make_wsgi_app
@@ -252,74 +184,67 @@ it.
WSGI Application Creation
~~~~~~~~~~~~~~~~~~~~~~~~~
-.. ignore-next-block
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
-
- app = config.make_wsgi_app()
+ :lines: 13
After configuring views and ending configuration, the script creates a WSGI
-*application* via the :meth:`pyramid.config.Configurator.make_wsgi_app`
-method. A call to ``make_wsgi_app`` implies that all configuration is
-finished (meaning all method calls to the configurator which set up views,
-and various other configuration settings have been performed). The
-``make_wsgi_app`` method returns a :term:`WSGI` application object that can
-be used by any WSGI server to present an application to a requestor.
-:term:`WSGI` is a protocol that allows servers to talk to Python
-applications. We don't discuss :term:`WSGI` in any depth within this book,
-however, you can learn more about it by visiting `wsgi.org
-<http://wsgi.org>`_.
-
-The :app:`Pyramid` application object, in particular, is an instance of a
-class representing a :app:`Pyramid` :term:`router`. It has a reference to
-the :term:`application registry` which resulted from method calls to the
-configurator used to configure it. The :term:`router` consults the registry
-to obey the policy choices made by a single application. These policy
-choices were informed by method calls to the :term:`Configurator` made
-earlier; in our case, the only policy choices made were implied by two calls
-to its ``add_view`` method.
+*application* via the :meth:`pyramid.config.Configurator.make_wsgi_app` method.
+A call to ``make_wsgi_app`` implies that all configuration is finished
+(meaning all method calls to the configurator, which sets up views and various
+other configuration settings, have been performed). The ``make_wsgi_app``
+method returns a :term:`WSGI` application object that can be used by any WSGI
+server to present an application to a requestor. :term:`WSGI` is a protocol
+that allows servers to talk to Python applications. We don't discuss
+:term:`WSGI` in any depth within this book, but you can learn more about it by
+visiting `wsgi.org <http://wsgi.org>`_.
+
+The :app:`Pyramid` application object, in particular, is an instance of a class
+representing a :app:`Pyramid` :term:`router`. It has a reference to the
+:term:`application registry` which resulted from method calls to the
+configurator used to configure it. The :term:`router` consults the registry to
+obey the policy choices made by a single application. These policy choices
+were informed by method calls to the :term:`Configurator` made earlier; in our
+case, the only policy choices made were implied by calls to its ``add_view``
+and ``add_route`` methods.
WSGI Application Serving
~~~~~~~~~~~~~~~~~~~~~~~~
-.. ignore-next-block
-.. code-block:: python
+.. literalinclude:: helloworld.py
:linenos:
-
- serve(app, host='0.0.0.0')
-
-Finally, we actually serve the application to requestors by starting up a
-WSGI server. We happen to use the :func:`paste.httpserver.serve` WSGI server
-runner, passing it the ``app`` object (a :term:`router`) as the application
-we wish to serve. We also pass in an argument ``host=='0.0.0.0'``, meaning
-"listen on all TCP interfaces." By default, the Paste HTTP server listens
-only on the ``127.0.0.1`` interface, which is problematic if you're running
-the server on a remote system and you wish to access it with a web browser
-from a local system. We don't specify a TCP port number to listen on; this
-means we want to use the default TCP port, which is 8080.
-
-When this line is invoked, it causes the server to start listening on TCP
-port 8080. It will serve requests forever, or at least until we stop it by
-killing the process which runs it (usually by pressing ``Ctrl-C`` in the
-terminal we used to start it).
+ :lines: 14-15
+
+Finally, we actually serve the application to requestors by starting up a WSGI
+server. We happen to use the :mod:`wsgiref` ``make_server`` server maker for
+this purpose. We pass in as the first argument ``'0.0.0.0'``, which means
+"listen on all TCP interfaces". By default, the HTTP server listens only on
+the ``127.0.0.1`` interface, which is problematic if you're running the server
+on a remote system and you wish to access it with a web browser from a local
+system. We also specify a TCP port number to listen on, which is 8080, passing
+it as the second argument. The final argument is the ``app`` object (a
+:term:`router`), which is the application we wish to serve. Finally, we call
+the server's ``serve_forever`` method, which starts the main loop in which it
+will wait for requests from the outside world.
+
+When this line is invoked, it causes the server to start listening on TCP port
+8080. The server will serve requests forever, or at least until we stop it by
+killing the process which runs it (usually by pressing ``Ctrl-C`` or
+``Ctrl-Break`` in the terminal we used to start it).
Conclusion
~~~~~~~~~~
Our hello world application is one of the simplest possible :app:`Pyramid`
applications, configured "imperatively". We can see that it's configured
-imperatively because the full power of Python is available to us as we
-perform configuration tasks.
+imperatively because the full power of Python is available to us as we perform
+configuration tasks.
References
----------
-For more information about the API of a :term:`Configurator` object,
-see :class:`~pyramid.config.Configurator` .
+For more information about the API of a :term:`Configurator` object, see
+:class:`~pyramid.config.Configurator` .
For more information about :term:`view configuration`, see
:ref:`view_config_chapter`.
-
-An example of using *declarative* configuration (:term:`ZCML`) instead of
-imperative configuration to create a similar "hello world" is available
-within the documentation for :term:`pyramid_zcml`.