summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcguardia <carlos.delaguardia@gmail.com>2011-04-25 00:37:33 -0500
committercguardia <carlos.delaguardia@gmail.com>2011-04-25 00:37:33 -0500
commitb61680ad87abcb524ae3fe846cd591c6ec1d54ef (patch)
treee2fcd960d9119efde4a1b7eecec3880f98397d2f
parent1b395e6d43b9450ea652d9addb675936b507ea52 (diff)
parentbb825910b3b68b4b167572fd5252cc99be88e17e (diff)
downloadpyramid-b61680ad87abcb524ae3fe846cd591c6ec1d54ef.tar.gz
pyramid-b61680ad87abcb524ae3fe846cd591c6ec1d54ef.tar.bz2
pyramid-b61680ad87abcb524ae3fe846cd591c6ec1d54ef.zip
Merge branch 'master' of https://github.com/Pylons/pyramid
-rw-r--r--CHANGES.txt115
-rw-r--r--CONTRIBUTORS.txt4
-rw-r--r--TODO.txt14
-rw-r--r--docs/api/request.rst45
-rw-r--r--docs/conf.py2
-rw-r--r--docs/narr/advconfig.rst12
-rw-r--r--docs/narr/assets.rst7
-rw-r--r--docs/narr/environment.rst63
-rw-r--r--docs/narr/hybrid.rst59
-rw-r--r--docs/narr/renderers.rst74
-rw-r--r--docs/narr/templates.rst14
-rw-r--r--docs/narr/urldispatch.rst152
-rw-r--r--docs/narr/viewconfig.rst3
-rw-r--r--docs/narr/zca.rst22
-rw-r--r--docs/tutorials/wiki/authorization.rst218
-rw-r--r--docs/tutorials/wiki/definingmodels.rst70
-rw-r--r--docs/tutorials/wiki/definingviews.rst45
-rw-r--r--docs/tutorials/wiki/index.rst1
-rw-r--r--docs/tutorials/wiki/src/tests/tutorial/tests.py216
-rw-r--r--docs/tutorials/wiki/tests.rst78
-rw-r--r--docs/tutorials/wiki2/authorization.rst28
-rw-r--r--docs/tutorials/wiki2/basiclayout.rst32
-rw-r--r--docs/tutorials/wiki2/definingmodels.rst8
-rw-r--r--docs/tutorials/wiki2/definingviews.rst38
-rw-r--r--docs/tutorials/wiki2/src/authorization/tutorial/__init__.py39
-rw-r--r--docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py5
-rw-r--r--docs/tutorials/wiki2/src/models/tutorial/__init__.py5
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/__init__.py21
-rw-r--r--pyramid/authentication.py24
-rw-r--r--pyramid/compat/__init__.py9
-rw-r--r--pyramid/config.py129
-rw-r--r--pyramid/paster.py31
-rw-r--r--pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl7
-rw-r--r--pyramid/renderers.py46
-rw-r--r--pyramid/request.py74
-rw-r--r--pyramid/static.py43
-rw-r--r--pyramid/testing.py24
-rw-r--r--pyramid/tests/ccbugapp/__init__.py11
-rw-r--r--pyramid/tests/exceptionviewapp/__init__.py26
-rw-r--r--pyramid/tests/hybridapp/__init__.py3
-rw-r--r--pyramid/tests/restbugapp/__init__.py23
-rw-r--r--pyramid/tests/test_asset.py6
-rw-r--r--pyramid/tests/test_authentication.py88
-rw-r--r--pyramid/tests/test_chameleon_text.py26
-rw-r--r--pyramid/tests/test_chameleon_zpt.py26
-rw-r--r--pyramid/tests/test_config.py648
-rw-r--r--pyramid/tests/test_events.py4
-rw-r--r--pyramid/tests/test_exceptions.py8
-rw-r--r--pyramid/tests/test_i18n.py10
-rw-r--r--pyramid/tests/test_integration.py121
-rw-r--r--pyramid/tests/test_mako_templating.py10
-rw-r--r--pyramid/tests/test_paster.py89
-rw-r--r--pyramid/tests/test_path.py4
-rw-r--r--pyramid/tests/test_renderers.py115
-rw-r--r--pyramid/tests/test_request.py71
-rw-r--r--pyramid/tests/test_router.py44
-rw-r--r--pyramid/tests/test_security.py38
-rw-r--r--pyramid/tests/test_session.py12
-rw-r--r--pyramid/tests/test_static.py194
-rw-r--r--pyramid/tests/test_testing.py79
-rw-r--r--pyramid/tests/test_urldispatch.py44
-rw-r--r--pyramid/tests/test_view.py22
-rw-r--r--pyramid/tests/test_wsgi.py48
-rw-r--r--pyramid/tests/wsgiapp2app/__init__.py17
-rw-r--r--pyramid/urldispatch.py19
-rw-r--r--pyramid/wsgi.py40
-rw-r--r--setup.py4
-rw-r--r--tox.ini16
68 files changed, 2420 insertions, 1223 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 0bd19572a..d329c260d 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -25,9 +25,25 @@ Documentation
``pyramid.config.Configurator.set_view_mapper`` and refer to it within
Hooks chapter section named "Using a View Mapper".
+- Added section to the "Environment Variables and ``.ini`` File Settings"
+ chapter in the narrative documentation section entitled "Adding a Custom
+ Setting".
+
Features
--------
+- Accessing the ``response`` attribute of a ``pyramid.request.Request``
+ object (e.g. ``request.response`` within a view) now produces a new
+ ``pyramid.response.Response`` object. This feature is meant to be used
+ mainly when a view configured with a renderer needs to set response
+ attributes: all renderers will use the Response object implied by
+ ``request.response`` as the response object returned to the router.
+
+ ``request.response`` can also be used by code in a view that does not use a
+ renderer, however the response object that is produced by
+ ``request.response`` must be returned when a renderer is not in play (it is
+ not a "global" response).
+
- Integers and longs passed as ``elements`` to ``pyramid.url.resource_url``
or ``pyramid.request.Request.resource_url`` e.g. ``resource_url(context,
request, 1, 2)`` (``1`` and ``2`` are the ``elements``) will now be
@@ -64,6 +80,16 @@ Features
Bug Fixes
---------
+- URL pattern markers used in URL dispatch are permitted to specify a custom
+ regex. For example, the pattern ``/{foo:\d+}`` means to match ``/12345``
+ (foo==12345 in the match dictionary) but not ``/abc``. However, custom
+ regexes in a pattern marker which used squiggly brackets did not work. For
+ example, ``/{foo:\d{4}}`` would fail to match ``/1234`` and
+ ``/{foo:\d{1,2}}`` would fail to match ``/1`` or ``/11``. One level of
+ inner squiggly brackets is now recognized so that the prior two patterns
+ given as examples now work. See also
+ https://github.com/Pylons/pyramid/issues/#issue/123.
+
- Don't send port numbers along with domain information in cookies set by
AuthTktCookieHelper (see https://github.com/Pylons/pyramid/issues/131).
@@ -104,6 +130,95 @@ Bug Fixes
DummyRequest instead of eagerly assigning an attribute.
See also https://github.com/Pylons/pyramid/issues/165
+- When visiting a URL that represented a static view which resolved to a
+ subdirectory, the ``index.html`` of that subdirectory would not be served
+ properly. Instead, a redirect to ``/subdir`` would be issued. This has
+ been fixed, and now visiting a subdirectory that contains an ``index.html``
+ within a static view returns the index.html properly. See also
+ https://github.com/Pylons/pyramid/issues/67.
+
+- Redirects issued by a static view did not take into account any existing
+ ``SCRIPT_NAME`` (such as one set by a url mapping composite). Now they do.
+
+- The ``pyramid.wsgi.wsgiapp2`` decorator did not take into account the
+ ``SCRIPT_NAME`` in the origin request.
+
+- The ``pyramid.wsgi.wsgiapp2`` decorator effectively only worked when it
+ decorated a view found via traversal; it ignored the ``PATH_INFO`` that was
+ part of a url-dispatch-matched view.
+
+Deprecations
+------------
+
+- Deprecated all assignments to ``request.response_*`` attributes (for
+ example ``request.response_content_type = 'foo'`` is now deprecated).
+ Assignments and mutations of assignable request attributes that were
+ considered by the framework for response influence are now deprecated:
+ ``response_content_type``, ``response_headerlist``, ``response_status``,
+ ``response_charset``, and ``response_cache_for``. Instead of assigning
+ these to the request object for later detection by the rendering machinery,
+ users should use the appropriate API of the Response object created by
+ accessing ``request.response`` (e.g. code which does
+ ``request.response_content_type = 'abc'`` should be changed to
+ ``request.response.content_type = 'abc'``).
+
+- Passing view-related parameters to
+ ``pyramid.config.Configurator.add_route`` is now deprecated. Previously, a
+ view was permitted to be connected to a route using a set of ``view*``
+ parameters passed to the ``add_route`` method of the Configurator. This
+ was a shorthand which replaced the need to perform a subsequent call to
+ ``add_view``. For example, it was valid (and often recommended) to do::
+
+ config.add_route('home', '/', view='mypackage.views.myview',
+ view_renderer='some/renderer.pt')
+
+ Passing ``view*`` arguments to ``add_route`` is now deprecated in favor of
+ connecting a view to a predefined route via ``Configurator.add_view`` using
+ the route's ``route_name`` parameter. As a result, the above example
+ should now be spelled::
+
+ config.add_route('home', '/')
+ config.add_view('mypackage.views.myview', route_name='home')
+ renderer='some/renderer.pt')
+
+ This deprecation was done to reduce confusion observed in IRC, as well as
+ to (eventually) reduce documentation burden (see also
+ https://github.com/Pylons/pyramid/issues/164). A deprecation warning is
+ now issued when any view-related parameter is passed to
+ ``Configurator.add_route``.
+
+Behavior Changes
+----------------
+
+- A custom request factory is now required to return a response object that
+ has a ``response`` attribute (or "reified"/lazy property) if they the
+ request is meant to be used in a view that uses a renderer. This
+ ``response`` attribute should be an instance of the class
+ ``pyramid.response.Response``.
+
+- The JSON and string renderer factories now assign to
+ ``request.response.content_type`` rather than
+ ``request.response_content_type``. Each renderer factory determines
+ whether it should change the content type of the response by comparing the
+ response's content type against the response's default content type; if the
+ content type is not the default content type (usually ``text/html``), the
+ renderer changes the content type (to ``application/json`` or
+ ``text/plain`` for JSON and string renderers respectively).
+
+- The ``pyramid.wsgi.wsgiapp2`` now uses a slightly different method of
+ figuring out how to "fix" ``SCRIPT_NAME`` and ``PATH_INFO`` for the
+ downstream application. As a result, those values may differ slightly from
+ the perspective of the downstream application (for example, ``SCRIPT_NAME``
+ will now never possess a trailing slash).
+
+Dependencies
+------------
+
+- Pyramid now depends on WebOb >= 1.0.2 as tests depend on the bugfix in that
+ release: "Fix handling of WSGI environs with missing ``SCRIPT_NAME``".
+ (Note that in reality, everyone should probably be using 1.0.4 or better
+ though, as WebOb 1.0.2 and 1.0.3 were effectively brownbag releases.)
+
1.0 (2011-01-30)
================
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 1ef785c3d..5a72f242e 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -131,3 +131,7 @@ Contributors
- Malthe Borch, 2011/02/28
+- Joel Bohman, 2011/04/16
+
+- Juliusz Gonera, 2011/04/17
+
diff --git a/TODO.txt b/TODO.txt
index cb4d5dad4..ac915955c 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -6,9 +6,6 @@ Should-Have
- MultiDict documentation.
-- https://github.com/Pylons/pyramid/issues#issue/67 (fixing would make it
- possible to render a static site from a static dir).
-
- Speed up startup time (defer _bootstrap and registerCommonDirectives()
until needed by ZCML, as well as unfound speedups).
@@ -27,11 +24,6 @@ Should-Have
- translationdir ZCML directive use of ``path_spec`` should maybe die.
-- Provide a response_set_cookie method on the request for rendered responses
- that can be used as input to response.set_cookie? Or maybe accessing
- ``request.response`` creates a Response, and you do
- ``request.response.set_cookie(...)``.
-
- Fix message catalog extraction / compilation documentation.
- Review http://alexmarandon.com/articles/zodb_bfg_pyramid_notes .
@@ -39,6 +31,9 @@ Should-Have
Nice-to-Have
------------
+- Response.RequestClass should probably be pyramid.request.Request but this
+ may imply actually subclassing webob.Response
+
- Consider per-form_id CSRF instead of per-session global CSRF token.
- Better "Extending" chapter.
@@ -94,9 +89,6 @@ Nice-to-Have
action = '^foo$'
mypackage.views.MyView.foo_GET
-- Raise an exception when a value in response_headerlist is not a
- string or decide to encode.
-
- Update App engine chapter with less creaky directions.
- Add functionality that mocks the behavior of ``repoze.browserid``.
diff --git a/docs/api/request.rst b/docs/api/request.rst
index d17441c0a..639d0fcd8 100644
--- a/docs/api/request.rst
+++ b/docs/api/request.rst
@@ -85,6 +85,41 @@
of ``request.exception`` will be ``None`` within response and
finished callbacks.
+ .. attribute:: response
+
+ This attribute is actually a "reified" property which returns an
+ instance of the :class:`pyramid.response.Response` class. The response
+ object returned does not exist until this attribute is accessed. Once
+ it is accessed, subsequent accesses to this request object will return
+ the same :class:`~pyramid.response.Response` object.
+
+ The ``request.response`` API can is used by renderers. A render obtains
+ the response object it will return from a view that uses that renderer
+ by accessing ``request.response``. Therefore, it's possible to use the
+ ``request.response`` API to set up a response object with "the right"
+ attributes (e.g. by calling ``request.response.set_cookie(...)`` or
+ ``request.response.content_type = 'text/plain'``, etc) within a view
+ that uses a renderer. For example, within a view that uses a
+ :term:`renderer`::
+
+ response = request.response
+ response.set_cookie('mycookie', 'mine, all mine!')
+ return {'text':'Value that will be used by the renderer'}
+
+ Mutations to this response object will be preserved in the response sent
+ to the client after rendering.
+
+ Non-renderer code can also make use of request.response instead of
+ creating a response "by hand". For example, in view code::
+
+ response = request.response
+ response.body = 'Hello!'
+ response.content_type = 'text/plain'
+ return response
+
+ Note that the response in this circumstance is not "global"; it still
+ must be returned from the view code if a renderer is not used.
+
.. attribute:: session
If a :term:`session factory` has been configured, this attribute
@@ -127,10 +162,18 @@
.. attribute:: response_*
+ .. warning:: As of Pyramid 1.1, assignment to ``response_*`` attrs are
+ deprecated. Assigning to one will cause a deprecation warning to be
+ emitted. Instead of assigning ``response_*`` attributes to the
+ request, use API of the the :attr:`pyramid.request.Request.response`
+ object (exposed to view code as ``request.response``) to influence
+ response behavior.
+
You can set attributes on a :class:`pyramid.request.Request` which will
influence the behavor of *rendered* responses (views which use a
:term:`renderer` and which don't directly return a response). These
attributes begin with ``response_``, such as ``response_headerlist``. If
you need to influence response values from a view that uses a renderer
(such as the status code, a header, the content type, etc) see,
- :ref:`response_request_attrs`.
+ :ref:`response_prefixed_attrs`.
+
diff --git a/docs/conf.py b/docs/conf.py
index a987106d4..a610351ff 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -93,7 +93,7 @@ copyright = '%s, Agendaless Consulting' % datetime.datetime.now().year
# other places throughout the built documents.
#
# The short X.Y version.
-version = '1.0'
+version = '1.1a0'
# The full version, including alpha/beta/rc tags.
release = version
diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst
index 099bce35f..5ee554284 100644
--- a/docs/narr/advconfig.rst
+++ b/docs/narr/advconfig.rst
@@ -295,15 +295,9 @@ These are the methods of the configurator which provide conflict detection:
:meth:`~pyramid.config.Configurator.set_locale_negotiator` and
:meth:`~pyramid.config.Configurator.set_default_permission`.
-Some other methods of the configurator also indirectly provide conflict
-detection, because they're implemented in terms of conflict-aware methods:
-
-- :meth:`~pyramid.config.Configurator.add_route` does a second type of
- conflict detection when a ``view`` parameter is passed (it calls
- ``add_view``).
-
-- :meth:`~pyramid.config.Configurator.static_view`, a frontend for
- ``add_route`` and ``add_view``.
+:meth:`~pyramid.config.Configurator.add_static_view` also indirectly
+provides conflict detection, because it's implemented in terms of the
+conflict-aware ``add_route`` and ``add_view`` methods.
.. _including_configuration:
diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst
index bbb673ecc..8d0e7058c 100644
--- a/docs/narr/assets.rst
+++ b/docs/narr/assets.rst
@@ -341,7 +341,8 @@ application's startup code.
# .. every other add_route declaration should come
# before this one, as it will, by default, catch all requests
- config.add_route('catchall_static', '/*subpath', 'myapp.static.static_view')
+ config.add_route('catchall_static', '/*subpath')
+ config.add_view('myapp.static.static_view', route_name='catchall_static')
The special name ``*subpath`` above is used by the
:class:`~pyramid.view.static` view callable to signify the path of the file
@@ -384,8 +385,8 @@ Or you might register it to be the view callable for a particular route:
.. code-block:: python
:linenos:
- config.add_route('favicon', '/favicon.ico',
- view='myapp.views.favicon_view')
+ config.add_route('favicon', '/favicon.ico')
+ config.add_view('myapp.views.favicon_view', route_name='favicon')
Because this is a simple view callable, it can be protected with a
:term:`permission` or can be configured to respond under different
diff --git a/docs/narr/environment.rst b/docs/narr/environment.rst
index 7b7946aae..8c299f3a3 100644
--- a/docs/narr/environment.rst
+++ b/docs/narr/environment.rst
@@ -381,3 +381,66 @@ around in overridden asset directories. ``reload_assets`` makes the system
*very slow* when templates are in use. Never set ``reload_assets`` to
``True`` on a production system.
+Adding A Custom Setting
+-----------------------
+
+From time to time, you may need to add a custom setting to your application.
+Here's how:
+
+- If you're using an ``.ini`` file, change the ``.ini`` file, adding the
+ setting to the ``[app:foo]`` section representing your Pyramid application.
+ For example:
+
+ .. code-block:: ini
+
+ [app:myapp]
+ # .. other settings
+ debug_frobnosticator = True
+
+- In the ``main()`` function that represents the place that your Pyramid WSGI
+ application is created, anticipate that you'll be getting this key/value
+ pair as a setting and do any type conversion necessary.
+
+ If you've done any type conversion of your custom value, reset the
+ converted values into the ``settings`` dictionary *before* you pass the
+ dictionary as ``settings`` to the :term:`Configurator`. For example:
+
+ .. code-block:: python
+
+ def main(global_config, **settings):
+ # ...
+ from pyramid.settings import asbool
+ debug_frobnosticator = asbool(settings.get(
+ 'debug_frobnosticator', 'false'))
+ settings['debug_frobnosticator'] = debug_frobnosticator
+ config = Configurator(settings=settings)
+
+ .. note:: It's especially important that you mutate the ``settings``
+ dictionary with the converted version of the variable *before* passing
+ it to the Configurator: the configurator makes a *copy* of ``settings``,
+ it doesn't use the one you pass directly.
+
+- In the runtime code that you need to access the new settings value, find
+ the value in the ``registry.settings`` dictionary and use it. In
+ :term:`view` code (or any other code that has access to the request), the
+ easiest way to do this is via ``request.registry.settings``. For example:
+
+ .. code-block:: python
+
+ registry = request.registry.settings
+ debug_frobnosticator = settings['debug_frobnosticator']
+
+ If you wish to use the value in code that does not have access to the
+ request and you wish to use the value, you'll need to use the
+ :func:`pyramid.threadlocal.get_current_registry` API to obtain the current
+ registry, then ask for its ``settings`` attribute. For example:
+
+ .. code-block:: python
+
+ registry = pyramid.threadlocal.get_current_registry()
+ settings = registry.settings
+ debug_frobnosticator = settings['debug_frobnosticator']
+
+
+
+
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index 780cb0975..f8ed743fb 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -33,7 +33,7 @@ URL Dispatch Only
~~~~~~~~~~~~~~~~~
An application that uses :term:`url dispatch` exclusively to map URLs to code
-will often have statements like this within your application startup
+will often have statements like this within application startup
configuration:
.. code-block:: python
@@ -41,15 +41,20 @@ configuration:
# config is an instance of pyramid.config.Configurator
- config.add_route('foobar', '{foo}/{bar}', view='myproject.views.foobar')
- config.add_route('bazbuz', '{baz}/{buz}', view='myproject.views.bazbuz')
+ config.add_route('foobar', '{foo}/{bar}')
+ config.add_route('bazbuz', '{baz}/{buz}')
-Each :term:`route` typically corresponds to a single view callable,
-and when that route is matched during a request, the view callable
-named by the ``view`` attribute is invoked.
+ config.add_view('myproject.views.foobar', route_name='foobar')
+ config.add_view('myproject.views.bazbuz', route_name='bazbuz')
-Typically, an application that uses only URL dispatch won't perform any calls
-to :meth:`pyramid.config.Configurator.add_view` in its startup code.
+Each :term:`route` corresponds to one or more view callables. Each view
+callable is associated with a route by passing a ``route_name`` parameter
+that matches its name during a call to
+:meth:`~pyramid.config.Configurator.add_view`. When a route is matched
+during a request, :term:`view lookup` is used to match the request to its
+associated view callable. The presence of calls to
+:meth:`~pyramid.config.Configurator.add_route` signify that an application is
+using URL dispatch.
Traversal Only
~~~~~~~~~~~~~~
@@ -196,12 +201,9 @@ remainder becomes the path used to perform traversal.
The ``*remainder`` route pattern syntax is explained in more
detail within :ref:`route_pattern_syntax`.
-Note that unlike the examples provided within :ref:`urldispatch_chapter`, the
-``add_route`` configuration statement named previously does not pass a
-``view`` argument. This is because a hybrid mode application relies on
-:term:`traversal` to do :term:`resource location` and :term:`view lookup`
-instead of invariably invoking a specific view callable named directly within
-the matched route's configuration.
+A hybrid mode application relies more heavily on :term:`traversal` to do
+:term:`resource location` and :term:`view lookup` than most examples indicate
+within :ref:`urldispatch_chapter`.
Because the pattern of the above route ends with ``*traverse``, when this
route configuration is matched during a request, :app:`Pyramid` will attempt
@@ -426,13 +428,11 @@ attribute.
Using ``*subpath`` in a Route Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There are certain extremely rare cases when you'd like to influence
-the traversal :term:`subpath` when a route matches without actually
-performing traversal. For instance, the
-:func:`pyramid.wsgi.wsgiapp2` decorator and the
-:class:`pyramid.view.static` helper attempt to compute
-``PATH_INFO`` from the request's subpath, so it's useful to be able to
-influence this value.
+There are certain extremely rare cases when you'd like to influence the
+traversal :term:`subpath` when a route matches without actually performing
+traversal. For instance, the :func:`pyramid.wsgi.wsgiapp2` decorator and the
+:class:`pyramid.view.static` helper attempt to compute ``PATH_INFO`` from the
+request's subpath, so it's useful to be able to influence this value.
When ``*subpath`` exists in a pattern, no path is actually traversed,
but the traversal algorithm will return a :term:`subpath` list implied
@@ -442,8 +442,8 @@ commonly in route declarations that look like this:
.. code-block:: python
:linenos:
- config.add_route('static', '/static/*subpath',
- view='mypackage.views.static_view')
+ config.add_route('static', '/static/*subpath')
+ config.add_view('mypackage.views.static_view', route_name='static')
Where ``mypackage.views.static_view`` is an instance of
:class:`pyramid.view.static`. This effectively tells the static helper to
@@ -458,11 +458,16 @@ application. We'll detail them here.
Registering a Default View for a Route That Has a ``view`` Attribute
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. warning:: As of :app:`Pyramid` 1.1 this section is slated to be removed in
+ a later documentation release because the the ability to add views
+ directly to the :term:`route configuration` by passing a ``view`` argument
+ to ``add_route`` has been deprecated.
+
It is an error to provide *both* a ``view`` argument to a :term:`route
configuration` *and* a :term:`view configuration` which names a
``route_name`` that has no ``name`` value or the empty ``name`` value. For
-example, this pair of declarations will generate a "conflict" error at
-startup time.
+example, this pair of declarations will generate a conflict error at startup
+time.
.. code-block:: python
:linenos:
@@ -490,8 +495,8 @@ Can also be spelled like so:
config.add_route('home', '{foo}/{bar}/*traverse')
config.add_view('myproject.views.home', route_name='home')
-The two spellings are logically equivalent. In fact, the former is
-just a syntactical shortcut for the latter.
+The two spellings are logically equivalent. In fact, the former is just a
+syntactical shortcut for the latter.
Binding Extra Views Against a Route Configuration that Doesn't Have a ``*traverse`` Element In Its Pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst
index 0b7cdb834..c3533648b 100644
--- a/docs/narr/renderers.rst
+++ b/docs/narr/renderers.rst
@@ -92,8 +92,8 @@ will be employed.
return HTTPFound(location='http://example.com') # any renderer avoided
Views which use a renderer can vary non-body response attributes (such as
-headers and the HTTP status code) by attaching properties to the request.
-See :ref:`response_request_attrs`.
+headers and the HTTP status code) by attaching a property to the
+``request.response`` attribute See :ref:`request_response_attr`.
Additional renderers can be added by developers to the system as necessary
(see :ref:`adding_and_overriding_renderers`).
@@ -147,7 +147,8 @@ representing the ``str()`` serialization of the return value:
{'content': 'Hello!'}
Views which use the string renderer can vary non-body response attributes by
-attaching properties to the request. See :ref:`response_request_attrs`.
+using the API of the ``request.response`` attribute. See
+:ref:`request_response_attr`.
.. index::
pair: renderer; JSON
@@ -199,7 +200,8 @@ You can configure a view to use the JSON renderer by naming ``json`` as the
Views which use the JSON renderer can vary non-body response attributes by
-attaching properties to the request. See :ref:`response_request_attrs`.
+using the api of the ``request.response`` attribute. See
+:ref:`request_response_attr`.
.. index::
pair: renderer; chameleon
@@ -269,8 +271,9 @@ Here's an example view configuration which uses a Chameleon text renderer:
context='myproject.resources.Hello',
renderer='myproject:templates/foo.txt')
-Views which use a Chameleon renderer can vary response attributes by
-attaching properties to the request. See :ref:`response_request_attrs`.
+Views which use a Chameleon renderer can vary response attributes by using
+the API of the ``request.response`` attribute. See
+:ref:`request_response_attr`.
.. index::
pair: renderer; mako
@@ -333,7 +336,7 @@ additional :ref:`mako_template_renderer_settings`.
single: response headers (from a renderer)
single: renderer response headers
-.. _response_request_attrs:
+.. _request_response_attr:
Varying Attributes of Rendered Responses
----------------------------------------
@@ -342,9 +345,43 @@ Before a response constructed by a :term:`renderer` is returned to
:app:`Pyramid`, several attributes of the request are examined which have the
potential to influence response behavior.
-View callables that don't directly return a response should set these
-attributes on the ``request`` object via ``setattr`` during their execution,
-to influence associated response attributes.
+View callables that don't directly return a response should use the API of
+the :class:`pyramid.response.Response` attribute available as
+``request.response`` during their execution, to influence associated response
+behavior.
+
+For example, if you need to change the response status from within a view
+callable that uses a renderer, assign the ``status`` attribute to the
+``response`` attribute of the request before returning a result:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.view import view_config
+
+ @view_config(name='gone', renderer='templates/gone.pt')
+ def myview(request):
+ request.response.status = '404 Not Found'
+ return {'URL':request.URL}
+
+For more information on attributes of the request, see the API documentation
+in :ref:`request_module`. For more information on the API of
+``request.response``, see :class:`pyramid.response.Response`.
+
+.. _response_prefixed_attrs:
+
+Deprecated Mechanism to Vary Attributes of Rendered Responses
+-------------------------------------------------------------
+
+.. warning:: This section describes behavior deprecated in Pyramid 1.1.
+
+In previous releases of Pyramid (1.0 and before), the ``request.response``
+attribute did not exist. Instead, Pyramid required users to set special
+``response_`` -prefixed attributes of the request to influence response
+behavior. As of Pyramid 1.1, those request attributes are deprecated and
+their use will cause a deprecation warning to be issued when used. Until
+their existence is removed completely, we document them below, for benefit of
+people with older code bases.
``response_content_type``
Defines the content-type of the resulting response,
@@ -367,23 +404,6 @@ to influence associated response attributes.
returning various values in the ``response_headerlist``, this is purely a
convenience.
-For example, if you need to change the response status from within a view
-callable that uses a renderer, assign the ``response_status`` attribute to
-the request before returning a result:
-
-.. code-block:: python
- :linenos:
-
- from pyramid.view import view_config
-
- @view_config(name='gone', renderer='templates/gone.pt')
- def myview(request):
- request.response_status = '404 Not Found'
- return {'URL':request.URL}
-
-For more information on attributes of the request, see the API
-documentation in :ref:`request_module`.
-
.. index::
single: renderer (adding)
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 426ec229b..150b173e3 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -367,13 +367,13 @@ templates as renderers. See :ref:`available_template_system_bindings`.
render a view without needing to fork your code to do so. See
:ref:`extending_chapter` for more information.
-By default, views rendered via a template renderer return a
-:term:`Response` object which has a *status code* of ``200 OK``, and a
-*content-type* of ``text/html``. To vary attributes of the response
-of a view that uses a renderer, such as the content-type, headers, or
-status attributes, you must set attributes on the *request* object
-within the view before returning the dictionary. See
-:ref:`response_request_attrs` for more information.
+By default, views rendered via a template renderer return a :term:`Response`
+object which has a *status code* of ``200 OK``, and a *content-type* of
+``text/html``. To vary attributes of the response of a view that uses a
+renderer, such as the content-type, headers, or status attributes, you must
+use the API of the :class:`pyramid.response.Response` object exposed as
+``request.response`` within the view before returning the dictionary. See
+:ref:`request_response_attr` for more information.
The same set of system values are provided to templates rendered via a
renderer view configuration as those provided to templates rendered
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 219753882..1024dd188 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -54,17 +54,19 @@ Route Configuration
-------------------
:term:`Route configuration` is the act of adding a new :term:`route` to an
-application. A route has a *pattern*, representing a pattern meant to match
+application. A route has a *name*, which acts as an identifier to be used
+for URL generation. The name also allows developers to associate a view
+configuration with the route. A route also has a *pattern*, meant to match
against the ``PATH_INFO`` portion of a URL (the portion following the scheme
-and port, e.g. ``/foo/bar`` in the URL ``http://localhost:8080/foo/bar``),
-and a *route name*, which is used by developers within a :app:`Pyramid`
-application to uniquely identify a particular route when generating a URL.
-It also optionally has a ``factory``, a set of :term:`route predicate`
-parameters, and a set of :term:`view` parameters.
+and port, e.g. ``/foo/bar`` in the URL ``http://localhost:8080/foo/bar``). It
+also optionally has a ``factory`` and a set of :term:`route predicate`
+attributes.
.. index::
single: add_route
+.. _config-add-route:
+
Configuring a Route via The ``add_route`` Configurator Method
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -79,7 +81,8 @@ example:
# pyramid.config.Configurator class; "myview" is assumed
# to be a "view callable" function
from views import myview
- config.add_route('myroute', '/prefix/{one}/{two}', view=myview)
+ config.add_route('myroute', '/prefix/{one}/{two}')
+ config.add_view(myview, route_name='myroute')
.. versionchanged:: 1.0a4
Prior to 1.0a4, routes allow for a marker starting with a ``:``, for
@@ -89,9 +92,47 @@ example:
.. index::
single: route configuration; view callable
+.. _add_route_view_config:
+
Route Configuration That Names a View Callable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. warning:: This section describes a feature which has been deprecated in
+ Pyramid 1.1 and higher. In order to reduce confusion and documentation
+ burden, passing view-related parameters to
+ :meth:`~pyramid.config.Configurator.add_route` is deprecated.
+
+ In versions earlier than 1.1, a view was permitted to be connected to a
+ route using a set of ``view*`` parameters passed to the
+ :meth:`~pyramid.config.Configurator.add_route`. This was a shorthand
+ which replaced the need to perform a subsequent call to
+ :meth:`~pyramid.config.Configurator.add_view` as described in
+ :ref:`config-add-route`. For example, it was valid (and often recommended)
+ to do:
+
+ .. code-block:: python
+
+ config.add_route('home', '/', view='mypackage.views.myview',
+ view_renderer='some/renderer.pt')
+
+ Instead of the equivalent:
+
+ .. code-block:: python
+
+ config.add_route('home', '/')
+ config.add_view('mypackage.views.myview', route_name='home')
+ renderer='some/renderer.pt')
+
+ Passing ``view*`` arguments to ``add_route`` as shown in the first
+ example above is now deprecated in favor of connecting a view to a
+ predefined route via :meth:`~pyramid.config.Configurator.add_view` using
+ the route's ``route_name`` parameter, as shown in the second example
+ above.
+
+ A deprecation warning is now issued when any view-related parameter is
+ passed to ``Configurator.add_route``. The recommended way to associate a
+ view with a route is documented in :ref:`config-add-route`.
+
When a route configuration declaration names a ``view`` attribute, the value
of the attribute will reference a :term:`view callable`. This view callable
will be invoked when the route matches. A view callable, as described in
@@ -125,6 +166,9 @@ When a route configuration names a ``view`` attribute, the :term:`view
callable` named as that ``view`` attribute will always be found and invoked
when the associated route pattern matches during a request.
+See :meth:`pyramid.config.Configurator.add_route` for a description of
+view-related arguments.
+
.. index::
single: route path pattern syntax
@@ -363,8 +407,9 @@ resource of the view callable ultimately found via :term:`view lookup`.
.. code-block:: python
:linenos:
- config.add_route('abc', '/abc', view='myproject.views.theview',
+ config.add_route('abc', '/abc',
factory='myproject.resources.root_factory')
+ config.add_view('myproject.views.theview', route_name='abc')
The factory can either be a Python object or a :term:`dotted Python name` (a
string) which points to such a Python object, as it is above.
@@ -395,7 +440,8 @@ process. Examples of route predicate arguments are ``pattern``, ``xhr``, and
``request_method``.
Other arguments are view configuration related arguments. These only have an
-effect when the route configuration names a ``view``.
+effect when the route configuration names a ``view``. These arguments have
+been deprecated as of :app:`Pyramid` 1.1 (see :ref:`add_route_view_config`).
Other arguments are ``name`` and ``factory``. These arguments represent
neither predicates nor view configuration information.
@@ -547,8 +593,8 @@ If any route matches, the route matching process stops. The :term:`request`
is decorated with a special :term:`interface` which describes it as a "route
request", the :term:`context` resource is generated, and the context and the
resulting request are handed off to :term:`view lookup`. During view lookup,
-if any ``view`` argument was provided within the matched route configuration,
-the :term:`view callable` it points to is called.
+if a :term:`view callable` associated with the matched route is found, that
+view is called.
When a route configuration is declared, it may contain :term:`route
predicate` arguments. All route predicates associated with a route
@@ -621,7 +667,8 @@ result in a particular view callable being invoked:
.. code-block:: python
:linenos:
- config.add_route('idea', 'site/{id}', view='mypackage.views.site_view')
+ config.add_route('idea', 'site/{id}')
+ config.add_view('mypackage.views.site_view', route_name='idea')
When a route configuration with a ``view`` attribute is added to the system,
and an incoming request matches the *pattern* of the route configuration, the
@@ -665,9 +712,13 @@ add to your application:
.. code-block:: python
:linenos:
- config.add_route('idea', 'ideas/{idea}', view='mypackage.views.idea_view')
- config.add_route('user', 'users/{user}', view='mypackage.views.user_view')
- config.add_route('tag', 'tags/{tags}', view='mypackage.views.tag_view')
+ config.add_route('idea', 'ideas/{idea}')
+ config.add_route('user', 'users/{user}')
+ config.add_route('tag', 'tags/{tags}')
+
+ config.add_view('mypackage.views.idea_view', route_name='idea')
+ config.add_view('mypackage.views.user_view', route_name='user')
+ config.add_view('mypackage.views.tag_view', route_name='tag')
The above configuration will allow :app:`Pyramid` to service URLs in these
forms:
@@ -717,9 +768,8 @@ An example of using a route with a factory:
.. code-block:: python
:linenos:
- config.add_route('idea', 'ideas/{idea}',
- view='myproject.views.idea_view',
- factory='myproject.resources.Idea')
+ config.add_route('idea', 'ideas/{idea}', factory='myproject.resources.Idea')
+ config.add_view('myproject.views.idea_view', route_name='idea')
The above route will manufacture an ``Idea`` resource as a :term:`context`,
assuming that ``mypackage.resources.Idea`` resolves to a class that accepts a
@@ -735,34 +785,6 @@ request in its ``__init__``. For example:
In a more complicated application, this root factory might be a class
representing a :term:`SQLAlchemy` model.
-Example 4
-~~~~~~~~~
-
-It is possible to create a route declaration without a ``view`` attribute,
-but associate the route with a :term:`view callable` using a ``view``
-declaration.
-
-.. code-block:: python
- :linenos:
-
- config.add_route('idea', 'site/{id}')
- config.add_view(route_name='idea', view='mypackage.views.site_view')
-
-This set of configuration parameters creates a configuration completely
-equivalent to this example provided in :ref:`urldispatch_example1`:
-
-.. code-block:: python
- :linenos:
-
- config.add_route('idea', 'site/{id}', view='mypackage.views.site_view')
-
-In fact, the spelling which names a ``view`` attribute is just syntactic
-sugar for the more verbose spelling which contains separate view and route
-registrations.
-
-More uses for this style of associating views with routes are explored in
-:ref:`hybrid_chapter`.
-
.. index::
single: matching the root URL
single: root url (matching)
@@ -777,14 +799,14 @@ It's not entirely obvious how to use a route pattern to match the root URL
.. code-block:: python
:linenos:
- config.add_route('root', '', view='mypackage.views.root_view')
+ config.add_route('root', '')
Or provide the literal string ``/`` as the pattern:
.. code-block:: python
:linenos:
- config.add_route('root', '/', view='mypackage.views.root_view')
+ config.add_route('root', '/')
.. index::
single: generating route URLs
@@ -834,10 +856,11 @@ route configuration looks like so:
.. code-block:: python
:linenos:
- config.add_route('noslash', 'no_slash',
- view='myproject.views.no_slash')
- config.add_route('hasslash', 'has_slash/',
- view='myproject.views.has_slash')
+ config.add_route('noslash', 'no_slash')
+ config.add_route('hasslash', 'has_slash/')
+
+ config.add_view('myproject.views.no_slash', route_name='noslash')
+ config.add_view('myproject.views.has_slash', route_name='hasslash')
If a request enters the application with the ``PATH_INFO`` value of
``/has_slash/``, the second route will match. If a request enters the
@@ -864,8 +887,8 @@ the application's startup configuration, adding the following stanza:
.. code-block:: python
:linenos:
- config.add_view(context='pyramid.exceptions.NotFound',
- view='pyramid.view.append_slash_notfound_view')
+ config.add_view('pyramid.view.append_slash_notfound_view',
+ context='pyramid.exceptions.NotFound')
See :ref:`view_module` and :ref:`changing_the_notfound_view` for more
information about the slash-appending not found view and for a more general
@@ -1063,30 +1086,25 @@ is executed.
Route View Callable Registration and Lookup Details
---------------------------------------------------
-The purpose of making it possible to specify a view callable within a route
-configuration is to prevent developers from needing to deeply understand the
-details of :term:`resource location` and :term:`view lookup`. When a route
-names a view callable as a ``view`` argument, and a request enters the system
-which matches the pattern of the route, the result is simple: the view
-callable associated with the route is invoked with the request that caused
-the invocation.
+When a request enters the system which matches the pattern of the route, the
+usual result is simple: the view callable associated with the route is
+invoked with the request that caused the invocation.
For most usage, you needn't understand more than this; how it works is an
implementation detail. In the interest of completeness, however, we'll
explain how it *does* work in the this section. You can skip it if you're
uninterested.
-When a ``view`` attribute is attached to a route configuration,
-:app:`Pyramid` ensures that a :term:`view configuration` is registered that
-will always be found when the route pattern is matched during a request. To
-do so:
+When a view is associated with a route configuration, :app:`Pyramid` ensures
+that a :term:`view configuration` is registered that will always be found
+when the route pattern is matched during a request. To do so:
- A special route-specific :term:`interface` is created at startup time for
each route configuration declaration.
-- When a route configuration declaration mentions a ``view`` attribute, a
+- When an ``add_view`` statement mentions a ``route name`` attribute, a
:term:`view configuration` is registered at startup time. This view
- configuration uses the route-specific interface as a :term:`request` type.
+ configuration uses a route-specific interface as a :term:`request` type.
- At runtime, when a request causes any route to match, the :term:`request`
object is decorated with the route-specific interface.
diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst
index 9b2500a2b..743cc016e 100644
--- a/docs/narr/viewconfig.rst
+++ b/docs/narr/viewconfig.rst
@@ -59,7 +59,8 @@ View configuration is performed in one of these ways:
- By specifying a view within a :term:`route configuration`. View
configuration via a route configuration is performed by using the
:meth:`pyramid.config.Configurator.add_route` method, passing a ``view``
- argument specifying a view callable.
+ argument specifying a view callable. This pattern of view configuration is
+ deprecated as of :app:`Pyramid` 1.1.
.. note:: A package named ``pyramid_handlers`` (available from PyPI) provides
an analogue of :term:`Pylons` -style "controllers", which are a special
diff --git a/docs/narr/zca.rst b/docs/narr/zca.rst
index fcab0653e..19c52d0c9 100644
--- a/docs/narr/zca.rst
+++ b/docs/narr/zca.rst
@@ -66,15 +66,15 @@ more than a single application per process. For example, use of a
:term:`Paste` "composite" allows you to run separate individual WSGI
applications in the same process, each answering requests for some URL
prefix. This makes it possible to run, for example, a TurboGears
-application at ``/turbogears`` and a BFG application at ``/bfg``, both
-served up using the same :term:`WSGI` server within a single Python
-process.
+application at ``/turbogears`` and a :app:`Pyramid` application at
+``/pyramid``, both served up using the same :term:`WSGI` server
+within a single Python process.
Most production Zope applications are relatively large, making it
impractical due to memory constraints to run more than one Zope
-application per Python process. However, a :app:`Pyramid`
-application may be very small and consume very little memory, so it's
-a reasonable goal to be able to run more than one BFG application per
+application per Python process. However, a :app:`Pyramid` application
+may be very small and consume very little memory, so it's a reasonable
+goal to be able to run more than one :app:`Pyramid` application per
process.
In order to make it possible to run more than one :app:`Pyramid`
@@ -182,10 +182,10 @@ global ZCA API. Without special treatment, the ZCA global APIs will
always return the global ZCA registry (the one in
``zope.component.globalregistry.base``).
-To "fix" this and make the ZCA global APIs use the "current" BFG
-registry, you need to call
-:meth:`~pyramid.config.Configurator.hook_zca` within your
-setup code. For example:
+To "fix" this and make the ZCA global APIs use the "current"
+:app:`Pyramid` registry, you need to call
+:meth:`~pyramid.config.Configurator.hook_zca` within your setup code.
+For example:
.. code-block:: python
:linenos:
@@ -253,7 +253,7 @@ Lines 5, 6, and 7 above are the interesting ones. Line 5 retrieves
the global ZCA component registry. Line 6 creates a
:term:`Configurator`, passing the global ZCA registry into its
constructor as the ``registry`` argument. Line 7 "sets up" the global
-registry with BFG-specific registrations; this is code that is
+registry with Pyramid-specific registrations; this is code that is
normally executed when a registry is constructed rather than created,
but we must call it "by hand" when we pass an explicit registry.
diff --git a/docs/tutorials/wiki/authorization.rst b/docs/tutorials/wiki/authorization.rst
index ee86eb543..e4480d6d9 100644
--- a/docs/tutorials/wiki/authorization.rst
+++ b/docs/tutorials/wiki/authorization.rst
@@ -7,21 +7,25 @@ edit, and add pages to our wiki. For purposes of demonstration we'll change
our application to allow people whom are members of a *group* named
``group:editors`` to add and edit wiki pages but we'll continue allowing
anyone with access to the server to view pages. :app:`Pyramid` provides
-facilities for *authorization* and *authentication*. We'll make use of both
-features to provide security to our application.
+facilities for :term:`authorization` and :term:`authentication`. We'll make
+use of both features to provide security to our application.
-The source code for this tutorial stage can be browsed via
-`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/
-<http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/>`_.
+We will add an :term:`authentication policy` and an
+:term:`authorization policy` to our :term:`application
+registry`, add a ``security.py`` module and give our :term:`root`
+resource an :term:`ACL`.
+Then we will add ``login`` and ``logout`` views, and modify the
+existing views to make them return a ``logged_in`` flag to the
+renderer and add :term:`permission` declarations to their ``view_config``
+decorators.
-Configuring a ``pyramid`` Authentication Policy
---------------------------------------------------
+Finally, we will add a ``login.pt`` template and change the existing
+``view.pt`` and ``edit.pt`` to show a "Logout" link when not logged in.
-For any :app:`Pyramid` application to perform authorization, we need to add a
-``security.py`` module and we'll need to change our :term:`application
-registry` to add an :term:`authentication policy` and a :term:`authorization
-policy`.
+The source code for this tutorial stage can be browsed via
+`http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/
+<http://github.com/Pylons/pyramid/tree/master/docs/tutorials/wiki/src/authorization/>`_.
Adding Authentication and Authorization Policies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -64,6 +68,43 @@ user and groups sources. Note that the ``editor`` user is a member of the
``group:editors`` group in our dummy group data (the ``GROUPS`` data
structure).
+Giving Our Root Resource an ACL
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We need to give our root resource object an :term:`ACL`. This ACL will be
+sufficient to provide enough information to the :app:`Pyramid` security
+machinery to challenge a user who doesn't have appropriate credentials when
+he attempts to invoke the ``add_page`` or ``edit_page`` views.
+
+We need to perform some imports at module scope in our ``models.py`` file:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.security import Allow
+ from pyramid.security import Everyone
+
+Our root resource object is a ``Wiki`` instance. We'll add the following
+line at class scope to our ``Wiki`` class:
+
+.. code-block:: python
+ :linenos:
+
+ __acl__ = [ (Allow, Everyone, 'view'),
+ (Allow, 'group:editors', 'edit') ]
+
+It's only happenstance that we're assigning this ACL at class scope. An ACL
+can be attached to an object *instance* too; this is how "row level security"
+can be achieved in :app:`Pyramid` applications. We actually only need *one*
+ACL for the entire system, however, because our security requirements are
+simple, so this feature is not demonstrated.
+
+Our resulting ``models.py`` file will now look like so:
+
+.. literalinclude:: src/authorization/tutorial/models.py
+ :linenos:
+ :language: python
+
Adding Login and Logout Views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -129,6 +170,38 @@ template. For example:
logged_in = logged_in,
edit_url = edit_url)
+Adding ``permission`` Declarations to our ``view_config`` Decorators
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To protect each of our views with a particular permission, we need to pass a
+``permission`` argument to each of our :class:`pyramid.view.view_config`
+decorators. To do so, within ``views.py``:
+
+- We add ``permission='view'`` to the decorator attached to the
+ ``view_wiki`` and ``view_page`` view functions. This makes the
+ assertion that only users who possess the ``view`` permission
+ against the context resource at the time of the request may
+ invoke these views. We've granted
+ :data:`pyramid.security.Everyone` the view permission at the
+ root model via its ACL, so everyone will be able to invoke the
+ ``view_wiki`` and ``view_page`` views.
+
+- We add ``permission='edit'`` to the decorator attached to the
+ ``add_page`` and ``edit_page`` view functions. This makes the
+ assertion that only users who possess the effective ``edit``
+ permission against the context resource at the time of the
+ request may invoke these views. We've granted the
+ ``group:editors`` principal the ``edit`` permission at the
+ root model via its ACL, so only a user whom is a member of
+ the group named ``group:editors`` will able to invoke the
+ ``add_page`` or ``edit_page`` views. We've likewise given
+ the ``editor`` user membership to this group via the
+ ``security.py`` file by mapping him to the ``group:editors``
+ group in the ``GROUPS`` data structure (``GROUPS
+ = {'editor':['group:editors']}``); the ``groupfinder``
+ function consults the ``GROUPS`` data structure. This means
+ that the ``editor`` user can add and edit pages.
+
Adding the ``login.pt`` Template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -154,92 +227,29 @@ class="app-welcome align-right">`` div:
<a href="${request.application_url}/logout">Logout</a>
</span>
-Giving Our Root Resource an ACL
--------------------------------
-
-We need to give our root resource object an :term:`ACL`. This ACL will be
-sufficient to provide enough information to the :app:`Pyramid` security
-machinery to challenge a user who doesn't have appropriate credentials when
-he attempts to invoke the ``add_page`` or ``edit_page`` views.
+Seeing Our Changes To ``views.py`` and our Templates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We need to perform some imports at module scope in our ``models.py`` file:
+Our ``views.py`` module will look something like this when we're done:
-.. code-block:: python
+.. literalinclude:: src/authorization/tutorial/views.py
:linenos:
+ :language: python
- from pyramid.security import Allow
- from pyramid.security import Everyone
-
-Our root resource object is a ``Wiki`` instance. We'll add the following
-line at class scope to our ``Wiki`` class:
+Our ``edit.pt`` template will look something like this when we're done:
-.. code-block:: python
+.. literalinclude:: src/authorization/tutorial/templates/edit.pt
:linenos:
+ :language: xml
- __acl__ = [ (Allow, Everyone, 'view'),
- (Allow, 'group:editors', 'edit') ]
-
-It's only happenstance that we're assigning this ACL at class scope. An ACL
-can be attached to an object *instance* too; this is how "row level security"
-can be achieved in :app:`Pyramid` applications. We actually only need *one*
-ACL for the entire system, however, because our security requirements are
-simple, so this feature is not demonstrated.
-
-Our resulting ``models.py`` file will now look like so:
+Our ``view.pt`` template will look something like this when we're done:
-.. literalinclude:: src/authorization/tutorial/models.py
+.. literalinclude:: src/authorization/tutorial/templates/view.pt
:linenos:
- :language: python
-
-Adding ``permission`` Declarations to our ``view_config`` Decorators
---------------------------------------------------------------------
-
-To protect each of our views with a particular permission, we need to pass a
-``permission`` argument to each of our :class:`pyramid.view.view_config`
-decorators. To do so, within ``views.py``:
-
-- We add ``permission='view'`` to the decorator attached to the ``view_wiki``
- view function. This makes the assertion that only users who possess the
- ``view`` permission against the context resource at the time of the request
- may invoke this view. We've granted :data:`pyramid.security.Everyone` the
- view permission at the root model via its ACL, so everyone will be able to
- invoke the ``view_wiki`` view.
-
-- We add ``permission='view'`` to the decorator attached to the ``view_page``
- view function. This makes the assertion that only users who possess the
- effective ``view`` permission against the context resource at the time of
- the request may invoke this view. We've granted
- :data:`pyramid.security.Everyone` the view permission at the root model via
- its ACL, so everyone will be able to invoke the ``view_page`` view.
-
-- We add ``permission='edit'`` to the decorator attached to the ``add_page``
- view function. This makes the assertion that only users who possess the
- effective ``edit`` permission against the context resource at the time of
- the request may invoke this view. We've granted the ``group:editors``
- principal the ``edit`` permission at the root model via its ACL, so only
- the a user whom is a member of the group named ``group:editors`` will able
- to invoke the ``add_page`` view. We've likewise given the ``editor`` user
- membership to this group via thes ``security.py`` file by mapping him to
- the ``group:editors`` group in the ``GROUPS`` data structure (``GROUPS =
- {'editor':['group:editors']}``); the ``groupfinder`` function consults the
- ``GROUPS`` data structure. This means that the ``editor`` user can add
- pages.
-
-- We add ``permission='edit'`` to the decorator attached to the ``edit_page``
- view function. This makes the assertion that only users who possess the
- effective ``edit`` permission against the context resource at the time of
- the request may invoke this view. We've granted the ``group:editors``
- principal the ``edit`` permission at the root model via its ACL, so only
- the a user whom is a member of the group named ``group:editors`` will able
- to invoke the ``edit_page`` view. We've likewise given the ``editor`` user
- membership to this group via thes ``security.py`` file by mapping him to
- the ``group:editors`` group in the ``GROUPS`` data structure (``GROUPS =
- {'editor':['group:editors']}``); the ``groupfinder`` function consults the
- ``GROUPS`` data structure. This means that the ``editor`` user can edit
- pages.
+ :language: xml
Viewing the Application in a Browser
-------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We can finally examine our application in a browser. The views we'll try are
as follows:
@@ -267,35 +277,7 @@ as follows:
credentials with the username ``editor``, password ``editor`` will
show the edit page form being displayed.
-Seeing Our Changes To ``views.py`` and our Templates
-----------------------------------------------------
-
-Our ``views.py`` module will look something like this when we're done:
-
-.. literalinclude:: src/authorization/tutorial/views.py
- :linenos:
- :language: python
-
-Our ``edit.pt`` template will look something like this when we're done:
-
-.. literalinclude:: src/authorization/tutorial/templates/edit.pt
- :linenos:
- :language: xml
-
-Our ``view.pt`` template will look something like this when we're done:
-
-.. literalinclude:: src/authorization/tutorial/templates/view.pt
- :linenos:
- :language: xml
-
-Revisiting the Application
----------------------------
-
-When we revisit the application in a browser, and log in (as a result
-of hitting an edit or add page and submitting the login form with the
-``editor`` credentials), we'll see a Logout link in the upper right
-hand corner. When we click it, we're logged out, and redirected back
-to the front page.
-
-
-
+- After logging in (as a result of hitting an edit or add page and
+ submitting the login form with the ``editor`` credentials), we'll see
+ a Logout link in the upper right hand corner. When we click it,
+ we're logged out, and redirected back to the front page.
diff --git a/docs/tutorials/wiki/definingmodels.rst b/docs/tutorials/wiki/definingmodels.rst
index 3d2d01061..baf497458 100644
--- a/docs/tutorials/wiki/definingmodels.rst
+++ b/docs/tutorials/wiki/definingmodels.rst
@@ -89,70 +89,16 @@ something like this:
:linenos:
:language: python
-Removing View Configuration
----------------------------
-
-In a previous step in this chapter, we removed the
-``tutorial.models.MyModel`` class. However, our ``views.py`` module still
-attempts to import this class. Temporarily, we'll change ``views.py`` so
-that it no longer references ``MyModel`` by removing its imports and removing
-a reference to it from the arguments passed to the ``@view_config``
-:term:`configuration decoration` decorator which sits atop the ``my_view``
-view callable.
-
-The result of all of our edits to ``views.py`` will end up looking
-something like this:
-
-.. literalinclude:: src/models/tutorial/views.py
- :linenos:
- :language: python
-
-Testing the Models
-------------------
-
-To make sure the code we just wrote works, we write tests for the model
-classes and the appmaker. Changing ``tests.py``, we'll write a separate test
-class for each model class, and we'll write a test class for the
-``appmaker``.
-
-To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a
-result of the ``pyramid_zodb`` project generator. We'll add three test
-classes: one for the ``Page`` model named ``PageModelTests``, one for the
-``Wiki`` model named ``WikiModelTests``, and one for the appmaker named
-``AppmakerTests``.
-
-When we're done changing ``tests.py``, it will look something like so:
-
-.. literalinclude:: src/models/tutorial/tests.py
- :linenos:
- :language: python
+Viewing the Application in a Browser
+------------------------------------
-Running the Tests
------------------
-
-We can run these tests by using ``setup.py test`` in the same way we
-did in :ref:`running_tests`. Assuming our shell's current working
-directory is the "tutorial" distribution directory:
-
-On UNIX:
-
-.. code-block:: text
-
- $ ../bin/python setup.py test -q
-
-On Windows:
-
-.. code-block:: text
-
- c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
-
-The expected output is something like this:
+We can't. At this point, our system is in a "non-runnable" state; we'll need
+to change view-related files in the next chapter to be able to start the
+application successfully. If you try to start the application, you'll wind
+up with a Python traceback on your console that ends with this exception:
.. code-block:: text
- .....
- ----------------------------------------------------------------------
- Ran 5 tests in 0.008s
-
- OK
+ ImportError: cannot import name MyModel
+This will also happen if you attempt to run the tests.
diff --git a/docs/tutorials/wiki/definingviews.rst b/docs/tutorials/wiki/definingviews.rst
index 233e571f1..b6c083bbf 100644
--- a/docs/tutorials/wiki/definingviews.rst
+++ b/docs/tutorials/wiki/definingviews.rst
@@ -318,48 +318,3 @@ browser. The views we'll try are as follows:
will generate an ``IndexError`` for the expression
``request.subpath[0]``. You'll see an interactive traceback
facility provided by :term:`WebError`.
-
-Testing the Views
-=================
-
-We'll modify our ``tests.py`` file, adding tests for each view function we
-added above. As a result, we'll *delete* the ``ViewTests`` test in the file,
-and add four other test classes: ``ViewWikiTests``, ``ViewPageTests``,
-``AddPageTests``, and ``EditPageTests``. These test the ``view_wiki``,
-``view_page``, ``add_page``, and ``edit_page`` views respectively.
-
-Once we're done with the ``tests.py`` module, it will look a lot like the
-below:
-
-.. literalinclude:: src/views/tutorial/tests.py
- :linenos:
- :language: python
-
-Running the Tests
-=================
-
-We can run these tests by using ``setup.py test`` in the same way we did in
-:ref:`running_tests`. Assuming our shell's current working directory is the
-"tutorial" distribution directory:
-
-On UNIX:
-
-.. code-block:: text
-
- $ ../bin/python setup.py test -q
-
-On Windows:
-
-.. code-block:: text
-
- c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
-
-The expected result looks something like:
-
-.. code-block:: text
-
- .........
- ----------------------------------------------------------------------
- Ran 9 tests in 0.203s
-
- OK
diff --git a/docs/tutorials/wiki/index.rst b/docs/tutorials/wiki/index.rst
index 660bf3bd3..c984c4f01 100644
--- a/docs/tutorials/wiki/index.rst
+++ b/docs/tutorials/wiki/index.rst
@@ -23,5 +23,6 @@ tutorial can be browsed at
definingmodels
definingviews
authorization
+ tests
distributing
diff --git a/docs/tutorials/wiki/src/tests/tutorial/tests.py b/docs/tutorials/wiki/src/tests/tutorial/tests.py
new file mode 100644
index 000000000..d9ff866f1
--- /dev/null
+++ b/docs/tutorials/wiki/src/tests/tutorial/tests.py
@@ -0,0 +1,216 @@
+import unittest
+
+from pyramid import testing
+
+class PageModelTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from tutorial.models import Page
+ return Page
+
+ def _makeOne(self, data=u'some data'):
+ return self._getTargetClass()(data=data)
+
+ def test_constructor(self):
+ instance = self._makeOne()
+ self.assertEqual(instance.data, u'some data')
+
+class WikiModelTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from tutorial.models import Wiki
+ return Wiki
+
+ def _makeOne(self):
+ return self._getTargetClass()()
+
+ def test_it(self):
+ wiki = self._makeOne()
+ self.assertEqual(wiki.__parent__, None)
+ self.assertEqual(wiki.__name__, None)
+
+class AppmakerTests(unittest.TestCase):
+ def _callFUT(self, zodb_root):
+ from tutorial.models import appmaker
+ return appmaker(zodb_root)
+
+ def test_it(self):
+ root = {}
+ self._callFUT(root)
+ self.assertEqual(root['app_root']['FrontPage'].data,
+ 'This is the front page')
+
+class ViewWikiTests(unittest.TestCase):
+ def test_it(self):
+ from tutorial.views import view_wiki
+ context = testing.DummyResource()
+ request = testing.DummyRequest()
+ response = view_wiki(context, request)
+ self.assertEqual(response.location, 'http://example.com/FrontPage')
+
+class ViewPageTests(unittest.TestCase):
+ def _callFUT(self, context, request):
+ from tutorial.views import view_page
+ return view_page(context, request)
+
+ def test_it(self):
+ wiki = testing.DummyResource()
+ wiki['IDoExist'] = testing.DummyResource()
+ context = testing.DummyResource(data='Hello CruelWorld IDoExist')
+ context.__parent__ = wiki
+ context.__name__ = 'thepage'
+ request = testing.DummyRequest()
+ info = self._callFUT(context, request)
+ self.assertEqual(info['page'], context)
+ self.assertEqual(
+ info['content'],
+ '<div class="document">\n'
+ '<p>Hello <a href="http://example.com/add_page/CruelWorld">'
+ 'CruelWorld</a> '
+ '<a href="http://example.com/IDoExist/">'
+ 'IDoExist</a>'
+ '</p>\n</div>\n')
+ self.assertEqual(info['edit_url'],
+ 'http://example.com/thepage/edit_page')
+
+
+class AddPageTests(unittest.TestCase):
+ def _callFUT(self, context, request):
+ from tutorial.views import add_page
+ return add_page(context, request)
+
+ def test_it_notsubmitted(self):
+ from pyramid.url import resource_url
+ context = testing.DummyResource()
+ request = testing.DummyRequest()
+ request.subpath = ['AnotherPage']
+ info = self._callFUT(context, request)
+ self.assertEqual(info['page'].data,'')
+ self.assertEqual(
+ info['save_url'],
+ resource_url(context, request, 'add_page', 'AnotherPage'))
+
+ def test_it_submitted(self):
+ context = testing.DummyResource()
+ request = testing.DummyRequest({'form.submitted':True,
+ 'body':'Hello yo!'})
+ request.subpath = ['AnotherPage']
+ self._callFUT(context, request)
+ page = context['AnotherPage']
+ self.assertEqual(page.data, 'Hello yo!')
+ self.assertEqual(page.__name__, 'AnotherPage')
+ self.assertEqual(page.__parent__, context)
+
+class EditPageTests(unittest.TestCase):
+ def _callFUT(self, context, request):
+ from tutorial.views import edit_page
+ return edit_page(context, request)
+
+ def test_it_notsubmitted(self):
+ from pyramid.url import resource_url
+ context = testing.DummyResource()
+ request = testing.DummyRequest()
+ info = self._callFUT(context, request)
+ self.assertEqual(info['page'], context)
+ self.assertEqual(info['save_url'],
+ resource_url(context, request, 'edit_page'))
+
+ def test_it_submitted(self):
+ context = testing.DummyResource()
+ request = testing.DummyRequest({'form.submitted':True,
+ 'body':'Hello yo!'})
+ response = self._callFUT(context, request)
+ self.assertEqual(response.location, 'http://example.com/')
+ self.assertEqual(context.data, 'Hello yo!')
+
+class FunctionalTests(unittest.TestCase):
+
+ viewer_login = '/login?login=viewer&password=viewer' \
+ '&came_from=FrontPage&form.submitted=Login'
+ viewer_wrong_login = '/login?login=viewer&password=incorrect' \
+ '&came_from=FrontPage&form.submitted=Login'
+ editor_login = '/login?login=editor&password=editor' \
+ '&came_from=FrontPage&form.submitted=Login'
+
+ def setUp(self):
+ import tempfile
+ import os.path
+ from tutorial import main
+ self.tmpdir = tempfile.mkdtemp()
+
+ dbpath = os.path.join( self.tmpdir, 'test.db')
+ settings = { 'zodb_uri' : 'file://' + dbpath }
+
+ app = main({}, **settings)
+ from repoze.zodbconn.middleware import EnvironmentDeleterMiddleware
+ app = EnvironmentDeleterMiddleware(app)
+ from webtest import TestApp
+ self.testapp = TestApp(app)
+
+ def tearDown(self):
+ import shutil
+ shutil.rmtree( self.tmpdir )
+
+ def test_root(self):
+ res = self.testapp.get('/', status=302)
+ self.assertTrue(not res.body)
+
+ def test_FrontPage(self):
+ res = self.testapp.get('/FrontPage', status=200)
+ self.assertTrue('FrontPage' in res.body)
+
+ def test_unexisting_page(self):
+ res = self.testapp.get('/SomePage', status=404)
+ self.assertTrue('Not Found' in res.body)
+
+ def test_successful_log_in(self):
+ res = self.testapp.get( self.viewer_login, status=302)
+ self.assertTrue(res.location == 'FrontPage')
+
+ def test_failed_log_in(self):
+ res = self.testapp.get( self.viewer_wrong_login, status=200)
+ self.assertTrue('login' in res.body)
+
+ def test_logout_link_present_when_logged_in(self):
+ res = self.testapp.get( self.viewer_login, status=302)
+ res = self.testapp.get('/FrontPage', status=200)
+ self.assertTrue('Logout' in res.body)
+
+ def test_logout_link_not_present_after_logged_out(self):
+ res = self.testapp.get( self.viewer_login, status=302)
+ res = self.testapp.get('/FrontPage', status=200)
+ res = self.testapp.get('/logout', status=302)
+ self.assertTrue('Logout' not in res.body)
+
+ def test_anonymous_user_cannot_edit(self):
+ res = self.testapp.get('/FrontPage/edit_page', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_anonymous_user_cannot_add(self):
+ res = self.testapp.get('/add_page/NewPage', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_viewer_user_cannot_edit(self):
+ res = self.testapp.get( self.viewer_login, status=302)
+ res = self.testapp.get('/FrontPage/edit_page', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_viewer_user_cannot_add(self):
+ res = self.testapp.get( self.viewer_login, status=302)
+ res = self.testapp.get('/add_page/NewPage', status=200)
+ self.assertTrue('Login' in res.body)
+
+ def test_editors_member_user_can_edit(self):
+ res = self.testapp.get( self.editor_login, status=302)
+ res = self.testapp.get('/FrontPage/edit_page', status=200)
+ self.assertTrue('Editing' in res.body)
+
+ def test_editors_member_user_can_add(self):
+ res = self.testapp.get( self.editor_login, status=302)
+ res = self.testapp.get('/add_page/NewPage', status=200)
+ self.assertTrue('Editing' in res.body)
+
+ def test_editors_member_user_can_view(self):
+ res = self.testapp.get( self.editor_login, status=302)
+ res = self.testapp.get('/FrontPage', status=200)
+ self.assertTrue('FrontPage' in res.body)
diff --git a/docs/tutorials/wiki/tests.rst b/docs/tutorials/wiki/tests.rst
new file mode 100644
index 000000000..f3151dbcc
--- /dev/null
+++ b/docs/tutorials/wiki/tests.rst
@@ -0,0 +1,78 @@
+============
+Adding Tests
+============
+
+We will now add tests for the models and the views and a few functional
+tests in the ``tests.py``. Tests ensure that an application works, and
+that it continues to work after some changes are made in the future.
+
+Testing the Models
+==================
+
+We write tests for the model
+classes and the appmaker. Changing ``tests.py``, we'll write a separate test
+class for each model class, and we'll write a test class for the
+``appmaker``.
+
+To do so, we'll retain the ``tutorial.tests.ViewTests`` class provided as a
+result of the ``pyramid_zodb`` project generator. We'll add three test
+classes: one for the ``Page`` model named ``PageModelTests``, one for the
+``Wiki`` model named ``WikiModelTests``, and one for the appmaker named
+``AppmakerTests``.
+
+Testing the Views
+=================
+
+We'll modify our ``tests.py`` file, adding tests for each view function we
+added above. As a result, we'll *delete* the ``ViewTests`` test in the file,
+and add four other test classes: ``ViewWikiTests``, ``ViewPageTests``,
+``AddPageTests``, and ``EditPageTests``. These test the ``view_wiki``,
+``view_page``, ``add_page``, and ``edit_page`` views respectively.
+
+
+Functional tests
+================
+
+We test the whole application, covering security aspects that are not
+tested in the unit tests, like logging in, logging out, checking that
+the ``viewer`` user cannot add or edit pages, but the ``editor`` user
+can, and so on.
+
+Viewing the results of all our edits to ``tests.py``
+====================================================
+
+Once we're done with the ``tests.py`` module, it will look a lot like the
+below:
+
+.. literalinclude:: src/tests/tutorial/tests.py
+ :linenos:
+ :language: python
+
+Running the Tests
+=================
+
+We can run these tests by using ``setup.py test`` in the same way we did in
+:ref:`running_tests`. Assuming our shell's current working directory is the
+"tutorial" distribution directory:
+
+On UNIX:
+
+.. code-block:: text
+
+ $ ../bin/python setup.py test -q
+
+On Windows:
+
+.. code-block:: text
+
+ c:\pyramidtut\tutorial> ..\Scripts\python setup.py test -q
+
+The expected result looks something like:
+
+.. code-block:: text
+
+ .........
+ ----------------------------------------------------------------------
+ Ran 9 tests in 0.203s
+
+ OK
diff --git a/docs/tutorials/wiki2/authorization.rst b/docs/tutorials/wiki2/authorization.rst
index 64cab30db..19d438fad 100644
--- a/docs/tutorials/wiki2/authorization.rst
+++ b/docs/tutorials/wiki2/authorization.rst
@@ -76,7 +76,14 @@ For any :app:`Pyramid` application to perform authorization, we need to add a
We'll change our ``__init__.py`` file to enable an
``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` to enable
-declarative security checking.
+declarative security checking. We need to import the new policies:
+
+.. literalinclude:: src/authorization/tutorial/__init__.py
+ :lines: 2-3,8
+ :linenos:
+ :language: python
+
+Then, we'll add those policies to the configuration:
.. literalinclude:: src/authorization/tutorial/__init__.py
:lines: 15-21
@@ -97,25 +104,32 @@ We'll also change ``__init__.py``, adding a call to
:term:`view callable`. This is also known as a :term:`forbidden view`:
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 24-26
+ :lines: 24-26,41-43
:linenos:
:language: python
A forbidden view configures our newly created login view to show up when
:app:`Pyramid` detects that a view invocation can not be authorized.
-We'll also add ``view_permission`` arguments with the value ``edit`` to the
-``edit_page`` and ``add_page`` routes. This indicates that the view
-callables which these routes reference cannot be invoked without the
+A ``logout`` :term:`view callable` will allow users to log out later:
+
+.. literalinclude:: src/authorization/tutorial/__init__.py
+ :lines: 27-28
+ :linenos:
+ :language: python
+
+We'll also add ``permission`` arguments with the value ``edit`` to the
+``edit_page`` and ``add_page`` views. This indicates that the view
+callables which these views reference cannot be invoked without the
authenticated user possessing the ``edit`` permission with respect to the
current context.
.. literalinclude:: src/authorization/tutorial/__init__.py
- :lines: 32-39
+ :lines: 37-40
:linenos:
:language: python
-Adding these ``view_permission`` arguments causes Pyramid to make the
+Adding these ``permission`` arguments causes Pyramid to make the
assertion that only users who possess the effective ``edit`` permission at
the time of the request may invoke those two views. We've granted the
``group:editors`` principal the ``edit`` permission at the root model via its
diff --git a/docs/tutorials/wiki2/basiclayout.rst b/docs/tutorials/wiki2/basiclayout.rst
index 0dbcf6684..82e112c64 100644
--- a/docs/tutorials/wiki2/basiclayout.rst
+++ b/docs/tutorials/wiki2/basiclayout.rst
@@ -81,28 +81,34 @@ via the :meth:`pyramid.config.Configurator.add_route` method that will be
used when the URL is ``/``:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 13-14
+ :lines: 13
:language: py
Since this route has a ``pattern`` equalling ``/`` it is the route that will
-be called when the URL ``/`` is visted, e.g. ``http://localhost:6543/``. The
-argument named ``view`` with the value ``tutorial.views.my_view`` is the
+be matched when the URL ``/`` is visted, e.g. ``http://localhost:6543/``.
+
+Mapping the ``home`` route to code is done by registering a view. You will
+use :meth:`pyramid.config.Configurator.add_view` in :term:`URL dispatch` to
+register views for the routes, mapping your patterns to code:
+
+ .. literalinclude:: src/basiclayout/tutorial/__init__.py
+ :lines: 14
+ :language: py
+
+The first positional ``add_view`` argument ``tutorial.views.my_view`` is the
dotted name to a *function* we write (generated by the
``pyramid_routesalchemy`` scaffold) that is given a ``request`` object and
-which returns a response or a dictionary.
-
-You will use :meth:`pyramid.config.Configurator.add_route` statements in a
-:term:`URL dispatch` based application to map URLs to code. This route also
-names a ``view_renderer``, which is a template which lives in the
-``templates`` subdirectory of the package. When the
-``tutorial.views.my_view`` view returns a dictionary, a :term:`renderer` will
-use this template to create a response.
+which returns a response or a dictionary. This view also names a
+``renderer``, which is a template which lives in the ``templates``
+subdirectory of the package. When the ``tutorial.views.my_view`` view
+returns a dictionary, a :term:`renderer` will use this template to create a
+response. This
-Fimnally, we use the :meth:`pyramid.config.Configurator.make_wsgi_app`
+Finally, we use the :meth:`pyramid.config.Configurator.make_wsgi_app`
method to return a :term:`WSGI` application:
.. literalinclude:: src/basiclayout/tutorial/__init__.py
- :lines: 15
+ :lines: 16
:language: py
Our final ``__init__.py`` file will look like this:
diff --git a/docs/tutorials/wiki2/definingmodels.rst b/docs/tutorials/wiki2/definingmodels.rst
index 1661753c1..e5d283125 100644
--- a/docs/tutorials/wiki2/definingmodels.rst
+++ b/docs/tutorials/wiki2/definingmodels.rst
@@ -26,6 +26,14 @@ The first thing we want to do is remove the stock ``MyModel`` class from the
generated ``models.py`` file. The ``MyModel`` class is only a sample and
we're not going to use it.
+Next, we'll remove the :class:`sqlalchemy.Unicode` import and replace it
+with :class:`sqlalchemy.Text`.
+
+.. literalinclude:: src/models/tutorial/models.py
+ :lines: 5
+ :linenos:
+ :language: py
+
Then, we'll add a ``Page`` class. Because this is a SQLAlchemy
application, this class should inherit from an instance of
:class:`sqlalchemy.ext.declarative.declarative_base`. Declarative
diff --git a/docs/tutorials/wiki2/definingviews.rst b/docs/tutorials/wiki2/definingviews.rst
index c5a452d11..832f90b92 100644
--- a/docs/tutorials/wiki2/definingviews.rst
+++ b/docs/tutorials/wiki2/definingviews.rst
@@ -272,8 +272,8 @@ Mapping Views to URLs in ``__init__.py``
========================================
The ``__init__.py`` file contains
-:meth:`pyramid.config.Configurator.add_route` calls which serve to map
-URLs via :term:`url dispatch` to view functions. First, we’ll get rid of the
+:meth:`pyramid.config.Configurator.add_view` calls which serve to map
+routes via :term:`url dispatch` to views. First, we’ll get rid of the
existing route created by the template using the name ``home``. It’s only an
example and isn’t relevant to our application.
@@ -282,21 +282,33 @@ these declarations is very important. ``route`` declarations are matched in
the order they're found in the ``__init__.py`` file.
#. Add a declaration which maps the pattern ``/`` (signifying the root URL)
- to the view named ``view_wiki`` in our ``views.py`` file with the name
- ``view_wiki``. This is the :term:`default view` for the wiki.
+ to the route named ``view_wiki``.
-#. Add a declaration which maps the pattern ``/{pagename}`` to the view named
- ``view_page`` in our ``views.py`` file with the view name ``view_page``.
- This is the regular view for a page.
+#. Add a declaration which maps the pattern ``/{pagename}`` to the route named
+ ``view_page``. This is the regular view for a page.
-#. Add a declaration which maps the pattern
- ``/add_page/{pagename}`` to the view named ``add_page`` in our
- ``views.py`` file with the name ``add_page``. This is the add view
- for a new page.
+#. Add a declaration which maps the pattern ``/add_page/{pagename}`` to the
+ route named ``add_page``. This is the add view for a new page.
#. Add a declaration which maps the pattern ``/{pagename}/edit_page`` to the
- view named ``edit_page`` in our ``views.py`` file with the name
- ``edit_page``. This is the edit view for a page.
+ route named ``edit_page``. This is the edit view for a page.
+
+After we've defined the routes for our application, we can register views
+to handle the processing and rendering that needs to happen when each route is
+requested.
+
+#. Add a declaration which maps the ``view_wiki`` route to the view named
+ ``view_wiki`` in our ``views.py`` file. This is the :term:`default view`
+ for the wiki.
+
+#. Add a declaration which maps the ``view_page`` route to the view named
+ ``view_page`` in our ``views.py`` file.
+
+#. Add a declaration which maps the ``add_page`` route to the view named
+ ``add_page`` in our ``views.py`` file.
+
+#. Add a declaration which maps the ``edit_page`` route to the view named
+ ``edit_page`` in our ``views.py`` file.
As a result of our edits, the ``__init__.py`` file should look
something like so:
diff --git a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
index 025b94927..e8baa568c 100644
--- a/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/authorization/tutorial/__init__.py
@@ -20,25 +20,26 @@ def main(global_config, **settings):
authentication_policy=authn_policy,
authorization_policy=authz_policy)
config.add_static_view('static', 'tutorial:static')
- config.add_route('view_wiki', '/', view='tutorial.views.view_wiki')
- config.add_route('login', '/login',
- view='tutorial.login.login',
- view_renderer='tutorial:templates/login.pt')
- config.add_route('logout', '/logout',
- view='tutorial.login.logout')
- config.add_route('view_page', '/{pagename}',
- view='tutorial.views.view_page',
- view_renderer='tutorial:templates/view.pt')
- config.add_route('add_page', '/add_page/{pagename}',
- view='tutorial.views.add_page',
- view_renderer='tutorial:templates/edit.pt',
- view_permission='edit')
- config.add_route('edit_page', '/{pagename}/edit_page',
- view='tutorial.views.edit_page',
- view_renderer='tutorial:templates/edit.pt',
- view_permission='edit')
+
+ config.add_route('view_wiki', '/')
+ config.add_route('login', '/login')
+ config.add_route('logout', '/logout')
+ config.add_route('view_page', '/{pagename}')
+ config.add_route('add_page', '/add_page/{pagename}')
+ config.add_route('edit_page', '/{pagename}/edit_page')
+ config.add_route('view_wiki', '/')
+
+ config.add_view('tutorial.login.login', route_name='login',
+ renderer='tutorial:templates/login.pt')
+ config.add_view('tutorial.login.logout', route_name='logout')
+ config.add_view('tutorial.views.view_page', route_name='view_page',
+ renderer='tutorial:templates/view.pt')
+ config.add_view('tutorial.views.add_page', route_name='add_page',
+ renderer='tutorial:templates/edit.pt', permission='edit')
+ config.add_view('tutorial.views.edit_page', route_name='edit_page',
+ renderer='tutorial:templates/edit.pt', permission='edit')
config.add_view('tutorial.login.login',
- renderer='tutorial:templates/login.pt',
- context='pyramid.exceptions.Forbidden')
+ context='pyramid.exceptions.Forbidden',
+ renderer='tutorial:templates/login.pt')
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
index d27b891c0..c74f07652 100644
--- a/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/basiclayout/tutorial/__init__.py
@@ -10,8 +10,9 @@ def main(global_config, **settings):
initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'tutorial:static')
- config.add_route('home', '/', view='tutorial.views.my_view',
- view_renderer='templates/mytemplate.pt')
+ config.add_route('home', '/')
+ config.add_view('tutorial.views.my_view', route_name='home',
+ renderer='templates/mytemplate.pt')
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki2/src/models/tutorial/__init__.py b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
index c912a015b..ecc41ca9f 100644
--- a/docs/tutorials/wiki2/src/models/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/models/tutorial/__init__.py
@@ -10,6 +10,7 @@ def main(global_config, **settings):
initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'tutorial:static')
- config.add_route('home', '/', view='tutorial.views.my_view',
- view_renderer='templates/mytemplate.pt')
+ config.add_route('home', '/')
+ config.add_view('tutorial.views.my_view', route_name='home',
+ renderer='templates/mytemplate.pt')
return config.make_wsgi_app()
diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
index 1a8d24499..ad89c124e 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
@@ -10,15 +10,16 @@ def main(global_config, **settings):
initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'tutorial:static')
- config.add_route('view_wiki', '/', view='tutorial.views.view_wiki')
- config.add_route('view_page', '/{pagename}',
- view='tutorial.views.view_page',
- view_renderer='tutorial:templates/view.pt')
- config.add_route('add_page', '/add_page/{pagename}',
- view='tutorial.views.add_page',
- view_renderer='tutorial:templates/edit.pt')
- config.add_route('edit_page', '/{pagename}/edit_page',
- view='tutorial.views.edit_page',
- view_renderer='tutorial:templates/edit.pt')
+ config.add_route('view_wiki', '/')
+ config.add_route('view_page', '/{pagename}')
+ config.add_route('add_page', '/add_page/{pagename}')
+ config.add_route('edit_page', '/{pagename}/edit_page')
+ config.add_view('tutorial.views.view_wiki', route_name='view_wiki')
+ config.add_view('tutorial.views.view_page', route_name='view_page',
+ renderer='tutorial:templates/view.pt')
+ config.add_view('tutorial.views.add_page', route_name='add_page',
+ renderer='tutorial:templates/edit.pt')
+ config.add_view('tutorial.views.edit_page', route_name='edit_page',
+ renderer='tutorial:templates/edit.pt')
return config.make_wsgi_app()
diff --git a/pyramid/authentication.py b/pyramid/authentication.py
index 78349854b..a6c74e549 100644
--- a/pyramid/authentication.py
+++ b/pyramid/authentication.py
@@ -61,12 +61,12 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
``callback``
- Default: ``None``. A callback passed the :mod:`repoze.who`
- identity and the :term:`request`, expected to return ``None``
- if the user represented by the identity doesn't exist or a
- sequence of group identifiers (possibly empty) if the user
- does exist. If ``callback`` is None, the userid will be
- assumed to exist with no groups.
+ Default: ``None``. A callback passed the :mod:`repoze.who` identity
+ and the :term:`request`, expected to return ``None`` if the user
+ represented by the identity doesn't exist or a sequence of principal
+ identifiers (possibly empty) representing groups if the user does
+ exist. If ``callback`` is None, the userid will be assumed to exist
+ with no group principals.
Objects of this class implement the interface described by
:class:`pyramid.interfaces.IAuthenticationPolicy`.
@@ -149,10 +149,10 @@ class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy):
``callback``
Default: ``None``. A callback passed the userid and the request,
- expected to return None if the userid doesn't exist or a sequence
- of group identifiers (possibly empty) if the user does exist.
- If ``callback`` is None, the userid will be assumed to exist with no
- groups.
+ expected to return None if the userid doesn't exist or a sequence of
+ principal identifiers (possibly empty) representing groups if the
+ user does exist. If ``callback`` is None, the userid will be assumed
+ to exist with no group principals.
Objects of this class implement the interface described by
:class:`pyramid.interfaces.IAuthenticationPolicy`.
@@ -187,9 +187,9 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
Default: ``None``. A callback passed the userid and the
request, expected to return ``None`` if the userid doesn't
- exist or a sequence of group identifiers (possibly empty) if
+ exist or a sequence of principal identifiers (possibly empty) if
the user does exist. If ``callback`` is ``None``, the userid
- will be assumed to exist with no groups. Optional.
+ will be assumed to exist with no principals. Optional.
``cookie_name``
diff --git a/pyramid/compat/__init__.py b/pyramid/compat/__init__.py
index 8bbf79703..096fb3ddf 100644
--- a/pyramid/compat/__init__.py
+++ b/pyramid/compat/__init__.py
@@ -146,3 +146,12 @@ except ImportError: # pragma: no cover
import md5
md5 = md5.new
+try:
+ any = any # make importable
+except NameError: # pragma: no cover
+ def any(L):
+ for thing in L:
+ if thing:
+ return True
+ return False
+
diff --git a/pyramid/config.py b/pyramid/config.py
index 6206d64c4..a24392302 100644
--- a/pyramid/config.py
+++ b/pyramid/config.py
@@ -4,6 +4,7 @@ import re
import sys
import types
import traceback
+import warnings
import venusian
@@ -50,6 +51,7 @@ from pyramid import renderers
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.compat import all
from pyramid.compat import md5
+from pyramid.compat import any
from pyramid.events import ApplicationCreated
from pyramid.exceptions import ConfigurationError
from pyramid.exceptions import Forbidden
@@ -1378,6 +1380,52 @@ class Configurator(object):
discriminator = tuple(discriminator)
self.action(discriminator, register)
+ def _add_view_from_route(self,
+ route_name,
+ view,
+ context,
+ permission,
+ renderer,
+ attr,
+ ):
+ if view:
+ self.add_view(
+ permission=permission,
+ context=context,
+ view=view,
+ name='',
+ route_name=route_name,
+ renderer=renderer,
+ attr=attr,
+ )
+ else:
+ # prevent mistakes due to misunderstanding of how hybrid calls to
+ # add_route and add_view interact
+ if attr:
+ raise ConfigurationError(
+ 'view_attr argument not permitted without view '
+ 'argument')
+ if context:
+ raise ConfigurationError(
+ 'view_context argument not permitted without view '
+ 'argument')
+ if permission:
+ raise ConfigurationError(
+ 'view_permission argument not permitted without view '
+ 'argument')
+ if renderer:
+ raise ConfigurationError(
+ 'view_renderer argument not permitted without '
+ 'view argument')
+
+ warnings.warn(
+ 'Passing view-related arguments to add_route() is deprecated as of '
+ 'Pyramid 1.1. Use add_view() to associate a view with a route '
+ 'instead. See "Deprecations" in "What\'s New in Pyramid 1.1" '
+ 'within the general Pyramid documentation for further details.',
+ DeprecationWarning,
+ 4)
+
@action_method
def add_route(self,
name,
@@ -1484,6 +1532,14 @@ class Configurator(object):
by applications, it is meant to be hooked by frameworks
that use :app:`Pyramid` as a base.
+ use_global_views
+
+ When a request matches this route, and view lookup cannot
+ find a view which has a ``route_name`` predicate argument
+ that matches the route, try to fall back to using a view
+ that otherwise matches the context, request, and view name
+ (but which does not match the route_name predicate).
+
Predicate Arguments
pattern
@@ -1592,14 +1648,27 @@ class Configurator(object):
View-Related Arguments
+ .. warning:: The arguments described below have been deprecated as of
+ :app:`Pyramid` 1.1. *Do not use these for new development; they
+ should only be used to support older code bases which depend upon
+ them.* Use a separate call to
+ :meth:`pyramid.config.Configurator.add_view` to associate a view
+ with a route. See :ref:`add_route_view_config` for more info.
+
view
+ .. warning:: Deprecated as of :app:`Pyramid` 1.1; see
+ :ref:`add_route_view_config`.
+
A Python object or :term:`dotted Python name` to the same
object that will be used as a view callable when this route
matches. e.g. ``mypackage.views.my_view``.
view_context
+ .. warning:: Deprecated as of :app:`Pyramid` 1.1; see
+ :ref:`add_route_view_config`.
+
A class or an :term:`interface` or :term:`dotted Python
name` to the same object which the :term:`context` of the
view should match for the view named by the route to be
@@ -1614,6 +1683,9 @@ class Configurator(object):
view_permission
+ .. warning:: Deprecated as of :app:`Pyramid` 1.1; see
+ :ref:`add_route_view_config`.
+
The permission name required to invoke the view associated
with this route. e.g. ``edit``. (see
:ref:`using_security_with_urldispatch` for more information
@@ -1626,6 +1698,9 @@ class Configurator(object):
view_renderer
+ .. warning:: Deprecated as of :app:`Pyramid` 1.1; see
+ :ref:`add_route_view_config`.
+
This is either a single string term (e.g. ``json``) or a
string implying a path or :term:`asset specification`
(e.g. ``templates/views.pt``). If the renderer value is a
@@ -1648,6 +1723,9 @@ class Configurator(object):
view_attr
+ .. warning:: Deprecated as of :app:`Pyramid` 1.1; see
+ :ref:`add_route_view_config`.
+
The view machinery defaults to using the ``__call__`` method
of the view callable (or the function itself, if the view
callable is a function) to obtain a response dictionary.
@@ -1662,14 +1740,6 @@ class Configurator(object):
If the ``view`` argument is not provided, this argument has no
effect.
- use_global_views
-
- When a request matches this route, and view lookup cannot
- find a view which has a ``route_name`` predicate argument
- that matches the route, try to fall back to using a view
- that otherwise matches the context, request, and view name
- (but which does not match the route_name predicate).
-
"""
# these are route predicates; if they do not match, the next route
# in the routelist will be tried
@@ -1698,42 +1768,17 @@ class Configurator(object):
for info in view_info:
self.add_view(**info)
- if view_context is None:
- view_context = view_for
- if view_context is None:
- view_context = for_
- view_permission = view_permission or permission
- view_renderer = view_renderer or renderer
-
- if view:
- self.add_view(
- permission=view_permission,
- context=view_context,
- view=view,
- name='',
+ # deprecated adding views from add_route
+ if any([view, view_context, view_permission, view_renderer,
+ view_for, for_, permission, renderer, view_attr]):
+ self._add_view_from_route(
route_name=name,
- renderer=view_renderer,
+ view=view,
+ permission=view_permission or permission,
+ context=view_context or view_for or for_,
+ renderer=view_renderer or renderer,
attr=view_attr,
- )
- else:
- # prevent mistakes due to misunderstanding of how hybrid calls to
- # add_route and add_view interact
- if view_attr:
- raise ConfigurationError(
- 'view_attr argument not permitted without view '
- 'argument')
- if view_context:
- raise ConfigurationError(
- 'view_context argument not permitted without view '
- 'argument')
- if view_permission:
- raise ConfigurationError(
- 'view_permission argument not permitted without view '
- 'argument')
- if view_renderer:
- raise ConfigurationError(
- 'view_renderer argument not permitted without '
- 'view argument')
+ )
mapper = self.get_routes_mapper()
diff --git a/pyramid/paster.py b/pyramid/paster.py
index 4437db497..a94b4f2d3 100644
--- a/pyramid/paster.py
+++ b/pyramid/paster.py
@@ -10,7 +10,7 @@ from paste.util.template import paste_script_template_renderer
from pyramid.scripting import get_root
class PyramidTemplate(Template):
- def pre(self, command, output_dir, vars): # pragma: no cover
+ def pre(self, command, output_dir, vars):
vars['random_string'] = os.urandom(20).encode('hex')
package_logger = vars['package']
if package_logger == 'root':
@@ -19,9 +19,12 @@ class PyramidTemplate(Template):
vars['package_logger'] = package_logger
return Template.pre(self, command, output_dir, vars)
- def post(self, *arg, **kw): # pragma: no cover
- print 'Welcome to Pyramid. Sorry for the convenience.'
- return Template.post(self, *arg, **kw)
+ def post(self, command, output_dir, vars):
+ self.out('Welcome to Pyramid. Sorry for the convenience.')
+ return Template.post(self, command, output_dir, vars)
+
+ def out(self, msg): # pragma: no cover (replaceable testing hook)
+ print msg
class StarterProjectTemplate(PyramidTemplate):
_template_dir = 'paster_templates/starter'
@@ -88,7 +91,7 @@ class PShellCommand(PCommand):
command will almost certainly fail.
"""
- summary = "Open an interactive shell with a pyramid app loaded"
+ summary = "Open an interactive shell with a Pyramid application loaded"
min_args = 2
max_args = 2
@@ -100,10 +103,11 @@ class PShellCommand(PCommand):
help="Don't use IPython even if it is available")
def command(self, IPShell=_marker):
- if IPShell is _marker:
- try: #pragma no cover
+ # IPShell passed to command method is for testing purposes
+ if IPShell is _marker: # pragma: no cover
+ try:
from IPython.Shell import IPShell
- except ImportError: #pragma no cover
+ except ImportError:
IPShell = None
cprt =('Type "help" for more information. "root" is the Pyramid app '
'root object, "registry" is the Pyramid registry object.')
@@ -113,16 +117,17 @@ class PShellCommand(PCommand):
app = self.get_app(config_file, section_name, loadapp=self.loadapp[0])
root, closer = self.get_root(app)
shell_globals = {'root':root, 'registry':app.registry}
- if IPShell is not None and not self.options.disable_ipython:
+
+ if (IPShell is None) or self.options.disable_ipython:
try:
- shell = IPShell(argv=[], user_ns=shell_globals)
- shell.IP.BANNER = shell.IP.BANNER + '\n\n' + banner
- shell.mainloop()
+ self.interact[0](banner, local=shell_globals)
finally:
closer()
else:
try:
- self.interact[0](banner, local=shell_globals)
+ shell = IPShell(argv=[], user_ns=shell_globals)
+ shell.IP.BANNER = shell.IP.BANNER + '\n\n' + banner
+ shell.mainloop()
finally:
closer()
diff --git a/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl b/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl
index 479740297..f5e3a0630 100644
--- a/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl
+++ b/pyramid/paster_templates/routesalchemy/+package+/__init__.py_tmpl
@@ -10,8 +10,9 @@ def main(global_config, **settings):
initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', '{{package}}:static')
- config.add_route('home', '/', view='{{package}}.views.my_view',
- view_renderer='templates/mytemplate.pt')
+ config.add_route('home', '/')
+ config.add_view('{{package}}.views.my_view',
+ route_name='home',
+ renderer='templates/mytemplate.pt')
return config.make_wsgi_app()
-
diff --git a/pyramid/renderers.py b/pyramid/renderers.py
index c8771709a..a6dce9b3a 100644
--- a/pyramid/renderers.py
+++ b/pyramid/renderers.py
@@ -1,6 +1,7 @@
import os
import pkg_resources
import threading
+import warnings
from zope.interface import implements
@@ -134,8 +135,10 @@ def json_renderer_factory(info):
def _render(value, system):
request = system.get('request')
if request is not None:
- if not hasattr(request, 'response_content_type'):
- request.response_content_type = 'application/json'
+ response = request.response
+ ct = response.content_type
+ if ct == response.default_content_type:
+ response.content_type = 'application/json'
return json.dumps(value)
return _render
@@ -145,8 +148,10 @@ def string_renderer_factory(info):
value = str(value)
request = system.get('request')
if request is not None:
- if not hasattr(request, 'response_content_type'):
- request.response_content_type = 'text/plain'
+ response = request.response
+ ct = response.content_type
+ if ct == response.default_content_type:
+ response.content_type = 'text/plain'
return value
return _render
@@ -344,29 +349,54 @@ class RendererHelper(object):
return self._make_response(result, request)
def _make_response(self, result, request):
- registry = self.registry
- response_factory = registry.queryUtility(IResponseFactory,
- default=Response)
+ response = getattr(request, 'response', None)
+ if response is None:
+ # request is None or request is not a pyramid.response.Response
+ registry = self.registry
+ response_factory = registry.queryUtility(IResponseFactory,
+ default=Response)
+
+ response = response_factory()
- response = response_factory(result)
+ if result is None:
+ result = ''
+
+ if isinstance(result, unicode):
+ response.unicode_body = result
+ else:
+ response.body = result
if request is not None:
+ # deprecated mechanism to set up request.response_* attrs
attrs = request.__dict__
content_type = attrs.get('response_content_type', None)
if content_type is not None:
response.content_type = content_type
+ deprecate_req_attr('Setting', 'content_type',
+ 'set', 'content_type')
headerlist = attrs.get('response_headerlist', None)
if headerlist is not None:
for k, v in headerlist:
response.headers.add(k, v)
+ deprecate_req_attr('Setting or mutating', 'headerlist',
+ 'set or mutate', 'headerlist')
status = attrs.get('response_status', None)
if status is not None:
response.status = status
+ deprecate_req_attr('Setting', 'status', 'set', 'status')
charset = attrs.get('response_charset', None)
if charset is not None:
response.charset = charset
+ deprecate_req_attr('Setting', 'charset', 'set', 'charset')
cache_for = attrs.get('response_cache_for', None)
if cache_for is not None:
response.cache_expires = cache_for
+ deprecate_req_attr('Setting', 'cache_for',
+ 'set', 'cache_expires')
return response
+
+def deprecate_req_attr(*args):
+ depwarn = ('%s "request.response_%s" is deprecated as of Pyramid 1.1; %s '
+ '"request.response.%s" instead.')
+ warnings.warn(depwarn % args, DeprecationWarning, 3)
diff --git a/pyramid/request.py b/pyramid/request.py
index b607f159f..0fe8b9379 100644
--- a/pyramid/request.py
+++ b/pyramid/request.py
@@ -5,9 +5,12 @@ from webob import Request as WebobRequest
from pyramid.interfaces import IRequest
from pyramid.interfaces import ISessionFactory
+from pyramid.interfaces import IResponseFactory
from pyramid.exceptions import ConfigurationError
from pyramid.decorator import reify
+from pyramid.response import Response
+from pyramid.traversal import quote_path_segment
from pyramid.url import resource_url
from pyramid.url import route_url
from pyramid.url import static_url
@@ -298,6 +301,26 @@ class Request(WebobRequest):
"""
return route_path(route_name, self, *elements, **kw)
+ @reify
+ def response(self):
+ """This attribute is actually a "reified" property which returns an
+ instance of the :class:`pyramid.response.Response`. class. The
+ response object returned does not exist until this attribute is
+ accessed. Once it is accessed, subsequent accesses will return the
+ same Response object.
+
+ The ``request.response`` API is used by renderers. A render obtains
+ the response object it will return from a view that uses that renderer
+ by accessing ``request.response``. Therefore, it's possible to use the
+ ``request.response`` API to set up a response object with "the
+ right" attributes (e.g. by calling ``request.response.set_cookie()``)
+ within a view that uses a renderer. Mutations to this response object
+ will be preserved in the response sent to the client."""
+ registry = self.registry
+ response_factory = registry.queryUtility(IResponseFactory,
+ default=Response)
+ return response_factory()
+
# override default WebOb "environ['adhoc_attr']" mutation behavior
__getattr__ = object.__getattribute__
__setattr__ = object.__setattr__
@@ -371,3 +394,54 @@ def add_global_response_headers(request, headerlist):
response.headerlist.append((k, v))
request.add_response_callback(add_headers)
+def call_app_with_subpath_as_path_info(request, app):
+ # Copy the request. Use the source request's subpath (if it exists) as
+ # the new request's PATH_INFO. Set the request copy's SCRIPT_NAME to the
+ # prefix before the subpath. Call the application with the new request
+ # and return a response.
+ #
+ # Postconditions:
+ # - SCRIPT_NAME and PATH_INFO are empty or start with /
+ # - At least one of SCRIPT_NAME or PATH_INFO are set.
+ # - SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should
+ # be '/').
+
+ environ = request.environ
+ script_name = environ.get('SCRIPT_NAME', '')
+ path_info = environ.get('PATH_INFO', '/')
+ subpath = list(getattr(request, 'subpath', ()))
+
+ new_script_name = ''
+
+ # compute new_path_info
+ new_path_info = '/' + '/'.join([x.encode('utf-8') for x in subpath])
+
+ if new_path_info != '/': # don't want a sole double-slash
+ if path_info != '/': # if orig path_info is '/', we're already done
+ if path_info.endswith('/'):
+ # readd trailing slash stripped by subpath (traversal)
+ # conversion
+ new_path_info += '/'
+
+ # compute new_script_name
+ workback = (script_name + path_info).split('/')
+
+ tmp = []
+ while workback:
+ if tmp == subpath:
+ break
+ el = workback.pop()
+ if el:
+ tmp.insert(0, el.decode('utf-8'))
+
+ # strip all trailing slashes from workback to avoid appending undue slashes
+ # to end of script_name
+ while workback and (workback[-1] == ''):
+ workback = workback[:-1]
+
+ new_script_name = '/'.join(workback)
+
+ new_request = request.copy()
+ new_request.environ['SCRIPT_NAME'] = new_script_name
+ new_request.environ['PATH_INFO'] = new_path_info
+ return new_request.get_response(app)
diff --git a/pyramid/static.py b/pyramid/static.py
index 3866126ac..ec7b4cb00 100644
--- a/pyramid/static.py
+++ b/pyramid/static.py
@@ -13,6 +13,7 @@ from zope.interface import implements
from pyramid.asset import resolve_asset_spec
from pyramid.interfaces import IStaticURLInfo
from pyramid.path import caller_package
+from pyramid.request import call_app_with_subpath_as_path_info
from pyramid.url import route_url
class PackageURLParser(StaticURLParser):
@@ -37,21 +38,18 @@ class PackageURLParser(StaticURLParser):
filename = request.path_info_pop(environ)
resource = os.path.normcase(os.path.normpath(
self.resource_name + '/' + filename))
- if ( (self.root_resource is not None) and
- (not resource.startswith(self.root_resource)) ):
+ if not resource.startswith(self.root_resource):
# Out of bounds
return self.not_found(environ, start_response)
if not pkg_resources.resource_exists(self.package_name, resource):
return self.not_found(environ, start_response)
if pkg_resources.resource_isdir(self.package_name, resource):
# @@: Cache?
- child_root = (self.root_resource is not None and
- self.root_resource or self.resource_name)
return self.__class__(
- self.package_name, resource, root_resource=child_root,
+ self.package_name, resource, root_resource=self.resource_name,
cache_max_age=self.cache_max_age)(environ, start_response)
- if (environ.get('PATH_INFO')
- and environ.get('PATH_INFO') != '/'): # pragma: no cover
+ pi = environ.get('PATH_INFO')
+ if pi and pi != '/':
return self.error_extra_path(environ, start_response)
full = pkg_resources.resource_filename(self.package_name, resource)
if_none_match = environ.get('HTTP_IF_NONE_MATCH')
@@ -151,13 +149,26 @@ class StaticURLInfo(object):
permission = extra.pop('permission', None)
if permission is None:
permission = '__no_permission_required__'
- extra['view_permission'] = permission
- extra['view'] = view
- # register a route using the computed view, permission, and pattern,
- # plus any extras passed to us via add_static_view
+ context = extra.pop('view_context', None)
+ if context is None:
+ context = extra.pop('view_for', None)
+ if context is None:
+ context = extra.pop('for_', None)
+
+ renderer = extra.pop('view_renderer', None)
+ if renderer is None:
+ renderer = extra.pop('renderer', None)
+
+ attr = extra.pop('view_attr', None)
+
+ # register a route using the computed view, permission, and
+ # pattern, plus any extras passed to us via add_static_view
pattern = "%s*subpath" % name # name already ends with slash
self.config.add_route(name, pattern, **extra)
+ self.config.add_view(route_name=name, view=view,
+ permission=permission, context=context,
+ renderer=renderer, attr=attr)
self.registrations.append((name, spec, False))
class static_view(object):
@@ -211,12 +222,4 @@ class static_view(object):
self.app = app
def __call__(self, context, request):
- subpath = '/'.join(request.subpath)
- request_copy = request.copy()
- # Fix up PATH_INFO to get rid of everything but the "subpath"
- # (the actual path to the file relative to the root dir).
- request_copy.environ['PATH_INFO'] = '/' + subpath
- # Zero out SCRIPT_NAME for good measure.
- request_copy.environ['SCRIPT_NAME'] = ''
- return request_copy.get_response(self.app)
-
+ return call_app_with_subpath_as_path_info(request, self.app)
diff --git a/pyramid/testing.py b/pyramid/testing.py
index a98807a19..36cc38830 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -9,12 +9,14 @@ from zope.interface import Interface
from zope.interface import alsoProvides
from pyramid.interfaces import IRequest
+from pyramid.interfaces import IResponseFactory
from pyramid.interfaces import ISecuredView
from pyramid.interfaces import IView
from pyramid.interfaces import IViewClassifier
from pyramid.interfaces import ISession
from pyramid.config import Configurator
+from pyramid.decorator import reify
from pyramid.exceptions import Forbidden
from pyramid.response import Response
from pyramid.registry import Registry
@@ -653,6 +655,8 @@ class DummyRequest(object):
response_callbacks = ()
charset = 'UTF-8'
script_name = ''
+ _registry = None
+
def __init__(self, params=None, environ=None, headers=None, path='/',
cookies=None, post=None, **kw):
if environ is None:
@@ -698,9 +702,23 @@ class DummyRequest(object):
self.response_callbacks = []
self.response_callbacks.append(callback)
- @property
- def registry(self):
- return get_current_registry()
+ def _get_registry(self):
+ if self._registry is None:
+ return get_current_registry()
+ return self._registry
+
+ def _set_registry(self, registry):
+ self._registry = registry
+
+ def _del_registry(self):
+ self._registry = None
+
+ registry = property(_get_registry, _set_registry, _del_registry)
+
+ @reify
+ def response(self):
+ f = self.registry.queryUtility(IResponseFactory, default=Response)
+ return f()
def setUp(registry=None, request=None, hook_zca=True, autocommit=True,
settings=None):
diff --git a/pyramid/tests/ccbugapp/__init__.py b/pyramid/tests/ccbugapp/__init__.py
index 6c2eb6ecf..ad6387a75 100644
--- a/pyramid/tests/ccbugapp/__init__.py
+++ b/pyramid/tests/ccbugapp/__init__.py
@@ -1,7 +1,8 @@
def includeme(config):
- config.add_route('rdf',
- 'licenses/:license_code/:license_version/rdf',
- '.views.rdf_view')
+ config.add_route('rdf', 'licenses/:license_code/:license_version/rdf')
config.add_route('juri',
- 'licenses/:license_code/:license_version/:jurisdiction',
- '.views.juri_view')
+ 'licenses/:license_code/:license_version/:jurisdiction')
+ config.add_view('.views.rdf_view', route_name='rdf')
+ config.add_view('.views.juri_view', route_name='juri')
+
+
diff --git a/pyramid/tests/exceptionviewapp/__init__.py b/pyramid/tests/exceptionviewapp/__init__.py
index cf69227cd..f169e0cd5 100644
--- a/pyramid/tests/exceptionviewapp/__init__.py
+++ b/pyramid/tests/exceptionviewapp/__init__.py
@@ -1,21 +1,23 @@
def includeme(config):
+ config.add_route('route_raise_exception', 'route_raise_exception')
+ config.add_route('route_raise_exception2', 'route_raise_exception2',
+ factory='.models.route_factory')
+ config.add_route('route_raise_exception3', 'route_raise_exception3',
+ factory='.models.route_factory2')
+ config.add_route('route_raise_exception4', 'route_raise_exception4')
config.add_view('.views.maybe')
config.add_view('.views.no', context='.models.NotAnException')
config.add_view('.views.yes', context=".models.AnException")
config.add_view('.views.raise_exception', name='raise_exception')
- config.add_route('route_raise_exception', 'route_raise_exception',
- view='.views.raise_exception')
- config.add_route('route_raise_exception2',
- 'route_raise_exception2',
- view='.views.raise_exception',
- factory='.models.route_factory')
- config.add_route('route_raise_exception3',
- 'route_raise_exception3',
- view='.views.raise_exception',
- factory='.models.route_factory2')
+ config.add_view('.views.raise_exception',
+ route_name='route_raise_exception')
+ config.add_view('.views.raise_exception',
+ route_name='route_raise_exception2')
+ config.add_view('.views.raise_exception',
+ route_name='route_raise_exception3')
config.add_view('.views.whoa', context='.models.AnException',
route_name='route_raise_exception3')
- config.add_route('route_raise_exception4', 'route_raise_exception4',
- view='.views.raise_exception')
+ config.add_view('.views.raise_exception',
+ route_name='route_raise_exception4')
config.add_view('.views.whoa', context='.models.AnException',
route_name='route_raise_exception4')
diff --git a/pyramid/tests/hybridapp/__init__.py b/pyramid/tests/hybridapp/__init__.py
index 5b51e3d1e..1cc2dde83 100644
--- a/pyramid/tests/hybridapp/__init__.py
+++ b/pyramid/tests/hybridapp/__init__.py
@@ -1,6 +1,7 @@
def includeme(config):
# <!-- we want this view to "win" -->
- config.add_route('route', 'abc', view='.views.route_view')
+ config.add_route('route', 'abc')
+ config.add_view('.views.route_view', route_name='route')
# <!-- .. even though this one has a more specific context -->
config.add_view('.views.global_view',
context='pyramid.traversal.DefaultRootFactory')
diff --git a/pyramid/tests/restbugapp/__init__.py b/pyramid/tests/restbugapp/__init__.py
index 461fcce92..9ad79e32e 100644
--- a/pyramid/tests/restbugapp/__init__.py
+++ b/pyramid/tests/restbugapp/__init__.py
@@ -1,14 +1,15 @@
def includeme(config):
config.add_route('gameactions_pet_get_pets', '/pet',
- view='.views.PetRESTView',
- view_attr='GET',
- request_method='GET',
- permission='view',
- renderer='json')
+ request_method='GET')
config.add_route('gameactions_pet_care_for_pet', '/pet',
- view='.views.PetRESTView',
- view_attr='POST',
- request_method='POST',
- permission='view',
- renderer='json')
-
+ request_method='POST')
+ config.add_view('.views.PetRESTView',
+ route_name='gameactions_pet_get_pets',
+ attr='GET',
+ permission='view',
+ renderer='json')
+ config.add_view('.views.PetRESTView',
+ route_name='gameactions_pet_care_for_pet',
+ attr='POST',
+ permission='view',
+ renderer='json')
diff --git a/pyramid/tests/test_asset.py b/pyramid/tests/test_asset.py
index 4a93b14a0..1bd855cdb 100644
--- a/pyramid/tests/test_asset.py
+++ b/pyramid/tests/test_asset.py
@@ -74,7 +74,7 @@ class TestOverrideProvider(unittest.TestCase):
import pyramid.tests
provider = self._makeOne(pyramid.tests)
result = provider.resource_listdir(resource_name)
- self.failUnless(result)
+ self.assertTrue(result)
def test_get_resource_filename_override_returns_None(self):
overrides = DummyOverrides(None)
@@ -137,7 +137,7 @@ class TestOverrideProvider(unittest.TestCase):
import pyramid.tests
provider = self._makeOne(pyramid.tests)
result = provider.resource_listdir(resource_name)
- self.failUnless(result)
+ self.assertTrue(result)
def test_get_resource_filename_override_returns_value(self):
overrides = DummyOverrides('value')
@@ -371,7 +371,7 @@ class TestPackageOverrides(unittest.TestCase):
package = DummyPackage('package')
po = self._makeOne(package)
po.overrides= overrides
- self.failUnless(po.listdir('whatever'))
+ self.assertTrue(po.listdir('whatever'))
def test_listdir_doesnt_exist(self):
overrides = [ DummyOverride(None), DummyOverride(
diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py
index 1d2b939b7..ecd76a71c 100644
--- a/pyramid/tests/test_authentication.py
+++ b/pyramid/tests/test_authentication.py
@@ -470,7 +470,7 @@ class TestAuthTktCookieHelper(unittest.TestCase):
plugin.now = now + 1
request = self._makeRequest({'HTTP_COOKIE':'auth_tkt=bogus'})
result = plugin.identify(request)
- self.failUnless(result)
+ self.assertTrue(result)
self.assertEqual(len(request.callbacks), 1)
response = DummyResponse()
request.callbacks[0](None, response)
@@ -486,7 +486,7 @@ class TestAuthTktCookieHelper(unittest.TestCase):
request = self._makeRequest({'HTTP_COOKIE':'auth_tkt=bogus'})
request._authtkt_reissued = True
result = plugin.identify(request)
- self.failUnless(result)
+ self.assertTrue(result)
self.assertEqual(len(request.callbacks), 0)
def test_identify_cookie_reissue_notyet(self):
@@ -497,7 +497,7 @@ class TestAuthTktCookieHelper(unittest.TestCase):
plugin.now = now + 1
request = self._makeRequest({'HTTP_COOKIE':'auth_tkt=bogus'})
result = plugin.identify(request)
- self.failUnless(result)
+ self.assertTrue(result)
self.assertEqual(len(request.callbacks), 0)
def test_identify_cookie_reissue_with_tokens_default(self):
@@ -510,13 +510,13 @@ class TestAuthTktCookieHelper(unittest.TestCase):
plugin.now = now + 1
request = self._makeRequest({'HTTP_COOKIE':'auth_tkt=bogus'})
result = plugin.identify(request)
- self.failUnless(result)
+ self.assertTrue(result)
self.assertEqual(len(request.callbacks), 1)
response = DummyResponse()
request.callbacks[0](None, response)
self.assertEqual(len(response.headerlist), 3)
self.assertEqual(response.headerlist[0][0], 'Set-Cookie')
- self.failUnless("'tokens': []" in response.headerlist[0][1])
+ self.assertTrue("'tokens': []" in response.headerlist[0][1])
def test_remember(self):
plugin = self._makeOne('secret')
@@ -525,16 +525,16 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(len(result), 3)
self.assertEqual(result[0][0], 'Set-Cookie')
- self.failUnless(result[0][1].endswith('; Path=/'))
- self.failUnless(result[0][1].startswith('auth_tkt='))
+ self.assertTrue(result[0][1].endswith('; Path=/'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
self.assertEqual(result[1][0], 'Set-Cookie')
- self.failUnless(result[1][1].endswith('; Path=/; Domain=localhost'))
- self.failUnless(result[1][1].startswith('auth_tkt='))
+ self.assertTrue(result[1][1].endswith('; Path=/; Domain=localhost'))
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
self.assertEqual(result[2][0], 'Set-Cookie')
- self.failUnless(result[2][1].endswith('; Path=/; Domain=.localhost'))
- self.failUnless(result[2][1].startswith('auth_tkt='))
+ self.assertTrue(result[2][1].endswith('; Path=/; Domain=.localhost'))
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
def test_remember_include_ip(self):
plugin = self._makeOne('secret', include_ip=True)
@@ -543,16 +543,16 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(len(result), 3)
self.assertEqual(result[0][0], 'Set-Cookie')
- self.failUnless(result[0][1].endswith('; Path=/'))
- self.failUnless(result[0][1].startswith('auth_tkt='))
+ self.assertTrue(result[0][1].endswith('; Path=/'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
self.assertEqual(result[1][0], 'Set-Cookie')
- self.failUnless(result[1][1].endswith('; Path=/; Domain=localhost'))
- self.failUnless(result[1][1].startswith('auth_tkt='))
+ self.assertTrue(result[1][1].endswith('; Path=/; Domain=localhost'))
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
self.assertEqual(result[2][0], 'Set-Cookie')
- self.failUnless(result[2][1].endswith('; Path=/; Domain=.localhost'))
- self.failUnless(result[2][1].startswith('auth_tkt='))
+ self.assertTrue(result[2][1].endswith('; Path=/; Domain=.localhost'))
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
def test_remember_path(self):
plugin = self._makeOne('secret', include_ip=True,
@@ -562,18 +562,18 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(len(result), 3)
self.assertEqual(result[0][0], 'Set-Cookie')
- self.failUnless(result[0][1].endswith('; Path=/cgi-bin/app.cgi/'))
- self.failUnless(result[0][1].startswith('auth_tkt='))
+ self.assertTrue(result[0][1].endswith('; Path=/cgi-bin/app.cgi/'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
self.assertEqual(result[1][0], 'Set-Cookie')
- self.failUnless(result[1][1].endswith(
+ self.assertTrue(result[1][1].endswith(
'; Path=/cgi-bin/app.cgi/; Domain=localhost'))
- self.failUnless(result[1][1].startswith('auth_tkt='))
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
self.assertEqual(result[2][0], 'Set-Cookie')
- self.failUnless(result[2][1].endswith(
+ self.assertTrue(result[2][1].endswith(
'; Path=/cgi-bin/app.cgi/; Domain=.localhost'))
- self.failUnless(result[2][1].startswith('auth_tkt='))
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
def test_remember_http_only(self):
plugin = self._makeOne('secret', include_ip=True, http_only=True)
@@ -582,16 +582,16 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(len(result), 3)
self.assertEqual(result[0][0], 'Set-Cookie')
- self.failUnless(result[0][1].endswith('; HttpOnly'))
- self.failUnless(result[0][1].startswith('auth_tkt='))
+ self.assertTrue(result[0][1].endswith('; HttpOnly'))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
self.assertEqual(result[1][0], 'Set-Cookie')
- self.failUnless(result[1][1].endswith('; HttpOnly'))
- self.failUnless(result[1][1].startswith('auth_tkt='))
+ self.assertTrue(result[1][1].endswith('; HttpOnly'))
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
self.assertEqual(result[2][0], 'Set-Cookie')
- self.failUnless(result[2][1].endswith('; HttpOnly'))
- self.failUnless(result[2][1].startswith('auth_tkt='))
+ self.assertTrue(result[2][1].endswith('; HttpOnly'))
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
def test_remember_secure(self):
plugin = self._makeOne('secret', include_ip=True, secure=True)
@@ -600,16 +600,16 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(len(result), 3)
self.assertEqual(result[0][0], 'Set-Cookie')
- self.failUnless('; Secure' in result[0][1])
- self.failUnless(result[0][1].startswith('auth_tkt='))
+ self.assertTrue('; Secure' in result[0][1])
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
self.assertEqual(result[1][0], 'Set-Cookie')
- self.failUnless('; Secure' in result[1][1])
- self.failUnless(result[1][1].startswith('auth_tkt='))
+ self.assertTrue('; Secure' in result[1][1])
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
self.assertEqual(result[2][0], 'Set-Cookie')
- self.failUnless('; Secure' in result[2][1])
- self.failUnless(result[2][1].startswith('auth_tkt='))
+ self.assertTrue('; Secure' in result[2][1])
+ self.assertTrue(result[2][1].startswith('auth_tkt='))
def test_remember_wild_domain_disabled(self):
plugin = self._makeOne('secret', wild_domain=False)
@@ -619,11 +619,11 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(result[0][0], 'Set-Cookie')
self.assertTrue(result[0][1].endswith('; Path=/'))
- self.failUnless(result[0][1].startswith('auth_tkt='))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
self.assertEqual(result[1][0], 'Set-Cookie')
self.assertTrue(result[1][1].endswith('; Path=/; Domain=localhost'))
- self.failUnless(result[1][1].startswith('auth_tkt='))
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
def test_remember_domain_has_port(self):
plugin = self._makeOne('secret', wild_domain=False)
@@ -634,11 +634,11 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(result[0][0], 'Set-Cookie')
self.assertTrue(result[0][1].endswith('; Path=/'))
- self.failUnless(result[0][1].startswith('auth_tkt='))
+ self.assertTrue(result[0][1].startswith('auth_tkt='))
self.assertEqual(result[1][0], 'Set-Cookie')
self.assertTrue(result[1][1].endswith('; Path=/; Domain=example.com'))
- self.failUnless(result[1][1].startswith('auth_tkt='))
+ self.assertTrue(result[1][1].startswith('auth_tkt='))
def test_remember_string_userid(self):
plugin = self._makeOne('secret')
@@ -690,7 +690,7 @@ class TestAuthTktCookieHelper(unittest.TestCase):
values = self._parseHeaders(result)
self.assertEqual(len(result), 3)
value = values[0]
- self.failUnless('userid' in value.value)
+ self.assertTrue('userid' in value.value)
def test_remember_max_age(self):
plugin = self._makeOne('secret')
@@ -700,7 +700,7 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(len(result), 3)
self.assertEqual(values[0]['max-age'], '500')
- self.failUnless(values[0]['expires'])
+ self.assertTrue(values[0]['expires'])
def test_remember_tokens(self):
plugin = self._makeOne('secret')
@@ -709,13 +709,13 @@ class TestAuthTktCookieHelper(unittest.TestCase):
self.assertEqual(len(result), 3)
self.assertEqual(result[0][0], 'Set-Cookie')
- self.failUnless("'tokens': ('foo', 'bar')" in result[0][1])
+ self.assertTrue("'tokens': ('foo', 'bar')" in result[0][1])
self.assertEqual(result[1][0], 'Set-Cookie')
- self.failUnless("'tokens': ('foo', 'bar')" in result[1][1])
+ self.assertTrue("'tokens': ('foo', 'bar')" in result[1][1])
self.assertEqual(result[2][0], 'Set-Cookie')
- self.failUnless("'tokens': ('foo', 'bar')" in result[2][1])
+ self.assertTrue("'tokens': ('foo', 'bar')" in result[2][1])
def test_remember_non_string_token(self):
plugin = self._makeOne('secret')
diff --git a/pyramid/tests/test_chameleon_text.py b/pyramid/tests/test_chameleon_text.py
index dcc4f8344..213f25f51 100644
--- a/pyramid/tests/test_chameleon_text.py
+++ b/pyramid/tests/test_chameleon_text.py
@@ -49,7 +49,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template, instance.__dict__['template'])
@@ -58,7 +58,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
minimal = self._getTemplatePath('minimal.txt')
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.translate, lookup.translate)
@@ -68,7 +68,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
lookup.debug = True
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.debug, True)
@@ -78,7 +78,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
lookup.auto_reload = True
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.auto_reload, True)
@@ -88,7 +88,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
lookup.auto_reload = False
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.auto_reload, False)
@@ -98,7 +98,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
result = instance({}, {})
- self.failUnless(isinstance(result, str))
+ self.assertTrue(isinstance(result, str))
self.assertEqual(result, 'Hello.\n')
@skip_on('java')
@@ -114,7 +114,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne(nonminimal, lookup)
result = instance({'name':'Chris'}, {})
- self.failUnless(isinstance(result, str))
+ self.assertTrue(isinstance(result, str))
self.assertEqual(result, 'Hello, Chris!\n')
@skip_on('java')
@@ -123,7 +123,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
result = instance.implementation()()
- self.failUnless(isinstance(result, str))
+ self.assertTrue(isinstance(result, str))
self.assertEqual(result, 'Hello.\n')
class RenderTemplateTests(Base, unittest.TestCase):
@@ -135,7 +135,7 @@ class RenderTemplateTests(Base, unittest.TestCase):
def test_it(self):
minimal = self._getTemplatePath('minimal.txt')
result = self._callFUT(minimal)
- self.failUnless(isinstance(result, str))
+ self.assertTrue(isinstance(result, str))
self.assertEqual(result, 'Hello.\n')
class RenderTemplateToResponseTests(Base, unittest.TestCase):
@@ -148,7 +148,7 @@ class RenderTemplateToResponseTests(Base, unittest.TestCase):
minimal = self._getTemplatePath('minimal.txt')
result = self._callFUT(minimal)
from webob import Response
- self.failUnless(isinstance(result, Response))
+ self.assertTrue(isinstance(result, Response))
self.assertEqual(result.app_iter, ['Hello.\n'])
self.assertEqual(result.status, '200 OK')
self.assertEqual(len(result.headerlist), 2)
@@ -162,7 +162,7 @@ class RenderTemplateToResponseTests(Base, unittest.TestCase):
self._registerUtility(Response2, IResponseFactory)
minimal = self._getTemplatePath('minimal.txt')
result = self._callFUT(minimal)
- self.failUnless(isinstance(result, Response2))
+ self.assertTrue(isinstance(result, Response2))
class GetRendererTests(Base, unittest.TestCase):
def _callFUT(self, name):
@@ -180,7 +180,7 @@ class GetRendererTests(Base, unittest.TestCase):
return renderer
self._registerUtility(rf, IRendererFactory, name='foo')
result = self._callFUT('foo')
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
class GetTemplateTests(Base, unittest.TestCase):
def _callFUT(self, name):
@@ -199,7 +199,7 @@ class GetTemplateTests(Base, unittest.TestCase):
return renderer
self._registerUtility(rf, IRendererFactory, name='foo')
result = self._callFUT('foo')
- self.failUnless(result is renderer.template)
+ self.assertTrue(result is renderer.template)
class DummyLookup(object):
auto_reload=True
diff --git a/pyramid/tests/test_chameleon_zpt.py b/pyramid/tests/test_chameleon_zpt.py
index 9bdb47776..84eaedcf4 100644
--- a/pyramid/tests/test_chameleon_zpt.py
+++ b/pyramid/tests/test_chameleon_zpt.py
@@ -51,7 +51,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
result = instance({}, {})
- self.failUnless(isinstance(result, unicode))
+ self.assertTrue(isinstance(result, unicode))
self.assertEqual(result.rstrip('\n'),
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
@@ -60,7 +60,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template, instance.__dict__['template'])
@@ -69,7 +69,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
minimal = self._getTemplatePath('minimal.pt')
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.translate, lookup.translate)
@@ -79,7 +79,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
lookup.debug = True
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.debug, True)
@@ -89,7 +89,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
lookup.debug = False
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.debug, False)
@@ -99,7 +99,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
lookup.auto_reload = True
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.auto_reload, True)
@@ -109,7 +109,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
lookup.auto_reload = False
instance = self._makeOne(minimal, lookup)
- self.failIf('template' in instance.__dict__)
+ self.assertFalse('template' in instance.__dict__)
template = instance.template
self.assertEqual(template.auto_reload, False)
@@ -126,7 +126,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne(minimal, lookup)
result = instance.implementation()()
- self.failUnless(isinstance(result, unicode))
+ self.assertTrue(isinstance(result, unicode))
self.assertEqual(result.rstrip('\n'),
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
@@ -140,7 +140,7 @@ class RenderTemplateTests(Base, unittest.TestCase):
def test_it(self):
minimal = self._getTemplatePath('minimal.pt')
result = self._callFUT(minimal)
- self.failUnless(isinstance(result, unicode))
+ self.assertTrue(isinstance(result, unicode))
self.assertEqual(result.rstrip('\n'),
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
@@ -154,7 +154,7 @@ class RenderTemplateToResponseTests(Base, unittest.TestCase):
minimal = self._getTemplatePath('minimal.pt')
result = self._callFUT(minimal)
from webob import Response
- self.failUnless(isinstance(result, Response))
+ self.assertTrue(isinstance(result, Response))
self.assertEqual(result.app_iter[0].rstrip('\n'),
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
self.assertEqual(result.status, '200 OK')
@@ -169,7 +169,7 @@ class RenderTemplateToResponseTests(Base, unittest.TestCase):
self._registerUtility(Response2, IResponseFactory)
minimal = self._getTemplatePath('minimal.pt')
result = self._callFUT(minimal)
- self.failUnless(isinstance(result, Response2))
+ self.assertTrue(isinstance(result, Response2))
class GetRendererTests(Base, unittest.TestCase):
def _callFUT(self, name):
@@ -187,7 +187,7 @@ class GetRendererTests(Base, unittest.TestCase):
return renderer
self._registerUtility(rf, IRendererFactory, name='foo')
result = self._callFUT('foo')
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
class GetTemplateTests(Base, unittest.TestCase):
def _callFUT(self, name):
@@ -206,7 +206,7 @@ class GetTemplateTests(Base, unittest.TestCase):
return renderer
self._registerUtility(rf, IRendererFactory, name='foo')
result = self._callFUT('foo')
- self.failUnless(result is renderer.template)
+ self.assertTrue(result is renderer.template)
class DummyLookup(object):
auto_reload=True
diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py
index d5903d4fb..f52d194b6 100644
--- a/pyramid/tests/test_config.py
+++ b/pyramid/tests/test_config.py
@@ -68,6 +68,12 @@ class ConfiguratorTests(unittest.TestCase):
request.registry = config.registry
return request
+ def _conflictFunctions(self, e):
+ conflicts = e._conflicts.values()
+ for conflict in conflicts:
+ for confinst in conflict:
+ yield confinst[2]
+
def test_ctor_no_registry(self):
import sys
from pyramid.interfaces import ISettings
@@ -75,20 +81,20 @@ class ConfiguratorTests(unittest.TestCase):
from pyramid.interfaces import IRendererFactory
config = Configurator()
this_pkg = sys.modules['pyramid.tests']
- self.failUnless(config.registry.getUtility(ISettings))
+ self.assertTrue(config.registry.getUtility(ISettings))
self.assertEqual(config.package, this_pkg)
- self.failUnless(config.registry.getUtility(IRendererFactory, 'json'))
- self.failUnless(config.registry.getUtility(IRendererFactory, 'string'))
+ self.assertTrue(config.registry.getUtility(IRendererFactory, 'json'))
+ self.assertTrue(config.registry.getUtility(IRendererFactory, 'string'))
if not __pypy__:
- self.failUnless(config.registry.getUtility(IRendererFactory, '.pt'))
- self.failUnless(config.registry.getUtility(IRendererFactory,'.txt'))
- self.failUnless(config.registry.getUtility(IRendererFactory, '.mak'))
- self.failUnless(config.registry.getUtility(IRendererFactory, '.mako'))
+ self.assertTrue(config.registry.getUtility(IRendererFactory, '.pt'))
+ self.assertTrue(config.registry.getUtility(IRendererFactory,'.txt'))
+ self.assertTrue(config.registry.getUtility(IRendererFactory, '.mak'))
+ self.assertTrue(config.registry.getUtility(IRendererFactory, '.mako'))
def test__set_settings_as_None(self):
config = self._makeOne()
settings = config._set_settings(None)
- self.failUnless(settings)
+ self.assertTrue(settings)
def test__set_settings_as_dictwithvalues(self):
config = self._makeOne()
@@ -171,7 +177,7 @@ class ConfiguratorTests(unittest.TestCase):
def test_ctor_no_root_factory(self):
from pyramid.interfaces import IRootFactory
config = self._makeOne()
- self.failUnless(config.registry.getUtility(IRootFactory))
+ self.assertTrue(config.registry.getUtility(IRootFactory))
def test_ctor_alternate_renderers(self):
from pyramid.interfaces import IRendererFactory
@@ -390,7 +396,7 @@ class ConfiguratorTests(unittest.TestCase):
reg = Registry()
config = self._makeOne(reg)
config.setup_registry()
- self.failUnless(reg.getUtility(IRootFactory))
+ self.assertTrue(reg.getUtility(IRootFactory))
def test_setup_registry_dottedname_root_factory(self):
from pyramid.registry import Registry
@@ -591,9 +597,9 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(app.__class__, Router)
self.assertEqual(manager.pushed['registry'], config.registry)
self.assertEqual(manager.pushed['request'], None)
- self.failUnless(manager.popped)
+ self.assertTrue(manager.popped)
self.assertEqual(len(subscriber), 1)
- self.failUnless(IApplicationCreated.providedBy(subscriber[0]))
+ self.assertTrue(IApplicationCreated.providedBy(subscriber[0]))
def test_include_with_dotted_name(self):
from pyramid import tests
@@ -610,7 +616,7 @@ class ConfiguratorTests(unittest.TestCase):
)
self.assertEqual(context_after.basepath, None)
self.assertEqual(context_after.includepath, ())
- self.failUnless(context_after is context_before)
+ self.assertTrue(context_after is context_before)
def test_include_with_python_callable(self):
from pyramid import tests
@@ -627,7 +633,7 @@ class ConfiguratorTests(unittest.TestCase):
)
self.assertEqual(context_after.basepath, None)
self.assertEqual(context_after.includepath, ())
- self.failUnless(context_after is context_before)
+ self.assertTrue(context_after is context_before)
def test_include_with_module_defaults_to_includeme(self):
from pyramid import tests
@@ -644,7 +650,7 @@ class ConfiguratorTests(unittest.TestCase):
)
self.assertEqual(context_after.basepath, None)
self.assertEqual(context_after.includepath, ())
- self.failUnless(context_after is context_before)
+ self.assertTrue(context_after is context_before)
def test_with_context(self):
config = self._makeOne()
@@ -683,7 +689,7 @@ class ConfiguratorTests(unittest.TestCase):
self._registerRenderer(config, name='dummy')
config.add_view(renderer='dummy')
view = self._getViewCallable(config)
- self.failUnless('Hello!' in view(None, None).body)
+ self.assertTrue('Hello!' in view(None, None).body)
def test_add_view_wrapped_view_is_decorated(self):
def view(request): # request-only wrapper
@@ -729,7 +735,7 @@ class ConfiguratorTests(unittest.TestCase):
config = self._makeOne(autocommit=True)
config.add_view(view=view, decorator=view_wrapper)
wrapper = self._getViewCallable(config)
- self.failIf(wrapper is view)
+ self.assertFalse(wrapper is view)
self.assertEqual(wrapper.__doc__, view.__doc__)
result = wrapper(None, None)
self.assertEqual(result, 'OK')
@@ -900,7 +906,7 @@ class ConfiguratorTests(unittest.TestCase):
return 'OK'
config.add_view(view=newview, xhr=True)
wrapper = self._getViewCallable(config)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
request = DummyRequest()
request.is_xhr = True
self.assertEqual(wrapper(None, request), 'OK')
@@ -926,7 +932,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=newview, xhr=True, context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
request = DummyRequest()
request.is_xhr = True
self.assertEqual(wrapper(None, request), 'OK')
@@ -945,7 +951,7 @@ class ConfiguratorTests(unittest.TestCase):
return 'OK'
config.add_view(view=newview)
wrapper = self._getViewCallable(config)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
request = DummyRequest()
request.is_xhr = True
self.assertEqual(wrapper(None, request), 'OK')
@@ -967,7 +973,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=newview, context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
request = DummyRequest()
request.is_xhr = True
self.assertEqual(wrapper(None, request), 'OK')
@@ -988,7 +994,7 @@ class ConfiguratorTests(unittest.TestCase):
return 'OK'
config.add_view(view=newview)
wrapper = self._getViewCallable(config)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
request = DummyRequest()
request.is_xhr = True
self.assertEqual(wrapper(None, request), 'OK')
@@ -1012,7 +1018,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=newview, context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
request = DummyRequest()
request.is_xhr = True
self.assertEqual(wrapper(None, request), 'OK')
@@ -1030,7 +1036,7 @@ class ConfiguratorTests(unittest.TestCase):
view, (IViewClassifier, IRequest, Interface), IView, name='')
config.add_view(view=view)
wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(wrapper(None, None), 'OK')
def test_add_view_exc_multiview_replaces_existing_view(self):
@@ -1054,7 +1060,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=view, context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(wrapper(None, None), 'OK')
def test_add_view_multiview_replaces_existing_securedview(self):
@@ -1071,7 +1077,7 @@ class ConfiguratorTests(unittest.TestCase):
ISecuredView, name='')
config.add_view(view=view)
wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(wrapper(None, None), 'OK')
def test_add_view_exc_multiview_replaces_existing_securedview(self):
@@ -1095,7 +1101,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=view, context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(wrapper(None, None), 'OK')
def test_add_view_with_accept_multiview_replaces_existing_view(self):
@@ -1113,7 +1119,7 @@ class ConfiguratorTests(unittest.TestCase):
view, (IViewClassifier, IRequest, Interface), IView, name='')
config.add_view(view=view2, accept='text/html')
wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(len(wrapper.views), 1)
self.assertEqual(len(wrapper.media_views), 1)
self.assertEqual(wrapper(None, None), 'OK')
@@ -1144,7 +1150,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=view2, accept='text/html', context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(len(wrapper.views), 1)
self.assertEqual(len(wrapper.media_views), 1)
self.assertEqual(wrapper(None, None), 'OK')
@@ -1169,7 +1175,7 @@ class ConfiguratorTests(unittest.TestCase):
view, (IViewClassifier, IRequest, Interface), IView, name='')
config.add_view(view=view2)
wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(len(wrapper.views), 1)
self.assertEqual(len(wrapper.media_views), 1)
self.assertEqual(wrapper(None, None), 'OK2')
@@ -1202,7 +1208,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=view2, context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual(len(wrapper.views), 1)
self.assertEqual(len(wrapper.media_views), 1)
self.assertEqual(wrapper(None, None), 'OK2')
@@ -1223,7 +1229,7 @@ class ConfiguratorTests(unittest.TestCase):
view2 = lambda *arg: 'OK2'
config.add_view(view=view2)
wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])
self.assertEqual(wrapper(None, None), 'OK1')
@@ -1247,7 +1253,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_view(view=view2, context=RuntimeError)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertTrue(IMultiView.providedBy(wrapper))
self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])
self.assertEqual(wrapper(None, None), 'OK1')
@@ -1268,10 +1274,10 @@ class ConfiguratorTests(unittest.TestCase):
view, (IViewClassifier, IRequest, ISuper), IView, name='')
config.add_view(view=view2, for_=ISub)
wrapper = self._getViewCallable(config, ISuper, IRequest)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
self.assertEqual(wrapper(None, None), 'OK')
wrapper = self._getViewCallable(config, ISub, IRequest)
- self.failIf(IMultiView.providedBy(wrapper))
+ self.assertFalse(IMultiView.providedBy(wrapper))
self.assertEqual(wrapper(None, None), 'OK2')
def test_add_view_multiview_exception_superclass_then_subclass(self):
@@ -1298,14 +1304,14 @@ class ConfiguratorTests(unittest.TestCase):
wrapper_exc_view = self._getViewCallable(
config, implementedBy(Super), IRequest, exception_view=True)
self.assertEqual(wrapper_exc_view, wrapper)
- self.failIf(IMultiView.providedBy(wrapper_exc_view))
+ self.assertFalse(IMultiView.providedBy(wrapper_exc_view))
self.assertEqual(wrapper_exc_view(None, None), 'OK')
wrapper = self._getViewCallable(
config, implementedBy(Sub), IRequest)
wrapper_exc_view = self._getViewCallable(
config, implementedBy(Sub), IRequest, exception_view=True)
self.assertEqual(wrapper_exc_view, wrapper)
- self.failIf(IMultiView.providedBy(wrapper_exc_view))
+ self.assertFalse(IMultiView.providedBy(wrapper_exc_view))
self.assertEqual(wrapper_exc_view(None, None), 'OK2')
def test_add_view_multiview_call_ordering(self):
@@ -1486,9 +1492,9 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(wrapper, None)
config.add_route('foo', '/a/b')
request_iface = self._getRouteRequestIface(config, 'foo')
- self.failIfEqual(request_iface, None)
+ self.assertNotEqual(request_iface, None)
wrapper = self._getViewCallable(config, request_iface=request_iface)
- self.failIfEqual(wrapper, None)
+ self.assertNotEqual(wrapper, None)
self.assertEqual(wrapper(None, None), 'OK')
def test_add_view_with_route_name_deferred_views_already_exist(self):
@@ -1532,11 +1538,11 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(wrapper_exc_view, None)
config.add_route('foo', '/a/b')
request_iface = self._getRouteRequestIface(config, 'foo')
- self.failIfEqual(request_iface, None)
+ self.assertNotEqual(request_iface, None)
wrapper_exc_view = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError),
request_iface=request_iface, exception_view=True)
- self.failIfEqual(wrapper_exc_view, None)
+ self.assertNotEqual(wrapper_exc_view, None)
wrapper = self._getViewCallable(
config, ctx_iface=implementedBy(RuntimeError),
request_iface=request_iface)
@@ -1979,129 +1985,6 @@ class ConfiguratorTests(unittest.TestCase):
request.accept = ['text/html']
self.assertEqual(predicate(None, request), False)
- def test_add_route_with_view(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
-
- def test_add_route_with_view_context(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_context=IDummy)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, IDummy, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(config, IOther, request_type)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_view_exception(self):
- from zope.interface import implementedBy
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_context=RuntimeError)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError),
- request_iface=request_type, exception_view=True)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(
- config, ctx_iface=IOther,
- request_iface=request_type, exception_view=True)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_view_for(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_for=IDummy)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, IDummy, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(config, IOther, request_type)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_for_(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, for_=IDummy)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, IDummy, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(config, IOther, request_type)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_view_renderer(self):
- config = self._makeOne(autocommit=True)
- self._registerRenderer(config)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view,
- view_renderer='fixtures/minimal.txt')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.assertEqual(wrapper(None, None).body, 'Hello!')
-
- def test_add_route_with_view_attr(self):
- config = self._makeOne(autocommit=True)
- self._registerRenderer(config)
- class View(object):
- def __init__(self, context, request):
- pass
- def alt(self):
- return 'OK'
- config.add_route('name', 'path', view=View, view_attr='alt')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- request = self._makeRequest(config)
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_route_with_view_renderer_alias(self):
- config = self._makeOne(autocommit=True)
- self._registerRenderer(config)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view,
- renderer='fixtures/minimal.txt')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.assertEqual(wrapper(None, None).body, 'Hello!')
-
- def test_add_route_with_view_permission(self):
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.interfaces import IAuthorizationPolicy
- config = self._makeOne(autocommit=True)
- policy = lambda *arg: None
- config.registry.registerUtility(policy, IAuthenticationPolicy)
- config.registry.registerUtility(policy, IAuthorizationPolicy)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_permission='edit')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.failUnless(hasattr(wrapper, '__call_permissive__'))
-
- def test_add_route_with_view_permission_alias(self):
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.interfaces import IAuthorizationPolicy
- config = self._makeOne(autocommit=True)
- policy = lambda *arg: None
- config.registry.registerUtility(policy, IAuthenticationPolicy)
- config.registry.registerUtility(policy, IAuthorizationPolicy)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, permission='edit')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.failUnless(hasattr(wrapper, '__call_permissive__'))
-
def test_add_route_no_pattern_with_path(self):
config = self._makeOne(autocommit=True)
route = config.add_route('name', path='path')
@@ -2163,14 +2046,14 @@ class ConfiguratorTests(unittest.TestCase):
return 'OK'
config = self._makeOne()
result = config.derive_view(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result(None, None), 'OK')
def test_derive_view_dottedname(self):
config = self._makeOne()
result = config.derive_view(
'pyramid.tests.test_config.dummy_view')
- self.failIf(result is dummy_view)
+ self.assertFalse(result is dummy_view)
self.assertEqual(result(None, None), 'OK')
def test_derive_view_with_default_renderer_no_explicit_renderer(self):
@@ -2184,7 +2067,7 @@ class ConfiguratorTests(unittest.TestCase):
def view(request):
return 'OK'
result = config.derive_view(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result(None, None).body, 'moo')
def test_derive_view_with_default_renderer_with_explicit_renderer(self):
@@ -2200,7 +2083,7 @@ class ConfiguratorTests(unittest.TestCase):
config.add_renderer(None, moo)
config.add_renderer('foo', foo)
result = config.derive_view(view, renderer='foo')
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest(config)
self.assertEqual(result(None, request).body, 'foo')
@@ -2350,7 +2233,7 @@ class ConfiguratorTests(unittest.TestCase):
result = view(None, request)
finally:
config.end()
- self.failUnless('div' in result.body)
+ self.assertTrue('div' in result.body)
def test_set_forbidden_view(self):
from zope.interface import implementedBy
@@ -2397,7 +2280,7 @@ class ConfiguratorTests(unittest.TestCase):
result = view(None, request)
finally:
config.end()
- self.failUnless('div' in result.body)
+ self.assertTrue('div' in result.body)
def test__set_authentication_policy(self):
from pyramid.interfaces import IAuthenticationPolicy
@@ -2791,7 +2674,7 @@ class ConfiguratorTests(unittest.TestCase):
from pyramid.interfaces import IAuthenticationPolicy
from pyramid.interfaces import IAuthorizationPolicy
ut = config.registry.getUtility(IAuthenticationPolicy)
- self.failUnless(isinstance(ut, DummySecurityPolicy))
+ self.assertTrue(isinstance(ut, DummySecurityPolicy))
ut = config.registry.getUtility(IAuthorizationPolicy)
self.assertEqual(ut.userid, 'user')
self.assertEqual(ut.groupids, ('group1', 'group2'))
@@ -2899,7 +2782,7 @@ class ConfiguratorTests(unittest.TestCase):
config = self._makeOne(autocommit=True)
renderer = config.testing_add_renderer('templates/foo.pt')
from pyramid.testing import DummyTemplateRenderer
- self.failUnless(isinstance(renderer, DummyTemplateRenderer))
+ self.assertTrue(isinstance(renderer, DummyTemplateRenderer))
from pyramid.renderers import render_to_response
# must provide request to pass in registry (this is a functest)
request = DummyRequest()
@@ -2915,8 +2798,8 @@ class ConfiguratorTests(unittest.TestCase):
renderer1 = config.testing_add_renderer('templates/foo.pt')
renderer2 = config.testing_add_renderer('templates/bar.pt')
from pyramid.testing import DummyTemplateRenderer
- self.failUnless(isinstance(renderer1, DummyTemplateRenderer))
- self.failUnless(isinstance(renderer2, DummyTemplateRenderer))
+ self.assertTrue(isinstance(renderer1, DummyTemplateRenderer))
+ self.assertTrue(isinstance(renderer2, DummyTemplateRenderer))
from pyramid.renderers import render_to_response
# must provide request to pass in registry (this is a functest)
request = DummyRequest()
@@ -2955,7 +2838,7 @@ class ConfiguratorTests(unittest.TestCase):
config = self._makeOne(autocommit=True)
renderer = config.testing_add_template('templates/foo.pt')
from pyramid.testing import DummyTemplateRenderer
- self.failUnless(isinstance(renderer, DummyTemplateRenderer))
+ self.assertTrue(isinstance(renderer, DummyTemplateRenderer))
from pyramid.renderers import render_to_response
# must provide request to pass in registry (this is a functest)
request = DummyRequest()
@@ -3035,24 +2918,6 @@ class ConfiguratorTests(unittest.TestCase):
registeredview = self._getViewCallable(config)
self.assertEqual(registeredview.__name__, 'view3')
- def test_conflict_route_with_view(self):
- from zope.configuration.config import ConfigurationConflictError
- config = self._makeOne()
- def view1(request): pass
- def view2(request): pass
- config.add_route('a', '/a', view=view1)
- config.add_route('a', '/a', view=view2)
- try:
- config.commit()
- except ConfigurationConflictError, why:
- c1, c2, c3, c4 = self._conflictFunctions(why)
- self.assertEqual(c1, 'test_conflict_route_with_view')
- self.assertEqual(c2, 'test_conflict_route_with_view')
- self.assertEqual(c3, 'test_conflict_route_with_view')
- self.assertEqual(c4, 'test_conflict_route_with_view')
- else: # pragma: no cover
- raise AssertionError
-
def test_conflict_set_notfound_view(self):
from zope.configuration.config import ConfigurationConflictError
config = self._makeOne()
@@ -3102,16 +2967,10 @@ class ConfiguratorTests(unittest.TestCase):
yield confinst[3]
which = list(scanconflicts(why))
self.assertEqual(len(which), 4)
- self.failUnless("@view_config(renderer='string')" in which)
- self.failUnless("@view_config(name='two', renderer='string')" in
+ self.assertTrue("@view_config(renderer='string')" in which)
+ self.assertTrue("@view_config(name='two', renderer='string')" in
which)
- def _conflictFunctions(self, e):
- conflicts = e._conflicts.values()
- for conflict in conflicts:
- for confinst in conflict:
- yield confinst[2]
-
def test___getattr__missing_when_directives_exist(self):
config = self._makeOne()
directives = {}
@@ -3128,7 +2987,7 @@ class ConfiguratorTests(unittest.TestCase):
directives = {'foo':(foo, True)}
config.registry._directives = directives
foo_meth = config.foo
- self.failUnless(foo_meth.im_func.__docobj__ is foo)
+ self.assertTrue(foo_meth.im_func.__docobj__ is foo)
def test___getattr__matches_no_action_wrap(self):
config = self._makeOne()
@@ -3136,7 +2995,218 @@ class ConfiguratorTests(unittest.TestCase):
directives = {'foo':(foo, False)}
config.registry._directives = directives
foo_meth = config.foo
- self.failUnless(foo_meth.im_func is foo)
+ self.assertTrue(foo_meth.im_func is foo)
+
+class TestConfiguratorDeprecatedFeatures(unittest.TestCase):
+ def setUp(self):
+ import warnings
+ warnings.filterwarnings('ignore')
+
+ def tearDown(self):
+ import warnings
+ warnings.resetwarnings()
+
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+ return Configurator(*arg, **kw)
+
+ def _getRouteRequestIface(self, config, name):
+ from pyramid.interfaces import IRouteRequest
+ iface = config.registry.getUtility(IRouteRequest, name)
+ return iface
+
+ def _getViewCallable(self, config, ctx_iface=None, request_iface=None,
+ name='', exception_view=False):
+ from zope.interface import Interface
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ if exception_view:
+ classifier = IExceptionViewClassifier
+ else:
+ classifier = IViewClassifier
+ if ctx_iface is None:
+ ctx_iface = Interface
+ return config.registry.adapters.lookup(
+ (classifier, request_iface, ctx_iface), IView, name=name,
+ default=None)
+
+ def _registerRenderer(self, config, name='.txt'):
+ from pyramid.interfaces import IRendererFactory
+ from pyramid.interfaces import ITemplateRenderer
+ from zope.interface import implements
+ class Renderer:
+ implements(ITemplateRenderer)
+ def __init__(self, info):
+ self.__class__.info = info
+ def __call__(self, *arg):
+ return 'Hello!'
+ config.registry.registerUtility(Renderer, IRendererFactory, name=name)
+ return Renderer
+
+ def _assertRoute(self, config, name, path, num_predicates=0):
+ from pyramid.interfaces import IRoutesMapper
+ mapper = config.registry.getUtility(IRoutesMapper)
+ routes = mapper.get_routes()
+ route = routes[0]
+ self.assertEqual(len(routes), 1)
+ self.assertEqual(route.name, name)
+ self.assertEqual(route.path, path)
+ self.assertEqual(len(routes[0].predicates), num_predicates)
+ return route
+
+ def _makeRequest(self, config):
+ request = DummyRequest()
+ request.registry = config.registry
+ return request
+
+ def _conflictFunctions(self, e):
+ conflicts = e._conflicts.values()
+ for conflict in conflicts:
+ for confinst in conflict:
+ yield confinst[2]
+
+ def test_add_route_with_view(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+
+ def test_add_route_with_view_context(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_context=IDummy)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, IDummy, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(config, IOther, request_type)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_view_exception(self):
+ from zope.interface import implementedBy
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_context=RuntimeError)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError),
+ request_iface=request_type, exception_view=True)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(
+ config, ctx_iface=IOther,
+ request_iface=request_type, exception_view=True)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_view_for(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_for=IDummy)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, IDummy, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(config, IOther, request_type)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_for_(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, for_=IDummy)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, IDummy, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(config, IOther, request_type)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_view_renderer(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view,
+ view_renderer='fixtures/minimal.txt')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.assertEqual(wrapper(None, None).body, 'Hello!')
+
+ def test_add_route_with_view_attr(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config)
+ class View(object):
+ def __init__(self, context, request):
+ pass
+ def alt(self):
+ return 'OK'
+ config.add_route('name', 'path', view=View, view_attr='alt')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_route_with_view_renderer_alias(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view,
+ renderer='fixtures/minimal.txt')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.assertEqual(wrapper(None, None).body, 'Hello!')
+
+ def test_add_route_with_view_permission(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ config = self._makeOne(autocommit=True)
+ policy = lambda *arg: None
+ config.registry.registerUtility(policy, IAuthenticationPolicy)
+ config.registry.registerUtility(policy, IAuthorizationPolicy)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_permission='edit')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.assertTrue(hasattr(wrapper, '__call_permissive__'))
+
+ def test_add_route_with_view_permission_alias(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ config = self._makeOne(autocommit=True)
+ policy = lambda *arg: None
+ config.registry.registerUtility(policy, IAuthenticationPolicy)
+ config.registry.registerUtility(policy, IAuthorizationPolicy)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, permission='edit')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.assertTrue(hasattr(wrapper, '__call_permissive__'))
+
+ def test_conflict_route_with_view(self):
+ from zope.configuration.config import ConfigurationConflictError
+ config = self._makeOne()
+ def view1(request): pass
+ def view2(request): pass
+ config.add_route('a', '/a', view=view1)
+ config.add_route('a', '/a', view=view2)
+ try:
+ config.commit()
+ except ConfigurationConflictError, why:
+ c1, c2, c3, c4 = self._conflictFunctions(why)
+ self.assertEqual(c1, 'test_conflict_route_with_view')
+ self.assertEqual(c2, 'test_conflict_route_with_view')
+ self.assertEqual(c3, 'test_conflict_route_with_view')
+ self.assertEqual(c4, 'test_conflict_route_with_view')
+ else: # pragma: no cover
+ raise AssertionError
+
class TestConfigurator_add_directive(unittest.TestCase):
@@ -3250,7 +3320,7 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result(None, None), 'OK')
def test_requestonly_function_with_renderer(self):
@@ -3265,7 +3335,7 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne(renderer=moo())
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
context = testing.DummyResource()
self.assertEqual(result(context, request), 'moo')
@@ -3283,7 +3353,7 @@ class TestViewDeriver(unittest.TestCase):
self.config.add_renderer('moo', moo)
deriver = self._makeOne(renderer='string')
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
request.override_renderer = 'moo'
context = testing.DummyResource()
@@ -3301,12 +3371,12 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne(renderer=moo())
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
request.__view__ = 'view'
context = testing.DummyResource()
self.assertEqual(result(context, request), 'moo')
- self.failIf(hasattr(request, '__view__'))
+ self.assertFalse(hasattr(request, '__view__'))
def test_class_without_attr(self):
class View(object):
@@ -3337,8 +3407,8 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne()
result = deriver(view)
- self.failUnless(result is view)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertTrue(result is view)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
self.assertEqual(view(None, None), 'OK')
def test_as_function_requestonly(self):
@@ -3346,11 +3416,11 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_as_newstyle_class_context_and_request(self):
@@ -3361,11 +3431,11 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
self.assertEqual(request.__view__.__class__, view)
@@ -3378,11 +3448,11 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
self.assertEqual(request.__view__.__class__, view)
@@ -3395,11 +3465,11 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
self.assertEqual(request.__view__.__class__, view)
@@ -3412,11 +3482,11 @@ class TestViewDeriver(unittest.TestCase):
return 'OK'
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
self.assertEqual(request.__view__.__class__, view)
@@ -3428,8 +3498,8 @@ class TestViewDeriver(unittest.TestCase):
view = View()
deriver = self._makeOne()
result = deriver(view)
- self.failUnless(result is view)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertTrue(result is view)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_as_instance_requestonly(self):
@@ -3439,11 +3509,11 @@ class TestViewDeriver(unittest.TestCase):
view = View()
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertTrue('instance' in result.__name__)
+ self.assertFalse(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_with_debug_authorization_no_authpol(self):
@@ -3456,7 +3526,7 @@ class TestViewDeriver(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
request.view_name = 'view_name'
request.url = 'url'
@@ -3479,7 +3549,7 @@ class TestViewDeriver(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
request.view_name = 'view_name'
request.url = 'url'
@@ -3502,7 +3572,7 @@ class TestViewDeriver(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
request.view_name = 'view_name'
request.url = 'url'
@@ -3524,7 +3594,7 @@ class TestViewDeriver(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
request.view_name = 'view_name'
request.url = 'url'
@@ -3624,7 +3694,7 @@ class TestViewDeriver(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
request.view_name = 'view_name'
request.url = 'url'
@@ -3645,7 +3715,7 @@ class TestViewDeriver(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
request.view_name = 'view_name'
request.url = 'url'
@@ -3662,7 +3732,7 @@ class TestViewDeriver(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertFalse(hasattr(result, '__call_permissive__'))
request = self._makeRequest()
request.view_name = 'view_name'
request.url = 'url'
@@ -3736,7 +3806,7 @@ class TestViewDeriver(unittest.TestCase):
deriver = self._makeOne(viewname='inner',
wrapper_viewname='owrap')
result = deriver(inner_view)
- self.failIf(result is inner_view)
+ self.assertFalse(result is inner_view)
self.assertEqual(inner_view.__module__, result.__module__)
self.assertEqual(inner_view.__doc__, result.__doc__)
request = self._makeRequest()
@@ -3768,7 +3838,7 @@ class TestViewDeriver(unittest.TestCase):
return {'a':'1'}
deriver = self._makeOne(renderer=renderer(), attr='index')
result = deriver(View)
- self.failIf(result is View)
+ self.assertFalse(result is View)
self.assertEqual(result.__module__, View.__module__)
self.assertEqual(result.__doc__, View.__doc__)
self.assertEqual(result.__name__, View.__name__)
@@ -3791,7 +3861,7 @@ class TestViewDeriver(unittest.TestCase):
return {'a':'1'}
deriver = self._makeOne(renderer=renderer(), attr='index')
result = deriver(View)
- self.failIf(result is View)
+ self.assertFalse(result is View)
self.assertEqual(result.__module__, View.__module__)
self.assertEqual(result.__doc__, View.__doc__)
self.assertEqual(result.__name__, View.__name__)
@@ -3814,7 +3884,7 @@ class TestViewDeriver(unittest.TestCase):
return {'a':'1'}
deriver = self._makeOne(renderer=renderer(), attr='index')
result = deriver(View)
- self.failIf(result is View)
+ self.assertFalse(result is View)
self.assertEqual(result.__module__, View.__module__)
self.assertEqual(result.__doc__, View.__doc__)
self.assertEqual(result.__name__, View.__name__)
@@ -3837,7 +3907,7 @@ class TestViewDeriver(unittest.TestCase):
return {'a':'1'}
deriver = self._makeOne(renderer=renderer(), attr='index')
result = deriver(View)
- self.failIf(result is View)
+ self.assertFalse(result is View)
self.assertEqual(result.__module__, View.__module__)
self.assertEqual(result.__doc__, View.__doc__)
self.assertEqual(result.__name__, View.__name__)
@@ -3859,7 +3929,7 @@ class TestViewDeriver(unittest.TestCase):
deriver = self._makeOne(renderer=renderer(), attr='index')
view = View()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result.__module__, view.__module__)
self.assertEqual(result.__doc__, view.__doc__)
request = self._makeRequest()
@@ -3880,7 +3950,7 @@ class TestViewDeriver(unittest.TestCase):
deriver = self._makeOne(renderer=renderer(), attr='index')
view = View()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result.__module__, view.__module__)
self.assertEqual(result.__doc__, view.__doc__)
request = self._makeRequest()
@@ -3898,7 +3968,7 @@ class TestViewDeriver(unittest.TestCase):
def view(context, request): return 'NOTOK'
deriver = self._makeOne(mapper=mapper)
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result(None, None), 'OK')
def test_with_view_mapper_view_specified(self):
@@ -3913,7 +3983,7 @@ class TestViewDeriver(unittest.TestCase):
view.__view_mapper__ = mapper
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result(None, None), 'OK')
def test_with_view_mapper_default_mapper_specified(self):
@@ -3928,7 +3998,7 @@ class TestViewDeriver(unittest.TestCase):
def view(context, request): return 'NOTOK'
deriver = self._makeOne()
result = deriver(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
self.assertEqual(result(None, None), 'OK')
def test_attr_wrapped_view_branching_default_phash(self):
@@ -3968,7 +4038,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne()
result = mapper(view)
- self.failUnless(result is view)
+ self.assertTrue(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -3977,7 +4047,7 @@ class TestDefaultViewMapper(unittest.TestCase):
""" """
mapper = self._makeOne(attr='__name__')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertRaises(TypeError, result, None, request)
@@ -3986,7 +4056,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne()
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -3995,7 +4065,7 @@ class TestDefaultViewMapper(unittest.TestCase):
""" """
mapper = self._makeOne(attr='__name__')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertRaises(TypeError, result, None, request)
@@ -4007,7 +4077,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne()
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4019,7 +4089,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne(attr='index')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4031,7 +4101,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne()
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4043,7 +4113,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne(attr='index')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4055,7 +4125,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne()
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4067,7 +4137,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne(attr='index')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4079,7 +4149,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne()
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4091,7 +4161,7 @@ class TestDefaultViewMapper(unittest.TestCase):
return 'OK'
mapper = self._makeOne(attr='index')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4102,7 +4172,7 @@ class TestDefaultViewMapper(unittest.TestCase):
view = View()
mapper = self._makeOne()
result = mapper(view)
- self.failUnless(result is view)
+ self.assertTrue(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4113,7 +4183,7 @@ class TestDefaultViewMapper(unittest.TestCase):
view = View()
mapper = self._makeOne(attr='index')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4124,7 +4194,7 @@ class TestDefaultViewMapper(unittest.TestCase):
view = View()
mapper = self._makeOne()
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4135,7 +4205,7 @@ class TestDefaultViewMapper(unittest.TestCase):
view = View()
mapper = self._makeOne(attr='index')
result = mapper(view)
- self.failIf(result is view)
+ self.assertFalse(result is view)
request = self._makeRequest()
self.assertEqual(result(None, request), 'OK')
@@ -4148,7 +4218,7 @@ class Test_preserve_view_attrs(unittest.TestCase):
def view(context, request):
""" """
result = self._callFUT(view, view)
- self.failUnless(result is view)
+ self.assertTrue(result is view)
def test_it_different_with_existing_original_view(self):
def view1(context, request): pass
@@ -4156,7 +4226,7 @@ class Test_preserve_view_attrs(unittest.TestCase):
def view2(context, request): pass
result = self._callFUT(view1, view2)
self.assertEqual(result.__original_view__, 'abc')
- self.failIf(result is view1)
+ self.assertFalse(result is view1)
def test_it_different(self):
class DummyView1:
@@ -4187,15 +4257,15 @@ class Test_preserve_view_attrs(unittest.TestCase):
view2 = DummyView2()
result = self._callFUT(view2, view1)
self.assertEqual(result, view1)
- self.failUnless(view1.__original_view__ is view2)
- self.failUnless(view1.__doc__ is view2.__doc__)
- self.failUnless(view1.__module__ is view2.__module__)
- self.failUnless(view1.__name__ is view2.__name__)
- self.failUnless(view1.__call_permissive__.im_func is
+ self.assertTrue(view1.__original_view__ is view2)
+ self.assertTrue(view1.__doc__ is view2.__doc__)
+ self.assertTrue(view1.__module__ is view2.__module__)
+ self.assertTrue(view1.__name__ is view2.__name__)
+ self.assertTrue(view1.__call_permissive__.im_func is
view2.__call_permissive__.im_func)
- self.failUnless(view1.__permitted__.im_func is
+ self.assertTrue(view1.__permitted__.im_func is
view2.__permitted__.im_func)
- self.failUnless(view1.__predicated__.im_func is
+ self.assertTrue(view1.__predicated__.im_func is
view2.__predicated__.im_func)
class Test__make_predicates(unittest.TestCase):
@@ -4206,7 +4276,7 @@ class Test__make_predicates(unittest.TestCase):
def test_ordering_xhr_and_request_method_trump_only_containment(self):
order1, _, _ = self._callFUT(xhr=True, request_method='GET')
order2, _, _ = self._callFUT(containment=True)
- self.failUnless(order1 < order2)
+ self.assertTrue(order1 < order2)
def test_ordering_number_of_predicates(self):
order1, _, _ = self._callFUT(
@@ -4286,15 +4356,15 @@ class Test__make_predicates(unittest.TestCase):
order11, _, _ = self._callFUT(
)
self.assertEqual(order1, order2)
- self.failUnless(order3 > order2)
- self.failUnless(order4 > order3)
- self.failUnless(order5 > order4)
- self.failUnless(order6 > order5)
- self.failUnless(order7 > order6)
- self.failUnless(order8 > order7)
- self.failUnless(order9 > order8)
- self.failUnless(order10 > order9)
- self.failUnless(order11 > order10)
+ self.assertTrue(order3 > order2)
+ self.assertTrue(order4 > order3)
+ self.assertTrue(order5 > order4)
+ self.assertTrue(order6 > order5)
+ self.assertTrue(order7 > order6)
+ self.assertTrue(order8 > order7)
+ self.assertTrue(order9 > order8)
+ self.assertTrue(order10 > order9)
+ self.assertTrue(order11 > order10)
def test_ordering_importance_of_predicates(self):
order1, _, _ = self._callFUT(
@@ -4324,14 +4394,14 @@ class Test__make_predicates(unittest.TestCase):
order9, _, _ = self._callFUT(
custom=(DummyCustomPredicate(),),
)
- self.failUnless(order1 > order2)
- self.failUnless(order2 > order3)
- self.failUnless(order3 > order4)
- self.failUnless(order4 > order5)
- self.failUnless(order5 > order6)
- self.failUnless(order6 > order7)
- self.failUnless(order7 > order8)
- self.failUnless(order8 > order9)
+ self.assertTrue(order1 > order2)
+ self.assertTrue(order2 > order3)
+ self.assertTrue(order3 > order4)
+ self.assertTrue(order4 > order5)
+ self.assertTrue(order5 > order6)
+ self.assertTrue(order6 > order7)
+ self.assertTrue(order7 > order8)
+ self.assertTrue(order8 > order9)
def test_ordering_importance_and_number(self):
order1, _, _ = self._callFUT(
@@ -4341,7 +4411,7 @@ class Test__make_predicates(unittest.TestCase):
order2, _, _ = self._callFUT(
custom=(DummyCustomPredicate(),),
)
- self.failUnless(order1 < order2)
+ self.assertTrue(order1 < order2)
order1, _, _ = self._callFUT(
xhr='xhr',
@@ -4351,7 +4421,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
custom=(DummyCustomPredicate(),),
)
- self.failUnless(order1 > order2)
+ self.assertTrue(order1 > order2)
order1, _, _ = self._callFUT(
xhr='xhr',
@@ -4362,7 +4432,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
custom=(DummyCustomPredicate(),),
)
- self.failUnless(order1 < order2)
+ self.assertTrue(order1 < order2)
order1, _, _ = self._callFUT(
xhr='xhr',
@@ -4374,7 +4444,7 @@ class Test__make_predicates(unittest.TestCase):
request_method='request_method',
custom=(DummyCustomPredicate(),),
)
- self.failUnless(order1 > order2)
+ self.assertTrue(order1 > order2)
def test_different_custom_predicates_with_same_hash(self):
class PredicateWithHash(object):
diff --git a/pyramid/tests/test_events.py b/pyramid/tests/test_events.py
index 9f655959d..22a42758a 100644
--- a/pyramid/tests/test_events.py
+++ b/pyramid/tests/test_events.py
@@ -190,12 +190,12 @@ class TestBeforeRender(unittest.TestCase):
def test__contains__True(self):
system = {'a':1}
event = self._makeOne(system)
- self.failUnless('a' in event)
+ self.assertTrue('a' in event)
def test__contains__False(self):
system = {}
event = self._makeOne(system)
- self.failIf('a' in event)
+ self.assertFalse('a' in event)
def test__getitem__success(self):
system = {'a':1}
diff --git a/pyramid/tests/test_exceptions.py b/pyramid/tests/test_exceptions.py
index 15eaa8698..5d0fa1e1a 100644
--- a/pyramid/tests/test_exceptions.py
+++ b/pyramid/tests/test_exceptions.py
@@ -7,7 +7,7 @@ class TestExceptionResponse(unittest.TestCase):
def test_app_iter(self):
exc = self._makeOne('')
- self.failUnless('<code></code>' in exc.app_iter[0])
+ self.assertTrue('<code></code>' in exc.app_iter[0])
def test_headerlist(self):
exc = self._makeOne('')
@@ -20,7 +20,7 @@ class TestExceptionResponse(unittest.TestCase):
def test_withmessage(self):
exc = self._makeOne('abc&123')
- self.failUnless('<code>abc&amp;123</code>' in exc.app_iter[0])
+ self.assertTrue('<code>abc&amp;123</code>' in exc.app_iter[0])
class TestNotFound(unittest.TestCase):
def _makeOne(self, message):
@@ -30,7 +30,7 @@ class TestNotFound(unittest.TestCase):
def test_it(self):
from pyramid.exceptions import ExceptionResponse
e = self._makeOne('notfound')
- self.failUnless(isinstance(e, ExceptionResponse))
+ self.assertTrue(isinstance(e, ExceptionResponse))
self.assertEqual(e.status, '404 Not Found')
class TestForbidden(unittest.TestCase):
@@ -41,5 +41,5 @@ class TestForbidden(unittest.TestCase):
def test_it(self):
from pyramid.exceptions import ExceptionResponse
e = self._makeOne('unauthorized')
- self.failUnless(isinstance(e, ExceptionResponse))
+ self.assertTrue(isinstance(e, ExceptionResponse))
self.assertEqual(e.status, '403 Forbidden')
diff --git a/pyramid/tests/test_i18n.py b/pyramid/tests/test_i18n.py
index 3155f0ba1..588f0a7cc 100644
--- a/pyramid/tests/test_i18n.py
+++ b/pyramid/tests/test_i18n.py
@@ -41,7 +41,7 @@ class TestLocalizer(unittest.TestCase):
localizer = self._makeOne(None, translations)
self.assertEqual(localizer.translate('123', domain='1',
mapping={}), '123')
- self.failUnless(localizer.translator)
+ self.assertTrue(localizer.translator)
def test_pluralize(self):
translations = DummyTranslations()
@@ -49,7 +49,7 @@ class TestLocalizer(unittest.TestCase):
self.assertEqual(localizer.pluralize('singular', 'plural', 1,
domain='1', mapping={}),
'singular')
- self.failUnless(localizer.pluralizer)
+ self.assertTrue(localizer.pluralizer)
def test_pluralize_pluralizer_already_added(self):
translations = DummyTranslations()
@@ -63,7 +63,7 @@ class TestLocalizer(unittest.TestCase):
result,
(('singular', 'plural', 1), {'domain': '1', 'mapping': {}})
)
- self.failUnless(localizer.pluralizer is pluralizer)
+ self.assertTrue(localizer.pluralizer is pluralizer)
class Test_negotiate_locale_name(unittest.TestCase):
def setUp(self):
@@ -174,7 +174,7 @@ class Test_make_localizer(unittest.TestCase):
self.assertEqual(result.translate('Approve', 'deformsite'),
'Genehmigen')
self.assertEqual(result.translate('Approve'), 'Approve')
- self.failUnless(hasattr(result, 'pluralize'))
+ self.assertTrue(hasattr(result, 'pluralize'))
def test_locale_from_mo_bad_mo(self):
import os
@@ -260,7 +260,7 @@ class Test_get_localizer(unittest.TestCase):
self.assertEqual(result.translate('Approve', 'deformsite'),
'Genehmigen')
self.assertEqual(result.translate('Approve'), 'Approve')
- self.failUnless(hasattr(result, 'pluralize'))
+ self.assertTrue(hasattr(result, 'pluralize'))
def test_locale_from_mo_bad_mo(self):
import os
diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py
index dc7525080..dd77d3aec 100644
--- a/pyramid/tests/test_integration.py
+++ b/pyramid/tests/test_integration.py
@@ -20,8 +20,8 @@ class WGSIAppPlusViewConfigTests(unittest.TestCase):
def test_it(self):
from venusian import ATTACH_ATTR
import types
- self.failUnless(getattr(wsgiapptest, ATTACH_ATTR))
- self.failUnless(type(wsgiapptest) is types.FunctionType)
+ self.assertTrue(getattr(wsgiapptest, ATTACH_ATTR))
+ self.assertTrue(type(wsgiapptest) is types.FunctionType)
context = DummyContext()
request = DummyRequest()
result = wsgiapptest(context, request)
@@ -45,7 +45,7 @@ here = os.path.dirname(__file__)
staticapp = static(os.path.join(here, 'fixtures'))
class TestStaticApp(unittest.TestCase):
- def test_it(self):
+ def test_basic(self):
from webob import Request
context = DummyContext()
from StringIO import StringIO
@@ -57,13 +57,68 @@ class TestStaticApp(unittest.TestCase):
'wsgi.version':(1,0),
'wsgi.url_scheme':'http',
'wsgi.input':StringIO()})
- request.subpath = ['minimal.pt']
+ request.subpath = ('minimal.pt',)
result = staticapp(context, request)
self.assertEqual(result.status, '200 OK')
self.assertEqual(
result.body.replace('\r', ''),
open(os.path.join(here, 'fixtures/minimal.pt'), 'r').read())
+ def test_file_in_subdir(self):
+ from webob import Request
+ context = DummyContext()
+ from StringIO import StringIO
+ request = Request({'PATH_INFO':'',
+ 'SCRIPT_NAME':'',
+ 'SERVER_NAME':'localhost',
+ 'SERVER_PORT':'80',
+ 'REQUEST_METHOD':'GET',
+ 'wsgi.version':(1,0),
+ 'wsgi.url_scheme':'http',
+ 'wsgi.input':StringIO()})
+ request.subpath = ('static', 'index.html',)
+ result = staticapp(context, request)
+ self.assertEqual(result.status, '200 OK')
+ self.assertEqual(
+ result.body.replace('\r', ''),
+ open(os.path.join(here, 'fixtures/static/index.html'), 'r').read())
+
+ def test_redirect_to_subdir(self):
+ from webob import Request
+ context = DummyContext()
+ from StringIO import StringIO
+ request = Request({'PATH_INFO':'',
+ 'SCRIPT_NAME':'',
+ 'SERVER_NAME':'localhost',
+ 'SERVER_PORT':'80',
+ 'REQUEST_METHOD':'GET',
+ 'wsgi.version':(1,0),
+ 'wsgi.url_scheme':'http',
+ 'wsgi.input':StringIO()})
+ request.subpath = ('static',)
+ result = staticapp(context, request)
+ self.assertEqual(result.status, '301 Moved Permanently')
+ self.assertEqual(result.location, 'http://localhost/static/')
+
+ def test_redirect_to_subdir_with_existing_script_name(self):
+ from webob import Request
+ context = DummyContext()
+ from StringIO import StringIO
+ request = Request({'PATH_INFO':'/static',
+ 'SCRIPT_NAME':'/script_name',
+ 'SERVER_NAME':'localhost',
+ 'SERVER_PORT':'80',
+ 'REQUEST_METHOD':'GET',
+ 'wsgi.version':(1,0),
+ 'wsgi.url_scheme':'http',
+ 'wsgi.input':StringIO()})
+ request.subpath = ('static',)
+ result = staticapp(context, request)
+ self.assertEqual(result.status, '301 Moved Permanently')
+ self.assertEqual(result.location,
+ 'http://localhost/script_name/static/')
+
+
class IntegrationBase(unittest.TestCase):
root_factory = None
package = None
@@ -201,13 +256,13 @@ class TestForbiddenAppHasResult(IntegrationBase):
def test_it(self):
res = self.testapp.get('/x', status=403)
message, result = [x.strip() for x in res.body.split('\n')]
- self.failUnless(message.endswith('failed permission check'))
- self.failUnless(
+ self.assertTrue(message.endswith('failed permission check'))
+ self.assertTrue(
result.startswith("ACLDenied permission 'private' via ACE "
"'<default deny>' in ACL "
"'<No ACL found on any object in resource "
"lineage>' on context"))
- self.failUnless(
+ self.assertTrue(
result.endswith("for principals ['system.Everyone']"))
class TestViewDecoratorApp(IntegrationBase):
@@ -221,20 +276,20 @@ class TestViewDecoratorApp(IntegrationBase):
# we use mako here instead of chameleon because it works on Jython
self._configure_mako()
res = self.testapp.get('/first', status=200)
- self.failUnless('OK' in res.body)
+ self.assertTrue('OK' in res.body)
def test_second(self):
# we use mako here instead of chameleon because it works on Jython
self._configure_mako()
res = self.testapp.get('/second', status=200)
- self.failUnless('OK2' in res.body)
+ self.assertTrue('OK2' in res.body)
class TestViewPermissionBug(IntegrationBase):
# view_execution_permitted bug as reported by Shane at http://lists.repoze.org/pipermail/repoze-dev/2010-October/003603.html
package = 'pyramid.tests.permbugapp'
def test_test(self):
res = self.testapp.get('/test', status=200)
- self.failUnless('ACLDenied' in res.body)
+ self.assertTrue('ACLDenied' in res.body)
def test_x(self):
self.testapp.get('/x', status=403)
@@ -244,15 +299,15 @@ class TestDefaultViewPermissionBug(IntegrationBase):
package = 'pyramid.tests.defpermbugapp'
def test_x(self):
res = self.testapp.get('/x', status=403)
- self.failUnless('failed permission check' in res.body)
+ self.assertTrue('failed permission check' in res.body)
def test_y(self):
res = self.testapp.get('/y', status=403)
- self.failUnless('failed permission check' in res.body)
+ self.assertTrue('failed permission check' in res.body)
def test_z(self):
res = self.testapp.get('/z', status=200)
- self.failUnless('public' in res.body)
+ self.assertTrue('public' in res.body)
from pyramid.tests.exceptionviewapp.models import AnException, NotAnException
excroot = {'anexception':AnException(),
@@ -263,31 +318,31 @@ class TestExceptionViewsApp(IntegrationBase):
root_factory = lambda *arg: excroot
def test_root(self):
res = self.testapp.get('/', status=200)
- self.failUnless('maybe' in res.body)
+ self.assertTrue('maybe' in res.body)
def test_notanexception(self):
res = self.testapp.get('/notanexception', status=200)
- self.failUnless('no' in res.body)
+ self.assertTrue('no' in res.body)
def test_anexception(self):
res = self.testapp.get('/anexception', status=200)
- self.failUnless('yes' in res.body)
+ self.assertTrue('yes' in res.body)
def test_route_raise_exception(self):
res = self.testapp.get('/route_raise_exception', status=200)
- self.failUnless('yes' in res.body)
+ self.assertTrue('yes' in res.body)
def test_route_raise_exception2(self):
res = self.testapp.get('/route_raise_exception2', status=200)
- self.failUnless('yes' in res.body)
+ self.assertTrue('yes' in res.body)
def test_route_raise_exception3(self):
res = self.testapp.get('/route_raise_exception3', status=200)
- self.failUnless('whoa' in res.body)
+ self.assertTrue('whoa' in res.body)
def test_route_raise_exception4(self):
res = self.testapp.get('/route_raise_exception4', status=200)
- self.failUnless('whoa' in res.body)
+ self.assertTrue('whoa' in res.body)
class ImperativeIncludeConfigurationTest(unittest.TestCase):
def setUp(self):
@@ -305,15 +360,15 @@ class ImperativeIncludeConfigurationTest(unittest.TestCase):
def test_root(self):
res = self.testapp.get('/', status=200)
- self.failUnless('root' in res.body)
+ self.assertTrue('root' in res.body)
def test_two(self):
res = self.testapp.get('/two', status=200)
- self.failUnless('two' in res.body)
+ self.assertTrue('two' in res.body)
def test_three(self):
res = self.testapp.get('/three', status=200)
- self.failUnless('three' in res.body)
+ self.assertTrue('three' in res.body)
class SelfScanAppTest(unittest.TestCase):
def setUp(self):
@@ -329,11 +384,27 @@ class SelfScanAppTest(unittest.TestCase):
def test_root(self):
res = self.testapp.get('/', status=200)
- self.failUnless('root' in res.body)
+ self.assertTrue('root' in res.body)
def test_two(self):
res = self.testapp.get('/two', status=200)
- self.failUnless('two' in res.body)
+ self.assertTrue('two' in res.body)
+
+class WSGIApp2AppTest(unittest.TestCase):
+ def setUp(self):
+ from pyramid.tests.wsgiapp2app import main
+ config = main()
+ app = config.make_wsgi_app()
+ from webtest import TestApp
+ self.testapp = TestApp(app)
+ self.config = config
+
+ def tearDown(self):
+ self.config.end()
+
+ def test_hello(self):
+ res = self.testapp.get('/hello', status=200)
+ self.assertTrue('Hello' in res.body)
class DummyContext(object):
pass
diff --git a/pyramid/tests/test_mako_templating.py b/pyramid/tests/test_mako_templating.py
index 8a03d4b5c..054c83d2b 100644
--- a/pyramid/tests/test_mako_templating.py
+++ b/pyramid/tests/test_mako_templating.py
@@ -260,7 +260,7 @@ class MakoLookupTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne('path', lookup)
result = instance({}, {'system':1})
- self.failUnless(isinstance(result, unicode))
+ self.assertTrue(isinstance(result, unicode))
self.assertEqual(result, u'result')
def test_call_with_system_context(self):
@@ -268,7 +268,7 @@ class MakoLookupTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne('path', lookup)
result = instance({}, {'context':1})
- self.failUnless(isinstance(result, unicode))
+ self.assertTrue(isinstance(result, unicode))
self.assertEqual(result, u'result')
self.assertEqual(lookup.values, {'_context':1})
@@ -289,7 +289,7 @@ class MakoLookupTemplateRendererTests(Base, unittest.TestCase):
lookup = DummyLookup()
instance = self._makeOne('path', lookup)
result = instance.implementation().render_unicode()
- self.failUnless(isinstance(result, unicode))
+ self.assertTrue(isinstance(result, unicode))
self.assertEqual(result, u'result')
class TestIntegration(unittest.TestCase):
@@ -378,12 +378,12 @@ class TestPkgResourceTemplateLookup(unittest.TestCase):
fixturedir = self.get_fixturedir()
inst = self._makeOne(directories=[fixturedir])
result = inst.get_template('helloworld.mak')
- self.failIf(result is None)
+ self.assertFalse(result is None)
def test_get_template_asset_spec_with_filesystem_checks(self):
inst = self._makeOne(filesystem_checks=True)
result = inst.get_template('pyramid.tests:fixtures/helloworld.mak')
- self.failIf(result is None)
+ self.assertFalse(result is None)
def test_get_template_asset_spec_missing(self):
from mako.exceptions import TopLevelLookupException
diff --git a/pyramid/tests/test_paster.py b/pyramid/tests/test_paster.py
index 85a79b681..f317e08db 100644
--- a/pyramid/tests/test_paster.py
+++ b/pyramid/tests/test_paster.py
@@ -1,5 +1,39 @@
import unittest
+class TestPyramidTemplate(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.paster import PyramidTemplate
+ return PyramidTemplate
+
+ def _makeOne(self, name):
+ cls = self._getTargetClass()
+ return cls(name)
+
+ def test_pre_logger_eq_root(self):
+ tmpl = self._makeOne('name')
+ vars = {'package':'root'}
+ result = tmpl.pre(None, None, vars)
+ self.assertEqual(result, None)
+ self.assertEqual(vars['package_logger'], 'app')
+ self.assertTrue(len(vars['random_string']) == 40)
+
+ def test_pre_logger_noteq_root(self):
+ tmpl = self._makeOne('name')
+ vars = {'package':'notroot'}
+ result = tmpl.pre(None, None, vars)
+ self.assertEqual(result, None)
+ self.assertEqual(vars['package_logger'], 'notroot')
+ self.assertTrue(len(vars['random_string']) == 40)
+
+ def test_post(self):
+ tmpl = self._makeOne('name')
+ vars = {'package':'root'}
+ L = []
+ tmpl.out = lambda msg: L.append(msg)
+ result = tmpl.post(None, None, vars)
+ self.assertEqual(result, None)
+ self.assertEqual(L, ['Welcome to Pyramid. Sorry for the convenience.'])
+
class TestPShellCommand(unittest.TestCase):
def _getTargetClass(self):
from pyramid.paster import PShellCommand
@@ -8,7 +42,7 @@ class TestPShellCommand(unittest.TestCase):
def _makeOne(self):
return self._getTargetClass()('pshell')
- def test_command_ipython_disabled(self):
+ def test_command_ipshell_is_None_ipython_enabled(self):
command = self._makeOne()
interact = DummyInteractor()
app = DummyApp()
@@ -18,18 +52,42 @@ class TestPShellCommand(unittest.TestCase):
command.args = ('/foo/bar/myapp.ini', 'myapp')
class Options(object): pass
command.options = Options()
- command.options.disable_ipython =True
+ command.options.disable_ipython = False
command.command(IPShell=None)
self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
self.assertEqual(loadapp.section_name, 'myapp')
- self.failUnless(loadapp.relative_to)
+ self.assertTrue(loadapp.relative_to)
+ self.assertEqual(len(app.threadlocal_manager.pushed), 1)
+ pushed = app.threadlocal_manager.pushed[0]
+ self.assertEqual(pushed['registry'], dummy_registry)
+ self.assertEqual(pushed['request'].registry, dummy_registry)
+ self.assertEqual(interact.local, {'root':dummy_root,
+ 'registry':dummy_registry})
+ self.assertTrue(interact.banner)
+ self.assertEqual(len(app.threadlocal_manager.popped), 1)
+
+ def test_command_ipshell_is_not_None_ipython_disabled(self):
+ command = self._makeOne()
+ interact = DummyInteractor()
+ app = DummyApp()
+ loadapp = DummyLoadApp(app)
+ command.interact = (interact,)
+ command.loadapp = (loadapp,)
+ command.args = ('/foo/bar/myapp.ini', 'myapp')
+ class Options(object): pass
+ command.options = Options()
+ command.options.disable_ipython = True
+ command.command(IPShell='notnone')
+ self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
+ self.assertEqual(loadapp.section_name, 'myapp')
+ self.assertTrue(loadapp.relative_to)
self.assertEqual(len(app.threadlocal_manager.pushed), 1)
pushed = app.threadlocal_manager.pushed[0]
self.assertEqual(pushed['registry'], dummy_registry)
self.assertEqual(pushed['request'].registry, dummy_registry)
self.assertEqual(interact.local, {'root':dummy_root,
'registry':dummy_registry})
- self.failUnless(interact.banner)
+ self.assertTrue(interact.banner)
self.assertEqual(len(app.threadlocal_manager.popped), 1)
def test_command_ipython_enabled(self):
@@ -45,7 +103,7 @@ class TestPShellCommand(unittest.TestCase):
command.command(IPShell=dummy_shell_factory)
self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
self.assertEqual(loadapp.section_name, 'myapp')
- self.failUnless(loadapp.relative_to)
+ self.assertTrue(loadapp.relative_to)
self.assertEqual(len(app.threadlocal_manager.pushed), 1)
pushed = app.threadlocal_manager.pushed[0]
self.assertEqual(pushed['registry'], dummy_registry)
@@ -53,7 +111,7 @@ class TestPShellCommand(unittest.TestCase):
self.assertEqual(dummy_shell_factory.shell.local_ns,
{'root':dummy_root, 'registry':dummy_registry})
self.assertEqual(dummy_shell_factory.shell.global_ns, {})
- self.failUnless('\n\n' in dummy_shell_factory.shell.IP.BANNER)
+ self.assertTrue('\n\n' in dummy_shell_factory.shell.IP.BANNER)
self.assertEqual(len(app.threadlocal_manager.popped), 1)
def test_command_get_app_hookable(self):
@@ -79,7 +137,7 @@ class TestPShellCommand(unittest.TestCase):
self.assertEqual(pushed['request'].registry, dummy_registry)
self.assertEqual(interact.local, {'root':dummy_root,
'registry':dummy_registry})
- self.failUnless(interact.banner)
+ self.assertTrue(interact.banner)
self.assertEqual(len(app.threadlocal_manager.popped), 1)
self.assertEqual(apped, [(('/foo/bar/myapp.ini', 'myapp'),
{'loadapp': loadapp})])
@@ -104,11 +162,11 @@ class TestPShellCommand(unittest.TestCase):
command.command(IPShell=None)
self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini')
self.assertEqual(loadapp.section_name, 'myapp')
- self.failUnless(loadapp.relative_to)
+ self.assertTrue(loadapp.relative_to)
self.assertEqual(len(app.threadlocal_manager.pushed), 0)
self.assertEqual(interact.local, {'root':root,
'registry':dummy_registry})
- self.failUnless(interact.banner)
+ self.assertTrue(interact.banner)
self.assertEqual(apps, [app])
class TestPRoutesCommand(unittest.TestCase):
@@ -133,6 +191,19 @@ class TestPRoutesCommand(unittest.TestCase):
self.assertEqual(result, None)
self.assertEqual(L, [])
+ def test_no_mapper(self):
+ command = self._makeOne()
+ command._get_mapper = lambda *arg:None
+ L = []
+ command.out = L.append
+ app = DummyApp()
+ loadapp = DummyLoadApp(app)
+ command.loadapp = (loadapp,)
+ command.args = ('/foo/bar/myapp.ini', 'myapp')
+ result = command.command()
+ self.assertEqual(result, None)
+ self.assertEqual(L, [])
+
def test_single_route_no_route_registered(self):
command = self._makeOne()
route = DummyRoute('a', '/a')
diff --git a/pyramid/tests/test_path.py b/pyramid/tests/test_path.py
index 5619aafa1..c2261d223 100644
--- a/pyramid/tests/test_path.py
+++ b/pyramid/tests/test_path.py
@@ -53,7 +53,7 @@ class TestCallerModule(unittest.TestCase):
def test_it_level_3(self):
from pyramid.tests import test_path
result = self._callFUT(3)
- self.failIfEqual(result, test_path)
+ self.assertNotEqual(result, test_path)
def test_it_no___name__(self):
class DummyFrame(object):
@@ -121,7 +121,7 @@ class TestPackagePath(unittest.TestCase):
from pyramid.tests import test_path
module = DummyPackageOrModule(test_path, raise_exc=TypeError)
result = self._callFUT(module)
- self.failIf(hasattr(module, '__abspath__'))
+ self.assertFalse(hasattr(module, '__abspath__'))
self.assertEqual(result, module.package_path)
class TestPackageOf(unittest.TestCase):
diff --git a/pyramid/tests/test_renderers.py b/pyramid/tests/test_renderers.py
index 70c2c620e..0dbb0d821 100644
--- a/pyramid/tests/test_renderers.py
+++ b/pyramid/tests/test_renderers.py
@@ -3,6 +3,18 @@ import unittest
from pyramid.testing import cleanUp
from pyramid import testing
+def hide_warnings(wrapped):
+ import warnings
+ def wrapper(*arg, **kw):
+ warnings.filterwarnings('ignore')
+ try:
+ wrapped(*arg, **kw)
+ finally:
+ warnings.resetwarnings()
+ wrapper.__name__ = wrapped.__name__
+ wrapper.__doc__ = wrapped.__doc__
+ return wrapper
+
class TestTemplateRendererFactory(unittest.TestCase):
def setUp(self):
self.config = cleanUp()
@@ -46,7 +58,7 @@ class TestTemplateRendererFactory(unittest.TestCase):
'type':'type',
})
result = self._callFUT(info, None)
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
class TestChameleonRendererLookup(unittest.TestCase):
def setUp(self):
@@ -190,7 +202,7 @@ class TestChameleonRendererLookup(unittest.TestCase):
})
lookup = self._makeOne(None)
result = lookup(info)
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
def test___call__abspath_notyetregistered(self):
import os
@@ -221,7 +233,7 @@ class TestChameleonRendererLookup(unittest.TestCase):
})
lookup = self._makeOne(None)
result = lookup(info)
- self.failUnless(renderer is result)
+ self.assertTrue(renderer is result)
def test___call__relpath_has_package_registered(self):
renderer = {}
@@ -237,7 +249,7 @@ class TestChameleonRendererLookup(unittest.TestCase):
})
lookup = self._makeOne(None)
result = lookup(info)
- self.failUnless(renderer is result)
+ self.assertTrue(renderer is result)
def test___call__spec_notfound(self):
spec = 'pyramid.tests:wont/exist'
@@ -267,7 +279,7 @@ class TestChameleonRendererLookup(unittest.TestCase):
self._registerTemplateRenderer(renderer, spec)
lookup = self._makeOne(None)
result = lookup(info)
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
def test___call__spec_notyetregistered(self):
import os
@@ -286,11 +298,11 @@ class TestChameleonRendererLookup(unittest.TestCase):
})
lookup = self._makeOne(factory)
result = lookup(info)
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
path = os.path.abspath(__file__).split('$')[0] # jython
if path.endswith('.pyc'): # pragma: no cover
path = path[:-1]
- self.failUnless(factory.path.startswith(path))
+ self.assertTrue(factory.path.startswith(path))
self.assertEqual(factory.kw, {})
def test___call__reload_assets_true(self):
@@ -312,7 +324,7 @@ class TestChameleonRendererLookup(unittest.TestCase):
})
lookup = self._makeOne(factory)
result = lookup(info)
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
spec = '%s:%s' % ('pyramid.tests', 'test_renderers.py')
self.assertEqual(reg.queryUtility(ITemplateRenderer, name=spec),
None)
@@ -334,7 +346,7 @@ class TestChameleonRendererLookup(unittest.TestCase):
})
lookup = self._makeOne(factory)
result = lookup(info)
- self.failUnless(result is renderer)
+ self.assertTrue(result is renderer)
spec = '%s:%s' % ('pyramid.tests', 'test_renderers.py')
self.assertNotEqual(reg.queryUtility(ITemplateRenderer, name=spec),
None)
@@ -394,6 +406,12 @@ class TestRendererFromName(unittest.TestCase):
class Test_json_renderer_factory(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+
+ def tearDown(self):
+ testing.tearDown()
+
def _callFUT(self, name):
from pyramid.renderers import json_renderer_factory
return json_renderer_factory(name)
@@ -407,14 +425,14 @@ class Test_json_renderer_factory(unittest.TestCase):
request = testing.DummyRequest()
renderer = self._callFUT(None)
renderer({'a':1}, {'request':request})
- self.assertEqual(request.response_content_type, 'application/json')
+ self.assertEqual(request.response.content_type, 'application/json')
def test_with_request_content_type_set(self):
request = testing.DummyRequest()
- request.response_content_type = 'text/mishmash'
+ request.response.content_type = 'text/mishmash'
renderer = self._callFUT(None)
renderer({'a':1}, {'request':request})
- self.assertEqual(request.response_content_type, 'text/mishmash')
+ self.assertEqual(request.response.content_type, 'text/mishmash')
class Test_string_renderer_factory(unittest.TestCase):
def _callFUT(self, name):
@@ -443,14 +461,14 @@ class Test_string_renderer_factory(unittest.TestCase):
request = testing.DummyRequest()
renderer = self._callFUT(None)
renderer(None, {'request':request})
- self.assertEqual(request.response_content_type, 'text/plain')
+ self.assertEqual(request.response.content_type, 'text/plain')
def test_with_request_content_type_set(self):
request = testing.DummyRequest()
- request.response_content_type = 'text/mishmash'
+ request.response.content_type = 'text/mishmash'
renderer = self._callFUT(None)
renderer(None, {'request':request})
- self.assertEqual(request.response_content_type, 'text/mishmash')
+ self.assertEqual(request.response.content_type, 'text/mishmash')
class TestRendererHelper(unittest.TestCase):
@@ -492,8 +510,15 @@ class TestRendererHelper(unittest.TestCase):
name='.foo')
return renderer
+ def _registerResponseFactory(self):
+ from pyramid.interfaces import IResponseFactory
+ class ResponseFactory(object):
+ pass
+ self.config.registry.registerUtility(ResponseFactory, IResponseFactory)
+
def test_render_to_response(self):
self._registerRendererFactory()
+ self._registerResponseFactory()
request = Dummy()
helper = self._makeOne('loo.foo')
response = helper.render_to_response('values', 'system_values',
@@ -502,6 +527,7 @@ class TestRendererHelper(unittest.TestCase):
def test_render_view(self):
self._registerRendererFactory()
+ self._registerResponseFactory()
request = Dummy()
helper = self._makeOne('loo.foo')
view = 'view'
@@ -532,7 +558,7 @@ class TestRendererHelper(unittest.TestCase):
helper = self._makeOne('loo.foo', registry=reg)
result = helper.render('value', {})
self.assertEqual(result, ('value', {}))
- self.failUnless(reg.queried)
+ self.assertTrue(reg.queried)
self.assertEqual(reg.event._system, {})
self.assertEqual(reg.event.__class__.__name__, 'BeforeRender')
@@ -561,8 +587,43 @@ class TestRendererHelper(unittest.TestCase):
result = helper.render('values', None)
self.assertEqual(result[1]['a'], 1)
+ def test__make_response_request_is_None(self):
+ request = None
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response('abc', request)
+ self.assertEqual(response.body, 'abc')
+
+ def test__make_response_request_is_None_response_factory_exists(self):
+ self._registerResponseFactory()
+ request = None
+ helper = self._makeOne('loo.foo')
+ response = helper._make_response('abc', request)
+ self.assertEqual(response.__class__.__name__, 'ResponseFactory')
+ self.assertEqual(response.body, 'abc')
+
+ def test__make_response_result_is_unicode(self):
+ from pyramid.response import Response
+ request = testing.DummyRequest()
+ request.response = Response()
+ helper = self._makeOne('loo.foo')
+ la = unicode('/La Pe\xc3\xb1a', 'utf-8')
+ response = helper._make_response(la, request)
+ self.assertEqual(response.body, la.encode('utf-8'))
+
+ def test__make_response_result_is_str(self):
+ from pyramid.response import Response
+ request = testing.DummyRequest()
+ request.response = Response()
+ helper = self._makeOne('loo.foo')
+ la = unicode('/La Pe\xc3\xb1a', 'utf-8')
+ response = helper._make_response(la.encode('utf-8'), request)
+ self.assertEqual(response.body, la.encode('utf-8'))
+
+ @hide_warnings
def test__make_response_with_content_type(self):
+ from pyramid.response import Response
request = testing.DummyRequest()
+ request.response = Response()
attrs = {'response_content_type':'text/nonsense'}
request.__dict__.update(attrs)
helper = self._makeOne('loo.foo')
@@ -570,8 +631,11 @@ class TestRendererHelper(unittest.TestCase):
self.assertEqual(response.content_type, 'text/nonsense')
self.assertEqual(response.body, 'abc')
+ @hide_warnings
def test__make_response_with_headerlist(self):
+ from pyramid.response import Response
request = testing.DummyRequest()
+ request.response = Response()
attrs = {'response_headerlist':[('a', '1'), ('b', '2')]}
request.__dict__.update(attrs)
helper = self._makeOne('loo.foo')
@@ -583,8 +647,11 @@ class TestRendererHelper(unittest.TestCase):
('b', '2')])
self.assertEqual(response.body, 'abc')
+ @hide_warnings
def test__make_response_with_status(self):
+ from pyramid.response import Response
request = testing.DummyRequest()
+ request.response = Response()
attrs = {'response_status':'406 You Lose'}
request.__dict__.update(attrs)
helper = self._makeOne('loo.foo')
@@ -592,16 +659,22 @@ class TestRendererHelper(unittest.TestCase):
self.assertEqual(response.status, '406 You Lose')
self.assertEqual(response.body, 'abc')
+ @hide_warnings
def test__make_response_with_charset(self):
+ from pyramid.response import Response
request = testing.DummyRequest()
+ request.response = Response()
attrs = {'response_charset':'UTF-16'}
request.__dict__.update(attrs)
helper = self._makeOne('loo.foo')
response = helper._make_response('abc', request)
self.assertEqual(response.charset, 'UTF-16')
+ @hide_warnings
def test__make_response_with_cache_for(self):
+ from pyramid.response import Response
request = testing.DummyRequest()
+ request.response = Response()
attrs = {'response_cache_for':100}
request.__dict__.update(attrs)
helper = self._makeOne('loo.foo')
@@ -611,21 +684,21 @@ class TestRendererHelper(unittest.TestCase):
def test_with_alternate_response_factory(self):
from pyramid.interfaces import IResponseFactory
class ResponseFactory(object):
- def __init__(self, result):
- self.result = result
+ def __init__(self):
+ pass
self.config.registry.registerUtility(ResponseFactory, IResponseFactory)
request = testing.DummyRequest()
helper = self._makeOne('loo.foo')
response = helper._make_response('abc', request)
self.assertEqual(response.__class__, ResponseFactory)
- self.assertEqual(response.result, 'abc')
+ self.assertEqual(response.body, 'abc')
def test__make_response_with_real_request(self):
# functional
from pyramid.request import Request
request = Request({})
- attrs = {'response_status':'406 You Lose'}
- request.__dict__.update(attrs)
+ request.registry = self.config.registry
+ request.response.status = '406 You Lose'
helper = self._makeOne('loo.foo')
response = helper._make_response('abc', request)
self.assertEqual(response.status, '406 You Lose')
diff --git a/pyramid/tests/test_request.py b/pyramid/tests/test_request.py
index 40940cfc9..60d59ece6 100644
--- a/pyramid/tests/test_request.py
+++ b/pyramid/tests/test_request.py
@@ -98,13 +98,13 @@ class TestRequest(unittest.TestCase):
def test___contains__(self):
environ ={'zooma':1}
inst = self._makeOne(environ)
- self.failUnless('zooma' in inst)
+ self.assertTrue('zooma' in inst)
def test___delitem__(self):
environ = {'zooma':1}
inst = self._makeOne(environ)
del inst['zooma']
- self.failIf('zooma' in environ)
+ self.assertFalse('zooma' in environ)
def test___getitem__(self):
environ = {'zooma':1}
@@ -325,6 +325,66 @@ class Test_add_global_response_headers(unittest.TestCase):
request.response_callbacks[0](None, response)
self.assertEqual(response.headerlist, [('c', 1)] )
+class Test_call_app_with_subpath_as_path_info(unittest.TestCase):
+ def _callFUT(self, request, app):
+ from pyramid.request import call_app_with_subpath_as_path_info
+ return call_app_with_subpath_as_path_info(request, app)
+
+ def test_it_all_request_and_environment_data_missing(self):
+ request = DummyRequest({})
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '')
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+
+ def test_it_with_subpath_and_path_info(self):
+ request = DummyRequest({'PATH_INFO':'/hello'})
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello')
+
+ def test_it_with_subpath_and_path_info_path_info_endswith_slash(self):
+ request = DummyRequest({'PATH_INFO':'/hello/'})
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello/')
+
+ def test_it_with_subpath_and_path_info_extra_script_name(self):
+ request = DummyRequest({'PATH_INFO':'/hello', 'SCRIPT_NAME':'/script'})
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/script')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello')
+
+ def test_it_with_extra_slashes_in_path_info(self):
+ request = DummyRequest({'PATH_INFO':'//hello/',
+ 'SCRIPT_NAME':'/script'})
+ request.subpath = ('hello',)
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/script')
+ self.assertEqual(request.environ['PATH_INFO'], '/hello/')
+
+ def test_subpath_path_info_and_script_name_have_utf8(self):
+ la = 'La Pe\xc3\xb1a'
+ request = DummyRequest({'PATH_INFO':'/'+la, 'SCRIPT_NAME':'/'+la})
+ request.subpath = (unicode(la, 'utf-8'), )
+ response = self._callFUT(request, 'app')
+ self.assertTrue(request.copied)
+ self.assertEqual(response, 'app')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/' + la)
+ self.assertEqual(request.environ['PATH_INFO'], '/' + la)
+
class DummyRequest:
def __init__(self, environ=None):
if environ is None:
@@ -334,6 +394,13 @@ class DummyRequest:
def add_response_callback(self, callback):
self.response_callbacks = [callback]
+ def get_response(self, app):
+ return app
+
+ def copy(self):
+ self.copied = True
+ return self
+
class DummyResponse:
def __init__(self):
self.headerlist = []
diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py
index ffda14738..b869a3830 100644
--- a/pyramid/tests/test_router.py
+++ b/pyramid/tests/test_router.py
@@ -117,8 +117,8 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
self.assertEqual(router.debug_notfound, False)
self.assertEqual(router.debug_routematch, False)
- self.failIf('debug_notfound' in router.__dict__)
- self.failIf('debug_routematch' in router.__dict__)
+ self.assertFalse('debug_notfound' in router.__dict__)
+ self.assertFalse('debug_routematch' in router.__dict__)
def test_root_policy(self):
context = DummyContext()
@@ -142,8 +142,8 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(NotFound, router, environ, start_response)
- self.failUnless('/' in why[0], why)
- self.failIf('debug_notfound' in why[0])
+ self.assertTrue('/' in why[0], why)
+ self.assertFalse('debug_notfound' in why[0])
self.assertEqual(len(logger.messages), 0)
def test_traverser_raises_notfound_class(self):
@@ -163,7 +163,7 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(NotFound, router, environ, start_response)
- self.failUnless('foo' in why[0], why)
+ self.assertTrue('foo' in why[0], why)
def test_traverser_raises_forbidden_class(self):
from pyramid.exceptions import Forbidden
@@ -182,7 +182,7 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(Forbidden, router, environ, start_response)
- self.failUnless('foo' in why[0], why)
+ self.assertTrue('foo' in why[0], why)
def test_call_no_view_registered_no_isettings(self):
from pyramid.exceptions import NotFound
@@ -193,8 +193,8 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(NotFound, router, environ, start_response)
- self.failUnless('/' in why[0], why)
- self.failIf('debug_notfound' in why[0])
+ self.assertTrue('/' in why[0], why)
+ self.assertFalse('debug_notfound' in why[0])
self.assertEqual(len(logger.messages), 0)
def test_call_no_view_registered_debug_notfound_false(self):
@@ -207,8 +207,8 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(NotFound, router, environ, start_response)
- self.failUnless('/' in why[0], why)
- self.failIf('debug_notfound' in why[0])
+ self.assertTrue('/' in why[0], why)
+ self.assertFalse('debug_notfound' in why[0])
self.assertEqual(len(logger.messages), 0)
def test_call_no_view_registered_debug_notfound_true(self):
@@ -221,19 +221,19 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(NotFound, router, environ, start_response)
- self.failUnless(
+ self.assertTrue(
"debug_notfound of url http://localhost:8080/; path_info: '/', "
"context:" in why[0])
- self.failUnless("view_name: '', subpath: []" in why[0])
- self.failUnless('http://localhost:8080' in why[0], why)
+ self.assertTrue("view_name: '', subpath: []" in why[0])
+ self.assertTrue('http://localhost:8080' in why[0], why)
self.assertEqual(len(logger.messages), 1)
message = logger.messages[0]
- self.failUnless('of url http://localhost:8080' in message)
- self.failUnless("path_info: '/'" in message)
- self.failUnless('DummyContext instance at' in message)
- self.failUnless("view_name: ''" in message)
- self.failUnless("subpath: []" in message)
+ self.assertTrue('of url http://localhost:8080' in message)
+ self.assertTrue("path_info: '/'" in message)
+ self.assertTrue('DummyContext instance at' in message)
+ self.assertTrue("view_name: ''" in message)
+ self.assertTrue("subpath: []" in message)
def test_call_view_returns_nonresponse(self):
from pyramid.interfaces import IViewClassifier
@@ -557,7 +557,7 @@ class TestRouter(unittest.TestCase):
self.assertEqual(request.matched_route.name, 'foo')
self.assertEqual(len(logger.messages), 1)
- self.failUnless(
+ self.assertTrue(
logger.messages[0].startswith(
"route matched for url http://localhost:8080"
"/archives/action1/article1; "
@@ -623,7 +623,7 @@ class TestRouter(unittest.TestCase):
self.assertEqual(environ['bfg.routes.route'].name, 'foo')
self.assertEqual(request.matchdict, matchdict)
self.assertEqual(request.matched_route.name, 'foo')
- self.failUnless(IFoo.providedBy(request))
+ self.assertTrue(IFoo.providedBy(request))
def test_root_factory_raises_notfound(self):
from pyramid.interfaces import IRootFactory
@@ -641,7 +641,7 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(NotFound, router, environ, start_response)
- self.failUnless('from root factory' in why[0])
+ self.assertTrue('from root factory' in why[0])
def test_root_factory_raises_forbidden(self):
from pyramid.interfaces import IRootFactory
@@ -659,7 +659,7 @@ class TestRouter(unittest.TestCase):
router = self._makeOne()
start_response = DummyStartResponse()
why = exc_raised(Forbidden, router, environ, start_response)
- self.failUnless('from root factory' in why[0])
+ self.assertTrue('from root factory' in why[0])
def test_root_factory_exception_propagating(self):
from pyramid.interfaces import IRootFactory
diff --git a/pyramid/tests/test_security.py b/pyramid/tests/test_security.py
index 94cefa642..86149d554 100644
--- a/pyramid/tests/test_security.py
+++ b/pyramid/tests/test_security.py
@@ -19,9 +19,9 @@ class TestAllPermissionsList(unittest.TestCase):
def test_it(self):
thing = self._makeOne()
- self.failUnless(thing.__eq__(thing))
+ self.assertTrue(thing.__eq__(thing))
self.assertEqual(thing.__iter__(), ())
- self.failUnless('anything' in thing)
+ self.assertTrue('anything' in thing)
def test_singleton(self):
from pyramid.security import ALL_PERMISSIONS
@@ -40,10 +40,10 @@ class TestAllowed(unittest.TestCase):
allowed = self._makeOne('hello')
self.assertEqual(allowed.msg, 'hello')
self.assertEqual(allowed, True)
- self.failUnless(allowed)
+ self.assertTrue(allowed)
self.assertEqual(str(allowed), 'hello')
- self.failUnless('<Allowed instance at ' in repr(allowed))
- self.failUnless("with msg 'hello'>" in repr(allowed))
+ self.assertTrue('<Allowed instance at ' in repr(allowed))
+ self.assertTrue("with msg 'hello'>" in repr(allowed))
class TestDenied(unittest.TestCase):
def _getTargetClass(self):
@@ -58,10 +58,10 @@ class TestDenied(unittest.TestCase):
denied = self._makeOne('hello')
self.assertEqual(denied.msg, 'hello')
self.assertEqual(denied, False)
- self.failIf(denied)
+ self.assertFalse(denied)
self.assertEqual(str(denied), 'hello')
- self.failUnless('<Denied instance at ' in repr(denied))
- self.failUnless("with msg 'hello'>" in repr(denied))
+ self.assertTrue('<Denied instance at ' in repr(denied))
+ self.assertTrue("with msg 'hello'>" in repr(denied))
class TestACLAllowed(unittest.TestCase):
def _getTargetClass(self):
@@ -76,12 +76,12 @@ class TestACLAllowed(unittest.TestCase):
msg = ("ACLAllowed permission 'permission' via ACE 'ace' in ACL 'acl' "
"on context 'ctx' for principals 'principals'")
allowed = self._makeOne('ace', 'acl', 'permission', 'principals', 'ctx')
- self.failUnless(msg in allowed.msg)
+ self.assertTrue(msg in allowed.msg)
self.assertEqual(allowed, True)
- self.failUnless(allowed)
+ self.assertTrue(allowed)
self.assertEqual(str(allowed), msg)
- self.failUnless('<ACLAllowed instance at ' in repr(allowed))
- self.failUnless("with msg %r>" % msg in repr(allowed))
+ self.assertTrue('<ACLAllowed instance at ' in repr(allowed))
+ self.assertTrue("with msg %r>" % msg in repr(allowed))
class TestACLDenied(unittest.TestCase):
def _getTargetClass(self):
@@ -96,12 +96,12 @@ class TestACLDenied(unittest.TestCase):
msg = ("ACLDenied permission 'permission' via ACE 'ace' in ACL 'acl' "
"on context 'ctx' for principals 'principals'")
denied = self._makeOne('ace', 'acl', 'permission', 'principals', 'ctx')
- self.failUnless(msg in denied.msg)
+ self.assertTrue(msg in denied.msg)
self.assertEqual(denied, False)
- self.failIf(denied)
+ self.assertFalse(denied)
self.assertEqual(str(denied), msg)
- self.failUnless('<ACLDenied instance at ' in repr(denied))
- self.failUnless("with msg %r>" % msg in repr(denied))
+ self.assertTrue('<ACLDenied instance at ' in repr(denied))
+ self.assertTrue("with msg %r>" % msg in repr(denied))
class TestViewExecutionPermitted(unittest.TestCase):
def setUp(self):
@@ -140,8 +140,8 @@ class TestViewExecutionPermitted(unittest.TestCase):
request = DummyRequest({})
result = self._callFUT(context, request, '')
msg = result.msg
- self.failUnless("Allowed: view name '' in context" in msg)
- self.failUnless('(no permission defined)' in msg)
+ self.assertTrue("Allowed: view name '' in context" in msg)
+ self.assertTrue('(no permission defined)' in msg)
self.assertEqual(result, True)
def test_with_permission(self):
@@ -156,7 +156,7 @@ class TestViewExecutionPermitted(unittest.TestCase):
request = DummyRequest({})
directlyProvides(request, IRequest)
result = self._callFUT(context, request, '')
- self.failUnless(result is True)
+ self.assertTrue(result is True)
class TestHasPermission(unittest.TestCase):
def setUp(self):
diff --git a/pyramid/tests/test_session.py b/pyramid/tests/test_session.py
index e8a3318ea..17a437af6 100644
--- a/pyramid/tests/test_session.py
+++ b/pyramid/tests/test_session.py
@@ -54,7 +54,7 @@ class TestUnencryptedCookieSession(unittest.TestCase):
session = self._makeOne(request)
session['a'] = 1
self.assertEqual(session.invalidate(), None)
- self.failIf('a' in session)
+ self.assertFalse('a' in session)
def test__set_cookie_on_exception(self):
request = testing.DummyRequest()
@@ -116,7 +116,7 @@ class TestUnencryptedCookieSession(unittest.TestCase):
cookieval= response.headerlist[0][1]
val, domain, path, secure, httponly = [x.strip() for x in
cookieval.split(';')]
- self.failUnless(val.startswith('abc='))
+ self.assertTrue(val.startswith('abc='))
self.assertEqual(domain, 'Domain=localhost')
self.assertEqual(path, 'Path=/foo')
self.assertEqual(secure, 'secure')
@@ -205,14 +205,14 @@ class TestUnencryptedCookieSession(unittest.TestCase):
session['_csrft_'] = 'token'
token = session.get_csrf_token()
self.assertEqual(token, 'token')
- self.failUnless('_csrft_' in session)
+ self.assertTrue('_csrft_' in session)
def test_get_csrf_token_new(self):
request = testing.DummyRequest()
session = self._makeOne(request)
token = session.get_csrf_token()
- self.failUnless(token)
- self.failUnless('_csrft_' in session)
+ self.assertTrue(token)
+ self.assertTrue('_csrft_' in session)
class Test_manage_accessed(unittest.TestCase):
def _makeOne(self, wrapped):
@@ -254,7 +254,7 @@ class Test_manage_accessed(unittest.TestCase):
response = webob.Response()
result = callbacks[0](request, response)
self.assertEqual(result, None)
- self.failIf('Set-Cookie' in dict(response.headerlist))
+ self.assertFalse('Set-Cookie' in dict(response.headerlist))
def test_cookie_is_set(self):
request = testing.DummyRequest()
diff --git a/pyramid/tests/test_static.py b/pyramid/tests/test_static.py
index acf5a754b..e7506628a 100644
--- a/pyramid/tests/test_static.py
+++ b/pyramid/tests/test_static.py
@@ -46,8 +46,8 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('301 Moved Permanently' in body)
- self.failUnless('http://example.com:6543/' in body)
+ self.assertTrue('301 Moved Permanently' in body)
+ self.assertTrue('http://example.com:6543/' in body)
def test_path_info_slash_means_index_html(self):
environ = self._makeEnviron()
@@ -55,7 +55,7 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('<html>static</html>' in body)
+ self.assertTrue('<html>static</html>' in body)
def test_resource_out_of_bounds(self):
environ = self._makeEnviron()
@@ -64,8 +64,8 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('404 Not Found' in body)
- self.failUnless('http://example.com:6543/' in body)
+ self.assertTrue('404 Not Found' in body)
+ self.assertTrue('http://example.com:6543/' in body)
def test_resource_doesnt_exist(self):
environ = self._makeEnviron(PATH_INFO='/notthere')
@@ -73,8 +73,8 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('404 Not Found' in body)
- self.failUnless('http://example.com:6543/' in body)
+ self.assertTrue('404 Not Found' in body)
+ self.assertTrue('http://example.com:6543/' in body)
def test_resource_isdir(self):
environ = self._makeEnviron(PATH_INFO='/subdir/')
@@ -82,7 +82,7 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('<html>subdir</html>' in body)
+ self.assertTrue('<html>subdir</html>' in body)
def test_resource_is_file(self):
environ = self._makeEnviron(PATH_INFO='/index.html')
@@ -90,7 +90,15 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('<html>static</html>' in body)
+ self.assertTrue('<html>static</html>' in body)
+
+ def test_resource_has_extra_path_info(self):
+ environ = self._makeEnviron(PATH_INFO='/static/index.html/more')
+ inst = self._makeOne('pyramid.tests', 'fixtures')
+ sr = DummyStartResponse()
+ response = inst(environ, sr)
+ body = response[0]
+ self.assertTrue("The trailing path '/more' is not allowed" in body)
def test_resource_is_file_with_cache_max_age(self):
environ = self._makeEnviron(PATH_INFO='/index.html')
@@ -99,7 +107,7 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('<html>static</html>' in body)
+ self.assertTrue('<html>static</html>' in body)
self.assertEqual(len(sr.headerlist), 8)
header_names = [ x[0] for x in sr.headerlist ]
header_names.sort()
@@ -114,7 +122,7 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst(environ, sr)
body = response[0]
- self.failUnless('<html>static</html>' in body)
+ self.assertTrue('<html>static</html>' in body)
self.assertEqual(len(sr.headerlist), 6)
header_names = [ x[0] for x in sr.headerlist ]
header_names.sort()
@@ -122,6 +130,15 @@ class TestPackageURLParser(unittest.TestCase):
['Accept-Ranges', 'Content-Length', 'Content-Range',
'Content-Type', 'ETag', 'Last-Modified'])
+ def test_with_root_resource(self):
+ environ = self._makeEnviron(PATH_INFO='/static/index.html')
+ inst = self._makeOne('pyramid.tests', 'fixtures',
+ root_resource='fixtures/static')
+ sr = DummyStartResponse()
+ response = inst(environ, sr)
+ body = response[0]
+ self.assertTrue('<html>static</html>' in body)
+
def test_if_none_match(self):
class DummyEq(object):
def __eq__(self, other):
@@ -136,10 +153,22 @@ class TestPackageURLParser(unittest.TestCase):
self.assertEqual(sr.headerlist[0][0], 'ETag')
self.assertEqual(response[0], '')
+ def test_if_none_match_miss(self):
+ class DummyEq(object):
+ def __eq__(self, other):
+ return False
+ dummy_eq = DummyEq()
+ environ = self._makeEnviron(HTTP_IF_NONE_MATCH=dummy_eq)
+ inst = self._makeOne('pyramid.tests', 'fixtures/static')
+ sr = DummyStartResponse()
+ inst(environ, sr)
+ self.assertEqual(len(sr.headerlist), 6)
+ self.assertEqual(sr.status, '200 OK')
+
def test_repr(self):
import os.path
inst = self._makeOne('pyramid.tests', 'fixtures/static')
- self.failUnless(
+ self.assertTrue(
repr(inst).startswith(
'<PackageURLParser pyramid.tests:%s at'
% os.path.join('fixtures', 'static')))
@@ -150,7 +179,7 @@ class TestPackageURLParser(unittest.TestCase):
sr = DummyStartResponse()
response = inst.not_found(environ, sr, 'debug_message')
body = response[0]
- self.failUnless('404 Not Found' in body)
+ self.assertTrue('404 Not Found' in body)
self.assertEqual(sr.status, '404 Not Found')
class Test_static_view(unittest.TestCase):
@@ -230,6 +259,54 @@ class Test_static_view(unittest.TestCase):
self.assertEqual(response.package_name, 'another')
self.assertEqual(response.cache_max_age, 3600)
+ def test_no_subpath_preserves_path_info_and_script_name(self):
+ view = self._makeOne('fixtures', package_name='another')
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ()
+ request.environ = self._makeEnviron(PATH_INFO='/path_info',
+ SCRIPT_NAME='/script_name')
+ view(context, request)
+ self.assertEqual(request.copied, True)
+ self.assertEqual(request.environ['PATH_INFO'], '/')
+ self.assertEqual(request.environ['SCRIPT_NAME'],
+ '/script_name/path_info')
+
+ def test_with_subpath_path_info_ends_with_slash(self):
+ view = self._makeOne('fixtures', package_name='another')
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ('subpath',)
+ request.environ = self._makeEnviron(PATH_INFO='/path_info/subpath/')
+ view(context, request)
+ self.assertEqual(request.copied, True)
+ self.assertEqual(request.environ['PATH_INFO'], '/subpath/')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/path_info')
+
+ def test_with_subpath_original_script_name_preserved(self):
+ view = self._makeOne('fixtures', package_name='another')
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ('subpath',)
+ request.environ = self._makeEnviron(PATH_INFO='/path_info/subpath/',
+ SCRIPT_NAME='/scriptname')
+ view(context, request)
+ self.assertEqual(request.copied, True)
+ self.assertEqual(request.environ['PATH_INFO'], '/subpath/')
+ self.assertEqual(request.environ['SCRIPT_NAME'],
+ '/scriptname/path_info')
+
+ def test_with_subpath_new_script_name_fixes_trailing_slashes(self):
+ view = self._makeOne('fixtures', package_name='another')
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ('sub', 'path')
+ request.environ = self._makeEnviron(PATH_INFO='/path_info//sub//path//')
+ view(context, request)
+ self.assertEqual(request.copied, True)
+ self.assertEqual(request.environ['PATH_INFO'], '/sub/path/')
+ self.assertEqual(request.environ['SCRIPT_NAME'], '/path_info')
+
class TestStaticURLInfo(unittest.TestCase):
def _getTargetClass(self):
from pyramid.static import StaticURLInfo
@@ -258,6 +335,14 @@ class TestStaticURLInfo(unittest.TestCase):
request = DummyRequest()
self.assertRaises(ValueError, inst.generate, 'path', request)
+ def test_generate_registration_miss(self):
+ inst = self._makeOne(None)
+ inst.registrations = [('name', 'spec', False),
+ ('http://example.com/foo/', 'package:path/',True)]
+ request = DummyRequest()
+ result = inst.generate('package:path/abc', request)
+ self.assertEqual(result, 'http://example.com/foo/abc')
+
def test_generate_slash_in_name1(self):
inst = self._makeOne(None)
inst.registrations = [('http://example.com/foo/', 'package:path/',True)]
@@ -306,32 +391,83 @@ class TestStaticURLInfo(unittest.TestCase):
def test_add_viewname(self):
from pyramid.static import static_view
- class Config:
- def add_route(self, *arg, **kw):
- self.arg = arg
- self.kw = kw
- config = Config()
+ config = DummyConfig()
inst = self._makeOne(config)
inst.add('view', 'anotherpackage:path', cache_max_age=1)
expected = [('view/', 'anotherpackage:path/', False)]
self.assertEqual(inst.registrations, expected)
- self.assertEqual(config.arg, ('view/', 'view/*subpath'))
- self.assertEqual(config.kw['view_permission'],
+ self.assertEqual(config.route_args, ('view/', 'view/*subpath'))
+ self.assertEqual(config.view_kw['permission'],
'__no_permission_required__')
- self.assertEqual(config.kw['view'].__class__, static_view)
- self.assertEqual(config.kw['view'].app.cache_max_age, 1)
- self.assertEqual(inst.registrations, expected)
+ self.assertEqual(config.view_kw['view'].__class__, static_view)
+ self.assertEqual(config.view_kw['view'].app.cache_max_age, 1)
def test_add_viewname_with_permission(self):
- class Config:
- def add_route(self, *arg, **kw):
- self.arg = arg
- self.kw = kw
- config = Config()
+ config = DummyConfig()
inst = self._makeOne(config)
inst.add('view', 'anotherpackage:path', cache_max_age=1,
permission='abc')
- self.assertEqual(config.kw['view_permission'], 'abc')
+ self.assertEqual(config.view_kw['permission'], 'abc')
+
+ def test_add_viewname_with_view_permission(self):
+ config = DummyConfig()
+ inst = self._makeOne(config)
+ inst.add('view', 'anotherpackage:path', cache_max_age=1,
+ view_permission='abc')
+ self.assertEqual(config.view_kw['permission'], 'abc')
+
+ def test_add_viewname_with_view_context(self):
+ config = DummyConfig()
+ inst = self._makeOne(config)
+ inst.add('view', 'anotherpackage:path', cache_max_age=1,
+ view_context=DummyContext)
+ self.assertEqual(config.view_kw['context'], DummyContext)
+
+ def test_add_viewname_with_view_for(self):
+ config = DummyConfig()
+ inst = self._makeOne(config)
+ inst.add('view', 'anotherpackage:path', cache_max_age=1,
+ view_for=DummyContext)
+ self.assertEqual(config.view_kw['context'], DummyContext)
+
+ def test_add_viewname_with_for_(self):
+ config = DummyConfig()
+ inst = self._makeOne(config)
+ inst.add('view', 'anotherpackage:path', cache_max_age=1,
+ for_=DummyContext)
+ self.assertEqual(config.view_kw['context'], DummyContext)
+
+ def test_add_viewname_with_view_renderer(self):
+ config = DummyConfig()
+ inst = self._makeOne(config)
+ inst.add('view', 'anotherpackage:path', cache_max_age=1,
+ view_renderer='mypackage:templates/index.pt')
+ self.assertEqual(config.view_kw['renderer'],
+ 'mypackage:templates/index.pt')
+
+ def test_add_viewname_with_renderer(self):
+ config = DummyConfig()
+ inst = self._makeOne(config)
+ inst.add('view', 'anotherpackage:path', cache_max_age=1,
+ renderer='mypackage:templates/index.pt')
+ self.assertEqual(config.view_kw['renderer'],
+ 'mypackage:templates/index.pt')
+
+ def test_add_viewname_with_view_attr(self):
+ config = DummyConfig()
+ inst = self._makeOne(config)
+ inst.add('view', 'anotherpackage:path', cache_max_age=1,
+ view_attr='attr')
+ self.assertEqual(config.view_kw['attr'], 'attr')
+
+class DummyConfig:
+ def add_route(self, *args, **kw):
+ self.route_args = args
+ self.route_kw = kw
+
+ def add_view(self, *args, **kw):
+ self.view_args = args
+ self.view_kw = kw
class DummyStartResponse:
def __call__(self, status, headerlist, exc_info=None):
diff --git a/pyramid/tests/test_testing.py b/pyramid/tests/test_testing.py
index 99b0a1911..0c94a2803 100644
--- a/pyramid/tests/test_testing.py
+++ b/pyramid/tests/test_testing.py
@@ -27,7 +27,7 @@ class Test_registerDummySecurityPolicy(TestBase):
from pyramid.interfaces import IAuthorizationPolicy
ut = self.registry.getUtility(IAuthenticationPolicy)
from pyramid.testing import DummySecurityPolicy
- self.failUnless(isinstance(ut, DummySecurityPolicy))
+ self.assertTrue(isinstance(ut, DummySecurityPolicy))
ut = self.registry.getUtility(IAuthorizationPolicy)
self.assertEqual(ut.userid, 'user')
self.assertEqual(ut.groupids, ('group1', 'group2'))
@@ -65,7 +65,7 @@ class Test_registerTemplateRenderer(TestBase):
from pyramid import testing
renderer = testing.registerTemplateRenderer('templates/foo')
from pyramid.testing import DummyTemplateRenderer
- self.failUnless(isinstance(renderer, DummyTemplateRenderer))
+ self.assertTrue(isinstance(renderer, DummyTemplateRenderer))
from pyramid.renderers import render_to_response
render_to_response('templates/foo', dict(foo=1, bar=2))
renderer.assert_(foo=1)
@@ -116,7 +116,7 @@ class Test_registerView(TestBase):
from pyramid import testing
view = testing.registerView('moo.html')
import types
- self.failUnless(isinstance(view, types.FunctionType))
+ self.assertTrue(isinstance(view, types.FunctionType))
from pyramid.view import render_view_to_response
request = DummyRequest()
request.registry = self.registry
@@ -127,7 +127,7 @@ class Test_registerView(TestBase):
from pyramid import testing
view = testing.registerView('moo.html', 'yo')
import types
- self.failUnless(isinstance(view, types.FunctionType))
+ self.assertTrue(isinstance(view, types.FunctionType))
from pyramid.view import render_view_to_response
request = DummyRequest()
request.registry = self.registry
@@ -141,7 +141,7 @@ class Test_registerView(TestBase):
return Response('123')
view = testing.registerView('moo.html', view=view)
import types
- self.failUnless(isinstance(view, types.FunctionType))
+ self.assertTrue(isinstance(view, types.FunctionType))
from pyramid.view import render_view_to_response
request = DummyRequest()
request.registry = self.registry
@@ -156,7 +156,7 @@ class Test_registerView(TestBase):
view = testing.registerView('moo.html', view=view, permission='bar')
testing.registerDummySecurityPolicy(permissive=False)
import types
- self.failUnless(isinstance(view, types.FunctionType))
+ self.assertTrue(isinstance(view, types.FunctionType))
from pyramid.view import render_view_to_response
request = DummyRequest()
request.registry = self.registry
@@ -171,7 +171,7 @@ class Test_registerView(TestBase):
view = testing.registerView('moo.html', view=view, permission='bar')
testing.registerDummySecurityPolicy(permissive=False)
import types
- self.failUnless(isinstance(view, types.FunctionType))
+ self.assertTrue(isinstance(view, types.FunctionType))
result = view_execution_permitted(None, None, 'moo.html')
self.assertEqual(result, False)
@@ -183,7 +183,7 @@ class Test_registerView(TestBase):
view = testing.registerView('moo.html', view=view, permission='bar')
testing.registerDummySecurityPolicy(permissive=True)
import types
- self.failUnless(isinstance(view, types.FunctionType))
+ self.assertTrue(isinstance(view, types.FunctionType))
from pyramid.view import render_view_to_response
request = DummyRequest()
request.registry = self.registry
@@ -355,9 +355,9 @@ class TestDummyResource(unittest.TestCase):
self.assertEqual(resource['abc'], dummy)
self.assertEqual(resource.get('abc'), dummy)
self.assertRaises(KeyError, resource.__getitem__, 'none')
- self.failUnless('abc' in resource)
+ self.assertTrue('abc' in resource)
del resource['abc']
- self.failIf('abc' in resource)
+ self.assertFalse('abc' in resource)
self.assertEqual(resource.get('abc', 'foo'), 'foo')
self.assertEqual(resource.get('abc'), None)
@@ -390,7 +390,7 @@ class TestDummyResource(unittest.TestCase):
def test_ctor_with__provides__(self):
resource = self._makeOne(__provides__=IDummy)
- self.failUnless(IDummy.providedBy(resource))
+ self.assertTrue(IDummy.providedBy(resource))
class TestDummyRequest(unittest.TestCase):
def _getTargetClass(self):
@@ -498,10 +498,55 @@ class TestDummyRequest(unittest.TestCase):
registry = Registry('this_test')
config = Configurator(registry=registry)
config.begin()
- self.failUnless(request.registry is registry)
+ self.assertTrue(request.registry is registry)
finally:
config.end()
+ def test_set_registry(self):
+ request = self._makeOne()
+ request.registry = 'abc'
+ self.assertEqual(request.registry, 'abc')
+
+ def test_del_registry(self):
+ # see https://github.com/Pylons/pyramid/issues/165
+ from pyramid.registry import Registry
+ from pyramid.config import Configurator
+ request = self._makeOne()
+ request.registry = 'abc'
+ self.assertEqual(request.registry, 'abc')
+ del request.registry
+ try:
+ registry = Registry('this_test')
+ config = Configurator(registry=registry)
+ config.begin()
+ self.assertTrue(request.registry is registry)
+ finally:
+ config.end()
+
+ def test_response_with_responsefactory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IResponseFactory
+ registry = Registry('this_test')
+ class ResponseFactory(object):
+ pass
+ registry.registerUtility(ResponseFactory, IResponseFactory)
+ request = self._makeOne()
+ request.registry = registry
+ resp = request.response
+ self.assertEqual(resp.__class__, ResponseFactory)
+ self.assertTrue(request.response is resp) # reified
+
+ def test_response_without_responsefactory(self):
+ from pyramid.registry import Registry
+ from pyramid.response import Response
+ registry = Registry('this_test')
+ request = self._makeOne()
+ request.registry = registry
+ resp = request.response
+ self.assertEqual(resp.__class__, Response)
+ self.assertTrue(request.response is resp) # reified
+
+
class TestDummyTemplateRenderer(unittest.TestCase):
def _getTargetClass(self, ):
from pyramid.testing import DummyTemplateRenderer
@@ -528,7 +573,7 @@ class TestDummyTemplateRenderer(unittest.TestCase):
renderer({'a':1, 'b':2})
self.assertRaises(AssertionError, renderer.assert_, c=1)
self.assertRaises(AssertionError, renderer.assert_, b=3)
- self.failUnless(renderer.assert_(a=1, b=2))
+ self.assertTrue(renderer.assert_(a=1, b=2))
def test_nondefault_string_response(self):
renderer = self._makeOne('abc')
@@ -550,7 +595,7 @@ class Test_setUp(unittest.TestCase):
try:
config = self._callFUT()
current = manager.get()
- self.failIf(current is old)
+ self.assertFalse(current is old)
self.assertEqual(config.registry, current['registry'])
self.assertEqual(current['registry'].__class__, Registry)
self.assertEqual(current['request'], None)
@@ -593,7 +638,7 @@ class Test_setUp(unittest.TestCase):
try:
self._callFUT(registry=registry, hook_zca=False)
sm = getSiteManager()
- self.failIf(sm is registry)
+ self.assertFalse(sm is registry)
finally:
getSiteManager.reset()
manager.clear()
@@ -780,7 +825,7 @@ class TestDummySession(unittest.TestCase):
session = self._makeOne()
session['a'] = 1
self.assertEqual(session.invalidate(), None)
- self.failIf('a' in session)
+ self.assertFalse('a' in session)
def test_flash_default(self):
session = self._makeOne()
@@ -838,7 +883,7 @@ class TestDummySession(unittest.TestCase):
session['_csrft_'] = 'token'
token = session.get_csrf_token()
self.assertEqual(token, 'token')
- self.failUnless('_csrft_' in session)
+ self.assertTrue('_csrft_' in session)
from zope.interface import Interface
diff --git a/pyramid/tests/test_urldispatch.py b/pyramid/tests/test_urldispatch.py
index 5be04478f..6e1474b1d 100644
--- a/pyramid/tests/test_urldispatch.py
+++ b/pyramid/tests/test_urldispatch.py
@@ -21,8 +21,8 @@ class TestRoute(unittest.TestCase):
self.assertEqual(route.path, ':path')
self.assertEqual(route.name, 'name')
self.assertEqual(route.factory, 'factory')
- self.failUnless(route.generate.__class__ is types.FunctionType)
- self.failUnless(route.match.__class__ is types.FunctionType)
+ self.assertTrue(route.generate.__class__ is types.FunctionType)
+ self.assertTrue(route.match.__class__ is types.FunctionType)
def test_ctor_defaults(self):
import types
@@ -31,8 +31,8 @@ class TestRoute(unittest.TestCase):
self.assertEqual(route.path, ':path')
self.assertEqual(route.name, 'name')
self.assertEqual(route.factory, None)
- self.failUnless(route.generate.__class__ is types.FunctionType)
- self.failUnless(route.match.__class__ is types.FunctionType)
+ self.assertTrue(route.generate.__class__ is types.FunctionType)
+ self.assertTrue(route.match.__class__ is types.FunctionType)
def test_match(self):
route = self._makeOne('name', ':path')
@@ -288,20 +288,28 @@ class TestCompileRoute(unittest.TestCase):
{'baz':'abc', 'buz':'buz'})
self.assertEqual(generator({'baz':1, 'buz':2}), '/foo/1/biz/2/bar')
- # XXX reenable after torturous_route_re replacement is found for
- # Jython
- ## def test_custom_regex_with_embedded_squigglies(self):
- ## matcher, generator = self._callFUT('/{buz:\d{4}}')
- ## self.assertEqual(matcher('/2001'), {'buz':'2001'})
- ## self.assertEqual(matcher('/200'), None)
- ## self.assertEqual(generator({'buz':2001}), '/2001')
-
- ## def test_custom_regex_with_embedded_squigglies2(self):
- ## matcher, generator = self._callFUT('/{buz:\d{3,4}}')
- ## self.assertEqual(matcher('/2001'), {'buz':'2001'})
- ## self.assertEqual(matcher('/200'), {'buz':'200'})
- ## self.assertEqual(matcher('/20'), None)
- ## self.assertEqual(generator({'buz':2001}), '/2001')
+ def test_custom_regex_with_embedded_squigglies(self):
+ matcher, generator = self._callFUT('/{buz:\d{4}}')
+ self.assertEqual(matcher('/2001'), {'buz':'2001'})
+ self.assertEqual(matcher('/200'), None)
+ self.assertEqual(generator({'buz':2001}), '/2001')
+
+ def test_custom_regex_with_embedded_squigglies2(self):
+ matcher, generator = self._callFUT('/{buz:\d{3,4}}')
+ self.assertEqual(matcher('/2001'), {'buz':'2001'})
+ self.assertEqual(matcher('/200'), {'buz':'200'})
+ self.assertEqual(matcher('/20'), None)
+ self.assertEqual(generator({'buz':2001}), '/2001')
+
+ def test_custom_regex_with_embedded_squigglies3(self):
+ matcher, generator = self._callFUT('/{buz:(\d{2}|\d{4})-[a-zA-Z]{3,4}-\d{2}}')
+ self.assertEqual(matcher('/2001-Nov-15'), {'buz':'2001-Nov-15'})
+ self.assertEqual(matcher('/99-June-10'), {'buz':'99-June-10'})
+ self.assertEqual(matcher('/2-Nov-15'), None)
+ self.assertEqual(matcher('/200-Nov-15'), None)
+ self.assertEqual(matcher('/2001-No-15'), None)
+ self.assertEqual(generator({'buz':'2001-Nov-15'}), '/2001-Nov-15')
+ self.assertEqual(generator({'buz':'99-June-10'}), '/99-June-10')
class TestCompileRouteMatchFunctional(unittest.TestCase):
def matches(self, pattern, path, expected):
diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py
index 826fc4290..b1d48b98b 100644
--- a/pyramid/tests/test_view.py
+++ b/pyramid/tests/test_view.py
@@ -267,7 +267,7 @@ class TestViewConfigDecorator(unittest.TestCase):
decorator.venusian = venusian
def foo(): pass
wrapped = decorator(foo)
- self.failUnless(wrapped is foo)
+ self.assertTrue(wrapped is foo)
settings = call_venusian(venusian)
self.assertEqual(len(settings), 1)
self.assertEqual(settings[0]['permission'], None)
@@ -281,7 +281,7 @@ class TestViewConfigDecorator(unittest.TestCase):
decorator.venusian.info.scope = 'class'
class foo(object): pass
wrapped = decorator(foo)
- self.failUnless(wrapped is foo)
+ self.assertTrue(wrapped is foo)
settings = call_venusian(venusian)
self.assertEqual(len(settings), 1)
self.assertEqual(settings[0]['permission'], None)
@@ -296,7 +296,7 @@ class TestViewConfigDecorator(unittest.TestCase):
decorator.venusian.info.scope = 'class'
class foo(object): pass
wrapped = decorator(foo)
- self.failUnless(wrapped is foo)
+ self.assertTrue(wrapped is foo)
settings = call_venusian(venusian)
self.assertEqual(len(settings), 1)
self.assertEqual(settings[0]['permission'], None)
@@ -314,8 +314,8 @@ class TestViewConfigDecorator(unittest.TestCase):
def foo(): pass
wrapped1 = decorator1(foo)
wrapped2 = decorator2(wrapped1)
- self.failUnless(wrapped1 is foo)
- self.failUnless(wrapped2 is foo)
+ self.assertTrue(wrapped1 is foo)
+ self.assertTrue(wrapped2 is foo)
settings1 = call_venusian(venusian1)
self.assertEqual(len(settings1), 1)
self.assertEqual(settings1[0]['name'], '1')
@@ -344,7 +344,7 @@ class TestViewConfigDecorator(unittest.TestCase):
decorator.venusian = venusian
def foo(context, request): pass
decorated = decorator(foo)
- self.failUnless(decorated is foo)
+ self.assertTrue(decorated is foo)
settings = call_venusian(venusian)
self.assertEqual(settings[0]['custom_predicates'], (1,))
@@ -355,7 +355,7 @@ class TestViewConfigDecorator(unittest.TestCase):
decorator.venusian = venusian
def foo(): pass
wrapped = decorator(foo)
- self.failUnless(wrapped is foo)
+ self.assertTrue(wrapped is foo)
settings = call_venusian(venusian)
self.assertEqual(len(settings), 1)
renderer = settings[0]['renderer']
@@ -369,7 +369,7 @@ class TestViewConfigDecorator(unittest.TestCase):
decorator.venusian = venusian
def foo(): pass
wrapped = decorator(foo)
- self.failUnless(wrapped is foo)
+ self.assertTrue(wrapped is foo)
settings = call_venusian(venusian)
self.assertEqual(len(settings), 1)
self.assertEqual(settings[0]['renderer'], {'a':1})
@@ -477,20 +477,20 @@ class Test_default_exceptionresponse_view(unittest.TestCase):
def test_is_exception(self):
context = Exception()
result = self._callFUT(context, None)
- self.failUnless(result is context)
+ self.assertTrue(result is context)
def test_is_not_exception_context_is_false_still_chose(self):
request = DummyRequest()
request.exception = 0
result = self._callFUT(None, request)
- self.failUnless(result is None)
+ self.assertTrue(result is None)
def test_is_not_exception_no_request_exception(self):
context = object()
request = DummyRequest()
request.exception = None
result = self._callFUT(context, request)
- self.failUnless(result is context)
+ self.assertTrue(result is context)
def test_is_not_exception_request_exception(self):
context = object()
diff --git a/pyramid/tests/test_wsgi.py b/pyramid/tests/test_wsgi.py
index f63667352..06bcf1cb2 100644
--- a/pyramid/tests/test_wsgi.py
+++ b/pyramid/tests/test_wsgi.py
@@ -20,11 +20,9 @@ class WSGIApp2Tests(unittest.TestCase):
def test_decorator_with_subpath_and_view_name(self):
context = DummyContext()
request = DummyRequest()
- request.traversed = ['a', 'b']
- request.virtual_root_path = ['a']
- request.subpath = ['subpath']
- request.view_name = 'view_name'
- request.environ = {'SCRIPT_NAME':'/foo'}
+ request.subpath = ('subpath',)
+ request.environ = {'SCRIPT_NAME':'/foo',
+ 'PATH_INFO':'/b/view_name/subpath'}
decorator = self._callFUT(dummyapp)
response = decorator(context, request)
self.assertEqual(response, dummyapp)
@@ -34,11 +32,8 @@ class WSGIApp2Tests(unittest.TestCase):
def test_decorator_with_subpath_no_view_name(self):
context = DummyContext()
request = DummyRequest()
- request.traversed = ['a', 'b']
- request.virtual_root_path = ['a']
- request.subpath = ['subpath']
- request.view_name = ''
- request.environ = {'SCRIPT_NAME':'/foo'}
+ request.subpath = ('subpath',)
+ request.environ = {'SCRIPT_NAME':'/foo', 'PATH_INFO':'/b/subpath'}
decorator = self._callFUT(dummyapp)
response = decorator(context, request)
self.assertEqual(response, dummyapp)
@@ -48,11 +43,8 @@ class WSGIApp2Tests(unittest.TestCase):
def test_decorator_no_subpath_with_view_name(self):
context = DummyContext()
request = DummyRequest()
- request.traversed = ['a', 'b']
- request.virtual_root_path = ['a']
- request.subpath = []
- request.view_name = 'view_name'
- request.environ = {'SCRIPT_NAME':'/foo'}
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME':'/foo', 'PATH_INFO':'/b/view_name'}
decorator = self._callFUT(dummyapp)
response = decorator(context, request)
self.assertEqual(response, dummyapp)
@@ -62,11 +54,8 @@ class WSGIApp2Tests(unittest.TestCase):
def test_decorator_traversed_empty_with_view_name(self):
context = DummyContext()
request = DummyRequest()
- request.traversed = []
- request.virtual_root_path = []
- request.subpath = []
- request.view_name = 'view_name'
- request.environ = {'SCRIPT_NAME':'/foo'}
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME':'/foo', 'PATH_INFO':'/view_name'}
decorator = self._callFUT(dummyapp)
response = decorator(context, request)
self.assertEqual(response, dummyapp)
@@ -76,11 +65,8 @@ class WSGIApp2Tests(unittest.TestCase):
def test_decorator_traversed_empty_no_view_name(self):
context = DummyContext()
request = DummyRequest()
- request.traversed = []
- request.virtual_root_path = []
- request.subpath = []
- request.view_name = ''
- request.environ = {'SCRIPT_NAME':'/foo'}
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME':'/foo', 'PATH_INFO':'/'}
decorator = self._callFUT(dummyapp)
response = decorator(context, request)
self.assertEqual(response, dummyapp)
@@ -90,11 +76,8 @@ class WSGIApp2Tests(unittest.TestCase):
def test_decorator_traversed_empty_no_view_name_no_script_name(self):
context = DummyContext()
request = DummyRequest()
- request.traversed = []
- request.virtual_root_path = []
- request.subpath = []
- request.view_name = ''
- request.environ = {'SCRIPT_NAME':''}
+ request.subpath = ()
+ request.environ = {'SCRIPT_NAME':'', 'PATH_INFO':'/'}
decorator = self._callFUT(dummyapp)
response = decorator(context, request)
self.assertEqual(response, dummyapp)
@@ -110,3 +93,8 @@ class DummyContext:
class DummyRequest:
def get_response(self, application):
return application
+
+ def copy(self):
+ self.copied = True
+ return self
+
diff --git a/pyramid/tests/wsgiapp2app/__init__.py b/pyramid/tests/wsgiapp2app/__init__.py
new file mode 100644
index 000000000..0880556ef
--- /dev/null
+++ b/pyramid/tests/wsgiapp2app/__init__.py
@@ -0,0 +1,17 @@
+from pyramid.view import view_config
+from pyramid.wsgi import wsgiapp2
+
+@view_config(name='hello', renderer='string')
+@wsgiapp2
+def hello(environ, start_response):
+ assert environ['PATH_INFO'] == '/'
+ assert environ['SCRIPT_NAME'] == '/hello'
+ response_headers = [('Content-Type', 'text/plain')]
+ start_response('200 OK', response_headers)
+ return ['Hello!']
+
+def main():
+ from pyramid.config import Configurator
+ c = Configurator()
+ c.scan()
+ return c
diff --git a/pyramid/urldispatch.py b/pyramid/urldispatch.py
index be737201b..989cc62b9 100644
--- a/pyramid/urldispatch.py
+++ b/pyramid/urldispatch.py
@@ -77,20 +77,11 @@ class RoutesMapper(object):
old_route_re = re.compile(r'(\:[a-zA-Z]\w*)')
star_in_brackets = re.compile(r'\{[^\}]*\*\w*[^\}]*\}')
-# The regex named ``torturous_route_re`` below allows us to support at least
-# one level of "inner" squigglies inside the expr of a {name:expr} pattern;
-# for example, {foo:\d{4}}. Thanks to Zart for the regex help.
-# ``torturous_route_re`` is meant to be a replacement for the regex named
-# ``route_re`` (which is just (\{[a-zA-Z][^\}]*\})) because ``route_re``
-# chokes when it encounters inner squigglies. However
-# http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507 means that the
-# torturous regex doesn't work on Jython (recursion error), so we've disabled
-# it in favor of ``route_re`` for now. If somebody can make something that
-# will work on Jython but also match inner squigglies, it'd be useful.
-
-# torturous_route_re = re.compile(r'(\{[a-zA-Z](?:\{[^\}]*\}|[^\{\}]*)*\})')
-
-route_re = re.compile(r'(\{[a-zA-Z][^\}]*\})')
+# The torturous nature of the regex named ``route_re`` below is due to the
+# fact that we need to support at least one level of "inner" squigglies
+# inside the expr of a {name:expr} pattern. This regex used to be just
+# (\{[a-zA-Z][^\}]*\}) but that choked when supplied with e.g. {foo:\d{4}}.
+route_re = re.compile(r'(\{[a-zA-Z][^{}]*(?:\{[^{}]*\}[^{}]*)*\})')
def update_pattern(matchobj):
name = matchobj.group(0)
diff --git a/pyramid/wsgi.py b/pyramid/wsgi.py
index e988a000e..e4c61ff63 100644
--- a/pyramid/wsgi.py
+++ b/pyramid/wsgi.py
@@ -1,5 +1,5 @@
from pyramid.compat import wraps
-from pyramid.traversal import quote_path_segment
+from pyramid.request import call_app_with_subpath_as_path_info
def wsgiapp(wrapped):
""" Decorator to turn a WSGI application into a :app:`Pyramid`
@@ -31,7 +31,7 @@ def wsgiapp(wrapped):
"""
def decorator(context, request):
return request.get_response(wrapped)
- return wraps(wrapped)(decorator) # grokkability
+ return wraps(wrapped)(decorator)
def wsgiapp2(wrapped):
""" Decorator to turn a WSGI application into a :app:`Pyramid`
@@ -56,31 +56,15 @@ def wsgiapp2(wrapped):
config.add_view(hello_world, name='hello_world.txt')
The ``wsgiapp2`` decorator will convert the result of the WSGI
- application to a Response and return it to :app:`Pyramid` as if
- the WSGI app were a :app:`Pyramid` view. The ``SCRIPT_NAME``
- and ``PATH_INFO`` values present in the WSGI environment are fixed
- up before the application is invoked. """
+ application to a Response and return it to :app:`Pyramid` as if the WSGI
+ app were a :app:`Pyramid` view. The ``SCRIPT_NAME`` and ``PATH_INFO``
+ values present in the WSGI environment are fixed up before the
+ application is invoked. In particular, a new WSGI environment is
+ generated, and the :term:`subpath` of the request passed to ``wsgiapp2``
+ is used as the new request's ``PATH_INFO`` and everything preceding the
+ subpath is used as the ``SCRIPT_NAME``. The new environment is passed to
+ the downstream WSGI application."""
def decorator(context, request):
- traversed = request.traversed
- vroot_path = request.virtual_root_path
- if not vroot_path:
- vroot_path = ()
- view_name = request.view_name
- subpath = request.subpath
- if not subpath:
- subpath = ()
- script_tuple = traversed[len(vroot_path):]
- script_list = [ quote_path_segment(name) for name in script_tuple ]
- if view_name:
- script_list.append(quote_path_segment(view_name))
- script_name = '/' + '/'.join(script_list)
- path_list = [ quote_path_segment(name) for name in subpath ]
- path_info = '/' + '/'.join(path_list)
- request.environ['PATH_INFO'] = path_info
- script_name = request.environ['SCRIPT_NAME'] + script_name
- if script_name.endswith('/'):
- script_name = script_name[:-1]
- request.environ['SCRIPT_NAME'] = script_name
- return request.get_response(wrapped)
- return wraps(wrapped)(decorator) # grokkability
+ return call_app_with_subpath_as_path_info(request, wrapped)
+ return wraps(wrapped)(decorator)
diff --git a/setup.py b/setup.py
index 4ab4cca82..f965353ed 100644
--- a/setup.py
+++ b/setup.py
@@ -31,7 +31,7 @@ install_requires=[
'Paste > 1.7', # temp version pin to prevent PyPi install failure :-(
'PasteDeploy',
'PasteScript',
- 'WebOb >= 1.0', # no "default_charset"
+ 'WebOb >= 1.0.2', # no "default_charset"; request.script_name doesnt error
'repoze.lru',
'setuptools',
'zope.component >= 3.6.0', # independent of zope.hookable
@@ -53,7 +53,7 @@ if sys.version_info[:2] < (2, 6):
install_requires.append('simplejson')
setup(name='pyramid',
- version='1.0',
+ version='1.1a0',
description=('The Pyramid web application development framework, a '
'Pylons project'),
long_description=README + '\n\n' + CHANGES,
diff --git a/tox.ini b/tox.ini
index 56307bacf..73a487ac8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,19 +1,27 @@
[tox]
envlist =
- py25,py26,py27,jython,pypy,cover
+ py24,py25,py26,py27,jython,pypy,cover
[testenv]
commands =
python setup.py test -q
-# if we ever want to run the paster template tests, we could also use:
-# python template_tests.py
-# they take forever, though
deps =
Sphinx
WebTest
repoze.sphinx.autointerface
virtualenv
+[testenv:py24]
+# Chameleon 2 doesnt work under py2.4
+commands =
+ python setup.py test -q
+deps =
+ Sphinx
+ WebTest
+ repoze.sphinx.autointerface
+ virtualenv
+ Chameleon<=1.999
+
[testenv:jython]
commands =
jython setup.py test -q