summaryrefslogtreecommitdiff
path: root/docs/narr
diff options
context:
space:
mode:
authorMichael Merickel <michael@merickel.org>2015-02-11 12:32:26 -0600
committerMichael Merickel <michael@merickel.org>2015-02-11 12:32:35 -0600
commit6e9e2dbb364f371b034b681dd44e6e6b831c5760 (patch)
treeb7d8c623706f5df330d9c72d4e1c9d84dd47b6cd /docs/narr
parent14126cae5cf308ed466ed3eea576094e9c2193b4 (diff)
parent1dc1f28e1184960f5359c6c510d23a0e6e9dafe8 (diff)
downloadpyramid-6e9e2dbb364f371b034b681dd44e6e6b831c5760.tar.gz
pyramid-6e9e2dbb364f371b034b681dd44e6e6b831c5760.tar.bz2
pyramid-6e9e2dbb364f371b034b681dd44e6e6b831c5760.zip
Merge branch 'master' into feature.py3-coverage
Diffstat (limited to 'docs/narr')
-rw-r--r--docs/narr/MyProject/myproject/tests.py37
-rw-r--r--docs/narr/MyProject/setup.py45
-rw-r--r--docs/narr/commandline.rst56
-rw-r--r--docs/narr/hooks.rst51
-rw-r--r--docs/narr/hybrid.rst2
-rw-r--r--docs/narr/introspector.rst16
-rw-r--r--docs/narr/logging.rst18
-rw-r--r--docs/narr/router.rst6
-rw-r--r--docs/narr/sessions.rst4
-rw-r--r--docs/narr/testing.rst142
-rw-r--r--docs/narr/webob.rst8
11 files changed, 260 insertions, 125 deletions
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py
index 64dcab1d5..8c60407e5 100644
--- a/docs/narr/MyProject/myproject/tests.py
+++ b/docs/narr/MyProject/myproject/tests.py
@@ -15,3 +15,40 @@ class ViewTests(unittest.TestCase):
request = testing.DummyRequest()
info = my_view(request)
self.assertEqual(info['project'], 'MyProject')
+
+class ViewIntegrationTests(unittest.TestCase):
+ def setUp(self):
+ """ This sets up the application registry with the
+ registrations your application declares in its ``includeme``
+ function.
+ """
+ self.config = testing.setUp()
+ self.config.include('myproject')
+
+ def tearDown(self):
+ """ Clear out the application registry """
+ testing.tearDown()
+
+ def test_my_view(self):
+ from myproject.views import my_view
+ request = testing.DummyRequest()
+ result = my_view(request)
+ self.assertEqual(result.status, '200 OK')
+ body = result.app_iter[0]
+ self.assertTrue('Welcome to' in body)
+ self.assertEqual(len(result.headerlist), 2)
+ self.assertEqual(result.headerlist[0],
+ ('Content-Type', 'text/html; charset=UTF-8'))
+ self.assertEqual(result.headerlist[1], ('Content-Length',
+ str(len(body))))
+
+class FunctionalTests(unittest.TestCase):
+ def setUp(self):
+ from myproject import main
+ app = main({})
+ from webtest import TestApp
+ self.testapp = TestApp(app)
+
+ def test_root(self):
+ res = self.testapp.get('/', status=200)
+ self.assertTrue('Pyramid' in res.body)
diff --git a/docs/narr/MyProject/setup.py b/docs/narr/MyProject/setup.py
index 8c019af51..9f34540a7 100644
--- a/docs/narr/MyProject/setup.py
+++ b/docs/narr/MyProject/setup.py
@@ -1,30 +1,42 @@
-import os
+"""Setup for the MyProject package.
+"""
+import os
from setuptools import setup, find_packages
-here = os.path.abspath(os.path.dirname(__file__))
-with open(os.path.join(here, 'README.txt')) as f:
- README = f.read()
-with open(os.path.join(here, 'CHANGES.txt')) as f:
- CHANGES = f.read()
-requires = [
+HERE = os.path.abspath(os.path.dirname(__file__))
+
+
+with open(os.path.join(HERE, 'README.txt')) as fp:
+ README = fp.read()
+
+
+with open(os.path.join(HERE, 'CHANGES.txt')) as fp:
+ CHANGES = fp.read()
+
+
+REQUIRES = [
'pyramid',
'pyramid_chameleon',
'pyramid_debugtoolbar',
'waitress',
]
+TESTS_REQUIRE = [
+ 'webtest'
+ ]
+
setup(name='MyProject',
version='0.0',
description='MyProject',
long_description=README + '\n\n' + CHANGES,
classifiers=[
- "Programming Language :: Python",
- "Framework :: Pyramid",
- "Topic :: Internet :: WWW/HTTP",
- "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
- ],
+ 'Programming Language :: Python',
+ 'Framework :: Pyramid',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+ ],
author='',
author_email='',
url='',
@@ -32,11 +44,10 @@ setup(name='MyProject',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
- install_requires=requires,
- tests_require=requires,
- test_suite="myproject",
+ install_requires=REQUIRES,
+ tests_require=TESTS_REQUIRE,
+ test_suite='myproject',
entry_points="""\
[paste.app_factory]
main = myproject:main
- """,
- )
+ """)
diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst
index 4f16617c4..1fe2d9278 100644
--- a/docs/narr/commandline.rst
+++ b/docs/narr/commandline.rst
@@ -312,24 +312,60 @@ For example:
:linenos:
$ $VENV/bin/proutes development.ini
- Name Pattern View
- ---- ------- ----
- home / <function my_view>
- home2 / <function my_view>
- another /another None
- static/ static/*subpath <static_view object>
- catchall /*subpath <function static_view>
-
-``proutes`` generates a table with three columns: *Name*, *Pattern*,
+ Name Pattern View
+ ---- ------- ----
+ debugtoolbar /_debug_toolbar/*subpath <wsgiapp> *
+ __static/ /static/*subpath dummy_starter:static/ *
+ __static2/ /static2/*subpath /var/www/static/ *
+ __pdt_images/ /pdt_images/*subpath pyramid_debugtoolbar:static/img/ *
+ a / <unknown> *
+ no_view_attached / <unknown> *
+ route_and_view_attached / app1.standard_views.route_and_view_attached *
+ method_conflicts /conflicts app1.standard_conflicts <route mismatch>
+ multiview /multiview app1.standard_views.multiview GET,PATCH
+ not_post /not_post app1.standard_views.multview !POST,*
+
+``proutes`` generates a table with four columns: *Name*, *Pattern*, *Method*,
and *View*. The items listed in the
Name column are route names, the items listed in the Pattern column are route
patterns, and the items listed in the View column are representations of the
view callable that will be invoked when a request matches the associated
-route pattern. The view column may show ``None`` if no associated view
+route pattern. The view column may show ``<unknown>`` if no associated view
callable could be found. If no routes are configured within your
application, nothing will be printed to the console when ``proutes``
is executed.
+It is convenient when using the ``proutes`` often to configure which columns
+and the order you would like to view them. To facilitate this, ``proutes`` will
+look for a special ``[proutes]`` section in your INI file and use those as
+defaults.
+
+For example you may remove request method and place the view first:
+
+.. code-block:: text
+ :linenos:
+
+ [proutes]
+ format = view
+ name
+ pattern
+
+You can also separate the formats with commas or spaces:
+
+.. code-block:: text
+ :linenos:
+
+ [proutes]
+ format = view name pattern
+
+ [proutes]
+ format = view, name, pattern
+
+If you want to temporarily configure the columns and order there is the
+``--format`` which is a comma separated list of columns you want to include. The
+current available formats are ``name``, ``pattern``, ``view``, and ``method``.
+
+
.. index::
pair: tweens; printing
single: ptweens
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 4da36e730..4fd7670b9 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -349,6 +349,55 @@ We attach and cache an object named ``extra`` to the ``request`` object.
the property
.. index::
+ single: response factory
+
+.. _changing_the_response_factory:
+
+Changing the Response Factory
+-------------------------------
+
+.. versionadded:: 1.6
+
+Whenever :app:`Pyramid` returns a response from a view it creates a
+:term:`response` object. By default, an instance of the
+:class:`pyramid.response.Response` class is created to represent the response
+object.
+
+The factory that :app:`Pyramid` uses to create a response object instance can be
+changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument to
+the constructor of the :term:`configurator`. This argument can be either a
+callable or a :term:`dotted Python name` representing a callable.
+
+The factory takes a single positional argument, which is a :term:`Request`
+object. The argument may be ``None``.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.response import Response
+
+ class MyResponse(Response):
+ pass
+
+ config = Configurator(response_factory=lambda r: MyResponse())
+
+If you're doing imperative configuration, and you'd rather do it after you've
+already constructed a :term:`configurator` it can also be registered via the
+:meth:`pyramid.config.Configurator.set_response_factory` method:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.config import Configurator
+ from pyramid.response import Response
+
+ class MyResponse(Response):
+ pass
+
+ config = Configurator()
+ config.set_response_factory(lambda r: MyResponse())
+
+.. index::
single: before render event
single: adding renderer globals
@@ -730,7 +779,7 @@ If you want to implement your own Response object instead of using the
:class:`pyramid.response.Response` object in any capacity at all, you'll have
to make sure the object implements every attribute and method outlined in
:class:`pyramid.interfaces.IResponse` and you'll have to ensure that it uses
-``zope.interface.implementer(IResponse)`` as a class decoratoror.
+``zope.interface.implementer(IResponse)`` as a class decorator.
.. code-block:: python
:linenos:
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index 4a3258d35..1c324d22b 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -453,7 +453,7 @@ commonly in route declarations that look like this:
.. code-block:: python
:linenos:
- from pryamid.static import static_view
+ from pyramid.static import static_view
www = static_view('mypackage:static', use_subpath=True)
diff --git a/docs/narr/introspector.rst b/docs/narr/introspector.rst
index a7bde4cf7..8caba522c 100644
--- a/docs/narr/introspector.rst
+++ b/docs/narr/introspector.rst
@@ -121,7 +121,7 @@ introspectables in categories not described here.
``subscriber``
The subscriber callable object (the resolution of the ``subscriber``
- argument passed to ``add_susbcriber``).
+ argument passed to ``add_subscriber``).
``interfaces``
@@ -137,12 +137,12 @@ introspectables in categories not described here.
``predicates``
The predicate objects created as the result of passing predicate arguments
- to ``add_susbcriber``
+ to ``add_subscriber``
``derived_predicates``
Wrappers around the predicate objects created as the result of passing
- predicate arguments to ``add_susbcriber`` (to be used when predicates take
+ predicate arguments to ``add_subscriber`` (to be used when predicates take
only one value but must be passed more than one).
``response adapters``
@@ -450,9 +450,9 @@ introspectables in categories not described here.
The :class:`pyramid.interfaces.IRendererInfo` object which represents
this template's renderer.
-``view mapper``
+``view mappers``
- Each introspectable in the ``permissions`` category represents a call to
+ Each introspectable in the ``view mappers`` category represents a call to
:meth:`pyramid.config.Configurator.add_view` that has an explicit
``mapper`` argument to *or* a call to
:meth:`pyramid.config.Configurator.set_view_mapper`; each will have
@@ -481,8 +481,8 @@ introspectables in categories not described here.
``translation directories``
- Each introspectable in the ``asset overrides`` category represents an
- individual element in a ``specs`` argument passed to
+ Each introspectable in the ``translation directories`` category represents
+ an individual element in a ``specs`` argument passed to
:meth:`pyramid.config.Configurator.add_translation_dirs`; each will have
the following data.
@@ -511,7 +511,7 @@ introspectables in categories not described here.
``type``
- ``implict`` or ``explicit`` as a string.
+ ``implicit`` or ``explicit`` as a string.
``under``
diff --git a/docs/narr/logging.rst b/docs/narr/logging.rst
index c16673ae6..921883091 100644
--- a/docs/narr/logging.rst
+++ b/docs/narr/logging.rst
@@ -254,16 +254,15 @@ level unless they're explicitly set differently. Meaning the ``myapp.views``,
``myapp.models`` (and all your app's modules') loggers by default have an
effective level of ``DEBUG`` too.
-For more advanced filtering, the logging module provides a `Filter
-<http://docs.python.org/lib/node423.html>`_ object; however it cannot be used
-directly from the configuration file.
+For more advanced filtering, the logging module provides a
+:class:`logging.Filter` object; however it cannot be used directly from the
+configuration file.
-Advanced Configuration
+Advanced Configuration
----------------------
-To capture log output to a separate file, use a `FileHandler
-<http://docs.python.org/lib/node412.html>`_ (or a `RotatingFileHandler
-<http://docs.python.org/lib/node413.html>`_):
+To capture log output to a separate file, use :class:`logging.FileHandler` (or
+:class:`logging.handlers.RotatingFileHandler`):
.. code-block:: ini
@@ -317,8 +316,9 @@ output, etc., but not web traffic. For web traffic logging Paste provides the
:term:`middleware`. TransLogger produces logs in the `Apache Combined Log
Format <http://httpd.apache.org/docs/2.2/logs.html#combined>`_. But
TransLogger does not write to files, the Python logging system must be
-configured to do this. The Python FileHandler_ logging handler can be used
-alongside TransLogger to create an ``access.log`` file similar to Apache's.
+configured to do this. The Python :class:`logging.FileHandler` logging
+handler can be used alongside TransLogger to create an ``access.log`` file
+similar to Apache's.
Like any standard :term:`middleware` with a Paste entry point, TransLogger can
be configured to wrap your application using ``.ini`` file syntax. First,
diff --git a/docs/narr/router.rst b/docs/narr/router.rst
index ac3deefdc..6f90c70cc 100644
--- a/docs/narr/router.rst
+++ b/docs/narr/router.rst
@@ -9,6 +9,9 @@
Request Processing
==================
+.. image:: ../_static/pyramid_request_processing.*
+ :alt: Request Processing
+
Once a :app:`Pyramid` application is up and running, it is ready to accept
requests and return responses. What happens from the time a :term:`WSGI`
request enters a :app:`Pyramid` application through to the point that
@@ -116,7 +119,8 @@ request enters a :app:`Pyramid` application through to the point that
#. The :term:`thread local` stack is popped.
-.. image:: router.png
+.. image:: ../_static/pyramid_router.*
+ :alt: Pyramid Router
This is a very high-level overview that leaves out various details. For more
detail about subsystems invoked by the :app:`Pyramid` router such as
diff --git a/docs/narr/sessions.rst b/docs/narr/sessions.rst
index 8da743a01..5c103405a 100644
--- a/docs/narr/sessions.rst
+++ b/docs/narr/sessions.rst
@@ -44,7 +44,7 @@ It is digitally signed, however, and thus its data cannot easily be
tampered with.
You can configure this session factory in your :app:`Pyramid` application
-by using the :meth:`pyramid.config.Configurator.set_session_factory`` method.
+by using the :meth:`pyramid.config.Configurator.set_session_factory` method.
.. code-block:: python
:linenos:
@@ -380,7 +380,7 @@ Checking CSRF Tokens Manually
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In request handling code, you can check the presence and validity of a CSRF
-token with :func:`pyramid.session.check_csrf_token(request)``. If the token is
+token with :func:`pyramid.session.check_csrf_token`. If the token is
valid, it will return ``True``, otherwise it will raise ``HTTPBadRequest``.
Optionally, you can specify ``raises=False`` to have the check return ``False``
instead of raising an exception.
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst
index e001ad81c..ecda57489 100644
--- a/docs/narr/testing.rst
+++ b/docs/narr/testing.rst
@@ -128,8 +128,9 @@ functions accepts various arguments that influence the environment of the
test. See the :ref:`testing_module` API for information about the extra
arguments supported by these functions.
-If you also want to make :func:`~pyramid.threadlocal.get_current_request` return something
-other than ``None`` during the course of a single test, you can pass a
+If you also want to make :func:`~pyramid.threadlocal.get_current_request`
+return something other than ``None`` during the course of a single test, you
+can pass a
:term:`request` object into the :func:`pyramid.testing.setUp` within the
``setUp`` method of your test:
@@ -333,66 +334,49 @@ Creating Integration Tests
--------------------------
In :app:`Pyramid`, a *unit test* typically relies on "mock" or "dummy"
-implementations to give the code under test only enough context to run.
+implementations to give the code under test enough context to run.
"Integration testing" implies another sort of testing. In the context of a
-:app:`Pyramid` integration test, the test logic tests the functionality of
-some code *and* its integration with the rest of the :app:`Pyramid`
+:app:`Pyramid` integration test, the test logic exercises the functionality of
+the code under test *and* its integration with the rest of the :app:`Pyramid`
framework.
-In :app:`Pyramid` applications that are plugins to Pyramid, you can create an
-integration test by including its ``includeme`` function via
-:meth:`pyramid.config.Configurator.include` in the test's setup code. This
-causes the entire :app:`Pyramid` environment to be set up and torn down as if
-your application was running "for real". This is a heavy-hammer way of
-making sure that your tests have enough context to run properly, and it tests
-your code's integration with the rest of :app:`Pyramid`.
+Creating an integration test for a :app:`Pyramid` application usually means
+invoking the application's ``includeme`` function via
+:meth:`pyramid.config.Configurator.include` within the test's setup code. This
+causes the entire :app:`Pyramid` environment to be set up, simulating what
+happens when your application is run "for real". This is a heavy-hammer way of
+making sure that your tests have enough context to run properly, and tests your
+code's integration with the rest of :app:`Pyramid`.
-Let's demonstrate this by showing an integration test for a view. The below
-test assumes that your application's package name is ``myapp``, and that
-there is a ``views`` module in the app with a function with the name
-``my_view`` in it that returns the response 'Welcome to this application'
-after accessing some values that require a fully set up environment.
+.. seealso::
-.. code-block:: python
- :linenos:
+ See also :ref:`including_configuration`
- import unittest
+Let's demonstrate this by showing an integration test for a view.
- from pyramid import testing
+Given the following view definition, which assumes that your application's
+:term:`package` name is ``myproject``, and within that :term:`package` there
+exists a module ``views``, which in turn contains a :term:`view` function named
+``my_view``:
- class ViewIntegrationTests(unittest.TestCase):
- def setUp(self):
- """ This sets up the application registry with the
- registrations your application declares in its ``includeme``
- function.
- """
- import myapp
- self.config = testing.setUp()
- self.config.include('myapp')
+ .. literalinclude:: MyProject/myproject/views.py
+ :linenos:
+ :lines: 1-6
+ :language: python
- def tearDown(self):
- """ Clear out the application registry """
- testing.tearDown()
+You'd then create a ``tests`` module within your ``myproject`` package,
+containing the following test code:
- def test_my_view(self):
- from myapp.views import my_view
- request = testing.DummyRequest()
- result = my_view(request)
- self.assertEqual(result.status, '200 OK')
- body = result.app_iter[0]
- self.assertTrue('Welcome to' in body)
- self.assertEqual(len(result.headerlist), 2)
- self.assertEqual(result.headerlist[0],
- ('Content-Type', 'text/html; charset=UTF-8'))
- self.assertEqual(result.headerlist[1], ('Content-Length',
- str(len(body))))
-
-Unless you cannot avoid it, you should prefer writing unit tests that use the
-:class:`~pyramid.config.Configurator` API to set up the right "mock"
-registrations rather than creating an integration test. Unit tests will run
-faster (because they do less for each test) and the result of a unit test is
-usually easier to make assertions about.
+ .. literalinclude:: MyProject/myproject/tests.py
+ :linenos:
+ :pyobject: ViewIntegrationTests
+ :language: python
+
+Writing unit tests that use the :class:`~pyramid.config.Configurator` API to
+set up the right "mock" registrations is often preferred to creating
+integration tests. Unit tests will run faster (because they do less for each
+test) and are usually easier to reason about.
.. index::
single: functional tests
@@ -404,34 +388,40 @@ Creating Functional Tests
Functional tests test your literal application.
-The below test assumes that your application's package name is ``myapp``, and
-that there is a view that returns an HTML body when the root URL is invoked.
-It further assumes that you've added a ``tests_require`` dependency on the
-``WebTest`` package within your ``setup.py`` file. :term:`WebTest` is a
-functional testing package written by Ian Bicking.
+In Pyramid, functional tests are typically written using the :term:`WebTest`
+package, which provides APIs for invoking HTTP(S) requests to your application.
-.. code-block:: python
- :linenos:
+Regardless of which testing :term:`package` you use, ensure to add a
+``tests_require`` dependency on that package to to your application's
+``setup.py`` file:
- import unittest
+ .. literalinclude:: MyProject/setup.py
+ :linenos:
+ :emphasize-lines: 26-28,48
+ :language: python
- class FunctionalTests(unittest.TestCase):
- def setUp(self):
- from myapp import main
- app = main({})
- from webtest import TestApp
- self.testapp = TestApp(app)
-
- def test_root(self):
- res = self.testapp.get('/', status=200)
- self.assertTrue('Pyramid' in res.body)
-
-When this test is run, each test creates a "real" WSGI application using the
-``main`` function in your ``myapp.__init__`` module and uses :term:`WebTest`
-to wrap that WSGI application. It assigns the result to ``self.testapp``.
-In the test named ``test_root``, we use the testapp's ``get`` method to
-invoke the root URL. We then assert that the returned HTML has the string
-``Pyramid`` in it.
+Assuming your :term:`package` is named ``myproject``, which contains a
+``views`` module, which in turn contains a :term:`view` function ``my_view``
+that returns a HTML body when the root URL is invoked:
+
+ .. literalinclude:: MyProject/myproject/views.py
+ :linenos:
+ :language: python
+
+Then the following example functional test (shown below) demonstrates invoking
+the :term:`view` shown above:
+
+ .. literalinclude:: MyProject/myproject/tests.py
+ :linenos:
+ :pyobject: FunctionalTests
+ :language: python
+
+When this test is run, each test method creates a "real" :term:`WSGI`
+application using the ``main`` function in your ``myproject.__init__`` module,
+using :term:`WebTest` to wrap that WSGI application. It assigns the result to
+``self.testapp``. In the test named ``test_root``. The ``TestApp``'s ``get``
+method is used to invoke the root URL. Finally, an assertion is made that the
+returned HTML contains the text ``MyProject``.
See the :term:`WebTest` documentation for further information about the
methods available to a :class:`webtest.app.TestApp` instance.
diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst
index 6a331e4bf..0eb070b06 100644
--- a/docs/narr/webob.rst
+++ b/docs/narr/webob.rst
@@ -310,6 +310,14 @@ Python's ``urllib2`` instead of a Javascript AJAX request:
req = urllib2.Request('http://localhost:6543/', json_payload, headers)
resp = urllib2.urlopen(req)
+If you are doing Cross-origin resource sharing (CORS), then the standard
+requires the browser to do a pre-flight HTTP OPTIONS request. The easiest way
+to handling this is adding an extra ``view_config`` for the same route, with
+``request_method`` set to ``OPTIONS``, and setting the desired response header
+before returning. You can find examples of response headers here_.
+
+.. _here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
+
.. index::
single: cleaning up after request