summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt75
-rw-r--r--TODO.txt24
-rw-r--r--docs/api/authentication.rst10
-rw-r--r--docs/api/security.rst2
-rw-r--r--docs/designdefense.rst8
-rw-r--r--docs/glossary.rst9
-rw-r--r--docs/narr/project.rst8
-rw-r--r--docs/narr/templates.rst2
-rw-r--r--docs/tutorials/wiki2/src/views/tutorial/__init__.py2
-rw-r--r--docs/zcml/handler.rst2
-rw-r--r--pyramid/authentication.py27
-rw-r--r--pyramid/config.py350
-rw-r--r--pyramid/interfaces.py19
-rw-r--r--pyramid/security.py18
-rw-r--r--pyramid/testing.py8
-rw-r--r--pyramid/tests/test_authentication.py33
-rw-r--r--pyramid/tests/test_config.py1434
-rw-r--r--pyramid/tests/test_security.py33
-rw-r--r--pyramid/tests/test_testing.py6
-rw-r--r--pyramid/tests/test_view.py5
-rw-r--r--pyramid/url.py2
-rw-r--r--pyramid/view.py6
22 files changed, 1262 insertions, 821 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 04f5a7d05..6471dd7a8 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -9,23 +9,70 @@ Bug Fixes
Instead of trying to resolve the view, if it cannot, it will now just print
``<unknown>``.
+- The `self` argument was included in new methods of the ``ISession`` interface
+ signature, causing ``pyramid_beaker`` tests to fail (jkrebs).
+
Features
--------
- ``config.add_view`` now accepts a ``decorator`` keyword argument, a callable
which will decorate the view callable before it is added to the registry.
-- ``config.add_view`` now accepts a ``view_mapper`` keyword argument, which
- should be a class which implements the new
- ``pyramid.interfaces.IViewMapperFactory`` interface. Use of an alternate
- view mapper allows objects that are meant to be used as view callables to
- have an arbitrary argument list and an arbitrary result. This feature will
- be used by Pyramid extension developers, not by "civilians".
-
-- If a handler class provides an __action_decorator__ attribute (usually a
- classmethod or staticmethod), use that as the decorator for each view
+- If a handler class provides an ``__action_decorator__`` attribute (usually
+ a classmethod or staticmethod), use that as the decorator for each view
registration for that handler.
+- The ``pyramid.interfaces.IAuthenticationPolicy`` interface now specifies an
+ ``unauthenticated_userid`` method. This method supports an important
+ optimization required by people who are using persistent storages which do
+ not support object caching and whom want to create a "user object" as a
+ request attribute.
+
+- A new API has been added to the ``pyramid.security`` module named
+ ``unauthenticated_userid``. This API function calls the
+ ``unauthenticated_userid`` method of the effective security policy.
+
+- An ``unauthenticated_userid`` method has been added to the dummy
+ authentication policy returned by
+ ``pyramid.config.Configurator.testing_securitypolicy``. It returns the
+ same thing as that the dummy authentication policy's
+ ``authenticated_userid`` method.
+
+- The class ``pyramid.authentication.AuthTktCookieHelper`` is now an API.
+ This class can be used by third-party authentication policy developers to
+ help in the mechanics of authentication cookie-setting.
+
+- New constructor argument to Configurator: ``default_view_mapper``. Useful
+ to create systems that have alternate view calling conventions. A view
+ mapper allows objects that are meant to be used as view callables to have
+ an arbitrary argument list and an arbitrary result. The object passed as
+ ``default_view_mapper`` should implement the
+ ``pyramid.interfaces.IViewMapperFactory`` interface.
+
+- add a ``set_view_mapper`` API to Configurator. Has
+ the same result as passing ``default_view_mapper`` to the Configurator
+ constructor.
+
+- ``config.add_view`` now accepts a ``view_mapper`` keyword argument, which
+ should either be ``None``, a string representing a Python dotted name, or
+ an object which is an ``IViewMapperFactory``. This feature is not useful
+ for "civilians", only for extension writers.
+
+- Allow static renderer provided during view registration to be overridden at
+ request time via a request attribute named ``override_renderer``, which
+ should be the name of a previously registered renderer. Useful to provide
+ "omnipresent" RPC using existing rendered views.
+
+Backwards Incompatibilities
+---------------------------
+
+- Since the ``pyramid.interfaces.IAuthenticationPolicy`` interface now
+ specifies that a policy implementation must implement an
+ ``unauthenticated_userid`` method, all third-party custom authentication
+ policies now must implement this method. It, however, will only be called
+ when the global function named ``pyramid.security.unauthenticated_userid``
+ is invoked, so if you're not invoking that, you will not notice any issues.
+
Documentation
-------------
@@ -51,6 +98,16 @@ Internals
- The class used as the "page template" in ``pyramid.chameleon_text`` was
removed, in preference to using a Chameleon-inbuilt version.
+- A view callable wrapper registered in the registry now contains an
+ ``__original_view__`` attribute which references the original view callable
+ (or class).
+
+- The (non-API) method of all internal authentication policy implementations
+ previously named ``_get_userid`` is now named ``unauthenticated_userid``,
+ promoted to an API method. If you were overriding this method, you'll now
+ need to override it as ``unauthenticated_userid`` instead.
+
+- Remove (non-API) function of config.py named _map_view.
1.0a8 (2010-12-27)
==================
diff --git a/TODO.txt b/TODO.txt
index 5acc923a1..5c04bec6f 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -11,14 +11,32 @@ Must-Have (before 1.0)
- Re-make testing.setUp() and testing.tearDown() the canonical APIs for test
configuration.
-- Document ``decorator=`` and ``view_mapper`` parameters to add_view.
+- Document ``decorator=`` and ``view_mapper`` parameters to add_view and
+ ``@view_config``.
-- Allow ``decorator=`` and ``view_mapper=`` to be passed via ZCML and the
- ``view_config`` decorator.
+- Allow ``decorator=`` and ``view_mapper=`` to be passed via ZCML.
+
+- Document ``Configurator.set_view_mapper``.
+
+- Document ``__view_mapper__`` attribute for view callable view mapper
+ preference.
+
+- ZCML directive for view mapper (or just use "utility", but it's not eager).
+
+- Decide whether ``self.decorated_view(view)`` is in the right place in the
+ view deriver chain.
+
+- API docs for ``pyramid.views.action``.
Should-Have
-----------
+- ``current_route_url`` function. https://gist.github.com/762842
+
+- Convert paster template and tutorial HTML templates to use
+ ``request.static_url('{{package}}:static/foo.css')`` rather than
+ ``${request.application_url}/static/foo.css``.
+
- Add notes about renderer response attrs to request docs.
- Add an example of using a cascade to serve static assets from the root.
diff --git a/docs/api/authentication.rst b/docs/api/authentication.rst
index 54db77417..a6d4c1e18 100644
--- a/docs/api/authentication.rst
+++ b/docs/api/authentication.rst
@@ -3,6 +3,9 @@
:mod:`pyramid.authentication`
--------------------------------
+Authentication Policies
+~~~~~~~~~~~~~~~~~~~~~~~
+
.. automodule:: pyramid.authentication
.. autoclass:: AuthTktAuthenticationPolicy
@@ -11,3 +14,10 @@
.. autoclass:: RemoteUserAuthenticationPolicy
+Helper Classes
+~~~~~~~~~~~~~~
+
+ .. autoclass:: AuthTktCookieHelper
+
+
+
diff --git a/docs/api/security.rst b/docs/api/security.rst
index 4acf5fe4d..de249355d 100644
--- a/docs/api/security.rst
+++ b/docs/api/security.rst
@@ -10,6 +10,8 @@ Authentication API Functions
.. autofunction:: authenticated_userid
+.. autofunction:: unauthenticated_userid
+
.. autofunction:: effective_principals
.. autofunction:: forget
diff --git a/docs/designdefense.rst b/docs/designdefense.rst
index 1d6941283..df14fb440 100644
--- a/docs/designdefense.rst
+++ b/docs/designdefense.rst
@@ -895,9 +895,9 @@ Pyramid Applications are Extensible; I Don't Believe In Application Extensibilit
Any :app:`Pyramid` application written obeying certain constraints is
*extensible*. This feature is discussed in the :app:`Pyramid` documentation
-chapters named :ref:`extending_chapter` and :ref:`advconf_narr`. It is made
-possible by the use of the :term:`Zope Component Architecture` and within
-:app:`Pyramid`.
+chapters named :ref:`extending_chapter` and :ref:`advconfig_narr`. It is
+made possible by the use of the :term:`Zope Component Architecture` and
+within :app:`Pyramid`.
"Extensible", in this context, means:
@@ -1018,7 +1018,7 @@ Challenge
:app:`Pyramid` performs automatic authorization checks only at :term:`view`
execution time. Zope 3 wraps context objects with a `security proxy
-<http://wiki.zope.org/zope3/WhatAreSecurityProxies>`, which causes Zope 3 to
+<http://wiki.zope.org/zope3/WhatAreSecurityProxies>`_, which causes Zope 3 to
do also security checks during attribute access. I like this, because it
means:
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 49d273197..5deb9f5c6 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -834,7 +834,7 @@ Glossary
:meth:`pyramid.config.Configurator.add_route` and
:meth:`pyramid.config.Configurator.add_view` to make it more
convenient to register a collection of views as a single class when
- using :term:`url dispatch`. See also :ref:`handlers_chapter`.
+ using :term:`url dispatch`. See also :ref:`views_chapter`.
Deployment settings
Deployment settings are settings passed to the :term:`Configurator` as a
@@ -850,6 +850,11 @@ Glossary
WSGI middleware which can display debuggable traceback information in
the browser when an exception is raised by a Pyramid application. See
http://pypi.python.org/pypi/WebError .
-
+ view mapper
+
+ A view mapper is a class which implements the
+ :class:`pyramid.interfaces.IViewMapperFactory` interface, which performs
+ view argument and return value mapping. This is a plug point for
+ extension builders, not normally used by "civilians".
diff --git a/docs/narr/project.rst b/docs/narr/project.rst
index 55a2711f3..5e84a4fa7 100644
--- a/docs/narr/project.rst
+++ b/docs/narr/project.rst
@@ -910,6 +910,8 @@ example.
See :ref:`testing_chapter` for more information about writing :app:`Pyramid`
unit tests.
+.. _modifying_package_structure:
+
Modifying Package Structure
----------------------------
@@ -958,12 +960,14 @@ To this:
.. code-block:: python
:linenos:
- config.add_view('myproject.views.blogs.my_view',
+ config.add_view('myproject.views.blog.my_view',
renderer='myproject:templates/mytemplate.pt')
You can then continue to add files to the ``views`` directory, and refer to
views or handler classes/functions within those files via the dotted name
-passed as the first argument to ``add_view``. For example:
+passed as the first argument to ``add_view``. For example, if you added a
+file named ``anothermodule.py`` to the ``views`` subdirectory, and added a
+view callable named ``my_view`` to it:
.. code-block:: python
:linenos:
diff --git a/docs/narr/templates.rst b/docs/narr/templates.rst
index 437b823e9..7ef8e1923 100644
--- a/docs/narr/templates.rst
+++ b/docs/narr/templates.rst
@@ -628,7 +628,7 @@ application's configuration section, e.g.:
.. code-block:: ini
:linenos:
- [app:main]
+ [app:MyProject]
use = egg:MyProject#app
debug_templates = true
diff --git a/docs/tutorials/wiki2/src/views/tutorial/__init__.py b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
index 334fde814..1a8d24499 100644
--- a/docs/tutorials/wiki2/src/views/tutorial/__init__.py
+++ b/docs/tutorials/wiki2/src/views/tutorial/__init__.py
@@ -10,7 +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.view_wiki')
+ 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')
diff --git a/docs/zcml/handler.rst b/docs/zcml/handler.rst
index 01d442ab6..64aac7e78 100644
--- a/docs/zcml/handler.rst
+++ b/docs/zcml/handler.rst
@@ -155,4 +155,4 @@ You can also add a :term:`route configuration` via:
See Also
~~~~~~~~
-See also :ref:`handlers_chapter`.
+See also :ref:`views_chapter`.
diff --git a/pyramid/authentication.py b/pyramid/authentication.py
index 86d725bcf..bf08b519a 100644
--- a/pyramid/authentication.py
+++ b/pyramid/authentication.py
@@ -17,7 +17,7 @@ from pyramid.security import Everyone
class CallbackAuthenticationPolicy(object):
""" Abstract class """
def authenticated_userid(self, request):
- userid = self._get_userid(request)
+ userid = self.unauthenticated_userid(request)
if userid is None:
return None
if self.callback is None:
@@ -27,7 +27,7 @@ class CallbackAuthenticationPolicy(object):
def effective_principals(self, request):
effective_principals = [Everyone]
- userid = self._get_userid(request)
+ userid = self.unauthenticated_userid(request)
if userid is None:
return effective_principals
if self.callback is None:
@@ -89,6 +89,12 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy):
if self.callback(identity, request) is not None: # is not None!
return identity['repoze.who.userid']
+ def unauthenticated_userid(self, request):
+ identity = self._get_identity(request)
+ if identity is None:
+ return None
+ return identity['repoze.who.userid']
+
def effective_principals(self, request):
effective_principals = [Everyone]
identity = self._get_identity(request)
@@ -147,7 +153,7 @@ class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy):
self.environ_key = environ_key
self.callback = callback
- def _get_userid(self, request):
+ def unauthenticated_userid(self, request):
return request.environ.get(self.environ_key)
def remember(self, request, principal, **kw):
@@ -264,7 +270,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
)
self.callback = callback
- def _get_userid(self, request):
+ def unauthenticated_userid(self, request):
result = self.cookie.identify(request)
if result:
return result['userid']
@@ -285,6 +291,12 @@ def b64decode(v):
EXPIRE = object()
class AuthTktCookieHelper(object):
+ """
+ A helper class for use in third-party authentication policy
+ implementations. See
+ :class:`pyramid.authentication.AuthTktAuthenticationPolicy' for the
+ meanings of the constructor arguments.
+ """
auth_tkt = auth_tkt # for tests
now = None # for tests
@@ -356,6 +368,8 @@ class AuthTktCookieHelper(object):
return cookies
def identify(self, request):
+ """ Return a dictionary with authentication information, or ``None``
+ if no valid auth_tkt is attached to ``request``"""
environ = request.environ
cookies = get_cookies(environ)
cookie = cookies.get(self.cookie_name)
@@ -411,11 +425,14 @@ class AuthTktCookieHelper(object):
return identity
def forget(self, request):
- # return a set of expires Set-Cookie headers
+ """ Return a set of expires Set-Cookie headers, which will destroy
+ any existing auth_tkt cookie when attached to a response"""
environ = request.environ
return self._get_cookies(environ, '', max_age=EXPIRE)
def remember(self, request, userid, max_age=None):
+ """ Return a set of Set-Cookie headers; when set into a response,
+ these headers will represent a valid authentication ticket."""
max_age = max_age or self.max_age
environ = request.environ
diff --git a/pyramid/config.py b/pyramid/config.py
index ee34adae1..8a908725f 100644
--- a/pyramid/config.py
+++ b/pyramid/config.py
@@ -246,7 +246,13 @@ class Configurator(object):
``autocommit`` is ``True``. If a conflict is detected a
``ConfigurationConflictError`` will be raised. Calling
:meth:`pyramid.config.Configurator.make_wsgi_app` always implies a final
- commit."""
+ commit.
+
+ If ``default_view_mapper`` is passed, it will be used as the default
+ view mapper factory for view configurations that don't otherwise specify
+ one (see :class:`pyramid.interfaces.IViewMapperFactory`).
+ If a default_view_mapper is not passed, a superdefault view mapper will
+ be used. """
manager = manager # for testing injection
venusian = venusian # for testing injection
@@ -267,6 +273,7 @@ class Configurator(object):
renderer_globals_factory=None,
default_permission=None,
session_factory=None,
+ default_view_mapper=None,
autocommit=False,
):
if package is None:
@@ -292,6 +299,7 @@ class Configurator(object):
renderer_globals_factory=renderer_globals_factory,
default_permission=default_permission,
session_factory=session_factory,
+ default_view_mapper=default_view_mapper,
)
def _set_settings(self, mapping):
@@ -343,8 +351,10 @@ class Configurator(object):
def _derive_view(self, view, permission=None, predicates=(),
attr=None, renderer=None, wrapper_viewname=None,
viewname=None, accept=None, order=MAX_ORDER,
- phash=DEFAULT_PHASH):
+ phash=DEFAULT_PHASH, decorator=None,
+ view_mapper=None):
view = self.maybe_dotted(view)
+ view_mapper = self.maybe_dotted(view_mapper)
if isinstance(renderer, basestring):
renderer = RendererHelper(name=renderer, package=self.package,
registry = self.registry)
@@ -354,18 +364,21 @@ class Configurator(object):
renderer = RendererHelper(name=None,
package=self.package,
registry=self.registry)
- deriver = ViewDeriver(
- registry=self.registry,
- permission=permission,
- predicates=predicates,
- attr=attr,
- renderer=renderer,
- wrapper_viewname=wrapper_viewname,
- viewname=viewname,
- accept=accept,
- order=order,
- phash=phash,
- package=self.package)
+
+ deriver = ViewDeriver(registry=self.registry,
+ permission=permission,
+ predicates=predicates,
+ attr=attr,
+ renderer=renderer,
+ wrapper_viewname=wrapper_viewname,
+ viewname=viewname,
+ accept=accept,
+ order=order,
+ phash=phash,
+ package=self.package,
+ view_mapper=view_mapper,
+ decorator=decorator)
+
return deriver(view)
def _override(self, package, path, override_package, override_prefix,
@@ -596,9 +609,8 @@ class Configurator(object):
authentication_policy=None, authorization_policy=None,
renderers=DEFAULT_RENDERERS, debug_logger=None,
locale_negotiator=None, request_factory=None,
- renderer_globals_factory=None,
- default_permission=None,
- session_factory=None):
+ renderer_globals_factory=None, default_permission=None,
+ session_factory=None, default_view_mapper=None):
""" When you pass a non-``None`` ``registry`` argument to the
:term:`Configurator` constructor, no initial 'setup' is performed
against the registry. This is because the registry you pass in may
@@ -644,7 +656,13 @@ class Configurator(object):
self.set_default_permission(default_permission)
if session_factory is not None:
self.set_session_factory(session_factory)
+ # commit before adding default_view_mapper, as the
+ # default_exceptionresponse_view above requires the superdefault view
+ # mapper
self.commit()
+ if default_view_mapper is not None:
+ self.set_view_mapper(default_view_mapper)
+ self.commit()
# getSiteManager is a unit testing dep injection
def hook_zca(self, getSiteManager=None):
@@ -925,7 +943,7 @@ class Configurator(object):
Any extra keyword arguments are passed along to ``add_route``.
- See :ref:`handlers_chapter` for more explanatory documentation.
+ See :ref:`views_chapter` for more explanatory documentation.
This method returns the result of add_route."""
handler = self.maybe_dotted(handler)
@@ -1140,11 +1158,11 @@ class Configurator(object):
decorator
A function which will be used to decorate the registered
- :term:`view callable`. The decorator function will be
- called with the view callable as a single argument, and it
- must return a replacement view callable which accepts the
- same arguments and returns the same type of values as the
- original function.
+ :term:`view callable`. The decorator function will be called with
+ the view callable as a single argument. The view callable it is
+ passed will accept ``(context, request)`. The decorator must
+ return a replacement view callable which also accepts ``(context,
+ request)``.
Predicate Arguments
@@ -1285,20 +1303,19 @@ class Configurator(object):
view_mapper
- A class implementing the
- :class:`pyramid.interfaces.IViewMapperFactory` interface, which
- performs view argument and response mapping. By default it is
- ``None``, which indicates that the view should use the default view
- mapper. This plug-point is useful for Pyramid extension
- developers, but it's not very useful for 'civilians' who are
- just developing stock Pyramid applications. Pay no attention to
- the man behind the curtain.
+ A Python object or :term:`dotted Python name` which refers to a
+ :term:`view mapper`, or ``None``. By default it is ``None``, which
+ indicates that the view should use the default view mapper. This
+ plug-point is useful for Pyramid extension developers, but it's not
+ very useful for 'civilians' who are just developing stock Pyramid
+ applications. Pay no attention to the man behind the curtain.
"""
view = self.maybe_dotted(view)
context = self.maybe_dotted(context)
for_ = self.maybe_dotted(for_)
containment = self.maybe_dotted(containment)
+ view_mapper = self.maybe_dotted(view_mapper)
if not view:
if renderer:
@@ -1369,19 +1386,21 @@ class Configurator(object):
# intent: will be None if no default permission is registered
permission = self.registry.queryUtility(IDefaultPermission)
- # NO_PERMISSION_REQUIRED handled by _secure_view
- derived_view = ViewDeriver(registry=self.registry,
- permission=permission,
- predicates=predicates,
- attr=attr,
- renderer=renderer,
- wrapper_viewname=wrapper,
- viewname=name,
- accept=accept,
- order=order,
- phash=phash,
- decorator=decorator,
- view_mapper=view_mapper)(view)
+ # __no_permission_required__ handled by _secure_view
+ deriver = ViewDeriver(registry=self.registry,
+ permission=permission,
+ predicates=predicates,
+ attr=attr,
+ renderer=renderer,
+ wrapper_viewname=wrapper,
+ viewname=name,
+ accept=accept,
+ order=order,
+ phash=phash,
+ package=self.package,
+ view_mapper=view_mapper,
+ decorator=decorator)
+ derived_view = deriver(view)
registered = self.registry.adapters.registered
@@ -2163,6 +2182,29 @@ class Configurator(object):
self.action(IDefaultPermission, None)
@action_method
+ def set_view_mapper(self, mapper):
+ """
+ Setting a :term:`view mapper` makes it possible to make use of
+ :term:`view callable` objects which implement different call
+ signatures than the ones supported by :app:`Pyramid` as described in
+ its narrative documentation.
+
+ The ``mapper`` should argument be an object implementing
+ :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted
+ Python name` to such an object.
+
+ The provided ``mapper`` will become the default view mapper to be
+ used by all subsequent :term:`view configuration` registrations, as
+ if you had passed a ``default_view_mapper`` argument to the
+ :class:`pyramid.config.Configurator` constructor.
+
+ See also :ref:`using_an_alternate_view_mapper`.
+ """
+ mapper = self.maybe_dotted(mapper)
+ self.registry.registerUtility(mapper, IViewMapperFactory)
+ self.action(IViewMapperFactory, None)
+
+ @action_method
def set_session_factory(self, session_factory):
"""
Configure the application with a :term:`session factory`. If
@@ -2695,6 +2737,10 @@ def wraps_view(wrapped):
def preserve_view_attrs(view, wrapped_view):
if wrapped_view is view:
return view
+ original_view = getattr(view, '__original_view__', None)
+ if original_view is None:
+ original_view = view
+ wrapped_view.__original_view__ = original_view
wrapped_view.__module__ = view.__module__
wrapped_view.__doc__ = view.__doc__
try:
@@ -2734,19 +2780,30 @@ class ViewDeriver(object):
self.logger = self.registry.queryUtility(IDebugLogger)
def __call__(self, view):
- mapper = self.kw.get('view_mapper')
- if mapper is None:
- mapper = DefaultViewMapper
- view = mapper(**self.kw)(view)
return self.attr_wrapped_view(
self.predicated_view(
self.authdebug_view(
self.secured_view(
- self.owrap_view(
- view)))))
+ self.owrapped_view(
+ self.decorated_view(
+ self.rendered_view(
+ self.mapped_view(view))))))))
+
+ @wraps_view
+ def mapped_view(self, view):
+ mapper = self.kw.get('view_mapper')
+ if mapper is None:
+ mapper = getattr(view, '__view_mapper__', None)
+ if mapper is None:
+ mapper = self.registry.queryUtility(IViewMapperFactory)
+ if mapper is None:
+ mapper = DefaultViewMapper
+
+ mapped_view = mapper(**self.kw)(view)
+ return mapped_view
@wraps_view
- def owrap_view(self, view):
+ def owrapped_view(self, view):
wrapper_viewname = self.kw.get('wrapper_viewname')
viewname = self.kw.get('viewname')
if not wrapper_viewname:
@@ -2860,29 +2917,64 @@ class ViewDeriver(object):
attr_view.__phash__ = phash
return attr_view
+ @wraps_view
+ def rendered_view(self, view):
+ wrapped_view = view
+ static_renderer = self.kw.get('renderer')
+ if static_renderer is None:
+ # register a default renderer if you want super-dynamic
+ # rendering. registering a default renderer will also allow
+ # override_renderer to work if a renderer is left unspecified for
+ # a view registration.
+ return view
+
+ def _rendered_view(context, request):
+ renderer = static_renderer
+ response = wrapped_view(context, request)
+ if not is_response(response):
+ attrs = getattr(request, '__dict__', {})
+ if 'override_renderer' in attrs:
+ # renderer overridden by newrequest event or other
+ renderer_name = attrs.pop('override_renderer')
+ renderer = RendererHelper(name=renderer_name,
+ package=self.kw.get('package'),
+ registry = self.kw['registry'])
+ if '__view__' in attrs:
+ view_inst = attrs.pop('__view__')
+ else:
+ view_inst = getattr(wrapped_view, '__original_view__',
+ wrapped_view)
+ return renderer.render_view(request, response, view_inst,
+ context)
+ return response
+
+ return _rendered_view
+
+ @wraps_view
+ def decorated_view(self, view):
+ decorator = self.kw.get('decorator')
+ if decorator is None:
+ return view
+ return decorator(view)
+
class DefaultViewMapper(object):
implements(IViewMapperFactory)
def __init__(self, **kw):
- self.renderer = kw.get('renderer')
self.attr = kw.get('attr')
- self.decorator = kw.get('decorator')
def __call__(self, view):
- decorator = self.decorator
if inspect.isclass(view):
- view = preserve_view_attrs(view, self.map_class(view))
+ view = self.map_class(view)
else:
- view = preserve_view_attrs(view, self.map_nonclass(view))
- if decorator is not None:
- view = preserve_view_attrs(view, decorator(view))
+ view = self.map_nonclass(view)
return view
def map_class(self, view):
- ronly = self.requestonly(view)
+ ronly = requestonly(view, self.attr)
if ronly:
- mapped_view = self._map_class_requestonly(view)
+ mapped_view = self.map_class_requestonly(view)
else:
- mapped_view = self._map_class_native(view)
+ mapped_view = self.map_class_native(view)
return mapped_view
def map_nonclass(self, view):
@@ -2890,47 +2982,41 @@ class DefaultViewMapper(object):
# view unless it actually requires wrapping (to avoid function call
# overhead).
mapped_view = view
- ronly = self.requestonly(view)
+ ronly = requestonly(view, self.attr)
if ronly:
- mapped_view = self._map_nonclass_requestonly(view)
+ mapped_view = self.map_nonclass_requestonly(view)
elif self.attr:
- mapped_view = self._map_nonclass_attr(view)
- elif self.renderer is not None:
- mapped_view = self._map_nonclass_rendered(view)
+ mapped_view = self.map_nonclass_attr(view)
return mapped_view
- def _map_class_requestonly(self, view):
+ def map_class_requestonly(self, view):
# its a class that has an __init__ which only accepts request
attr = self.attr
def _class_requestonly_view(context, request):
inst = view(request)
+ request.__view__ = inst
if attr is None:
response = inst()
else:
response = getattr(inst, attr)()
- if self.renderer is not None and not is_response(response):
- response = self.renderer.render_view(request, response, view,
- context)
return response
return _class_requestonly_view
- def _map_class_native(self, view):
+ def map_class_native(self, view):
# its a class that has an __init__ which accepts both context and
# request
attr = self.attr
def _class_view(context, request):
inst = view(context, request)
+ request.__view__ = inst
if attr is None:
response = inst()
else:
response = getattr(inst, attr)()
- if self.renderer is not None and not is_response(response):
- response = self.renderer.render_view(request, response, view,
- context)
return response
return _class_view
- def _map_nonclass_requestonly(self, view):
+ def map_nonclass_requestonly(self, view):
# its a function that has a __call__ which accepts only a single
# request argument
attr = self.attr
@@ -2939,86 +3025,58 @@ class DefaultViewMapper(object):
response = view(request)
else:
response = getattr(view, attr)(request)
- if self.renderer is not None and not is_response(response):
- response = self.renderer.render_view(request, response, view,
- context)
return response
return _requestonly_view
- def _map_nonclass_attr(self, view):
+ def map_nonclass_attr(self, view):
# its a function that has a __call__ which accepts both context and
# request, but still has an attr
- attr = self.attr
def _attr_view(context, request):
- response = getattr(view, attr)(context, request)
- if self.renderer is not None and not is_response(response):
- response = self.renderer.render_view(request, response, view,
- context)
+ response = getattr(view, self.attr)(context, request)
return response
return _attr_view
- def _map_nonclass_rendered(self, view):
- # it's a function that has a __call__ that accepts both context and
- # request, but requires rendering
- def _rendered_view(context, request):
- response = view(context, request)
- if self.renderer is not None and not is_response(response):
- response = self.renderer.render_view(request, response, view,
- context)
- return response
- return _rendered_view
-
- def requestonly(self, view):
- attr = self.attr
- if attr is None:
- attr = '__call__'
- if inspect.isfunction(view):
- fn = view
- elif inspect.isclass(view):
- try:
- fn = view.__init__
- except AttributeError:
- return False
- else:
- try:
- fn = getattr(view, attr)
- except AttributeError:
- return False
-
+def requestonly(view, attr=None):
+ if attr is None:
+ attr = '__call__'
+ if inspect.isfunction(view):
+ fn = view
+ elif inspect.isclass(view):
try:
- argspec = inspect.getargspec(fn)
- except TypeError:
+ fn = view.__init__
+ except AttributeError:
return False
-
- args = argspec[0]
- defaults = argspec[3]
-
- if hasattr(fn, 'im_func'):
- # it's an instance method
- if not args:
- return False
- args = args[1:]
- if not args:
+ else:
+ try:
+ fn = getattr(view, attr)
+ except AttributeError:
return False
- if len(args) == 1:
- return True
+ try:
+ argspec = inspect.getargspec(fn)
+ except TypeError:
+ return False
- elif args[0] == 'request':
- if len(args) - len(defaults) == 1:
- return True
+ args = argspec[0]
+ defaults = argspec[3]
+ if hasattr(fn, 'im_func'):
+ # it's an instance method
+ if not args:
+ return False
+ args = args[1:]
+ if not args:
return False
+ if len(args) == 1:
+ return True
-def isexception(o):
- if IInterface.providedBy(o):
- if IException.isEqualOrExtendedBy(o):
+ elif args[0] == 'request':
+ if len(args) - len(defaults) == 1:
return True
- return (
- isinstance(o, Exception) or
- (inspect.isclass(o) and (issubclass(o, Exception)))
- )
+
+ return False
+
class ActionPredicate(object):
action_name = 'action'
@@ -3065,20 +3123,18 @@ def translator(msg):
localizer = get_localizer(request)
return localizer.translate(msg)
-# b/c
-def _map_view(view, registry, attr=None, renderer=None):
- return DefaultViewMapper(registry=registry, attr=attr,
- renderer=renderer)(view)
-
-# b/c
-def requestonly(view, attr=None):
- """ Return true of the class or callable accepts only a request argument,
- as opposed to something that accepts context, request """
- return DefaultViewMapper(attr=attr).requestonly(view)
-
def is_response(ob):
if ( hasattr(ob, 'app_iter') and hasattr(ob, 'headerlist') and
hasattr(ob, 'status') ):
return True
return False
+def isexception(o):
+ if IInterface.providedBy(o):
+ if IException.isEqualOrExtendedBy(o):
+ return True
+ return (
+ isinstance(o, Exception) or
+ (inspect.isclass(o) and (issubclass(o, Exception)))
+ )
+
diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py
index 10a324b28..b109df77e 100644
--- a/pyramid/interfaces.py
+++ b/pyramid/interfaces.py
@@ -155,8 +155,19 @@ class IRouteRequest(Interface):
class IAuthenticationPolicy(Interface):
""" An object representing a Pyramid authentication policy. """
def authenticated_userid(request):
- """ Return the authenticated userid or ``None`` if no
- authenticated userid can be found. """
+ """ Return the authenticated userid or ``None`` if no authenticated
+ userid can be found. This method of the policy should ensure that a
+ record exists in whatever persistent store is used related to the
+ user (the user should not have been deleted); if a record associated
+ with the current id does not exist in a persistent store, it should
+ return ``None``."""
+
+ def unauthenticated_userid(request):
+ """ Return the *unauthenticated* userid. This method performs the
+ same duty as ``authenticated_userid`` but is permitted to return the
+ userid based only on data present in the request; it neednt (and
+ shouldn't) check any persistent store to ensure that the user record
+ related to the request userid exists."""
def effective_principals(request):
""" Return a sequence representing the effective principals
@@ -501,11 +512,11 @@ class ISession(Interface):
:meth:`pyramid.interfaces.ISesssion.flash`
"""
- def new_csrf_token(self):
+ def new_csrf_token():
""" Create and set into the session a new, random cross-site request
forgery protection token. Return the token. It will be a string."""
- def get_csrf_token(self):
+ def get_csrf_token():
""" Get the CSRF token previously added to the session via
``new_csrf_token``, and return the token. If no CSRF token exists,
the value returned will be ``None``.
diff --git a/pyramid/security.py b/pyramid/security.py
index 723e87a87..51c0802d5 100644
--- a/pyramid/security.py
+++ b/pyramid/security.py
@@ -64,6 +64,24 @@ def authenticated_userid(request):
return None
return policy.authenticated_userid(request)
+def unauthenticated_userid(request):
+ """ Return an object which represents the *claimed* (not verified) user
+ id of the credentials present in the request. ``None`` if there is no
+ :term:`authentication policy` in effect or there is no user data
+ associated with the current request. This differs from
+ :func:`~pyramid.security.authenticated_userid`, because the effective
+ authentication policy will not ensure that a record associated with the
+ userid exists in persistent storage."""
+ try:
+ reg = request.registry
+ except AttributeError:
+ reg = get_current_registry() # b/c
+
+ policy = reg.queryUtility(IAuthenticationPolicy)
+ if policy is None:
+ return None
+ return policy.unauthenticated_userid(request)
+
def effective_principals(request):
""" Return the list of 'effective' :term:`principal` identifiers
for the ``request``. This will include the userid of the
diff --git a/pyramid/testing.py b/pyramid/testing.py
index 61bb1843a..15fc385cd 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -44,9 +44,10 @@ def registerDummySecurityPolicy(userid=None, groupids=(), permissive=True):
:func:`pyramid.security.authenticated_userid` or
:func:`pyramid.security.effective_principals` APIs are used.
- This function is most useful when testing code that uses the APIs
- named :func:`pyramid.security.has_permission`,
+ This function is most useful when testing code that uses the APIs named
+ :func:`pyramid.security.has_permission`,
:func:`pyramid.security.authenticated_userid`,
+ :func:`pyramid.security.unauthenticated_userid`,
:func:`pyramid.security.effective_principals`, and
:func:`pyramid.security.principals_allowed_by_permission`.
@@ -332,6 +333,9 @@ class DummySecurityPolicy(object):
def authenticated_userid(self, request):
return self.userid
+ def unauthenticated_userid(self, request):
+ return self.userid
+
def effective_principals(self, request):
effective_principals = [Everyone]
if self.userid:
diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py
index d9d0c2c97..49d655466 100644
--- a/pyramid/tests/test_authentication.py
+++ b/pyramid/tests/test_authentication.py
@@ -18,11 +18,22 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase):
from pyramid.interfaces import IAuthenticationPolicy
verifyObject(IAuthenticationPolicy, self._makeOne())
+ def test_unauthenticated_userid_returns_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid(self):
+ request = DummyRequest(
+ {'repoze.who.identity':{'repoze.who.userid':'fred'}})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), 'fred')
+
def test_authenticated_userid_None(self):
request = DummyRequest({})
policy = self._makeOne()
self.assertEqual(policy.authenticated_userid(request), None)
-
+
def test_authenticated_userid(self):
request = DummyRequest(
{'repoze.who.identity':{'repoze.who.userid':'fred'}})
@@ -132,6 +143,16 @@ class TestRemoteUserAuthenticationPolicy(unittest.TestCase):
from pyramid.interfaces import IAuthenticationPolicy
verifyObject(IAuthenticationPolicy, self._makeOne())
+ def test_unauthenticated_userid_returns_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid(self):
+ request = DummyRequest({'REMOTE_USER':'fred'})
+ policy = self._makeOne()
+ self.assertEqual(policy.unauthenticated_userid(request), 'fred')
+
def test_authenticated_userid_None(self):
request = DummyRequest({})
policy = self._makeOne()
@@ -196,6 +217,16 @@ class TestAutkTktAuthenticationPolicy(unittest.TestCase):
from pyramid.interfaces import IAuthenticationPolicy
verifyObject(IAuthenticationPolicy, self._makeOne(None, None))
+ def test_unauthenticated_userid_returns_None(self):
+ request = DummyRequest({})
+ policy = self._makeOne(None, None)
+ self.assertEqual(policy.unauthenticated_userid(request), None)
+
+ def test_unauthenticated_userid(self):
+ request = DummyRequest({'REMOTE_USER':'fred'})
+ policy = self._makeOne(None, {'userid':'fred'})
+ self.assertEqual(policy.unauthenticated_userid(request), 'fred')
+
def test_authenticated_userid_no_cookie_identity(self):
request = DummyRequest({})
policy = self._makeOne(None, None)
diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py
index b2fa0e329..1632a4e5c 100644
--- a/pyramid/tests/test_config.py
+++ b/pyramid/tests/test_config.py
@@ -63,27 +63,11 @@ class ConfiguratorTests(unittest.TestCase):
config.registry.registerHandler(subscriber, (event_iface,))
return L
- def _registerLogger(self, config):
- from pyramid.interfaces import IDebugLogger
- logger = DummyLogger()
- config.registry.registerUtility(logger, IDebugLogger)
- return logger
-
def _makeRequest(self, config):
request = DummyRequest()
request.registry = config.registry
return request
- def _registerSecurityPolicy(self, config, permissive):
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.interfaces import IAuthorizationPolicy
- policy = DummySecurityPolicy(permissive)
- config.registry.registerUtility(policy, IAuthenticationPolicy)
- config.registry.registerUtility(policy, IAuthorizationPolicy)
-
- def _registerSettings(self, config, **settings):
- config.registry.settings = settings
-
def test_ctor_no_registry(self):
import sys
from pyramid.interfaces import ISettings
@@ -196,6 +180,13 @@ class ConfiguratorTests(unittest.TestCase):
config = self._makeOne(session_factory='factory')
self.assertEqual(config.registry.getUtility(ISessionFactory), 'factory')
+ def test_ctor_default_view_mapper(self):
+ from pyramid.interfaces import IViewMapperFactory
+ mapper = object()
+ config = self._makeOne(default_view_mapper=mapper)
+ self.assertEqual(config.registry.getUtility(IViewMapperFactory),
+ mapper)
+
def test_with_package_module(self):
from pyramid.tests import test_configuration
import pyramid.tests
@@ -790,8 +781,10 @@ class ConfiguratorTests(unittest.TestCase):
config = self._makeOne(autocommit=True)
config.add_view(view=view)
wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
self.assertEqual(result, 'OK')
+ self.assertEqual(request.__view__.__class__, view)
def test_add_view_as_oldstyle_class_requestonly(self):
class view:
@@ -803,8 +796,11 @@ class ConfiguratorTests(unittest.TestCase):
config = self._makeOne(autocommit=True)
config.add_view(view=view)
wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
+
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
self.assertEqual(result, 'OK')
+ self.assertEqual(request.__view__.__class__, view)
def test_add_view_context_as_class(self):
from zope.interface import implementedBy
@@ -1427,8 +1423,6 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(result.settings, settings)
def test_add_view_with_default_renderer(self):
- import pyramid.tests
- from pyramid.interfaces import ISettings
class view(object):
def __init__(self, context, request):
self.request = request
@@ -2340,7 +2334,8 @@ class ConfiguratorTests(unittest.TestCase):
request_type = self._getRouteRequestIface(config, 'name')
wrapper = self._getViewCallable(config, None, request_type)
self._assertRoute(config, 'name', 'path')
- self.assertEqual(wrapper(None, None), 'OK')
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(None, request), 'OK')
def test_add_route_with_view_renderer_alias(self):
config = self._makeOne(autocommit=True)
@@ -2437,6 +2432,52 @@ class ConfiguratorTests(unittest.TestCase):
else: # pragma: no cover
raise AssertionError
+ def test_derive_view_function(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne()
+ result = config.derive_view(view)
+ self.failIf(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.assertEqual(result(None, None), 'OK')
+
+ def test_derive_view_with_default_renderer_no_explicit_renderer(self):
+ config = self._makeOne()
+ class moo(object):
+ def __init__(self, view):
+ pass
+ def __call__(self, *arg, **kw):
+ return 'moo'
+ config.add_renderer(None, moo)
+ def view(request):
+ return 'OK'
+ result = config.derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(result(None, None).body, 'moo')
+
+ def test_derive_view_with_default_renderer_with_explicit_renderer(self):
+ class moo(object): pass
+ class foo(object):
+ def __init__(self, view):
+ pass
+ def __call__(self, *arg, **kw):
+ return 'foo'
+ def view(request):
+ return 'OK'
+ config = self._makeOne()
+ config.add_renderer(None, moo)
+ config.add_renderer('foo', foo)
+ result = config.derive_view(view, renderer='foo')
+ self.failIf(result is view)
+ request = self._makeRequest(config)
+ self.assertEqual(result(None, request).body, 'foo')
+
def test__override_not_yet_registered(self):
from pyramid.interfaces import IPackageOverrides
package = DummyPackage('package')
@@ -2633,6 +2674,22 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(config.registry.getUtility(IDefaultPermission),
'view')
+ def test_add_view_mapper(self):
+ from pyramid.interfaces import IViewMapperFactory
+ config = self._makeOne(autocommit=True)
+ mapper = object()
+ config.set_view_mapper(mapper)
+ result = config.registry.getUtility(IViewMapperFactory)
+ self.assertEqual(result, mapper)
+
+ def test_add_view_mapper_dottedname(self):
+ from pyramid.interfaces import IViewMapperFactory
+ config = self._makeOne(autocommit=True)
+ config.set_view_mapper('pyramid.tests.test_config')
+ result = config.registry.getUtility(IViewMapperFactory)
+ from pyramid.tests import test_config
+ self.assertEqual(result, test_config)
+
def test_set_session_factory(self):
from pyramid.interfaces import ISessionFactory
config = self._makeOne(autocommit=True)
@@ -2680,404 +2737,6 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(config.registry.getUtility(ITranslationDirectories),
[locale])
- def test_derive_view_function(self):
- def view(request):
- return 'OK'
- config = self._makeOne()
- result = config.derive_view(view)
- self.failIf(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.assertEqual(result(None, None), 'OK')
-
- def test_derive_view_with_renderer(self):
- def view(request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- class moo(object):
- def __init__(self, *arg, **kw):
- pass
- def __call__(self, *arg, **kw):
- return 'moo'
- config.add_renderer('moo', moo)
- result = config.derive_view(view, renderer='moo')
- self.failIf(result is view)
- self.assertEqual(result(None, None).body, 'moo')
-
- def test_derive_view_with_default_renderer_no_explicit_renderer(self):
- def view(request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- class moo(object):
- def __init__(self, *arg, **kw):
- pass
- def __call__(self, *arg, **kw):
- return 'moo'
- config.add_renderer(None, moo)
- result = config.derive_view(view)
- self.failIf(result is view)
- self.assertEqual(result(None, None).body, 'moo')
-
- def test_derive_view_with_default_renderer_with_explicit_renderer(self):
- def view(request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- class moo(object): pass
- class foo(object):
- def __init__(self, *arg, **kw):
- pass
- def __call__(self, *arg, **kw):
- return 'foo'
- config.add_renderer(None, moo)
- config.add_renderer('foo', foo)
- result = config.derive_view(view, renderer='foo')
- self.failIf(result is view)
- self.assertEqual(result(None, None).body, 'foo')
-
- def test_derive_view_class_without_attr(self):
- class View(object):
- def __init__(self, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config.derive_view(View)
- self.assertEqual(result(None, None), 'OK')
-
- def test_derive_view_class_with_attr(self):
- class View(object):
- def __init__(self, request):
- pass
- def another(self):
- return 'OK'
- config = self._makeOne()
- result = config.derive_view(View, attr='another')
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_function_context_and_request(self):
- def view(context, request):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failUnless(result is view)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(view(None, None), 'OK')
-
- def test__derive_view_as_function_requestonly(self):
- def view(request):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(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.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_newstyle_class_context_and_request(self):
- class view(object):
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(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.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_newstyle_class_requestonly(self):
- class view(object):
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(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.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_oldstyle_class_context_and_request(self):
- class view:
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(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.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_oldstyle_class_requestonly(self):
- class view:
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(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.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_instance_context_and_request(self):
- class View:
- def __call__(self, context, request):
- return 'OK'
- view = View()
- config = self._makeOne()
- result = config._derive_view(view)
- self.failUnless(result is view)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_instance_requestonly(self):
- class View:
- def __call__(self, request):
- return 'OK'
- view = View()
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(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.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_with_debug_authorization_no_authpol(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- logger = self._registerLogger(config)
- result = config._derive_view(view, permission='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__'))
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): Allowed "
- "(no authorization policy in use)")
-
- def test__derive_view_with_debug_authorization_no_permission(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- self._registerSecurityPolicy(config, True)
- logger = self._registerLogger(config)
- result = config._derive_view(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__'))
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): Allowed ("
- "no permission registered)")
-
- def test__derive_view_debug_auth_permission_authpol_permitted(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config, debug_authorization=True,
- reload_templates=True)
- logger = self._registerLogger(config)
- self._registerSecurityPolicy(config, True)
- result = config._derive_view(view, permission='view')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result.__call_permissive__, view)
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): True")
-
- def test__derive_view_debug_auth_permission_authpol_denied(self):
- from pyramid.exceptions import Forbidden
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- logger = self._registerLogger(config)
- self._registerSecurityPolicy(config, False)
- result = config._derive_view(view, permission='view')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result.__call_permissive__, view)
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertRaises(Forbidden, result, None, request)
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): False")
-
- def test__derive_view_debug_auth_permission_authpol_denied2(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- self._registerLogger(config)
- self._registerSecurityPolicy(config, False)
- result = config._derive_view(view, permission='view')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- permitted = result.__permitted__(None, None)
- self.assertEqual(permitted, False)
-
- def test__derive_view_debug_auth_permission_authpol_overridden(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- logger = self._registerLogger(config)
- self._registerSecurityPolicy(config, False)
- result = config._derive_view(view,
- permission='__no_permission_required__')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): False")
-
- def test__derive_view_with_predicates_all(self):
- view = lambda *arg: 'OK'
- predicates = []
- def predicate1(context, request):
- predicates.append(True)
- return True
- def predicate2(context, request):
- predicates.append(True)
- return True
- config = self._makeOne()
- result = config._derive_view(view, predicates=[predicate1, predicate2])
- request = self._makeRequest(config)
- request.method = 'POST'
- next = result(None, None)
- self.assertEqual(next, 'OK')
- self.assertEqual(predicates, [True, True])
-
- def test__derive_view_with_predicates_checker(self):
- view = lambda *arg: 'OK'
- predicates = []
- def predicate1(context, request):
- predicates.append(True)
- return True
- def predicate2(context, request):
- predicates.append(True)
- return True
- config = self._makeOne()
- result = config._derive_view(view, predicates=[predicate1, predicate2])
- request = self._makeRequest(config)
- request.method = 'POST'
- next = result.__predicated__(None, None)
- self.assertEqual(next, True)
- self.assertEqual(predicates, [True, True])
-
- def test__derive_view_with_predicates_notall(self):
- from pyramid.exceptions import NotFound
- view = lambda *arg: 'OK'
- predicates = []
- def predicate1(context, request):
- predicates.append(True)
- return True
- def predicate2(context, request):
- predicates.append(True)
- return False
- config = self._makeOne()
- result = config._derive_view(view, predicates=[predicate1, predicate2])
- request = self._makeRequest(config)
- request.method = 'POST'
- self.assertRaises(NotFound, result, None, None)
- self.assertEqual(predicates, [True, True])
-
- def test__derive_view_with_wrapper_viewname(self):
- from webob import Response
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- inner_response = Response('OK')
- def inner_view(context, request):
- return inner_response
- def outer_view(context, request):
- self.assertEqual(request.wrapped_response, inner_response)
- self.assertEqual(request.wrapped_body, inner_response.body)
- self.assertEqual(request.wrapped_view, inner_view)
- return Response('outer ' + request.wrapped_body)
- config = self._makeOne()
- config.registry.registerAdapter(
- outer_view, (IViewClassifier, None, None), IView, 'owrap')
- result = config._derive_view(inner_view, viewname='inner',
- wrapper_viewname='owrap')
- self.failIf(result is inner_view)
- self.assertEqual(inner_view.__module__, result.__module__)
- self.assertEqual(inner_view.__doc__, result.__doc__)
- request = self._makeRequest(config)
- request.registry = config.registry
- response = result(None, request)
- self.assertEqual(response.body, 'outer OK')
-
- def test__derive_view_with_wrapper_viewname_notfound(self):
- from webob import Response
- inner_response = Response('OK')
- def inner_view(context, request):
- return inner_response
- config = self._makeOne()
- request = self._makeRequest(config)
- request.registry = config.registry
- wrapped = config._derive_view(
- inner_view, viewname='inner', wrapper_viewname='owrap')
- self.assertRaises(ValueError, wrapped, None, request)
-
def test_override_asset_samename(self):
from pyramid.exceptions import ConfigurationError
config = self._makeOne()
@@ -3557,348 +3216,841 @@ class ConfiguratorTests(unittest.TestCase):
for confinst in conflict:
yield confinst[2]
-class Test__map_view(unittest.TestCase):
+class TestViewDeriver(unittest.TestCase):
def setUp(self):
- from pyramid.registry import Registry
- self.registry = Registry()
- testing.setUp(registry=self.registry)
+ self.config = testing.setUp()
def tearDown(self):
- del self.registry
- testing.tearDown()
-
- def _registerRenderer(self, typ='.txt'):
- from pyramid.interfaces import IRendererFactory
- from pyramid.interfaces import ITemplateRenderer
- from pyramid.renderers import RendererHelper
- from zope.interface import implements
- class DummyRenderer:
- implements(ITemplateRenderer)
- def __init__(self, path):
- self.__class__.path = path
- def __call__(self, *arg):
- return 'Hello!'
- self.registry.registerUtility(DummyRenderer, IRendererFactory, name=typ)
- renderer = RendererHelper(name='abc' + typ, registry=self.registry)
- return renderer
-
+ self.config = None
+
+ def _makeOne(self, **kw):
+ kw['registry'] = self.config.registry
+ from pyramid.config import ViewDeriver
+ return ViewDeriver(**kw)
+
def _makeRequest(self):
request = DummyRequest()
- request.registry = self.registry
+ request.registry = self.config.registry
return request
- def _callFUT(self, view, **kw):
- from pyramid.config import _map_view
- return _map_view(view, self.registry, **kw)
+ def _registerLogger(self):
+ from pyramid.interfaces import IDebugLogger
+ logger = DummyLogger()
+ self.config.registry.registerUtility(logger, IDebugLogger)
+ return logger
- def test__map_view_as_function_context_and_request(self):
- def view(context, request):
+ def _registerSecurityPolicy(self, permissive):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ policy = DummySecurityPolicy(permissive)
+ self.config.registry.registerUtility(policy, IAuthenticationPolicy)
+ self.config.registry.registerUtility(policy, IAuthorizationPolicy)
+
+ def test_requestonly_function(self):
+ def view(request):
return 'OK'
- result = self._callFUT(view)
- self.failUnless(result is view)
+ deriver = self._makeOne()
+ result = deriver(view)
+ self.failIf(result is view)
self.assertEqual(result(None, None), 'OK')
- def test__map_view_as_function_with_attr(self):
- def view(context, request):
- """ """
- result = self._callFUT(view, attr='__name__')
+ def test_requestonly_function_with_renderer(self):
+ class moo(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, 'OK')
+ self.assertEqual(view_inst, view)
+ self.assertEqual(ctx, context)
+ return 'moo'
+ def view(request):
+ return 'OK'
+ deriver = self._makeOne(renderer=moo())
+ result = deriver(view)
self.failIf(result is view)
- self.assertRaises(TypeError, result, None, None)
-
- def test__map_view_as_function_with_attr_and_renderer(self):
- renderer = self._registerRenderer()
- view = lambda *arg: 'OK'
- result = self._callFUT(view, attr='__name__', renderer=renderer)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), 'moo')
+
+ def test_requestonly_function_with_renderer_request_override(self):
+ def moo(info):
+ def inner(value, system):
+ self.assertEqual(value, 'OK')
+ self.assertEqual(system['request'], request)
+ self.assertEqual(system['context'], context)
+ return 'moo'
+ return inner
+ def view(request):
+ return 'OK'
+ self.config.add_renderer('moo', moo)
+ deriver = self._makeOne(renderer='string')
+ result = deriver(view)
self.failIf(result is view)
- self.assertRaises(TypeError, result, None, None)
+ request = self._makeRequest()
+ request.override_renderer = 'moo'
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request).body, 'moo')
- def test__map_view_as_function_requestonly(self):
+ def test_requestonly_function_with_renderer_request_has_view(self):
+ class moo(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, 'OK')
+ self.assertEqual(view_inst, 'view')
+ self.assertEqual(ctx, context)
+ return 'moo'
def view(request):
return 'OK'
- result = self._callFUT(view)
+ deriver = self._makeOne(renderer=moo())
+ result = deriver(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ request = self._makeRequest()
+ request.__view__ = 'view'
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), 'moo')
+ self.failIf(hasattr(request, '__view__'))
+
+ def test_class_without_attr(self):
+ class View(object):
+ def __init__(self, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ deriver = self._makeOne()
+ result = deriver(View)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(request.__view__.__class__, View)
- def test__map_view_as_function_requestonly_with_attr(self):
+ def test_class_with_attr(self):
+ class View(object):
+ def __init__(self, request):
+ pass
+ def another(self):
+ return 'OK'
+ deriver = self._makeOne(attr='another')
+ result = deriver(View)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(request.__view__.__class__, View)
+
+ def test_as_function_context_and_request(self):
+ def view(context, request):
+ return 'OK'
+ deriver = self._makeOne()
+ result = deriver(view)
+ self.failUnless(result is view)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(view(None, None), 'OK')
+
+ def test_as_function_requestonly(self):
def view(request):
- """ """
- result = self._callFUT(view, attr='__name__')
+ return 'OK'
+ deriver = self._makeOne()
+ result = deriver(view)
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.assertRaises(TypeError, result, None, None)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
- def test__map_view_as_newstyle_class_context_and_request(self):
+ def test_as_newstyle_class_context_and_request(self):
class view(object):
def __init__(self, context, request):
pass
def __call__(self):
return 'OK'
- result = self._callFUT(view)
+ deriver = self._makeOne()
+ result = deriver(view)
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ self.failIf(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(request.__view__.__class__, view)
- def test__map_view_as_newstyle_class_context_and_request_with_attr(self):
+ def test_as_newstyle_class_requestonly(self):
class view(object):
def __init__(self, context, request):
pass
- def index(self):
+ def __call__(self):
return 'OK'
- result = self._callFUT(view, attr='index')
+ deriver = self._makeOne()
+ result = deriver(view)
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ self.failIf(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(request.__view__.__class__, view)
- def test__map_view_as_newstyle_class_context_and_request_attr_and_renderer(
- self):
- renderer = self._registerRenderer()
- class view(object):
+ def test_as_oldstyle_class_context_and_request(self):
+ class view:
def __init__(self, context, request):
pass
- def index(self):
- return {'a':'1'}
- result = self._callFUT(view, attr='index', renderer=renderer)
+ def __call__(self):
+ return 'OK'
+ deriver = self._makeOne()
+ result = deriver(view)
self.failIf(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__'))
request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(request.__view__.__class__, view)
- def test__map_view_as_newstyle_class_requestonly(self):
- class view(object):
- def __init__(self, request):
+ def test_as_oldstyle_class_requestonly(self):
+ class view:
+ def __init__(self, context, request):
pass
def __call__(self):
return 'OK'
- result = self._callFUT(view)
+ deriver = self._makeOne()
+ result = deriver(view)
self.failIf(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__'))
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(request.__view__.__class__, view)
+
+ def test_as_instance_context_and_request(self):
+ class View:
+ def __call__(self, context, request):
+ return 'OK'
+ view = View()
+ deriver = self._makeOne()
+ result = deriver(view)
+ self.failUnless(result is view)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
- def test__map_view_as_newstyle_class_requestonly_with_attr(self):
- class view(object):
- def __init__(self, request):
- pass
- def index(self):
+ def test_as_instance_requestonly(self):
+ class View:
+ def __call__(self, request):
return 'OK'
- result = self._callFUT(view, attr='index')
+ view = View()
+ deriver = self._makeOne()
+ result = deriver(view)
self.failIf(result is view)
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
+ self.failUnless('instance' in result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
- def test__map_view_as_newstyle_class_requestonly_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class view(object):
+ def test_with_debug_authorization_no_authpol(self):
+ view = lambda *arg: 'OK'
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger()
+ deriver = self._makeOne(permission='view')
+ result = deriver(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__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed "
+ "(no authorization policy in use)")
+
+ def test_with_debug_authorization_no_permission(self):
+ view = lambda *arg: 'OK'
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True)
+ self._registerSecurityPolicy(True)
+ logger = self._registerLogger()
+ deriver = self._makeOne()
+ result = deriver(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__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed ("
+ "no permission registered)")
+
+ def test_debug_auth_permission_authpol_permitted(self):
+ view = lambda *arg: 'OK'
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(True)
+ deriver = self._makeOne(permission='view')
+ result = deriver(view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__, view)
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): True")
+
+ def test_debug_auth_permission_authpol_denied(self):
+ from pyramid.exceptions import Forbidden
+ view = lambda *arg: 'OK'
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(False)
+ deriver = self._makeOne(permission='view')
+ result = deriver(view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__, view)
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertRaises(Forbidden, result, None, request)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): False")
+
+ def test_debug_auth_permission_authpol_denied2(self):
+ view = lambda *arg: 'OK'
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True)
+ self._registerLogger()
+ self._registerSecurityPolicy(False)
+ deriver = self._makeOne(permission='view')
+ result = deriver(view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ permitted = result.__permitted__(None, None)
+ self.assertEqual(permitted, False)
+
+ def test_debug_auth_permission_authpol_overridden(self):
+ view = lambda *arg: 'OK'
+ self.config.registry.settings = dict(
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(False)
+ deriver = self._makeOne(permission='__no_permission_required__')
+ result = deriver(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__'))
+ request = self._makeRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): False")
+
+ def test_with_predicates_all(self):
+ view = lambda *arg: 'OK'
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+ deriver = self._makeOne(predicates=[predicate1, predicate2])
+ result = deriver(view)
+ request = self._makeRequest()
+ request.method = 'POST'
+ next = result(None, None)
+ self.assertEqual(next, 'OK')
+ self.assertEqual(predicates, [True, True])
+
+ def test_with_predicates_checker(self):
+ view = lambda *arg: 'OK'
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+ deriver = self._makeOne(predicates=[predicate1, predicate2])
+ result = deriver(view)
+ request = self._makeRequest()
+ request.method = 'POST'
+ next = result.__predicated__(None, None)
+ self.assertEqual(next, True)
+ self.assertEqual(predicates, [True, True])
+
+ def test_with_predicates_notall(self):
+ from pyramid.exceptions import NotFound
+ view = lambda *arg: 'OK'
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return False
+ deriver = self._makeOne(predicates=[predicate1, predicate2])
+ result = deriver(view)
+ request = self._makeRequest()
+ request.method = 'POST'
+ self.assertRaises(NotFound, result, None, None)
+ self.assertEqual(predicates, [True, True])
+
+ def test_with_wrapper_viewname(self):
+ from webob import Response
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ inner_response = Response('OK')
+ def inner_view(context, request):
+ return inner_response
+ def outer_view(context, request):
+ self.assertEqual(request.wrapped_response, inner_response)
+ self.assertEqual(request.wrapped_body, inner_response.body)
+ self.assertEqual(request.wrapped_view, inner_view)
+ return Response('outer ' + request.wrapped_body)
+ self.config.registry.registerAdapter(
+ outer_view, (IViewClassifier, None, None), IView, 'owrap')
+ deriver = self._makeOne(viewname='inner',
+ wrapper_viewname='owrap')
+ result = deriver(inner_view)
+ self.failIf(result is inner_view)
+ self.assertEqual(inner_view.__module__, result.__module__)
+ self.assertEqual(inner_view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ response = result(None, request)
+ self.assertEqual(response.body, 'outer OK')
+
+ def test_with_wrapper_viewname_notfound(self):
+ from webob import Response
+ inner_response = Response('OK')
+ def inner_view(context, request):
+ return inner_response
+ deriver = self._makeOne(viewname='inner', wrapper_viewname='owrap')
+ wrapped = deriver(inner_view)
+ request = self._makeRequest()
+ self.assertRaises(ValueError, wrapped, None, request)
+
+ def test_as_newstyle_class_context_and_request_attr_and_renderer(self):
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a':'1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return resp
+ class View(object):
+ def __init__(self, context, request):
+ pass
+ def index(self):
+ return {'a':'1'}
+ deriver = self._makeOne(renderer=renderer(), attr='index')
+ result = deriver(View)
+ self.failIf(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), {'a':'1'})
+
+ def test_as_newstyle_class_requestonly_attr_and_renderer(self):
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a':'1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return resp
+ class View(object):
+ def __init__(self, request):
+ pass
+ def index(self):
+ return {'a':'1'}
+ deriver = self._makeOne(renderer=renderer(), attr='index')
+ result = deriver(View)
+ self.failIf(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), {'a':'1'})
+
+ def test_as_oldstyle_cls_context_request_attr_and_renderer(self):
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a':'1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return resp
+ class View:
+ def __init__(self, context, request):
+ pass
+ def index(self):
+ return {'a':'1'}
+ deriver = self._makeOne(renderer=renderer(), attr='index')
+ result = deriver(View)
+ self.failIf(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), {'a':'1'})
+
+ def test_as_oldstyle_cls_requestonly_attr_and_renderer(self):
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a':'1'})
+ self.assertEqual(view_inst.__class__, View)
+ self.assertEqual(ctx, context)
+ return resp
+ class View:
def __init__(self, request):
pass
def index(self):
return {'a':'1'}
- result = self._callFUT(view, attr='index', renderer=renderer)
+ deriver = self._makeOne(renderer=renderer(), attr='index')
+ result = deriver(View)
+ self.failIf(result is View)
+ self.assertEqual(result.__module__, View.__module__)
+ self.assertEqual(result.__doc__, View.__doc__)
+ self.assertEqual(result.__name__, View.__name__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), {'a':'1'})
+
+ def test_as_instance_context_and_request_attr_and_renderer(self):
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a':'1'})
+ self.assertEqual(view_inst, view)
+ self.assertEqual(ctx, context)
+ return resp
+ class View:
+ def index(self, context, request):
+ return {'a':'1'}
+ deriver = self._makeOne(renderer=renderer(), attr='index')
+ view = View()
+ result = deriver(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__module__, view.__module__)
+ self.assertEqual(result.__doc__, view.__doc__)
request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), {'a':'1'})
+
+ def test_as_instance_requestonly_attr_and_renderer(self):
+ class renderer(object):
+ def render_view(inself, req, resp, view_inst, ctx):
+ self.assertEqual(req, request)
+ self.assertEqual(resp, {'a':'1'})
+ self.assertEqual(view_inst, view)
+ self.assertEqual(ctx, context)
+ return resp
+ class View:
+ def index(self, request):
+ return {'a':'1'}
+ deriver = self._makeOne(renderer=renderer(), attr='index')
+ view = View()
+ result = deriver(view)
+ self.failIf(result is view)
+ self.assertEqual(result.__module__, view.__module__)
+ self.assertEqual(result.__doc__, view.__doc__)
+ request = self._makeRequest()
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request), {'a':'1'})
+
+ def test_with_view_mapper_config_specified(self):
+ class mapper(object):
+ def __init__(self, **kw):
+ self.kw = kw
+ def __call__(self, view):
+ def wrapped(context, request):
+ return 'OK'
+ return wrapped
+ def view(context, request):
+ return 'NOTOK'
+ deriver = self._makeOne(view_mapper=mapper)
+ result = deriver(view)
+ self.failIf(result is view)
+ self.assertEqual(result(None, None), 'OK')
- def test__map_view_as_oldstyle_class_context_and_request(self):
- class view:
+ def test_with_view_mapper_view_specified(self):
+ def mapper(**kw):
+ def inner(view):
+ def superinner(context, request):
+ self.assertEqual(request, None)
+ return 'OK'
+ return superinner
+ return inner
+ def view(context, request):
+ return 'NOTOK'
+ view.__view_mapper__ = mapper
+ deriver = self._makeOne()
+ result = deriver(view)
+ self.failIf(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test_with_view_mapper_default_mapper_specified(self):
+ def mapper(**kw):
+ def inner(view):
+ def superinner(context, request):
+ self.assertEqual(request, None)
+ return 'OK'
+ return superinner
+ return inner
+ self.config.set_view_mapper(mapper)
+ def view(context, request):
+ return 'NOTOK'
+ deriver = self._makeOne()
+ result = deriver(view)
+ self.failIf(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+class TestDefaultViewMapper(unittest.TestCase):
+ def setUp(self):
+ self.config = testing.setUp()
+ self.registry = self.config.registry
+
+ def tearDown(self):
+ del self.registry
+ testing.tearDown()
+
+ def _makeOne(self, **kw):
+ from pyramid.config import DefaultViewMapper
+ kw['registry'] = self.registry
+ return DefaultViewMapper(**kw)
+
+ def _makeRequest(self):
+ request = DummyRequest()
+ request.registry = self.registry
+ return request
+
+ def test_view_as_function_context_and_request(self):
+ def view(context, request):
+ return 'OK'
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.failUnless(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test__view_as_function_with_attr(self):
+ def view(context, request):
+ """ """
+ mapper = self._makeOne(attr='__name__')
+ result = mapper(view)
+ self.failIf(result is view)
+ request = self._makeRequest()
+ self.assertRaises(TypeError, result, None, request)
+
+ def test_view_as_function_requestonly(self):
+ def view(request):
+ return 'OK'
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.failIf(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_function_requestonly_with_attr(self):
+ def view(request):
+ """ """
+ mapper = self._makeOne(attr='__name__')
+ result = mapper(view)
+ self.failIf(result is view)
+ request = self._makeRequest()
+ self.assertRaises(TypeError, result, None, request)
+
+ def test_view_as_newstyle_class_context_and_request(self):
+ class view(object):
def __init__(self, context, request):
pass
def __call__(self):
return 'OK'
- result = self._callFUT(view)
+ mapper = self._makeOne()
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_oldstyle_class_context_and_request_with_attr(self):
- class view:
+ def test_view_as_newstyle_class_context_and_request_with_attr(self):
+ class view(object):
def __init__(self, context, request):
pass
def index(self):
return 'OK'
- result = self._callFUT(view, attr='index')
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_oldstyle_cls_context_request_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class view:
- def __init__(self, context, request):
+ def test_view_as_newstyle_class_requestonly(self):
+ class view(object):
+ def __init__(self, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.failIf(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_newstyle_class_requestonly_with_attr(self):
+ class view(object):
+ def __init__(self, request):
pass
def index(self):
- return {'a':'1'}
- result = self._callFUT(view, attr='index', renderer=renderer)
+ return 'OK'
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_oldstyle_class_requestonly(self):
+ def test_view_as_oldstyle_class_context_and_request(self):
class view:
- def __init__(self, request):
+ def __init__(self, context, request):
pass
def __call__(self):
return 'OK'
- result = self._callFUT(view)
+ mapper = self._makeOne()
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_oldstyle_class_requestonly_with_attr(self):
+ def test_view_as_oldstyle_class_context_and_request_with_attr(self):
class view:
- def __init__(self, request):
+ def __init__(self, context, request):
pass
def index(self):
return 'OK'
- result = self._callFUT(view, attr='index')
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_oldstyle_class_requestonly_attr_and_renderer(self):
- renderer = self._registerRenderer()
+ def test_view_as_oldstyle_class_requestonly(self):
+ class view:
+ def __init__(self, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ mapper = self._makeOne()
+ result = mapper(view)
+ self.failIf(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
+
+ def test_view_as_oldstyle_class_requestonly_with_attr(self):
class view:
def __init__(self, request):
pass
def index(self):
- return {'a':'1'}
- result = self._callFUT(view, attr='index', renderer=renderer)
+ return 'OK'
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_instance_context_and_request(self):
+ def test_view_as_instance_context_and_request(self):
class View:
def __call__(self, context, request):
return 'OK'
view = View()
- result = self._callFUT(view)
+ mapper = self._makeOne()
+ result = mapper(view)
self.failUnless(result is view)
- self.assertEqual(result(None, None), 'OK')
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_instance_context_and_request_and_attr(self):
+ def test_view_as_instance_context_and_request_and_attr(self):
class View:
def index(self, context, request):
return 'OK'
view = View()
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_instance_context_and_request_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class View:
- def index(self, context, request):
- return {'a':'1'}
- view = View()
- result = self._callFUT(view, attr='index', renderer=renderer)
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
self.failIf(result is view)
request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_instance_requestonly(self):
+ def test_view_as_instance_requestonly(self):
class View:
def __call__(self, request):
return 'OK'
view = View()
- result = self._callFUT(view)
+ mapper = self._makeOne()
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- self.assertEqual(result(None, None), 'OK')
+ request = self._makeRequest()
+ self.assertEqual(result(None, request), 'OK')
- def test__map_view_as_instance_requestonly_with_attr(self):
+ def test_view_as_instance_requestonly_with_attr(self):
class View:
def index(self, request):
return 'OK'
view = View()
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_instance_requestonly_with_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class View:
- def index(self, request):
- return {'a':'1'}
- view = View()
- result = self._callFUT(view, attr='index', renderer=renderer)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_rendereronly(self):
- renderer = self._registerRenderer()
- def view(context, request):
- return {'a':'1'}
- result = self._callFUT(view, renderer=renderer)
+ mapper = self._makeOne(attr='index')
+ result = mapper(view)
self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_with_registry(self):
- renderer = self._registerRenderer()
- def view(context, request):
- return {'a':'1'}
- result = self._callFUT(view, renderer=renderer)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
+ self.assertEqual(result(None, request), 'OK')
-class Test_wraps_view(unittest.TestCase):
- def _callFUT(self, fn, view):
- from pyramid.config import wraps_view
- return wraps_view(fn)(None, view)
+class Test_preserve_view_attrs(unittest.TestCase):
+ def _callFUT(self, view, wrapped_view):
+ from pyramid.config import preserve_view_attrs
+ return preserve_view_attrs(view, wrapped_view)
def test_it_same(self):
def view(context, request):
""" """
- def afunc(self, view):
- return view
- result = self._callFUT(afunc, view)
+ result = self._callFUT(view, view)
self.failUnless(result is view)
+ def test_it_different_with_existing_original_view(self):
+ def view1(context, request): pass
+ view1.__original_view__ = 'abc'
+ def view2(context, request): pass
+ result = self._callFUT(view1, view2)
+ self.assertEqual(result.__original_view__, 'abc')
+ self.failIf(result is view1)
+
def test_it_different(self):
class DummyView1:
""" 1 """
@@ -3906,9 +4058,9 @@ class Test_wraps_view(unittest.TestCase):
__module__ = '1'
def __call__(self, context, request):
""" """
- def __call_permissive__(self, context, reuqest):
+ def __call_permissive__(self, context, request):
""" """
- def __predicated__(self, context, reuqest):
+ def __predicated__(self, context, request):
""" """
def __permitted__(self, context, request):
""" """
@@ -3918,18 +4070,17 @@ class Test_wraps_view(unittest.TestCase):
__module__ = '2'
def __call__(self, context, request):
""" """
- def __call_permissive__(self, context, reuqest):
+ def __call_permissive__(self, context, request):
""" """
- def __predicated__(self, context, reuqest):
+ def __predicated__(self, context, request):
""" """
def __permitted__(self, context, request):
""" """
view1 = DummyView1()
view2 = DummyView2()
- def afunc(self, view):
- return view1
- result = self._callFUT(afunc, view2)
+ 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__)
@@ -4395,24 +4546,23 @@ class TestMultiView(unittest.TestCase):
response = mv(context, request)
self.assertEqual(response, expected_response)
-
-class TestRequestOnly(unittest.TestCase):
- def _callFUT(self, arg):
+class Test_requestonly(unittest.TestCase):
+ def _callFUT(self, view, attr=None):
from pyramid.config import requestonly
- return requestonly(arg)
+ return requestonly(view, attr)
- def test_newstyle_class_no_init(self):
+ def test_requestonly_newstyle_class_no_init(self):
class foo(object):
""" """
self.assertFalse(self._callFUT(foo))
- def test_newstyle_class_init_toomanyargs(self):
+ def test_requestonly_newstyle_class_init_toomanyargs(self):
class foo(object):
def __init__(self, context, request):
""" """
self.assertFalse(self._callFUT(foo))
- def test_newstyle_class_init_onearg_named_request(self):
+ def test_requestonly_newstyle_class_init_onearg_named_request(self):
class foo(object):
def __init__(self, request):
""" """
@@ -4488,6 +4638,22 @@ class TestRequestOnly(unittest.TestCase):
""" """
self.assertFalse(self._callFUT(foo))
+ def test_function_with_attr_false(self):
+ def bar(context, request):
+ """ """
+ def foo(context, request):
+ """ """
+ foo.bar = bar
+ self.assertFalse(self._callFUT(foo, 'bar'))
+
+ def test_function_with_attr_true(self):
+ def bar(context, request):
+ """ """
+ def foo(request):
+ """ """
+ foo.bar = bar
+ self.assertTrue(self._callFUT(foo, 'bar'))
+
def test_function_onearg_named_request(self):
def foo(request):
""" """
diff --git a/pyramid/tests/test_security.py b/pyramid/tests/test_security.py
index dd9d48f45..94cefa642 100644
--- a/pyramid/tests/test_security.py
+++ b/pyramid/tests/test_security.py
@@ -224,6 +224,36 @@ class TestAuthenticatedUserId(unittest.TestCase):
result = self._callFUT(request)
self.assertEqual(result, 'yo')
+class TestUnauthenticatedUserId(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _callFUT(self, request):
+ from pyramid.security import unauthenticated_userid
+ return unauthenticated_userid(request)
+
+ def test_no_authentication_policy(self):
+ request = _makeRequest()
+ result = self._callFUT(request)
+ self.assertEqual(result, None)
+
+ def test_with_authentication_policy(self):
+ request = _makeRequest()
+ _registerAuthenticationPolicy(request.registry, 'yo')
+ result = self._callFUT(request)
+ self.assertEqual(result, 'yo')
+
+ def test_with_authentication_policy_no_reg_on_request(self):
+ from pyramid.threadlocal import get_current_registry
+ request = DummyRequest({})
+ registry = get_current_registry()
+ _registerAuthenticationPolicy(registry, 'yo')
+ result = self._callFUT(request)
+ self.assertEqual(result, 'yo')
+
class TestEffectivePrincipals(unittest.TestCase):
def setUp(self):
cleanUp()
@@ -355,6 +385,9 @@ class DummyAuthenticationPolicy:
def effective_principals(self, request):
return self.result
+ def unauthenticated_userid(self, request):
+ return self.result
+
def authenticated_userid(self, request):
return self.result
diff --git a/pyramid/tests/test_testing.py b/pyramid/tests/test_testing.py
index ec6fdac5f..d2ed957f2 100644
--- a/pyramid/tests/test_testing.py
+++ b/pyramid/tests/test_testing.py
@@ -297,7 +297,11 @@ class TestDummySecurityPolicy(unittest.TestCase):
def test_authenticated_userid(self):
policy = self._makeOne('user')
self.assertEqual(policy.authenticated_userid(None), 'user')
-
+
+ def test_unauthenticated_userid(self):
+ policy = self._makeOne('user')
+ self.assertEqual(policy.unauthenticated_userid(None), 'user')
+
def test_effective_principals_userid(self):
policy = self._makeOne('user', ('group1',))
from pyramid.security import Everyone
diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py
index 7fc066319..33c2b606d 100644
--- a/pyramid/tests/test_view.py
+++ b/pyramid/tests/test_view.py
@@ -229,11 +229,14 @@ class TestViewConfigDecorator(unittest.TestCase):
def test_create_nondefaults(self):
decorator = self._makeOne(name=None, request_type=None, for_=None,
- permission='foo')
+ permission='foo', view_mapper='mapper',
+ decorator='decorator')
self.assertEqual(decorator.name, None)
self.assertEqual(decorator.request_type, None)
self.assertEqual(decorator.context, None)
self.assertEqual(decorator.permission, 'foo')
+ self.assertEqual(decorator.view_mapper, 'mapper')
+ self.assertEqual(decorator.decorator, 'decorator')
def test_call_function(self):
decorator = self._makeOne()
diff --git a/pyramid/url.py b/pyramid/url.py
index ac569eecb..c11e39143 100644
--- a/pyramid/url.py
+++ b/pyramid/url.py
@@ -32,7 +32,7 @@ def route_url(route_name, request, *elements, **kw):
enough arguments, for example).
For example, if you've defined a route named "foobar" with the path
- ``:foo/{bar}/*traverse``::
+ ``{foo}/{bar}/*traverse``::
route_url('foobar', request, foo='1') => <KeyError exception>
route_url('foobar', request, foo='1', bar='2') => <KeyError exception>
diff --git a/pyramid/view.py b/pyramid/view.py
index 776185d8b..afd1c6d49 100644
--- a/pyramid/view.py
+++ b/pyramid/view.py
@@ -17,7 +17,6 @@ from zope.interface import providedBy
from pyramid.interfaces import IRoutesMapper
from pyramid.interfaces import IView
from pyramid.interfaces import IViewClassifier
-from pyramid.interfaces import IRendererFactory
from pyramid.httpexceptions import HTTPFound
from pyramid.renderers import RendererHelper
@@ -384,7 +383,8 @@ class view_config(object):
route_name=None, request_method=None, request_param=None,
containment=None, attr=None, renderer=None, wrapper=None,
xhr=False, accept=None, header=None, path_info=None,
- custom_predicates=(), context=None):
+ custom_predicates=(), context=None, decorator=None,
+ view_mapper=None):
self.name = name
self.request_type = request_type
self.context = context or for_
@@ -401,6 +401,8 @@ class view_config(object):
self.header = header
self.path_info = path_info
self.custom_predicates = custom_predicates
+ self.decorator = decorator
+ self.view_mapper = view_mapper
def __call__(self, wrapped):
settings = self.__dict__.copy()