summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-09-06 03:36:59 +0000
committerChris McDonough <chrism@agendaless.com>2009-09-06 03:36:59 +0000
commitd66bfb5d1f1aef5cce4941b49740dbd136c95605 (patch)
tree0204e233befdb8ad99332e498308468015f3558e
parent50df953770409dc9c9558c77bd5c0bbb17ac54f6 (diff)
downloadpyramid-d66bfb5d1f1aef5cce4941b49740dbd136c95605.tar.gz
pyramid-d66bfb5d1f1aef5cce4941b49740dbd136c95605.tar.bz2
pyramid-d66bfb5d1f1aef5cce4941b49740dbd136c95605.zip
Merge multiview2 branch to HEAD.
-rw-r--r--CHANGES.txt134
-rw-r--r--docs/narr/hybrid.rst14
-rw-r--r--docs/narr/urldispatch.rst101
-rw-r--r--docs/narr/views.rst129
-rw-r--r--repoze/bfg/interfaces.py41
-rw-r--r--repoze/bfg/paster_templates/alchemy/+package+/configure.zcml11
-rw-r--r--repoze/bfg/paster_templates/alchemy/+package+/views.py_tmpl3
-rw-r--r--repoze/bfg/paster_templates/routesalchemy/+package+/configure.zcml5
-rw-r--r--repoze/bfg/paster_templates/routesalchemy/+package+/views.py_tmpl3
-rw-r--r--repoze/bfg/paster_templates/zodb/+package+/configure.zcml5
-rw-r--r--repoze/bfg/paster_templates/zodb/+package+/views.py_tmpl3
-rw-r--r--repoze/bfg/request.py113
-rw-r--r--repoze/bfg/router.py77
-rw-r--r--repoze/bfg/security.py28
-rw-r--r--repoze/bfg/testing.py47
-rw-r--r--repoze/bfg/tests/test_integration.py35
-rw-r--r--repoze/bfg/tests/test_request.py268
-rw-r--r--repoze/bfg/tests/test_router.py292
-rw-r--r--repoze/bfg/tests/test_security.py33
-rw-r--r--repoze/bfg/tests/test_testing.py80
-rw-r--r--repoze/bfg/tests/test_view.py571
-rw-r--r--repoze/bfg/tests/test_zcml.py1905
-rw-r--r--repoze/bfg/view.py251
-rw-r--r--repoze/bfg/zcml.py494
24 files changed, 2869 insertions, 1774 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index fc86ac5b6..5dd17f4a4 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,117 @@
Next release
============
+- The ``route`` ZCML directive now honors ``view_request_method``,
+ ``view_request_param`` and ``view_containment`` attributes, which
+ pass along these values to the associated view if any is provided.
+ Additionally, the ``request_type`` attribute can now be spelled as
+ ``view_request_type``, and ``permission`` can be spelled as
+ ``view_permission``. Any attribute which starts with ``view_`` can
+ now be spelled without the ``view_`` prefix, so ``view_for`` can be
+ spelled as ``for`` now, etc. Both forms are documented in the
+ urldispatch narraitve documentation chapter.
+
+- The ``request_param`` ZCML view directive attribute (and its
+ ``bfg_view`` decorator cousin) can now specify both a key and a
+ value. For example, ``request_param="foo=123"`` means that the foo
+ key must have a value of ``123`` for the view to "match".
+
+- Bugfix: the ``discriminator`` for the ZCML "route" directive was
+ incorrect. It was possible to register two routes that collided
+ without the system spitting out a ConfigurationConflictError at
+ startup time.
+
+- The ``static`` ZCML directive now uses a custom root factory when
+ constructing a route.
+
+- The ordering of route declarations vs. the ordering of view
+ declarations that use a "route_name" in ZCML no longer matters.
+ Previously it had been impossible to use a route_name from a route
+ that had not yet been defined in ZCML (order-wise) within a "view"
+ declaration.
+
+- The ``@bfg_view`` decorator now accepts three additional arguments:
+ ``request_method``, ``request_param``, and ``containment``.
+ ``request_method`` is used when you'd like the view to match only a
+ request with a particular HTTP ``REQUEST_METHOD``; a string naming
+ the ``REQUEST_METHOD`` can also be supplied as ``request_type`` for
+ backwards compatibility. ``request_param`` is used when you'd like
+ a view to match only a request that contains a particular
+ ``request.params`` key (with or without a value). ``containment``
+ is used when you'd like to match a request that has a context that
+ has some class or interface in its graph lineage. These are
+ collectively known as "view predicates".
+
+- The interface ``IRequestFactories`` was removed from the
+ repoze.bfg.interfaces module. This interface was never an API.
+
+- The interfaces ``IPOSTRequest``, ``IGETRequest``, ``IPUTRequest``,
+ ``IDELETERequest``, and ``IHEADRequest`` have been removed from the
+ ``repoze.bfg.interfaces`` module. These were not documented as APIs
+ post-1.0. Instead of using one of these, use a ``request_method``
+ ZCML attribute or ``request_method`` bfg_view decorator parameter
+ containing an HTTP method name (one of ``GET``, ``POST``, ``HEAD``,
+ ``PUT``, ``DELETE``) instead of one of these interfaces if you were
+ using one explicitly. Passing a string in the set (``GET``,
+ ``HEAD``, ``PUT``, ``POST``, ``DELETE``) as a ``request_type``
+ argument will work too. Rationale: instead of relying on interfaces
+ attached to the request object, BFG now uses a "view predicate" to
+ determine the request type.
+
+- The function named ``named_request_factories`` and the data
+ structure named ``DEFAULT_REQUEST_FACTORIES`` have been removed from
+ the ``repoze.bfg.request`` module. These were never APIs.
+
+- Feature addition: view predicates. These are exposed as the
+ ``request_method``, ``request_param``, and ``containment``
+ attributes of a ZCML ``view`` declaration, or the respective
+ arguments to a ``@bfg_view`` decorator. View predicates can be used
+ to register a view for a more precise set of environment parameters
+ than was previously possible. For example, you can register two
+ views with the same ``name`` with different ``request_param``
+ attributes. If the ``request.params`` dict contains 'foo'
+ (request_param="foo"), one view might be called; if it contains
+ 'bar' (request_param="bar"), another view might be called.
+ ``request_param`` can also name a key/value pair ala ``foo=123``.
+ This will match only when the ``foo`` key is in the request.params
+ dict and it has the value '123'. This particular example makes it
+ possible to write separate view functions for different form
+ submissions. The other predicates, ``containment`` and
+ ``request_method`` work similarly. ``containment`` is a view
+ predicate that will match only when the context's graph lineage has
+ an object possessing a particular class or interface, for example.
+ ``request_method`` is a view predicate that will match when the HTTP
+ ``REQUEST_METHOD`` equals some string (eg. 'POST').
+
+- The repoze.bfg router now catches both
+ ``repoze.bfg.security.Unauthorized`` and
+ ``repoze.bfg.view.NotFound`` exceptions while rendering a view.
+ When the router catches an ``Unauthorized``, it returns the
+ registered forbidden view. When the router catches a ``NotFound``,
+ it returns the registered notfound view.
+
+- Custom ZCML directives which register an authentication or
+ authorization policy (ala "authtktauthenticationpolicy" or
+ "aclauthorizationpolicy") should register the policy "eagerly" in
+ the ZCML directive instead of from within a ZCML action. If an
+ authentication or authorization policy is not found in the component
+ registry by the view machinery during deferred ZCML processing, view
+ security will not work as expected.
+
+- The API ``repoze.bfg.testing.registerViewPermission`` has been
+ deprecated.
+
+- The API ``repoze.bfg.testing.registerView`` now takes a
+ ``permission`` argument. Use this instead of using
+ ``repoze.bfg.testing.registerViewPermission``.
+
+- Removed ViewPermissionFactory from ``repoze.bfg.security``. View
+ permission checking is now done by registering and looking up an
+ ISecuredView.
+
+- Views registered without the help of the ZCML ``view`` directive are
+ now responsible for performing their own authorization checking.
+
- The ``repoze.bfg.view.static`` class now accepts a string as its
first argument ("root_dir") that represents a package-relative name
e.g. ``somepackage:foo/bar/static``. This is now the preferred
@@ -975,12 +1086,12 @@ Features
policy defaults to an authorization implementation that uses ACLs
(``repoze.bfg.authorization.ACLAuthorizationPolicy``).
- .. note:: we no longer encourage configuration of "security
- policies" using ZCML, as previously we did for
- ``ISecurityPolicy``. This is because it's not uncommon to need to
- configure settings for concrete authorization or authentication
- policies using paste .ini parameters; the app entry point for your
- application is the natural place to do this.
+ We no longer encourage configuration of "security policies" using
+ ZCML, as previously we did for ``ISecurityPolicy``. This is because
+ it's not uncommon to need to configure settings for concrete
+ authorization or authentication policies using paste .ini
+ parameters; the app entry point for your application is the natural
+ place to do this.
- Two new abstractions have been added in the way of adapters used by
the system: an ``IAuthorizationPolicy`` and an
@@ -1387,9 +1498,8 @@ Features
source at installation time. In particular, ``repoze.bfg`` no
longer depends on the ``lxml`` package.
- .. note:: this change has introduced some backwards
- incompatibilities, described in the "Backwards
- Incompatibilities" section below.
+ This change has introduced some backwards incompatibilities,
+ described in the "Backwards Incompatibilities" section below.
- This release was tested on Windows XP. It appears to work fine and
all the tests pass.
@@ -1565,7 +1675,7 @@ Backwards Incompatibilities
opposed to URL-dispatch), and the root object supplied
the``repoze.bfg.interfaces.ILocation`` interface, but the children
returned via its ``__getitem__`` returned an object that did not
- implement the same interface, :mod:`repoze.bfg` provided some
+ implement the same interface, ``repoze.bfg`` provided some
implicit help during traversal. This traversal feature wrapped
subobjects from the root (and thereafter) that did not implement
``ILocation`` in proxies which automatically provided them with a
@@ -1815,7 +1925,7 @@ Features
- "Virtual root" support for traversal-based applications has been
added. Virtual root support is useful when you'd like to host some
- model in a :mod:`repoze.bfg` model graph as an application under a
+ model in a ``repoze.bfg`` model graph as an application under a
URL pathname that does not include the model path itself. For more
information, see the (new) "Virtual Hosting" chapter in the
documentation.
@@ -1854,7 +1964,7 @@ Features
--------
- You can now override the NotFound and Unauthorized responses that
- :mod:`repoze.bfg` generates when a view cannot be found or cannot be
+ ``repoze.bfg`` generates when a view cannot be found or cannot be
invoked due to lack of permission. See the "ZCML Hooks" chapter in
the docs for more information.
diff --git a/docs/narr/hybrid.rst b/docs/narr/hybrid.rst
index 48b2eedfc..34f606a97 100644
--- a/docs/narr/hybrid.rst
+++ b/docs/narr/hybrid.rst
@@ -259,9 +259,9 @@ application. Let's see what they are.
"Global" Views Match Any Route When A More Specific View Doesn't
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Note that views that *don't* mention a ``route_name`` will *also*
-match when *any* route matches. For example, the "bazbuz" view below
-will be found if the route named "abc" below is matched.
+Note that views that don't mention a ``route_name`` will *also* match
+when *any* route matches. For example, the "bazbuz" view below will
+be found if the route named "abc" below is matched.
.. code-block:: xml
@@ -323,7 +323,7 @@ name` to try to locate a view callable.
A view is registered for a ``route`` either as its default view via
the ``view=`` attribute of a ``route`` declaration in ZCML *or* as a
standalone ``<view>`` declaration (or via the ``@bfg_route``
-decorator) which has a ``route_name`` that matches the route's name).
+decorator) which has a ``route_name`` that matches the route's name.
At startup time, when such a registration is encountered, the view is
registered for the ``context`` type ``None`` (meaning *any* context)
and a *special* request type which is dynamically generated. This
@@ -463,9 +463,3 @@ statement ordering is very important, because routes are evaluated in
a specific order, unlike traversal, which depends on emergent behavior
rather than an ordered list of directives.
-A ``<route>`` Statement *Must* Precede Any ``<view>`` Statement Which Mentions It
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A ``<route>`` declaration *must* precede (in XML order) any ``<view>``
-declaration which names it as a ``route_name``. If it does not, at
-application startup time a ``ConfigurationError`` will be raised.
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index fdaea228f..dfae6e1b0 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -62,15 +62,22 @@ attributes are optional unless the description names them as required.
path
- The `route path
- <http://routes.groovie.org/manual.html#route-path>`_,
- e.g. ``ideas/:idea``. This attribute is required.
+ The path of the route e.g. ``ideas/:idea``. This attribute is
+ required. See :ref:`route_path_pattern_syntax` for information
+ about the syntax of route paths.
name
- The `route name
- <http://routes.groovie.org/manual.html#route-name>`_,
- e.g. ``myroute``. This attribute is required.
+ The name of the route, e.g. ``myroute``. This attribute is
+ required. It must be unique among all defined routes in a given
+ configuration.
+
+factory
+
+ The Python dotted-path name to a function that will generate a
+ :mod:`repoze.bfg` context object when this route matches.
+ e.g. ``mypackage.models.MyFactoryClass``. If this argument is not
+ specified, a default root factory will be used.
view
@@ -86,23 +93,79 @@ view_for
attribute is used. If this attribute is not specified, the default
(``None``) will be used.
-permission
+ If the ``view`` attribute is not provided, this attribute has no
+ effect.
- The permission name required to invoke the view.
- e.g. ``edit``. (see :ref:`using_security_with_urldispatch` for more
- information about permissions).
+ This attribute can also be spelled as ``for``.
-factory
+view_permission
- The Python dotted-path name to a function that will generate a
- :mod:`repoze.bfg` context object when this route matches.
- e.g. ``mypackage.models.MyFactoryClass``. If this argument is not
- specified, a default root factory will be used.
+ The permission name required to invoke the view associated with this
+ route. e.g. ``edit``. (see :ref:`using_security_with_urldispatch`
+ for more information about permissions).
+
+ If the ``view`` attribute is not provided, this attribute has no
+ effect.
+
+ This atribute can also be spelled as ``permission``.
+
+view_request_type
-request_type
+ A dotted Python name to an interface representing a :term:`request
+ type`. For backwards compatibility with :mod:`repoze.bfg` 1.0 and
+ before, this may also be a string naming an HTTP ``REQUEST_METHOD``
+ (any of ``GET``, ``POST``, ``HEAD``, ``DELETE``, ``PUT``). However,
+ these values should really be specified in ``request_method``. If
+ this argument is not specified, any request type will be considered
+ a match for the view associated with this route.
- A string representing an HTTP method name, e.g. ``GET`` or ``POST``
- or an interface representing a :term:`request type`.
+ If the ``view`` attribute is not provided, this attribute has no
+ effect.
+
+ This attribute can also be spelled as ``request_type``.
+
+view_request_method
+
+ A string representing an HTTP method name, e.g. ``GET``, ``POST``,
+ ``HEAD``, ``DELETE``, ``PUT``. If this argument is not specified
+ any request method will be considered a match for the view
+ associated with this route.
+
+ If the ``view`` attribute is not provided, this attribute has no
+ effect.
+
+ This attribute can also be spelled as ``request_method``.
+
+view_request_param
+
+ This value can be any string. A view declaration with this
+ attribute ensures that the associated view will only be called when
+ the request has a key in the ``request.params`` dictionary (an HTTP
+ ``GET`` or ``POST`` variable) that has a name which matches the
+ supplied value. If the value supplied to the attribute has a ``=``
+ sign in it, e.g. ``request_params="foo=123"``, then the key
+ (``foo``) must both exist in the ``request.params`` dictionary, and
+ the value must match the right hand side of the expression (``123``)
+ for the view to "match" the current request.
+
+ If the ``view`` attribute is not provided, this attribute has no
+ effect.
+
+ This attribute can also be spelled as ``request_param``.
+
+view_containment
+
+ This value should be a Python dotted-path string representing the
+ class that a graph traversal parent object of the :term:`context`
+ must be an instance of (or :term:`interface` that a parent object
+ must provide) in order for this view to be found and called. Your
+ models must be "location-aware" to use this feature. See
+ :ref:`location_aware` for more information about location-awareness.
+
+ If the ``view`` attribute is not provided, this attribute has no
+ effect.
+
+ This attribute can also be spelled as ``containment``.
The Matchdict
-------------
@@ -114,6 +177,8 @@ request named ``matchdict`` with the values that match patterns in the
``path`` element. If the URL pattern does not match, no matchdict is
generated.
+.. _route_path_pattern_syntax:
+
Path Pattern Syntax
--------------------
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index 389c4ddfc..28fe643d8 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -247,14 +247,34 @@ permission
call the view. See :ref:`view_security_section` for more
information about view security and permissions.
-request_type
+request_method
This value can either be one of the strings 'GET', 'POST', 'PUT',
- 'DELETE', or 'HEAD' representing an HTTP method, *or* it may be
- Python dotted-path string representing the :term:`interface` that
- the :term:`request` must have in order for this view to be found and
- called. See :ref:`view_request_types_section` for more information
- about request types.
+ 'DELETE', or 'HEAD' representing an HTTP ``REQUEST_METHOD``. A view
+ declaration with this attribute ensures that the view will only be
+ called when the request's ``method`` (aka ``REQUEST_METHOD``) string
+ matches the supplied value.
+
+request_param
+
+ This value can be any string. A view declaration with this
+ attribute ensures that the view will only be called when the request
+ has a key in the ``request.params`` dictionary (an HTTP ``GET`` or
+ ``POST`` variable) that has a name which matches the supplied value.
+ If the value supplied to the attribute has a ``=`` sign in it,
+ e.g. ``request_params="foo=123"``, then the key (``foo``) must both
+ exist in the ``request.params`` dictionary, and the value must match
+ the right hand side of the expression (``123``) for the view to
+ "match" the current request.
+
+containment
+
+ This value should be a Python dotted-path string representing the
+ class that a graph traversal parent object of the :term:`context`
+ must be an instance of (or :term:`interface` that a parent object
+ must provide) in order for this view to be found and called. Your
+ models must be "location-aware" to use this feature. See
+ :ref:`location_aware` for more information about location-awareness.
route_name
@@ -271,6 +291,69 @@ route_name
:term:`root factory`. See :ref:`hybrid_chapter` for more
information on using this advanced feature.
+request_type
+
+ This value should be a Python dotted-path string representing the
+ :term:`interface` that the :term:`request` must have in order for
+ this view to be found and called. See
+ :ref:`view_request_types_section` for more information about request
+ types. For backwards compatibility with :mod:`repoze.bfg` version
+ 1.0, this value may also be an HTTP ``REQUEST_METHOD`` string, e.g.
+ ('GET', 'HEAD', 'PUT', 'POST', or 'DELETE'). Passing request method
+ strings as a ``request_type`` is deprecated. Use the
+ ``request_method`` attribute instead for maximum forward
+ compatibility.
+
+.. _view_lookup_ordering:
+
+View Lookup Ordering
+--------------------
+
+Attributes of the ZCML ``view`` directive can be thought of like
+"narrowers" or "predicates". In general, the greater number of
+attributes possessed by a view directive, the more specific the
+circumstances need to be before the registered view will be called.
+
+For any given request, a view with five predicates will always be
+found and evaluated before a view with two, for example. All
+predicatese must match for the associated view to be called.
+
+This does not mean however, that :mod:`repoze.bfg` "stops looking"
+when it finds a view registration with predicates that don't match.
+If one set of view predicates does not match, the "next most specific"
+view (if any) view is consulted for predicates, and so on, until a
+view is found, or no view can be matched up with the request. The
+first view with a set of predicates all of which match the request
+environment will be invoked.
+
+If no view can be found which has predicates which allow it to be
+matched up with the request, :mod:`repoze.bfg` will return an error to
+the user's browser, representing a "not found" (404) page. See
+:ref:`changing_the_notfound_view` for more information about changing
+the default notfound view.
+
+There are a several exceptions to the the rule which says that ZCML
+directive attributes represent "narrowings". Several attributes of
+the ``view`` directive are *not* narrowing predicates. These are
+``permission`` and ``name``.
+
+The value of the ``permission`` attribute represents the permission
+that must be possessed by the user to invoke any found view. When a
+view is found that matches all predicates, but the invoking user does
+not possess the permission implied by any associated ``permission`` in
+the current context, processing stops, and an ``Unauthorized`` error
+is raised, usually resulting in a "forbidden" view being shown to the
+invoking user. No further view narrowing or view lookup is done.
+
+.. note::
+
+ See :ref:`changing_the_forbidden_view` for more information about
+ changing the default forbidden view.
+
+The value of the ``name`` attribute represents a direct match of the
+view name returned via traversal. It is part of intial view lookup
+rather than a predicate/narrower.
+
.. _mapping_views_to_urls_using_a_decorator_section:
Mapping Views to URLs Using a Decorator
@@ -281,7 +364,8 @@ more comfortable defining your view declarations using Python, you may
use the ``repoze.bfg.view.bfg_view`` decorator to associate your view
functions with URLs instead of using :term:`ZCML` for the same
purpose. ``repoze.bfg.view.bfg_view`` can be used to associate
-``for``, ``name``, ``permission`` and ``request_type`` information --
+``for``, ``name``, ``permission`` and ``request_method``,
+``containment``, ``request_param`` and ``request_type`` information --
as done via the equivalent ZCML -- with a function that acts as a
:mod:`repoze.bfg` view.
@@ -343,8 +427,9 @@ All arguments to ``bfg_view`` are optional.
If ``name`` is not supplied, the empty string is used (implying
the default view).
-If ``request_type`` is not supplied, the interface ``None`` is used,
-implying any request type.
+If ``request_type`` is not supplied, the value ``None`` is used,
+implying any request type. Otherwise, this should be a class or
+interface.
If ``for_`` is not supplied, the interface
``zope.interface.Interface`` (which matches any model) is used.
@@ -357,6 +442,21 @@ If ``route_name`` is supplied, the view will be invoked only if the
named route matches. *This is an advanced feature, not often used by
"civilians"*.
+If ``request_method`` is supplied, the view will be invoked only if
+the ``REQUEST_METHOD`` of the request matches the value.
+
+If ``request_param`` is supplied, the view will be invoked only if the
+``request.params`` data structure contains a key matching the value
+provided.
+
+If ``containment`` is supplied, the view will be invoked only if a
+location parent supplies the interface or class implied by the
+provided value.
+
+View lookup ordering for views registered with the ``bfg_view``
+decorator is the same as for those registered via ZCML. See
+:ref:`view_lookup_ordering` for more information.
+
All arguments may be omitted. For example:
.. code-block:: python
@@ -371,8 +471,8 @@ All arguments may be omitted. For example:
Such a registration as the one directly above implies that the view
name will be ``my_view``, registered ``for_`` any model type, using no
-permission, registered against requests which implement any request
-method or interface.
+permission, registered against requests with any request method /
+request type / request param / route name / containment.
If your view callable is a class, the ``bfg_view`` decorator can also
be used as a class decorator in Python 2.6 and better (Python 2.5 and
@@ -561,9 +661,10 @@ Custom View Request Types
You can make use of *custom* view request types by attaching an
:term:`interface` to the request and specifying this interface in the
-``request_type`` parameter. For example, you might want to make use
-of simple "content negotiation", only invoking a particular view if
-the request has a content-type of 'application/json'.
+``request_type`` parameter as a dotted Python name. For example, you
+might want to make use of simple "content negotiation", only invoking
+a particular view if the request has a content-type of
+'application/json'.
For information about using interface to specify a request type, see
:ref:`using_an_event_to_vary_the_request_type`.
diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py
index 779c0ef03..6a999a98c 100644
--- a/repoze/bfg/interfaces.py
+++ b/repoze/bfg/interfaces.py
@@ -6,20 +6,9 @@ from zope.component.interfaces import IObjectEvent
class IRequest(Interface):
""" Request type interface attached to all request objects """
-class IPOSTRequest(IRequest):
- """ Request type interface attached to POST requests"""
-
-class IGETRequest(IRequest):
- """ Request type interface attached to GET requests"""
-
-class IPUTRequest(IRequest):
- """ Request type interface attached to PUT requests"""
-
-class IDELETERequest(IRequest):
- """ Request type interface attached to DELETE requests"""
-
-class IHEADRequest(IRequest):
- """ Request type interface attached to HEAD requests"""
+class IRouteRequest(IRequest):
+ """ *internal only* interface used to mark a request when a route
+ matches. Not an API."""
class IResponseFactory(Interface):
""" A utility which generates a response factory """
@@ -36,7 +25,25 @@ class IResponse(Interface):
class IView(Interface):
def __call__(context, request):
- """ Must return an object that implements IResponse """
+ """ Must return an object that implements IResponse. May
+ optionally raise ``repoze.bfg.security.Unauthorized`` if an
+ authorization failure is detected during view execution."""
+
+class ISecuredView(IView):
+ """ Internal interface. Not an API. """
+ def __call_permissive__(context, request):
+ """ Guaranteed-permissive version of __call__ """
+
+ def __permitted__(context, request):
+ """ Return True if view execution will be permitted using the
+ context and request, False otherwise"""
+
+class IMultiView(ISecuredView):
+ """ *internal only*. A multiview is a secured view that is a
+ collection of other views. Each of the views is associated with
+ zero or more predicates. Not an API."""
+ def add(view, predicates, score):
+ """ Add a view to the multiview. """
class IRootFactory(Interface):
def __call__(environ):
@@ -227,10 +234,6 @@ class IAuthorizationPolicy(Interface):
def principals_allowed_by_permission(context, permission):
""" Return a set of principal identifiers allowed by the permission """
-class IRequestFactories(Interface):
- """ Marker utility interface representing a dictionary of request
- factory descriptions"""
-
class IPackageOverrides(Interface):
""" Utility for pkg_resources overrides """
diff --git a/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml b/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml
index 2ce917de8..418d04419 100644
--- a/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml
+++ b/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml
@@ -9,16 +9,15 @@
/>
<view
- for=".models.MyApp"
- view=".views.static_view"
- name="static"
- />
-
- <view
for=".models.MyModel"
view=".views.view_model"
/>
+ <static
+ name="static"
+ path="templates/static"
+ />
+
<subscriber for="repoze.bfg.interfaces.INewRequest"
handler=".run.handle_teardown"
/>
diff --git a/repoze/bfg/paster_templates/alchemy/+package+/views.py_tmpl b/repoze/bfg/paster_templates/alchemy/+package+/views.py_tmpl
index f34868ad1..2b176fb0d 100644
--- a/repoze/bfg/paster_templates/alchemy/+package+/views.py_tmpl
+++ b/repoze/bfg/paster_templates/alchemy/+package+/views.py_tmpl
@@ -1,7 +1,4 @@
from repoze.bfg.chameleon_zpt import render_template_to_response
-from repoze.bfg.view import static
-
-static_view = static('templates/static')
def view_root(context, request):
return render_template_to_response('templates/root.pt',
diff --git a/repoze/bfg/paster_templates/routesalchemy/+package+/configure.zcml b/repoze/bfg/paster_templates/routesalchemy/+package+/configure.zcml
index 14bb95cd6..f96a73ecf 100644
--- a/repoze/bfg/paster_templates/routesalchemy/+package+/configure.zcml
+++ b/repoze/bfg/paster_templates/routesalchemy/+package+/configure.zcml
@@ -12,10 +12,9 @@
view=".views.my_view"
/>
- <route
- path="/static/*subpath"
+ <static
name="static"
- view=".views.static_view"
+ path="templates/static"
/>
</configure>
diff --git a/repoze/bfg/paster_templates/routesalchemy/+package+/views.py_tmpl b/repoze/bfg/paster_templates/routesalchemy/+package+/views.py_tmpl
index c95b215ff..4b862ba61 100644
--- a/repoze/bfg/paster_templates/routesalchemy/+package+/views.py_tmpl
+++ b/repoze/bfg/paster_templates/routesalchemy/+package+/views.py_tmpl
@@ -1,11 +1,8 @@
from repoze.bfg.chameleon_zpt import render_template_to_response
-from repoze.bfg.view import static
from {{package}}.models import DBSession
from {{package}}.models import Model
-static_view = static('templates/static')
-
def my_view(request):
dbsession = DBSession()
root = dbsession.query(Model).filter(Model.name==u'root').first()
diff --git a/repoze/bfg/paster_templates/zodb/+package+/configure.zcml b/repoze/bfg/paster_templates/zodb/+package+/configure.zcml
index 89bf74525..aa98296c5 100644
--- a/repoze/bfg/paster_templates/zodb/+package+/configure.zcml
+++ b/repoze/bfg/paster_templates/zodb/+package+/configure.zcml
@@ -8,10 +8,9 @@
view=".views.my_view"
/>
- <view
- for=".models.MyModel"
- view=".views.static_view"
+ <static
name="static"
+ path="templates/static"
/>
</configure>
diff --git a/repoze/bfg/paster_templates/zodb/+package+/views.py_tmpl b/repoze/bfg/paster_templates/zodb/+package+/views.py_tmpl
index 9c5fe7a67..d9f0df378 100644
--- a/repoze/bfg/paster_templates/zodb/+package+/views.py_tmpl
+++ b/repoze/bfg/paster_templates/zodb/+package+/views.py_tmpl
@@ -1,7 +1,4 @@
from repoze.bfg.chameleon_zpt import render_template_to_response
-from repoze.bfg.view import static
-
-static_view = static('templates/static')
def my_view(context, request):
return render_template_to_response('templates/mytemplate.pt',
diff --git a/repoze/bfg/request.py b/repoze/bfg/request.py
index 932789e0a..9b29d3e1f 100644
--- a/repoze/bfg/request.py
+++ b/repoze/bfg/request.py
@@ -1,36 +1,14 @@
-from zope.component import getUtility
from zope.interface import implements
-from webob import Request as WebobRequest
-
-from zope.deprecation import deprecated
from zope.interface.interface import InterfaceClass
-from repoze.bfg.interfaces import IRequest
-from repoze.bfg.interfaces import IGETRequest
-from repoze.bfg.interfaces import IPOSTRequest
-from repoze.bfg.interfaces import IPUTRequest
-from repoze.bfg.interfaces import IDELETERequest
-from repoze.bfg.interfaces import IHEADRequest
-from repoze.bfg.interfaces import IRequestFactories
+from zope.component import queryUtility
-def request_factory(environ):
- try:
- method = environ['REQUEST_METHOD']
- except KeyError:
- method = None
-
- if 'bfg.routes.route' in environ:
- route = environ['bfg.routes.route']
- request_factories = getUtility(IRequestFactories, name=route.name or '')
- else:
- request_factories = DEFAULT_REQUEST_FACTORIES
+from webob import Request as WebobRequest
- try:
- request_factory = request_factories[method]['factory']
- except KeyError:
- request_factory = request_factories[None]['factory']
+from zope.deprecation import deprecated
- return request_factory(environ)
+from repoze.bfg.interfaces import IRequest
+from repoze.bfg.interfaces import IRouteRequest
def make_request_ascii(event):
""" An event handler that causes the request charset to be ASCII;
@@ -39,75 +17,26 @@ def make_request_ascii(event):
request = event.request
request.charset = None
-def named_request_factories(name=None):
- # We use 'precooked' Request subclasses that correspond to HTTP
- # request methods when returning a request object from
- # ``request_factory`` rather than using ``alsoProvides`` to attach
- # the proper interface to an unsubclassed webob.Request. This
- # pattern is purely an optimization (e.g. preventing calls to
- # ``alsoProvides`` means the difference between 590 r/s and 690
- # r/s on a MacBook 2GHz). This method should be never imported
- # directly by user code; it is *not* an API.
- if name is None:
- default_iface = IRequest
- get_iface = IGETRequest
- post_iface = IPOSTRequest
- put_iface = IPUTRequest
- delete_iface = IDELETERequest
- head_iface = IHEADRequest
- else:
- IC = InterfaceClass
- default_iface = IC('%s_IRequest' % name, (IRequest,))
- get_iface = IC('%s_IGETRequest' % name, (default_iface, IGETRequest))
- post_iface = IC('%s_IPOSTRequest' % name, (default_iface, IPOSTRequest))
- put_iface = IC('%s_IPUTRequest' % name, (default_iface, IPUTRequest))
- delete_iface = IC('%s_IDELETERequest' % name, (default_iface,
- IDELETERequest))
- head_iface = IC('%s_IHEADRequest' % name, (default_iface,
- IHEADRequest,))
-
- class Request(WebobRequest):
- implements(default_iface)
- charset = 'utf-8'
+class Request(WebobRequest):
+ implements(IRequest)
+ charset = 'utf-8'
- class GETRequest(WebobRequest):
- implements(get_iface)
- charset = 'utf-8'
-
- class POSTRequest(WebobRequest):
- implements(post_iface)
- charset = 'utf-8'
-
- class PUTRequest(WebobRequest):
- implements(put_iface)
- charset = 'utf-8'
-
- class DELETERequest(WebobRequest):
- implements(delete_iface)
- charset = 'utf-8'
+def request_factory(environ):
+ if 'bfg.routes.route' in environ:
+ route = environ['bfg.routes.route']
+ factory = queryUtility(IRouteRequest, name=route.name)
+ if factory is not None:
+ return factory(environ)
+ return Request(environ)
- class HEADRequest(WebobRequest):
- implements(head_iface)
+def create_route_request_factory(name):
+ iface = InterfaceClass('%s_IRequest' % name, (IRouteRequest,))
+
+ class RouteRequest(WebobRequest):
+ implements(iface)
charset = 'utf-8'
- factories = {
- IRequest:{'interface':default_iface, 'factory':Request},
- IGETRequest:{'interface':get_iface, 'factory':GETRequest},
- IPOSTRequest:{'interface':post_iface, 'factory':POSTRequest},
- IPUTRequest:{'interface':put_iface, 'factory':PUTRequest},
- IDELETERequest:{'interface':delete_iface, 'factory':DELETERequest},
- IHEADRequest:{'interface':head_iface, 'factory':HEADRequest},
- None:{'interface':default_iface, 'factory':Request},
- 'GET':{'interface':get_iface, 'factory':GETRequest},
- 'POST':{'interface':post_iface, 'factory':POSTRequest},
- 'PUT':{'interface':put_iface, 'factory':PUTRequest},
- 'DELETE':{'interface':delete_iface, 'factory':DELETERequest},
- 'HEAD':{'interface':head_iface, 'factory':HEADRequest},
- }
-
- return factories
-
-DEFAULT_REQUEST_FACTORIES = named_request_factories()
+ return RouteRequest
from repoze.bfg.threadlocal import get_current_request as get_request # b/c
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index 346e8f42f..d9502a435 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -12,18 +12,17 @@ from repoze.bfg.events import NewRequest
from repoze.bfg.events import NewResponse
from repoze.bfg.events import WSGIApplicationCreatedEvent
+from repoze.bfg.interfaces import IAuthorizationPolicy
+from repoze.bfg.interfaces import IAuthenticationPolicy
+from repoze.bfg.interfaces import IDefaultRootFactory
+from repoze.bfg.interfaces import IForbiddenView
from repoze.bfg.interfaces import ILogger
+from repoze.bfg.interfaces import INotFoundView
from repoze.bfg.interfaces import IRootFactory
from repoze.bfg.interfaces import IRouter
from repoze.bfg.interfaces import IRoutesMapper
from repoze.bfg.interfaces import ISettings
-from repoze.bfg.interfaces import IForbiddenView
-from repoze.bfg.interfaces import INotFoundView
from repoze.bfg.interfaces import IView
-from repoze.bfg.interfaces import IViewPermission
-from repoze.bfg.interfaces import IAuthorizationPolicy
-from repoze.bfg.interfaces import IAuthenticationPolicy
-from repoze.bfg.interfaces import IDefaultRootFactory
from repoze.bfg.log import make_stream_logger
@@ -32,7 +31,7 @@ from repoze.bfg.registry import populateRegistry
from repoze.bfg.request import request_factory
-from repoze.bfg.security import Allowed
+from repoze.bfg.security import Unauthorized
from repoze.bfg.settings import Settings
from repoze.bfg.settings import get_options
@@ -43,8 +42,9 @@ from repoze.bfg.traversal import _traverse
from repoze.bfg.urldispatch import RoutesRootFactory
-from repoze.bfg.view import default_forbidden_view
from repoze.bfg.view import default_notfound_view
+from repoze.bfg.view import default_forbidden_view
+from repoze.bfg.view import NotFound
_marker = object()
@@ -52,22 +52,19 @@ class Router(object):
""" The main repoze.bfg WSGI application. """
implements(IRouter)
- debug_authorization = False
debug_notfound = False
threadlocal_manager = manager
def __init__(self, registry):
self.registry = registry
self.logger = registry.queryUtility(ILogger, 'repoze.bfg.debug')
- self.forbidden_view = registry.queryUtility(
- IForbiddenView, default=default_forbidden_view)
self.notfound_view = registry.queryUtility(
INotFoundView, default=default_notfound_view)
+ self.forbidden_view = registry.queryUtility(
+ IForbiddenView, default=default_forbidden_view)
settings = registry.queryUtility(ISettings)
if settings is not None:
- self.debug_authorization = settings.debug_authorization
self.debug_notfound = settings.debug_notfound
- self.secured = not not registry.queryUtility(IAuthenticationPolicy)
self.root_factory = registry.queryUtility(IRootFactory,
default=DefaultRootFactory)
self.root_policy = self.root_factory # b/w compat
@@ -120,44 +117,10 @@ class Router(object):
'Non-response object returned from view %s: %r' %
(view_name, response))
- if self.secured:
- permitted = registry.queryMultiAdapter((context, request),
- IViewPermission,
- name=view_name)
- if permitted is None:
- if self.debug_authorization:
- permitted = Allowed(
- 'Allowed: view name %r against context %r (no '
- 'permission registered).' % (view_name, context))
- else:
- permitted = True
-
- else:
- if self.debug_authorization:
- permitted = Allowed(
- 'Allowed: view name %r against context %r (no '
- 'authentication policy in use).' % (view_name, context))
- else:
- permitted = True
-
- if self.debug_authorization:
- logger and logger.debug(
- 'debug_authorization of url %s (view name %r against '
- 'context %r): %s' % (request.url, view_name, context,
- permitted))
-
- if not permitted:
- if self.debug_authorization:
- msg = str(permitted)
- else:
- msg = 'Unauthorized: failed security policy check'
- environ['repoze.bfg.message'] = msg
- return respond(self.forbidden_view(context, request),
- '<IForbiddenView>')
-
+ provides = map(providedBy, (context, request))
view_callable = registry.adapters.lookup(
- map(providedBy, (context, request)), IView, name=view_name,
- default=None)
+ provides, IView, name=view_name, default=None)
+
if view_callable is None:
if self.debug_notfound:
@@ -175,7 +138,19 @@ class Router(object):
return respond(self.notfound_view(context, request),
'<INotFoundView>')
- response = view_callable(context, request)
+ try:
+ response = view_callable(context, request)
+ except Unauthorized, why:
+ msg = why[0]
+ environ = getattr(request, 'environ', {})
+ environ['repoze.bfg.message'] = msg
+ response = self.forbidden_view(context, request)
+ except NotFound, why:
+ msg = why[0]
+ environ = getattr(request, 'environ', {})
+ environ['repoze.bfg.message'] = msg
+ response = self.notfound_view(context, request)
+
return respond(response, view_name)
finally:
diff --git a/repoze/bfg/security.py b/repoze/bfg/security.py
index c11fea0b6..bb33435a0 100644
--- a/repoze/bfg/security.py
+++ b/repoze/bfg/security.py
@@ -1,14 +1,11 @@
-from zope.component import queryMultiAdapter
+from zope.component import getSiteManager
from zope.component import queryUtility
+from zope.component import providedBy
from zope.deprecation import deprecated
-from zope.interface import implements
-from zope.interface import classProvides
-
from repoze.bfg.interfaces import IAuthenticationPolicy
from repoze.bfg.interfaces import IAuthorizationPolicy
-from repoze.bfg.interfaces import IViewPermission
-from repoze.bfg.interfaces import IViewPermissionFactory
+from repoze.bfg.interfaces import ISecuredView
Everyone = 'system.Everyone'
Authenticated = 'system.Authenticated'
@@ -95,13 +92,14 @@ def view_execution_permitted(context, request, name=''):
``request``. Return a boolean result. If no authentication
policy is in effect, or if the view is not protected by a
permission, return True."""
- result = queryMultiAdapter((context, request), IViewPermission,
- name=name, default=None)
- if result is None:
+ sm = getSiteManager()
+ provides = map(providedBy, (context, request))
+ view = sm.adapters.lookup(provides, ISecuredView, name=name)
+ if view is None:
return Allowed(
'Allowed: view name %r in context %r (no permission defined)' %
(name, context))
- return result
+ return view.__permitted__(context, request)
def remember(request, principal, **kw):
""" Return a sequence of header tuples (e.g. ``[('Set-Cookie',
@@ -232,16 +230,6 @@ class ACLAllowed(ACLPermitsResult):
as the ``msg`` attribute."""
boolval = 1
-class ViewPermissionFactory(object):
- classProvides(IViewPermissionFactory)
- implements(IViewPermission)
-
- def __init__(self, permission_name):
- self.permission_name = permission_name
-
- def __call__(self, context, request):
- return has_permission(self.permission_name, context, request)
-
class Unauthorized(Exception):
pass
diff --git a/repoze/bfg/testing.py b/repoze/bfg/testing.py
index eebda54c8..99d3c5e8d 100644
--- a/repoze/bfg/testing.py
+++ b/repoze/bfg/testing.py
@@ -1,5 +1,7 @@
import copy
+from zope.deprecation import deprecated
+
from zope.interface import Interface
from zope.interface import implements
@@ -79,21 +81,40 @@ def registerDummyRenderer(path, renderer=None):
renderer = DummyTemplateRenderer()
return registerUtility(renderer, ITemplateRenderer, path)
-def registerView(name, result='', view=None, for_=(Interface, Interface)):
+def registerView(name, result='', view=None, for_=(Interface, Interface),
+ permission=None):
""" Registers ``repoze.bfg`` view function under the name
``name``. The view will return a webob Response object with the
``result`` value as its body attribute. To gain more control, if
you pass in a non-None ``view``, this view function will be used
instead of an automatically generated view function (and
- ``result`` is not used). This function is useful when dealing
- with code that wants to call,
+ ``result`` is not used). To protect the view using a permission,
+ pass in a non-``None`` value as ``permission``. This permission
+ will be checked by any existing security policy when view
+ execution is attempted. This function is useful when dealing with
+ code that wants to call,
e.g. ``repoze.bfg.view.render_view_to_response``."""
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import ISecuredView
+ from repoze.bfg.security import has_permission
+ from repoze.bfg.security import Unauthorized
if view is None:
def view(context, request):
from webob import Response
return Response(result)
- from repoze.bfg.interfaces import IView
- return registerAdapter(view, for_, IView, name)
+ if permission is None:
+ return registerAdapter(view, for_, IView, name)
+ else:
+ def _secure(context, request):
+ if not has_permission(permission, context, request):
+ raise Unauthorized('no permission')
+ else:
+ return view(context, request)
+ _secure.__call_permissive__ = view
+ def permitted(context, request):
+ return has_permission(permission, context, request)
+ _secure.__permitted__ = permitted
+ return registerAdapter(_secure, for_, ISecuredView, name)
def registerViewPermission(name, result=True, viewpermission=None,
for_=(Interface, Interface)):
@@ -108,7 +129,10 @@ def registerViewPermission(name, result=True, viewpermission=None,
used). This method is useful when dealing with code that
wants to call, e.g. ``repoze.bfg.view.view_execution_permitted``.
Note that view permissions are not checked unless a security
- policy is in effect (see ``registerSecurityPolicy``)."""
+ policy is in effect (see ``registerSecurityPolicy``).
+
+ **This function was deprecated in repoze.bfg 1.2.**
+ """
from repoze.bfg.security import Allowed
from repoze.bfg.security import Denied
if result is True:
@@ -121,6 +145,17 @@ def registerViewPermission(name, result=True, viewpermission=None,
from repoze.bfg.interfaces import IViewPermission
return registerAdapter(viewpermission, for_, IViewPermission, name)
+deprecated('registerViewPermission',
+ 'registerViewPermission has been deprecated. As of repoze.bfg '
+ 'version 1.2, view functions are now responsible for protecting '
+ 'their own execution. A call to this function wont prevent a '
+ 'view from being executed by the repoze.bfg router, nor '
+ 'will the ``repoze.bfg.security.view_execution_permitted`` function '
+ 'use the permission registered with this function. Instead,'
+ 'registering a view permission during testing, use the '
+ '``repoze.bfg.testing.registerView`` directive with a '
+ '``permission`` argument.')
+
def registerUtility(impl, iface=Interface, name=''):
""" Register a Zope component architecture utility component.
This is exposed as a convenience in this package to avoid needing
diff --git a/repoze/bfg/tests/test_integration.py b/repoze/bfg/tests/test_integration.py
index 14dd6a8ad..681dcf043 100644
--- a/repoze/bfg/tests/test_integration.py
+++ b/repoze/bfg/tests/test_integration.py
@@ -18,10 +18,6 @@ def wsgiapptest(environ, start_response):
""" """
return '123'
-def _getRequestInterface(name_or_iface=None):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES[name_or_iface]['interface']
-
class WGSIAppPlusBFGViewTests(unittest.TestCase):
def setUp(self):
cleanUp()
@@ -39,7 +35,8 @@ class WGSIAppPlusBFGViewTests(unittest.TestCase):
self.assertEqual(result, '123')
def test_scanned(self):
- IRequest = _getRequestInterface()
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IView
from repoze.bfg.zcml import scan
context = DummyContext()
@@ -48,9 +45,11 @@ class WGSIAppPlusBFGViewTests(unittest.TestCase):
actions = context.actions
self.assertEqual(len(actions), 1)
action = actions[0]
- self.assertEqual(action['args'],
- ('registerAdapter',
- wsgiapptest, (INothing, IRequest), IView, '', None))
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ view = sm.adapters.lookup((INothing, IRequest), IView, name='')
+ self.assertEqual(view, wsgiapptest)
here = os.path.dirname(__file__)
staticapp = static(os.path.join(here, 'fixtures'))
@@ -101,8 +100,8 @@ class TestGrokkedApp(unittest.TestCase):
def test_it(self):
import inspect
- from repoze.bfg.interfaces import IPOSTRequest
from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRequest
import repoze.bfg.tests.grokkedapp as package
from zope.configuration import config
from zope.configuration import xmlconfig
@@ -112,37 +111,25 @@ class TestGrokkedApp(unittest.TestCase):
xmlconfig.include(context, 'configure.zcml', package)
actions = context.actions
- post_iface = _getRequestInterface(IPOSTRequest)
- request_iface = _getRequestInterface()
-
postview = actions[-1]
self.assertEqual(postview[0][1], None)
self.assertEqual(postview[0][2], '')
- self.assertEqual(postview[0][3], post_iface)
+ self.assertEqual(postview[0][3], IRequest)
self.assertEqual(postview[0][4], IView)
- self.assertEqual(postview[2][1], package.grokked_post)
- self.assertEqual(postview[2][2], (None, post_iface))
- self.assertEqual(postview[2][3], IView)
klassview = actions[-2]
self.assertEqual(klassview[0][1], None)
self.assertEqual(klassview[0][2], 'grokked_klass')
- self.assertEqual(klassview[0][3], request_iface)
+ self.assertEqual(klassview[0][3], IRequest)
self.assertEqual(klassview[0][4], IView)
- self.assertEqual(klassview[2][1], package.grokked_klass)
- self.assertEqual(klassview[2][2], (None, request_iface))
- self.assertEqual(klassview[2][3], IView)
self.failUnless(inspect.isfunction(package.grokked_klass))
self.assertEqual(package.grokked_klass(None, None), None)
funcview = actions[-3]
self.assertEqual(funcview[0][1], None)
self.assertEqual(funcview[0][2], '')
- self.assertEqual(funcview[0][3], request_iface)
+ self.assertEqual(funcview[0][3], IRequest)
self.assertEqual(funcview[0][4], IView)
- self.assertEqual(funcview[2][1], package.grokked)
- self.assertEqual(funcview[2][2], (None, request_iface))
- self.assertEqual(funcview[2][3], IView)
class DummyContext:
pass
diff --git a/repoze/bfg/tests/test_request.py b/repoze/bfg/tests/test_request.py
index 5f61f4efc..8aeeff42d 100644
--- a/repoze/bfg/tests/test_request.py
+++ b/repoze/bfg/tests/test_request.py
@@ -12,7 +12,7 @@ class TestMakeRequestASCII(unittest.TestCase):
self._callFUT(event)
self.assertEqual(request.charset, None)
-class TestRequestSubclass(object):
+class RequestTestBase(object):
def _makeOne(self, environ):
request = self._getTargetClass()(environ)
return request
@@ -37,71 +37,22 @@ class TestRequestSubclass(object):
def test_class_implements(self):
from repoze.bfg.interfaces import IRequest
klass = self._getTargetClass()
- iface = self._getInterface()
- self.assertTrue(iface.implementedBy(klass))
self.assertTrue(IRequest.implementedBy(klass))
def test_instance_provides(self):
from repoze.bfg.interfaces import IRequest
inst = self._makeOne({})
- iface = self._getInterface()
- self.assertTrue(iface.providedBy(inst))
self.assertTrue(IRequest.providedBy(inst))
-
-class Test_Request(TestRequestSubclass, unittest.TestCase):
- def _getTargetClass(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES[None]['factory']
-
- def _getInterface(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES[None]['interface']
-
-class Test_GETRequest(TestRequestSubclass, unittest.TestCase):
- def _getTargetClass(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['GET']['factory']
-
- def _getInterface(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['GET']['interface']
-
-class Test_POSTRequest(TestRequestSubclass, unittest.TestCase):
- def _getTargetClass(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['POST']['factory']
-
- def _getInterface(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['POST']['interface']
-
-class Test_PUTRequest(TestRequestSubclass, unittest.TestCase):
- def _getTargetClass(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['PUT']['factory']
-
- def _getInterface(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['PUT']['interface']
-
-class Test_DELETERequest(TestRequestSubclass, unittest.TestCase):
- def _getTargetClass(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['DELETE']['factory']
-
- def _getInterface(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['DELETE']['interface']
-
-class Test_HEADRequest(TestRequestSubclass, unittest.TestCase):
- def _getTargetClass(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['HEAD']['factory']
-
- def _getInterface(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES['HEAD']['interface']
+class TestRequest(unittest.TestCase, RequestTestBase):
+ def _getTargetClass(self):
+ from repoze.bfg.request import Request
+ return Request
+
+class TestRouteRequest(unittest.TestCase, RequestTestBase):
+ def _getTargetClass(self):
+ from repoze.bfg.request import create_route_request_factory
+ return create_route_request_factory('abc')
class TestRequestFactory(unittest.TestCase):
def setUp(self):
@@ -114,187 +65,48 @@ class TestRequestFactory(unittest.TestCase):
from repoze.bfg.request import request_factory
return request_factory(environ)
- def _registerRequestFactories(self, name=''):
- from zope.component import getSiteManager
- from repoze.bfg.interfaces import IRequestFactories
- factories = {}
- def factory(environ):
- return environ
- for name in (None, 'GET', 'POST', 'PUT', 'DELETE', 'HEAD'):
- factories[name] = {'factory':factory}
- sm = getSiteManager()
- sm.registerUtility(factories, IRequestFactories, name=name)
- if name:
- sm.registerUtility(factories, IRequestFactories, name='')
-
- def _getRequestFactory(self, name_or_iface=None):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES[name_or_iface]['factory']
-
- def _makeRoute(self, name=None):
- route = DummyRoute(name)
- return route
-
- def test_no_route_no_request_method(self):
+ def test_it_no_route(self):
from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.request import Request
result = self._callFUT({})
- self.assertEqual(result.__class__, self._getRequestFactory())
- self.failUnless(IRequest.providedBy(result))
-
- def test_no_route_unknown(self):
- from repoze.bfg.interfaces import IRequest
- result = self._callFUT({'REQUEST_METHOD':'UNKNOWN'})
- self.assertEqual(result.__class__, self._getRequestFactory())
+ self.assertEqual(result.__class__, Request)
self.failUnless(IRequest.providedBy(result))
- def test_no_route_get(self):
- from repoze.bfg.interfaces import IGETRequest
- result = self._callFUT({'REQUEST_METHOD':'GET'})
- self.assertEqual(result.__class__, self._getRequestFactory('GET'))
- self.failUnless(IGETRequest.providedBy(result))
-
- def test_no_route_post(self):
- from repoze.bfg.interfaces import IPOSTRequest
- result = self._callFUT({'REQUEST_METHOD':'POST'})
- self.assertEqual(result.__class__, self._getRequestFactory('POST'))
- self.failUnless(IPOSTRequest.providedBy(result))
-
- def test_no_route_put(self):
- from repoze.bfg.interfaces import IPUTRequest
- result = self._callFUT({'REQUEST_METHOD':'PUT'})
- self.assertEqual(result.__class__, self._getRequestFactory('PUT'))
- self.failUnless(IPUTRequest.providedBy(result))
-
- def test_no_route_delete(self):
- from repoze.bfg.interfaces import IDELETERequest
- result = self._callFUT({'REQUEST_METHOD':'DELETE'})
- self.assertEqual(result.__class__, self._getRequestFactory('DELETE'))
- self.failUnless(IDELETERequest.providedBy(result))
-
- def test_no_route_head(self):
- from repoze.bfg.interfaces import IHEADRequest
- result = self._callFUT({'REQUEST_METHOD':'HEAD'})
- self.assertEqual(result.__class__, self._getRequestFactory('HEAD'))
- self.failUnless(IHEADRequest.providedBy(result))
-
- def test_route_no_request_method(self):
- self._registerRequestFactories()
- route = self._makeRoute()
- environ = {'bfg.routes.route':route}
- result = self._callFUT(environ)
- self.assertEqual(result, environ)
-
- def test_route_unknown(self):
- self._registerRequestFactories()
- route = self._makeRoute()
- environ = {'bfg.routes.route':route, 'REQUEST_METHOD':'UNKNOWN'}
- result = self._callFUT(environ)
- self.assertEqual(result, environ)
-
- def test_route_known(self):
- self._registerRequestFactories()
- route = self._makeRoute()
- environ = {'bfg.routes.route':route, 'REQUEST_METHOD':'GET'}
- result = self._callFUT(environ)
- self.assertEqual(result, environ)
-
-class TestNamedRequestFactories(unittest.TestCase):
+ def test_it_with_route_found(self):
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRouteRequest
+ sm = getSiteManager()
+ sm.registerUtility(DummyRequest, IRouteRequest, 'routename')
+ route = DummyRoute('routename')
+ result = self._callFUT({'bfg.routes.route':route})
+ self.assertEqual(result.__class__, DummyRequest)
+
+ def test_it_with_route_notfound(self):
+ from repoze.bfg.request import Request
+ route = DummyRoute('routename')
+ result = self._callFUT({'bfg.routes.route':route})
+ self.assertEqual(result.__class__, Request)
+
+class Test_create_route_request_factory(unittest.TestCase):
def _callFUT(self, name):
- from repoze.bfg.request import named_request_factories
- return named_request_factories(name)
-
- def test_it_unnamed(self):
- factories = self._callFUT(None)
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IGETRequest
- from repoze.bfg.interfaces import IPOSTRequest
- from repoze.bfg.interfaces import IPUTRequest
- from repoze.bfg.interfaces import IDELETERequest
- from repoze.bfg.interfaces import IHEADRequest
- for alias, iface in (
- (None, IRequest),
- ('GET', IGETRequest),
- ('POST', IPOSTRequest),
- ('PUT', IPUTRequest),
- ('DELETE', IDELETERequest),
- ('HEAD', IHEADRequest),
- ):
- self.failUnless(alias in factories)
- self.failUnless(iface in factories)
- self.assertEqual(factories[alias], factories[iface])
- named_iface = factories[alias]['interface']
- named_factory = factories[alias]['factory']
- default_iface = factories[None]['interface']
- self.assertEqual(factories[alias]['interface'], iface)
- self.assertEqual(factories[iface]['interface'], iface)
- self.assertEqual(factories[alias]['factory'].charset, 'utf-8')
- self.failUnless(named_iface.implementedBy(named_factory))
- self.failUnless(iface.implementedBy(named_factory))
- self.failUnless(IRequest.implementedBy(named_factory))
- self.failUnless(default_iface.implementedBy(named_factory))
+ from repoze.bfg.request import create_route_request_factory
+ return create_route_request_factory(name)
- def test_it_named(self):
- factories = self._callFUT('name')
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IGETRequest
- from repoze.bfg.interfaces import IPOSTRequest
- from repoze.bfg.interfaces import IPUTRequest
- from repoze.bfg.interfaces import IDELETERequest
- from repoze.bfg.interfaces import IHEADRequest
- for alias, iface in (
- (None, IRequest),
- ('GET', IGETRequest),
- ('POST', IPOSTRequest),
- ('PUT', IPUTRequest),
- ('DELETE', IDELETERequest),
- ('HEAD', IHEADRequest),
- ):
- self.failUnless(alias in factories)
- self.failUnless(iface in factories)
- self.assertEqual(factories[alias], factories[iface])
- self.assertEqual(factories[alias]['factory'].charset, 'utf-8')
- named_iface = factories[alias]['interface']
- named_factory = factories[alias]['factory']
- default_iface = factories[None]['interface']
- self.failUnless(named_iface.implementedBy(named_factory))
- self.failUnless(iface.implementedBy(named_factory))
- self.failUnless(IRequest.implementedBy(named_factory))
- self.failUnless(default_iface.implementedBy(named_factory))
-
-class TestDefaultRequestFactories(unittest.TestCase):
def test_it(self):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES as factories
+ from repoze.bfg.interfaces import IRouteRequest
from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IGETRequest
- from repoze.bfg.interfaces import IPOSTRequest
- from repoze.bfg.interfaces import IPUTRequest
- from repoze.bfg.interfaces import IDELETERequest
- from repoze.bfg.interfaces import IHEADRequest
- for alias, iface in (
- (None, IRequest),
- ('GET', IGETRequest),
- ('POST', IPOSTRequest),
- ('PUT', IPUTRequest),
- ('DELETE', IDELETERequest),
- ('HEAD', IHEADRequest),
- ):
- self.failUnless(alias in factories)
- self.failUnless(iface in factories)
- self.assertEqual(factories[alias], factories[iface])
- named_iface = factories[alias]['interface']
- named_factory = factories[alias]['factory']
- self.failUnless(named_iface.implementedBy(named_factory))
- self.assertEqual(factories[alias]['interface'], iface)
- self.assertEqual(factories[iface]['interface'], iface)
- self.assertEqual(factories[alias]['factory'].charset, 'utf-8')
-
+ factory = self._callFUT('routename')
+ self.failUnless(IRouteRequest.implementedBy(factory))
+ self.failUnless(IRequest.implementedBy(factory))
class DummyRoute:
def __init__(self, name):
- self.name=name
-
+ self.name = name
class DummyRequest:
- pass
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
class DummyNewRequestEvent:
def __init__(self, request):
diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py
index 566ffe4f1..a96765a01 100644
--- a/repoze/bfg/tests/test_router.py
+++ b/repoze/bfg/tests/test_router.py
@@ -33,12 +33,6 @@ class RouterTests(unittest.TestCase):
settings = Settings(**defaultkw)
self.registry.registerUtility(settings, ISettings)
- def _registerAuthenticationPolicy(self):
- from repoze.bfg.interfaces import IAuthenticationPolicy
- policy = DummyAuthenticationPolicy()
- self.registry.registerUtility(policy, IAuthenticationPolicy)
- return policy
-
def _registerTraverserFactory(self, context, view_name='', subpath=None,
traversed=None, virtual_root=None,
virtual_root_path=None, **kw):
@@ -75,20 +69,6 @@ class RouterTests(unittest.TestCase):
from repoze.bfg.interfaces import IView
self.registry.registerAdapter(app, for_, IView, name)
- def _registerViewPermission(self, view_name, allow=True):
- from zope.interface import Interface
- from repoze.bfg.interfaces import IViewPermission
- class Checker(object):
- def __call__(self, context, request):
- self.context = context
- self.request = request
- return allow
- checker = Checker()
- self.registry.registerAdapter(checker, (Interface, Interface),
- IViewPermission,
- view_name)
- return checker
-
def _registerEventListener(self, iface):
L = []
def listener(event):
@@ -239,31 +219,6 @@ class RouterTests(unittest.TestCase):
start_response = DummyStartResponse()
self.assertRaises(ValueError, router, environ, start_response)
- def test_iforbiddenview_returns_nonresponse(self):
- from repoze.bfg.interfaces import IForbiddenView
- from zope.interface import Interface
- from zope.interface import directlyProvides
- class IContext(Interface):
- pass
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- directlyProvides(context, IContext)
- self._registerTraverserFactory(context)
- self._registerAuthenticationPolicy()
- response = DummyResponse()
- view = DummyView(response)
- from repoze.bfg.security import ACLDenied
- denied = ACLDenied('ace', 'acl', 'permission', ['principals'], context)
- environ = self._makeEnviron()
- self._registerView(view, '', IContext, IRequest)
- checker = self._registerViewPermission('', denied)
- def app(context, request):
- """ """
- self.registry.registerUtility(app, IForbiddenView)
- router = self._makeOne()
- start_response = DummyStartResponse()
- self.assertRaises(ValueError, router, environ, start_response)
-
def test_call_view_registered_nonspecific_default_path(self):
context = DummyContext()
self._registerTraverserFactory(context)
@@ -369,72 +324,7 @@ class RouterTests(unittest.TestCase):
self.assertEqual(start_response.status, '404 Not Found')
self.failUnless('404' in result[0])
- def test_call_view_permission_none(self):
- from zope.interface import Interface
- from zope.interface import directlyProvides
- class IContext(Interface):
- pass
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- directlyProvides(context, IContext)
- self._registerTraverserFactory(context, subpath=[''])
- response = DummyResponse()
- view = DummyView(response)
- environ = self._makeEnviron()
- self._registerView(view, '', IContext, IRequest)
- router = self._makeOne()
- start_response = DummyStartResponse()
- result = router(environ, start_response)
- self.assertEqual(start_response.status, '200 OK')
-
- def test_call_view_no_authentication_policy_debug_authorization(self):
- logger = self._registerLogger()
- from zope.interface import Interface
- from zope.interface import directlyProvides
- class IContext(Interface):
- pass
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- directlyProvides(context, IContext)
- self._registerTraverserFactory(context, subpath=[''])
- response = DummyResponse()
- view = DummyView(response)
- environ = self._makeEnviron()
- self._registerView(view, '', IContext, IRequest)
- router = self._makeOne()
- router.debug_authorization = True
- start_response = DummyStartResponse()
- result = router(environ, start_response)
- self.assertEqual(start_response.status, '200 OK')
- self.assertEqual(len(logger.messages), 1)
- self.failUnless('no authentication policy' in logger.messages[0])
-
- def test_call_view_no_permission_registered_debug_authorization(self):
- self._registerAuthenticationPolicy()
- logger = self._registerLogger()
- from zope.interface import Interface
- from zope.interface import directlyProvides
- class IContext(Interface):
- pass
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- directlyProvides(context, IContext)
- self._registerTraverserFactory(context, subpath=[''])
- response = DummyResponse()
- view = DummyView(response)
- environ = self._makeEnviron()
- self._registerView(view, '', IContext, IRequest)
- router = self._makeOne()
- router.debug_authorization = True
- start_response = DummyStartResponse()
- result = router(environ, start_response)
- self.assertEqual(start_response.status, '200 OK')
- self.assertEqual(len(logger.messages), 1)
- self.failUnless('no permission registered' in logger.messages[0])
-
- def test_call_view_no_permission_registered_no_debug(self):
- self._registerAuthenticationPolicy()
- logger = self._registerLogger()
+ def test_call_view_raises_unauthorized(self):
from zope.interface import Interface
from zope.interface import directlyProvides
class IContext(Interface):
@@ -444,63 +334,16 @@ class RouterTests(unittest.TestCase):
directlyProvides(context, IContext)
self._registerTraverserFactory(context, subpath=[''])
response = DummyResponse()
- view = DummyView(response)
+ view = DummyView(response, raise_unauthorized=True)
environ = self._makeEnviron()
self._registerView(view, '', IContext, IRequest)
router = self._makeOne()
- router.debug_authorization = False
start_response = DummyStartResponse()
- result = router(environ, start_response)
- self.assertEqual(start_response.status, '200 OK')
- self.assertEqual(len(logger.messages), 0)
-
- def test_call_view_permission_succeeds(self):
- from zope.interface import Interface
- from zope.interface import directlyProvides
- class IContext(Interface):
- pass
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- directlyProvides(context, IContext)
- self._registerTraverserFactory(context, subpath=[''])
- self._registerAuthenticationPolicy()
- response = DummyResponse()
- view = DummyView(response)
- environ = self._makeEnviron()
- self._registerView(view, '', IContext, IRequest)
- checker = self._registerViewPermission('', True)
- router = self._makeOne()
- start_response = DummyStartResponse()
- result = router(environ, start_response)
- self.assertEqual(start_response.status, '200 OK')
- self.assertEqual(checker.context, context)
-
- def test_call_view_permission_fails_nosettings(self):
- from zope.interface import Interface
- from zope.interface import directlyProvides
- class IContext(Interface):
- pass
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- directlyProvides(context, IContext)
- self._registerTraverserFactory(context, subpath=[''])
- self._registerAuthenticationPolicy()
- response = DummyResponse()
- view = DummyView(response)
- from repoze.bfg.security import ACLDenied
- denied = ACLDenied('ace', 'acl', 'permission', ['principals'], context)
- environ = self._makeEnviron()
- self._registerView(view, '', IContext, IRequest)
- checker = self._registerViewPermission('', denied)
- router = self._makeOne()
- start_response = DummyStartResponse()
- result = router(environ, start_response)
+ response = router(environ, start_response)
self.assertEqual(start_response.status, '401 Unauthorized')
- message = environ['repoze.bfg.message']
- self.assertEqual(message, 'Unauthorized: failed security policy check')
- self.assertEqual(checker.context, context)
+ self.assertEqual(environ['repoze.bfg.message'], 'unauthorized')
- def test_call_view_permission_fails_no_debug_auth(self):
+ def test_call_view_raises_notfound(self):
from zope.interface import Interface
from zope.interface import directlyProvides
class IContext(Interface):
@@ -509,62 +352,15 @@ class RouterTests(unittest.TestCase):
context = DummyContext()
directlyProvides(context, IContext)
self._registerTraverserFactory(context, subpath=[''])
- self._registerAuthenticationPolicy()
response = DummyResponse()
- view = DummyView(response)
- from repoze.bfg.security import ACLDenied
- denied = ACLDenied('ace', 'acl', 'permission', ['principals'], context)
+ view = DummyView(response, raise_notfound=True)
environ = self._makeEnviron()
self._registerView(view, '', IContext, IRequest)
- checker = self._registerViewPermission('', denied)
- self._registerSettings(debug_authorization=False)
router = self._makeOne()
start_response = DummyStartResponse()
- result = router(environ, start_response)
- self.assertEqual(start_response.status, '401 Unauthorized')
- message = environ['repoze.bfg.message']
- self.failUnless('failed security policy check' in message)
- self.assertEqual(checker.context, context)
-
- def test_call_view_permission_fails_with_debug_auth(self):
- from zope.interface import Interface
- from zope.interface import directlyProvides
- class IContext(Interface):
- pass
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- directlyProvides(context, IContext)
- self._registerAuthenticationPolicy()
- self._registerTraverserFactory(context, subpath=[''])
- response = DummyResponse()
- view = DummyView(response)
- from repoze.bfg.security import ACLDenied
- environ = self._makeEnviron()
- self._registerView(view, '', IContext, IRequest)
- allowed = ACLDenied('ace', 'acl', 'permission', ['principals'], context)
- checker = self._registerViewPermission('', allowed)
- self._registerSettings(debug_authorization=True)
- logger = self._registerLogger()
- router = self._makeOne()
- start_response = DummyStartResponse()
- result = router(environ, start_response)
- self.assertEqual(start_response.status, '401 Unauthorized')
- message = environ['repoze.bfg.message']
- self.failUnless(
- "ACLDenied permission 'permission' via ACE 'ace' in ACL 'acl' "
- "on context" in message)
- self.failUnless("for principals ['principals']" in message)
- self.assertEqual(checker.context, context)
- self.assertEqual(len(logger.messages), 1)
- logged = logger.messages[0]
- self.failUnless(
- "debug_authorization of url http://localhost:8080/ (view name "
- "'' against context" in logged)
- self.failUnless(
- "ACLDenied permission 'permission' via ACE 'ace' in ACL 'acl' on "
- "context" in logged)
- self.failUnless(
- "for principals ['principals']" in logged)
+ response = router(environ, start_response)
+ self.assertEqual(start_response.status, '404 Not Found')
+ self.assertEqual(environ['repoze.bfg.message'], 'notfound')
def test_call_eventsends(self):
context = DummyContext()
@@ -601,65 +397,6 @@ class RouterTests(unittest.TestCase):
self.assertEqual(len(router.threadlocal_manager.pushed), 1)
self.assertEqual(len(router.threadlocal_manager.popped), 1)
- def test_call_post_method(self):
- from repoze.bfg.interfaces import INewRequest
- from repoze.bfg.interfaces import IPOSTRequest
- from repoze.bfg.interfaces import IPUTRequest
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- self._registerTraverserFactory(context)
- response = DummyResponse()
- response.app_iter = ['Hello world']
- view = DummyView(response)
- environ = self._makeEnviron(REQUEST_METHOD='POST')
- self._registerView(view, '', None, None)
- router = self._makeOne()
- start_response = DummyStartResponse()
- request_events = self._registerEventListener(INewRequest)
- result = router(environ, start_response)
- request = request_events[0].request
- self.failUnless(IPOSTRequest.providedBy(request))
- self.failIf(IPUTRequest.providedBy(request))
- self.failUnless(IRequest.providedBy(request))
-
- def test_call_put_method(self):
- from repoze.bfg.interfaces import INewRequest
- from repoze.bfg.interfaces import IPUTRequest
- from repoze.bfg.interfaces import IPOSTRequest
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- self._registerTraverserFactory(context)
- response = DummyResponse()
- response.app_iter = ['Hello world']
- view = DummyView(response)
- environ = self._makeEnviron(REQUEST_METHOD='PUT')
- self._registerView(view, '', None, None)
- router = self._makeOne()
- start_response = DummyStartResponse()
- request_events = self._registerEventListener(INewRequest)
- result = router(environ, start_response)
- request = request_events[0].request
- self.failUnless(IPUTRequest.providedBy(request))
- self.failIf(IPOSTRequest.providedBy(request))
- self.failUnless(IRequest.providedBy(request))
-
- def test_call_unknown_method(self):
- from repoze.bfg.interfaces import INewRequest
- from repoze.bfg.interfaces import IRequest
- context = DummyContext()
- self._registerTraverserFactory(context)
- response = DummyResponse()
- response.app_iter = ['Hello world']
- view = DummyView(response)
- environ = self._makeEnviron(REQUEST_METHOD='UNKNOWN')
- self._registerView(view, '', None, None)
- router = self._makeOne()
- start_response = DummyStartResponse()
- request_events = self._registerEventListener(INewRequest)
- result = router(environ, start_response)
- request = request_events[0].request
- self.failUnless(IRequest.providedBy(request))
-
class MakeAppTests(unittest.TestCase):
def setUp(self):
cleanUp()
@@ -917,10 +654,19 @@ class DummyContext:
pass
class DummyView:
- def __init__(self, response):
+ def __init__(self, response, raise_unauthorized=False,
+ raise_notfound=False):
self.response = response
+ self.raise_unauthorized = raise_unauthorized
+ self.raise_notfound = raise_notfound
def __call__(self, context, request):
+ if self.raise_unauthorized:
+ from repoze.bfg.security import Unauthorized
+ raise Unauthorized('unauthorized')
+ if self.raise_notfound:
+ from repoze.bfg.view import NotFound
+ raise NotFound('notfound')
return self.response
class DummyRootFactory:
diff --git a/repoze/bfg/tests/test_security.py b/repoze/bfg/tests/test_security.py
index bb1a54e04..e06386fdb 100644
--- a/repoze/bfg/tests/test_security.py
+++ b/repoze/bfg/tests/test_security.py
@@ -27,29 +27,6 @@ class TestAllPermissionsList(unittest.TestCase):
from repoze.bfg.security import ALL_PERMISSIONS
self.assertEqual(ALL_PERMISSIONS.__class__, self._getTargetClass())
-class TestViewPermissionFactory(unittest.TestCase):
- def setUp(self):
- cleanUp()
-
- def tearDown(self):
- cleanUp()
-
- def _getTargetClass(self):
- from repoze.bfg.security import ViewPermissionFactory
- return ViewPermissionFactory
-
- def _makeOne(self, *arg, **kw):
- klass = self._getTargetClass()
- return klass(*arg, **kw)
-
- def test_call(self):
- context = DummyContext()
- request = DummyRequest({})
- factory = self._makeOne('repoze.view')
- self.assertEqual(factory.permission_name, 'repoze.view')
- result = factory(context, request)
- self.assertEqual(result, True)
-
class TestAllowed(unittest.TestCase):
def _getTargetClass(self):
from repoze.bfg.security import Allowed
@@ -137,19 +114,19 @@ class TestViewExecutionPermitted(unittest.TestCase):
from repoze.bfg.security import view_execution_permitted
return view_execution_permitted(*arg, **kw)
- def _registerViewPermission(self, view_name, allow=True):
+ def _registerSecuredView(self, view_name, allow=True):
import zope.component
from zope.interface import Interface
- from repoze.bfg.interfaces import IViewPermission
+ from repoze.bfg.interfaces import ISecuredView
class Checker(object):
- def __call__(self, context, request):
+ def __permitted__(self, context, request):
self.context = context
self.request = request
return allow
checker = Checker()
gsm = zope.component.getGlobalSiteManager()
gsm.registerAdapter(checker, (Interface, Interface),
- IViewPermission,
+ ISecuredView,
view_name)
return checker
@@ -175,7 +152,7 @@ class TestViewExecutionPermitted(unittest.TestCase):
pass
context = DummyContext()
directlyProvides(context, IContext)
- checker = self._registerViewPermission('', True)
+ checker = self._registerSecuredView('', True)
request = DummyRequest({})
directlyProvides(request, IRequest)
result = self._callFUT(context, request, '')
diff --git a/repoze/bfg/tests/test_testing.py b/repoze/bfg/tests/test_testing.py
index 4ad3c83f6..e81a90219 100644
--- a/repoze/bfg/tests/test_testing.py
+++ b/repoze/bfg/tests/test_testing.py
@@ -4,9 +4,13 @@ import unittest
class TestTestingFunctions(unittest.TestCase):
def setUp(self):
cleanUp()
+ from zope.deprecation import __show__
+ __show__.off()
def tearDown(self):
cleanUp()
+ from zope.deprecation import __show__
+ __show__.on()
def test_registerDummySecurityPolicy(self):
from repoze.bfg import testing
@@ -143,34 +147,78 @@ class TestTestingFunctions(unittest.TestCase):
response = render_view_to_response(None, None, 'moo.html')
self.assertEqual(response.body, '123')
- def test_registerViewPermission_defaults(self):
+ def test_registerView_with_permission_denying(self):
+ from repoze.bfg import testing
+ from repoze.bfg.security import Unauthorized
+ def view(context, request):
+ """ """
+ view = testing.registerView('moo.html', view=view, permission='bar')
+ testing.registerDummySecurityPolicy(permissive=False)
+ import types
+ self.failUnless(isinstance(view, types.FunctionType))
+ from repoze.bfg.view import render_view_to_response
+ self.assertRaises(Unauthorized, render_view_to_response,
+ None, None, 'moo.html')
+
+ def test_registerView_with_permission_denying2(self):
+ from repoze.bfg import testing
from repoze.bfg.security import view_execution_permitted
+ def view(context, request):
+ """ """
+ view = testing.registerView('moo.html', view=view, permission='bar')
+ testing.registerDummySecurityPolicy(permissive=False)
+ import types
+ self.failUnless(isinstance(view, types.FunctionType))
+ result = view_execution_permitted(None, None, 'moo.html')
+ self.assertEqual(result, False)
+
+ def test_registerView_with_permission_allowing(self):
+ from repoze.bfg import testing
+ def view(context, request):
+ from webob import Response
+ return Response('123')
+ view = testing.registerView('moo.html', view=view, permission='bar')
+ testing.registerDummySecurityPolicy(permissive=True)
+ import types
+ self.failUnless(isinstance(view, types.FunctionType))
+ from repoze.bfg.view import render_view_to_response
+ result = render_view_to_response(None, None, 'moo.html')
+ self.assertEqual(result.app_iter, ['123'])
+
+ def test_registerViewPermission_defaults(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IViewPermission
from repoze.bfg import testing
view = testing.registerViewPermission('moo.html')
- testing.registerDummySecurityPolicy()
- result = view_execution_permitted(None, None, 'moo.html')
- self.failUnless(result)
- self.assertEqual(result.msg, 'message')
+ sm = getSiteManager()
+ result = sm.getMultiAdapter(
+ (Interface, Interface), IViewPermission, 'moo.html')
+ self.assertEqual(result, True)
def test_registerViewPermission_denying(self):
- from repoze.bfg.security import view_execution_permitted
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IViewPermission
from repoze.bfg import testing
view = testing.registerViewPermission('moo.html', result=False)
- testing.registerDummySecurityPolicy()
- result = view_execution_permitted(None, None, 'moo.html')
- self.failIf(result)
- self.assertEqual(result.msg, 'message')
+ sm = getSiteManager()
+ result = sm.getMultiAdapter(
+ (Interface, Interface), IViewPermission, 'moo.html')
+ self.assertEqual(result, False)
def test_registerViewPermission_custom(self):
- from repoze.bfg.security import view_execution_permitted
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IViewPermission
def viewperm(context, request):
return True
from repoze.bfg import testing
- view = testing.registerViewPermission('moo.html',
- viewpermission=viewperm)
- testing.registerDummySecurityPolicy()
- result = view_execution_permitted(None, None, 'moo.html')
- self.failUnless(result is True)
+ testing.registerViewPermission('moo.html', viewpermission=viewperm)
+ sm = getSiteManager()
+ result = sm.getMultiAdapter(
+ (Interface, Interface), IViewPermission, 'moo.html')
+ self.assertEqual(result, True)
def test_registerAdapter(self):
from zope.interface import implements
diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py
index 3c7d6f853..f496ebb36 100644
--- a/repoze/bfg/tests/test_view.py
+++ b/repoze/bfg/tests/test_view.py
@@ -15,28 +15,6 @@ class BaseTest(object):
from repoze.bfg.interfaces import IView
gsm.registerAdapter(app, for_, IView, name)
- def _registerViewPermission(self, view_name, allow=True):
- import zope.component
- from zope.interface import Interface
- from repoze.bfg.interfaces import IViewPermission
- class Checker(object):
- def __call__(self, context, request):
- self.context = context
- self.request = request
- return allow
- checker = Checker()
- gsm = zope.component.getGlobalSiteManager()
- gsm.registerAdapter(checker, (Interface, Interface),
- IViewPermission,
- view_name)
- return checker
-
- def _registerSecurityPolicy(self, secpol):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
- from repoze.bfg.interfaces import ISecurityPolicy
- gsm.registerUtility(secpol, ISecurityPolicy)
-
def _makeEnviron(self, **extras):
environ = {
'wsgi.url_scheme':'http',
@@ -61,7 +39,7 @@ class RenderViewToResponseTests(BaseTest, unittest.TestCase):
result = self._callFUT(context, request, name='notregistered')
self.assertEqual(result, None)
- def test_call_view_registered_secure_permission_disallows(self):
+ def test_call_view_registered_secure(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -70,20 +48,18 @@ class RenderViewToResponseTests(BaseTest, unittest.TestCase):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', False)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
- from repoze.bfg.security import Unauthorized
- self.assertRaises(Unauthorized, self._callFUT, context, request,
- name='registered', secure=True)
+ response = self._callFUT(context, request, name='registered',
+ secure=True)
+ self.assertEqual(response.status, '200 OK')
+
- def test_call_view_registered_secure_permission_allows(self):
+ def test_call_view_registered_insecure_no_call_permissive(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -92,20 +68,17 @@ class RenderViewToResponseTests(BaseTest, unittest.TestCase):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', True)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
response = self._callFUT(context, request, name='registered',
- secure=True)
+ secure=False)
self.assertEqual(response.status, '200 OK')
- def test_call_view_registered_insecure_permission_disallows(self):
+ def test_call_view_registered_insecure_with_call_permissive(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -114,11 +87,11 @@ class RenderViewToResponseTests(BaseTest, unittest.TestCase):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
+ def anotherview(context, request):
+ return DummyResponse('anotherview')
+ view.__call_permissive__ = anotherview
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', False)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
@@ -126,6 +99,7 @@ class RenderViewToResponseTests(BaseTest, unittest.TestCase):
response = self._callFUT(context, request, name='registered',
secure=False)
self.assertEqual(response.status, '200 OK')
+ self.assertEqual(response.app_iter, ['anotherview'])
class RenderViewToIterableTests(BaseTest, unittest.TestCase):
def _callFUT(self, *arg, **kw):
@@ -140,7 +114,7 @@ class RenderViewToIterableTests(BaseTest, unittest.TestCase):
result = self._callFUT(context, request, name='notregistered')
self.assertEqual(result, None)
- def test_call_view_registered_secure_permission_disallows(self):
+ def test_call_view_registered_secure(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -149,20 +123,17 @@ class RenderViewToIterableTests(BaseTest, unittest.TestCase):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', False)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
- from repoze.bfg.security import Unauthorized
- self.assertRaises(Unauthorized, self._callFUT, context, request,
- name='registered', secure=True)
+ iterable = self._callFUT(context, request, name='registered',
+ secure=True)
+ self.assertEqual(iterable, ())
- def test_call_view_registered_secure_permission_allows(self):
+ def test_call_view_registered_insecure_no_call_permissive(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -171,20 +142,17 @@ class RenderViewToIterableTests(BaseTest, unittest.TestCase):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', True)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
iterable = self._callFUT(context, request, name='registered',
- secure=True)
+ secure=False)
self.assertEqual(iterable, ())
- def test_call_view_registered_insecure_permission_disallows(self):
+ def test_call_view_registered_insecure_with_call_permissive(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -193,18 +161,18 @@ class RenderViewToIterableTests(BaseTest, unittest.TestCase):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
+ def anotherview(context, request):
+ return DummyResponse('anotherview')
+ view.__call_permissive__ = anotherview
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', False)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
iterable = self._callFUT(context, request, name='registered',
secure=False)
- self.assertEqual(iterable, ())
+ self.assertEqual(iterable, ['anotherview'])
class RenderViewTests(unittest.TestCase, BaseTest):
def _callFUT(self, *arg, **kw):
@@ -219,7 +187,7 @@ class RenderViewTests(unittest.TestCase, BaseTest):
result = self._callFUT(context, request, name='notregistered')
self.assertEqual(result, None)
- def test_call_view_registered_secure_permission_disallows(self):
+ def test_call_view_registered_secure(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -228,20 +196,16 @@ class RenderViewTests(unittest.TestCase, BaseTest):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', False)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
- from repoze.bfg.security import Unauthorized
- self.assertRaises(Unauthorized, self._callFUT, context, request,
- name='registered', secure=True)
+ s = self._callFUT(context, request, name='registered', secure=True)
+ self.assertEqual(s, '')
- def test_call_view_registered_secure_permission_allows(self):
+ def test_call_view_registered_insecure_no_call_permissive(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -250,19 +214,16 @@ class RenderViewTests(unittest.TestCase, BaseTest):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', True)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
- s = self._callFUT(context, request, name='registered', secure=True)
+ s = self._callFUT(context, request, name='registered', secure=False)
self.assertEqual(s, '')
- def test_call_view_registered_insecure_permission_disallows(self):
+ def test_call_view_registered_insecure_with_call_permissive(self):
context = DummyContext()
from zope.interface import Interface
from zope.interface import directlyProvides
@@ -271,17 +232,17 @@ class RenderViewTests(unittest.TestCase, BaseTest):
pass
directlyProvides(context, IContext)
response = DummyResponse()
- secpol = DummySecurityPolicy()
view = make_view(response)
+ def anotherview(context, request):
+ return DummyResponse('anotherview')
+ view.__call_permissive__ = anotherview
self._registerView(view, 'registered', IContext, IRequest)
- self._registerSecurityPolicy(secpol)
- self._registerViewPermission('registered', False)
environ = self._makeEnviron()
from webob import Request
request = Request(environ)
directlyProvides(request, IRequest)
s = self._callFUT(context, request, name='registered', secure=False)
- self.assertEqual(s, '')
+ self.assertEqual(s, 'anotherview')
class TestIsResponse(unittest.TestCase):
def _callFUT(self, *arg, **kw):
@@ -506,6 +467,461 @@ class TestDefaultNotFoundView(unittest.TestCase):
self.assertEqual(response.status, '404 Not Found')
self.failUnless('<code>abc&amp;123</code>' in response.body)
+class TestMultiView(unittest.TestCase):
+ def _getTargetClass(self):
+ from repoze.bfg.view import MultiView
+ return MultiView
+
+ def _makeOne(self, name='name'):
+ return self._getTargetClass()(name)
+
+ def test_class_implements_ISecuredView(self):
+ from zope.interface.verify import verifyClass
+ from repoze.bfg.interfaces import ISecuredView
+ verifyClass(ISecuredView, self._getTargetClass())
+
+ def test_instance_implements_ISecuredView(self):
+ from zope.interface.verify import verifyObject
+ from repoze.bfg.interfaces import ISecuredView
+ verifyObject(ISecuredView, self._makeOne())
+
+ def test_add(self):
+ mv = self._makeOne()
+ mv.add('view', 100)
+ self.assertEqual(mv.views, [(100, 'view')])
+ mv.add('view2', 99)
+ self.assertEqual(mv.views, [(99, 'view2'), (100, 'view')])
+
+ def test_match_not_found(self):
+ from repoze.bfg.view import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv.match, context, request)
+
+ def test_match_predicate_fails(self):
+ from repoze.bfg.view import NotFound
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ view.__predicated__ = lambda *arg: False
+ mv.views = [(100, view)]
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv.match, context, request)
+
+ def test_match_predicate_succeeds(self):
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ view.__predicated__ = lambda *arg: True
+ mv.views = [(100, view)]
+ context = DummyContext()
+ request = DummyRequest()
+ result = mv.match(context, request)
+ self.assertEqual(result, view)
+
+ def test_permitted_no_views(self):
+ from repoze.bfg.view import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv.__permitted__, context, request)
+
+ def test_permitted_no_match_with__permitted__(self):
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ mv.views = [(100, view)]
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertEqual(mv.__permitted__(None, None), True)
+
+ def test_permitted(self):
+ from zope.component import getSiteManager
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ def permitted(context, request):
+ return False
+ view.__permitted__ = permitted
+ mv.views = [(100, view)]
+ context = DummyContext()
+ request = DummyRequest()
+ sm = getSiteManager()
+ result = mv.__permitted__(context, request)
+ self.assertEqual(result, False)
+
+ def test__call__not_found(self):
+ from repoze.bfg.view import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv, context, request)
+
+ def test___call__intermediate_not_found(self):
+ from repoze.bfg.view import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view1(context, request):
+ raise NotFound
+ def view2(context, request):
+ return expected_response
+ mv.views = [(100, view1), (99, view2)]
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test___call__(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view(context, request):
+ return expected_response
+ mv.views = [(100, view)]
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test__call_permissive__not_found(self):
+ from repoze.bfg.view import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv, context, request)
+
+ def test___call_permissive_has_call_permissive(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view(context, request):
+ """ """
+ def permissive(context, request):
+ return expected_response
+ view.__call_permissive__ = permissive
+ mv.views = [(100, view)]
+ response = mv.__call_permissive__(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test___call_permissive_has_no_call_permissive(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view(context, request):
+ return expected_response
+ mv.views = [(100, view)]
+ response = mv.__call_permissive__(context, request)
+ self.assertEqual(response, expected_response)
+
+class TestMapView(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _callFUT(self, view, *arg, **kw):
+ from repoze.bfg.view import map_view
+ return map_view(view, *arg, **kw)
+
+ def test_view_as_function_context_and_request(self):
+ def view(context, request):
+ return 'OK'
+ result = self._callFUT(view)
+ self.failUnless(result is view)
+ self.assertEqual(view(None, None), 'OK')
+
+ def test_view_as_function_requestonly(self):
+ def view(request):
+ return 'OK'
+ result = self._callFUT(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')
+
+ 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)
+ 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')
+
+ def test_view_as_newstyle_class_requestonly(self):
+ class view(object):
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ result = self._callFUT(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')
+
+ def test_view_as_oldstyle_class_context_and_request(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ result = self._callFUT(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')
+
+ def test_view_as_oldstyle_class_requestonly(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ result = self._callFUT(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')
+
+ def test_view_as_instance_context_and_request(self):
+ class View:
+ def __call__(self, context, request):
+ return 'OK'
+ view = View()
+ result = self._callFUT(view)
+ self.failUnless(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test_view_as_instance_requestonly(self):
+ class View:
+ def __call__(self, request):
+ return 'OK'
+ view = View()
+ result = self._callFUT(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')
+
+class TestRequestOnly(unittest.TestCase):
+ def _callFUT(self, arg):
+ from repoze.bfg.view import requestonly
+ return requestonly(arg)
+
+ def test_newstyle_class_no_init(self):
+ class foo(object):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_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):
+ class foo(object):
+ def __init__(self, request):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_onearg_named_somethingelse(self):
+ class foo(object):
+ def __init__(self, req):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_defaultargs_firstname_not_request(self):
+ class foo(object):
+ def __init__(self, context, request=None):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_newstyle_class_init_defaultargs_firstname_request(self):
+ class foo(object):
+ def __init__(self, request, foo=1, bar=2):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_noargs(self):
+ class foo(object):
+ def __init__():
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_no_init(self):
+ class foo:
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_toomanyargs(self):
+ class foo:
+ def __init__(self, context, request):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_onearg_named_request(self):
+ class foo:
+ def __init__(self, request):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_oldstyle_class_init_onearg_named_somethingelse(self):
+ class foo:
+ def __init__(self, req):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_oldstyle_class_init_defaultargs_firstname_not_request(self):
+ class foo:
+ def __init__(self, context, request=None):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_defaultargs_firstname_request(self):
+ class foo:
+ def __init__(self, request, foo=1, bar=2):
+ """ """
+ self.assertTrue(self._callFUT(foo), True)
+
+ def test_oldstyle_class_init_noargs(self):
+ class foo:
+ def __init__():
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_toomanyargs(self):
+ def foo(context, request):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_onearg_named_request(self):
+ def foo(request):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_function_onearg_named_somethingelse(self):
+ def foo(req):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_function_defaultargs_firstname_not_request(self):
+ def foo(context, request=None):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_defaultargs_firstname_request(self):
+ def foo(request, foo=1, bar=2):
+ """ """
+ self.assertTrue(self._callFUT(foo), True)
+
+ def test_instance_toomanyargs(self):
+ class Foo:
+ def __call__(self, context, request):
+ """ """
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_defaultargs_onearg_named_request(self):
+ class Foo:
+ def __call__(self, request):
+ """ """
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo))
+
+ def test_instance_defaultargs_onearg_named_somethingelse(self):
+ class Foo:
+ def __call__(self, req):
+ """ """
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo))
+
+ def test_instance_defaultargs_firstname_not_request(self):
+ class Foo:
+ def __call__(self, context, request=None):
+ """ """
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_defaultargs_firstname_request(self):
+ class Foo:
+ def __call__(self, request, foo=1, bar=2):
+ """ """
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo), True)
+
+ def test_instance_nocall(self):
+ class Foo: pass
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+class TestDecorateView(unittest.TestCase):
+ def _callFUT(self, wrapped, original):
+ from repoze.bfg.view import decorate_view
+ return decorate_view(wrapped, original)
+
+ def test_it_same(self):
+ def view(context, request):
+ """ """
+ result = self._callFUT(view, view)
+ self.assertEqual(result, False)
+
+ def test_it_different(self):
+ class DummyView1:
+ """ 1 """
+ __name__ = '1'
+ __module__ = '1'
+ def __call__(self, context, request):
+ """ """
+ def __call_permissive__(self, context, reuqest):
+ """ """
+ def __predicated__(self, context, reuqest):
+ """ """
+ def __permitted__(self, context, request):
+ """ """
+ class DummyView2:
+ """ 2 """
+ __name__ = '2'
+ __module__ = '2'
+ def __call__(self, context, request):
+ """ """
+ def __call_permissive__(self, context, reuqest):
+ """ """
+ def __predicated__(self, context, reuqest):
+ """ """
+ def __permitted__(self, context, request):
+ """ """
+ view1 = DummyView1()
+ view2 = DummyView2()
+ result = self._callFUT(view1, view2)
+ self.assertEqual(result, True)
+ self.failUnless(view1.__doc__ is view2.__doc__)
+ self.failUnless(view1.__module__ is view2.__module__)
+ self.failUnless(view1.__name__ is view2.__name__)
+ self.failUnless(view1.__call_permissive__.im_func is
+ view2.__call_permissive__.im_func)
+ self.failUnless(view1.__permitted__.im_func is
+ view2.__permitted__.im_func)
+ self.failUnless(view1.__predicated__.im_func is
+ view2.__predicated__.im_func)
class DummyContext:
pass
@@ -531,8 +947,9 @@ def make_view(response):
class DummyResponse:
status = '200 OK'
headerlist = ()
- app_iter = ()
-
-class DummySecurityPolicy:
- pass
-
+ def __init__(self, body=None):
+ if body is None:
+ self.app_iter = ()
+ else:
+ self.app_iter = [body]
+
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index 49baa3a34..fdf8fa9e3 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -20,185 +20,144 @@ class TestViewDirective(unittest.TestCase):
'repoze.view', None)
def test_view_as_function(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
context = DummyContext()
- class IFoo:
+ class IFoo(Interface):
pass
view = lambda *arg: None
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- self.assertEqual(regadapt['args'][1], view)
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ self.failUnless(wrapper)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
def test_view_as_function_requestonly(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+
context = DummyContext()
def view(request):
return 'OK'
- class IFoo:
+ class IFoo(Interface):
pass
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
-
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- wrapper = regadapt['args'][1]
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
self.failIfEqual(wrapper, view)
self.assertEqual(wrapper.__module__, view.__module__)
self.assertEqual(wrapper.__name__, view.__name__)
self.assertEqual(wrapper.__doc__, view.__doc__)
result = wrapper(None, None)
self.assertEqual(result, 'OK')
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
def test_view_as_instance(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+
context = DummyContext()
class AView:
def __call__(self, context, request):
""" """
view = AView()
- class IFoo:
+ class IFoo(Interface):
pass
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
+ self.assertEqual(len(actions), 1)
- self.assertEqual(len(actions), 2)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ self.failUnless(wrapper)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- self.assertEqual(regadapt['args'][1], view)
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
def test_view_as_instance_requestonly(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+
context = DummyContext()
class AView:
def __call__(self, request):
return 'OK'
view = AView()
- class IFoo:
+ class IFoo(Interface):
pass
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
-
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- wrapper = regadapt['args'][1]
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
self.failIfEqual(wrapper, view)
self.assertEqual(wrapper.__module__, view.__module__)
self.failUnless('instance' in wrapper.__name__)
self.assertEqual(wrapper.__doc__, view.__doc__)
result = wrapper(None, None)
self.assertEqual(result, 'OK')
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
def test_view_as_oldstyle_class(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
context = DummyContext()
- class IFoo:
+ class IFoo(Interface):
pass
class view:
def __init__(self, context, request):
@@ -209,47 +168,36 @@ class TestViewDirective(unittest.TestCase):
return self
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- wrapper = regadapt['args'][1]
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
self.assertEqual(wrapper.__module__, view.__module__)
self.assertEqual(wrapper.__name__, view.__name__)
self.assertEqual(wrapper.__doc__, view.__doc__)
result = wrapper(None, None)
self.assertEqual(result.context, None)
self.assertEqual(result.request, None)
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
def test_view_as_oldstyle_class_requestonly(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+
context = DummyContext()
- class IFoo:
+ class IFoo(Interface):
pass
class view:
def __init__(self, request):
@@ -259,46 +207,35 @@ class TestViewDirective(unittest.TestCase):
return self
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
-
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- wrapper = regadapt['args'][1]
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
self.assertEqual(wrapper.__module__, view.__module__)
self.assertEqual(wrapper.__name__, view.__name__)
self.assertEqual(wrapper.__doc__, view.__doc__)
result = wrapper(None, None)
self.assertEqual(result.request, None)
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
+
def test_view_as_newstyle_class(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+
context = DummyContext()
- class IFoo:
+ class IFoo(Interface):
pass
class view(object):
def __init__(self, context, request):
@@ -309,47 +246,35 @@ class TestViewDirective(unittest.TestCase):
return self
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
-
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- wrapper = regadapt['args'][1]
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
self.assertEqual(wrapper.__module__, view.__module__)
self.assertEqual(wrapper.__name__, view.__name__)
self.assertEqual(wrapper.__doc__, view.__doc__)
result = wrapper(None, None)
self.assertEqual(result.context, None)
self.assertEqual(result.request, None)
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
def test_view_as_newstyle_class_requestonly(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+
context = DummyContext()
- class IFoo:
+ class IFoo(Interface):
pass
class view(object):
def __init__(self, request):
@@ -359,170 +284,470 @@ class TestViewDirective(unittest.TestCase):
return self
self._callFUT(context, 'repoze.view', IFoo, view=view)
actions = context.actions
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
-
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- wrapper = regadapt['args'][1]
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
self.assertEqual(wrapper.__module__, view.__module__)
self.assertEqual(wrapper.__name__, view.__name__)
self.assertEqual(wrapper.__doc__, view.__doc__)
result = wrapper(None, None)
self.assertEqual(result.request, None)
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
+
def test_request_type_asinterface(self):
- context = DummyContext()
- class IFoo:
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+ class IRequest(Interface):
+ pass
+ class IFoo(Interface):
pass
+ context = DummyContext(IRequest)
view = lambda *arg: None
self._callFUT(context, 'repoze.view', IFoo, view=view,
request_type=IDummy)
actions = context.actions
+
+ self.assertEqual(len(actions), 1)
+
+ action = actions[0]
+ discrim = ('view', IFoo, '', IDummy, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IDummy), IView, name='')
+ self.failUnless(wrapper)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
+
+ def test_request_type_as_noninterface(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from zope.interface import implementedBy
from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
+ class IFoo(Interface):
+ pass
+ class Dummy:
+ pass
+ context = DummyContext(Dummy)
+ view = lambda *arg: None
+ self._callFUT(context, 'repoze.view', IFoo, view=view,
+ request_type=Dummy)
+ actions = context.actions
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', DummyModule,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, DummyModule))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', DummyModule, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- self.assertEqual(regadapt['args'][1], view)
- self.assertEqual(regadapt['args'][2], (IFoo, DummyModule))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ action = actions[0]
+ discrim = ('view', IFoo, '', Dummy, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ iface = implementedBy(Dummy)
+ wrapper = sm.adapters.lookup((IFoo, iface), IView, name='')
+ self.failUnless(wrapper)
+ self.failIf(hasattr(wrapper, '__call_permissive__'))
def test_request_type_ashttpmethod(self):
+ from zope.interface import Interface
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRequest
context = DummyContext()
- class IFoo:
+ class IFoo(Interface):
pass
view = lambda *arg: None
self._callFUT(context, 'repoze.view', IFoo, view=view,
request_type='GET')
actions = context.actions
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IGETRequest
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- self.assertEqual(permission['args'][2], (IFoo, IGETRequest))
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IDummy, IView)
- self.assertEqual(regadapt['args'][2], (IFoo, IGETRequest))
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, 'GET', None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ request.method = 'GET'
+ self.assertEqual(wrapper.__predicated__(None, request), True)
+ request.method = 'POST'
+ self.assertEqual(wrapper.__predicated__(None, request), False)
+
def test_request_type_asinterfacestring(self):
- context = DummyContext()
- class IFoo:
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IViewPermission
+ class IFoo(Interface):
+ pass
+ class IRequest(Interface):
pass
+ context = DummyContext(IRequest)
view = lambda *arg: None
self._callFUT(context, 'repoze.view', IFoo, view=view,
request_type='whatever')
actions = context.actions
- from repoze.bfg.interfaces import IView
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
- permission = actions[0]
- self.assertEqual(permission['args'][2], (IFoo, DummyModule))
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', DummyModule, IView)
- self.assertEqual(regadapt['args'][2], (IFoo, DummyModule))
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(actions[0]['discriminator'], discrim)
+ register = actions[0]['callable']
+ register()
+ sm = getSiteManager()
+ regview = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ self.assertEqual(view, regview)
+ self.failIf(hasattr(view, '__call_permissive__'))
+
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, None)
def test_with_route_name(self):
+ from zope.interface import Interface
+ from zope.interface import implementedBy
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
+ class IFoo(Interface):
+ pass
+ context = DummyContext()
+ view = lambda *arg: '123'
+ self._callFUT(context, 'repoze.view', IFoo, view=view, route_name='foo')
+ actions = context.actions
+
+ self.assertEqual(len(actions), 1)
+
+ action = actions[0]
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ factory = sm.getUtility(IRouteRequest, 'foo')
+ request_type = implementedBy(factory)
+ discrim = ('view', IFoo, '', request_type, IView, None, None, None,
+ 'foo')
+ self.assertEqual(action['discriminator'], discrim)
+ the_view = sm.adapters.lookup((IFoo, request_type), IView, name='')
+ request = factory({})
+ self.assertEqual(the_view(None, request), '123')
+
+ def test_with_request_method_true(self):
from zope.component import getSiteManager
- from repoze.bfg.interfaces import IRequestFactories
- class IFoo:
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ context = DummyContext()
+ class IFoo(Interface):
pass
- class IDummyRequest:
+ view = lambda *arg: None
+ sm = getSiteManager()
+ def view(context, request):
+ return '123'
+ self._callFUT(context, None, IFoo, view=view, request_method='POST')
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, 'POST', None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ request.method = 'POST'
+ self.assertEqual(wrapper(None, request), '123')
+
+ def test_with_request_method_false(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.view import NotFound
+ context = DummyContext()
+ class IFoo(Interface):
pass
+ view = lambda *arg: None
+ sm = getSiteManager()
+ def view(context, request):
+ """ """
+ self._callFUT(context, None, IFoo, view=view, request_method='POST')
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, 'POST', None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ request.method = 'GET'
+ self.assertRaises(NotFound, wrapper, None, request)
+
+ def test_with_request_param_noval_true(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
context = DummyContext()
- factories = {None:{'interface':IDummyRequest}}
+ class IFoo(Interface):
+ pass
+ view = lambda *arg: None
sm = getSiteManager()
- sm.registerUtility(factories, IRequestFactories, name='foo')
+ def view(context, request):
+ return '123'
+ self._callFUT(context, None, IFoo, view=view, request_param='abc')
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, 'abc', None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ request.params = {'abc':''}
+ self.assertEqual(wrapper(None, request), '123')
+
+ def test_with_request_param_noval_false(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.view import NotFound
+ context = DummyContext()
+ class IFoo(Interface):
+ pass
view = lambda *arg: None
- self._callFUT(context, 'repoze.view', IFoo, view=view, route_name='foo')
+ sm = getSiteManager()
+ def view(context, request):
+ """ """
+ self._callFUT(context, None, IFoo, view=view, request_param='abc')
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, 'abc', None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ request.params = {}
+ self.assertRaises(NotFound, wrapper, None, request)
+
+ def test_with_request_paramoval_true(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ context = DummyContext()
+ class IFoo(Interface):
+ pass
+ view = lambda *arg: None
+ sm = getSiteManager()
+ def view(context, request):
+ return '123'
+ self._callFUT(context, None, IFoo, view=view, request_param='abc=123')
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, 'abc', None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ request.params = {'abc':'123'}
+ self.assertEqual(wrapper(None, request), '123')
+
+ def test_with_request_param_val_false(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.view import NotFound
+ context = DummyContext()
+ class IFoo(Interface):
+ pass
+ view = lambda *arg: None
+ sm = getSiteManager()
+ def view(context, request):
+ """ """
+ self._callFUT(context, None, IFoo, view=view, request_param='abc=123')
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, 'abc', None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ request.params = {'abc':'456'}
+ self.assertRaises(NotFound, wrapper, None, request)
+
+ def test_with_containment_true(self):
+ from zope.component import getSiteManager
+ from zope.interface import directlyProvides
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ context = DummyContext()
+ class IFoo(Interface):
+ pass
+ view = lambda *arg: None
+ sm = getSiteManager()
+ def view(context, request):
+ return '123'
+ sm.registerAdapter(view, (IFoo, IRequest), IView, name='')
+ self._callFUT(context, None, IFoo, view=view, containment=IFoo)
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, IFoo, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ context = Dummy()
+ directlyProvides(context, IFoo)
+ self.assertEqual(wrapper(context, request), '123')
+
+ def test_with_containment_false(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.view import NotFound
+ context = DummyContext()
+ class IFoo(Interface):
+ pass
+ view = lambda *arg: None
+ sm = getSiteManager()
+ def view(context, request):
+ """ """
+ self._callFUT(context, None, IFoo, view=view, containment=IFoo)
actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, IFoo, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ request = DummyRequest()
+ context = Dummy()
+ self.assertRaises(NotFound, wrapper, context, request)
+
+ def test_multiview_replaces_traditional_view(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IMultiView
from repoze.bfg.interfaces import IViewPermission
- from repoze.bfg.security import ViewPermissionFactory
- from repoze.bfg.zcml import handler
-
- self.assertEqual(len(actions), 2)
-
- permission = actions[0]
- permission_discriminator = ('permission', IFoo, '', IDummyRequest,
- IViewPermission)
- self.assertEqual(permission['discriminator'], permission_discriminator)
- self.assertEqual(permission['callable'], handler)
- self.assertEqual(permission['args'][0], 'registerAdapter')
- self.failUnless(isinstance(permission['args'][1],ViewPermissionFactory))
- self.assertEqual(permission['args'][1].permission_name, 'repoze.view')
- self.assertEqual(permission['args'][2], (IFoo, IDummyRequest))
- self.assertEqual(permission['args'][3], IViewPermission)
- self.assertEqual(permission['args'][4], '')
- self.assertEqual(permission['args'][5], None)
-
- regadapt = actions[1]
- regadapt_discriminator = ('view', IFoo, '', IDummyRequest, IView)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- self.assertEqual(regadapt['args'][1], view)
- self.assertEqual(regadapt['args'][2], (IFoo, IDummyRequest))
- self.assertEqual(regadapt['args'][3], IView)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
-
- def test_with_route_name_bad_order(self):
context = DummyContext()
- context.request_factories = {}
+ class IFoo(Interface):
+ pass
view = lambda *arg: None
- from zope.configuration.exceptions import ConfigurationError
- self.assertRaises(ConfigurationError, self._callFUT, context,
- 'repoze.view', None, view, '', None, 'foo')
+ sm = getSiteManager()
+ def view(context, request):
+ return '123'
+ sm.registerAdapter(view, (IFoo, IRequest), IView, name='')
+ self._callFUT(context, 'repoze.view', IFoo, view=view)
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ self.failUnless(IMultiView.providedBy(wrapper))
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, wrapper.__permitted__)
+ self.assertEqual(wrapper(None, None), '123')
+
+ def test_multiview_replaces_multiview(self):
+ from zope.component import getSiteManager
+ from zope.interface import Interface
+ from zope.interface import implements
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IMultiView
+ from repoze.bfg.interfaces import IViewPermission
+ context = DummyContext()
+ class IFoo(Interface):
+ pass
+ view = lambda *arg: None
+ sm = getSiteManager()
+ class DummyMultiView:
+ implements(IMultiView)
+ def __init__(self):
+ self.views = []
+ self.name = 'name'
+ def add(self, view, score):
+ self.views.append(view)
+ def __call__(self, context, request):
+ return '123'
+ def __permitted__(self, context, request):
+ """ """
+ view = DummyMultiView()
+ sm.registerAdapter(view, (IFoo, IRequest), IMultiView, name='')
+ def view2(context, request):
+ """ """
+ self._callFUT(context, None, IFoo, view=view2)
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', IFoo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='')
+ perm = sm.adapters.lookup((IFoo, IRequest), IViewPermission, name='')
+ self.assertEqual(perm, wrapper.__permitted__)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), '123')
+ self.assertEqual(wrapper.views, [view2])
+
+ def test_for_as_class(self):
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
+ from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
+ context = DummyContext()
+ class Foo:
+ pass
+ sm = getSiteManager()
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'repoze.view', Foo, view=view)
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+ action = actions[0]
+ discrim = ('view', Foo, '', IRequest, IView, None, None, None, None)
+ self.assertEqual(action['discriminator'], discrim)
+ register = action['callable']
+ register()
+ foo = implementedBy(Foo)
+ wrapper = sm.adapters.lookup((foo, IRequest), IView, name='')
+ self.assertEqual(wrapper, view)
class TestNotFoundDirective(unittest.TestCase):
def _callFUT(self, context, view):
@@ -530,27 +755,24 @@ class TestNotFoundDirective(unittest.TestCase):
return notfound(context, view)
def test_it(self):
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import INotFoundView
+
context = DummyContext()
def view(request):
return 'OK'
self._callFUT(context, view)
actions = context.actions
- from repoze.bfg.interfaces import INotFoundView
- from repoze.bfg.zcml import handler
-
self.assertEqual(len(actions), 1)
regadapt = actions[0]
- regadapt_discriminator = ('notfound_view',)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- derived_view = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], INotFoundView)
+ register = regadapt['callable']
+ register()
+ sm = getSiteManager()
+ derived_view = sm.getUtility(INotFoundView)
self.assertEqual(derived_view(None, None), 'OK')
self.assertEqual(derived_view.__name__, view.__name__)
- self.assertEqual(regadapt['args'][2], INotFoundView)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
class TestForbiddenDirective(unittest.TestCase):
def _callFUT(self, context, view):
@@ -558,155 +780,143 @@ class TestForbiddenDirective(unittest.TestCase):
return forbidden(context, view)
def test_it(self):
+ from zope.component import getSiteManager
context = DummyContext()
def view(request):
return 'OK'
self._callFUT(context, view)
actions = context.actions
from repoze.bfg.interfaces import IForbiddenView
- from repoze.bfg.zcml import handler
self.assertEqual(len(actions), 1)
regadapt = actions[0]
- regadapt_discriminator = ('notfound_view',)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- derived_view = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IForbiddenView)
+ register = regadapt['callable']
+ register()
+ sm = getSiteManager()
+ derived_view = sm.getUtility(IForbiddenView)
self.assertEqual(derived_view(None, None), 'OK')
self.assertEqual(derived_view.__name__, view.__name__)
- self.assertEqual(regadapt['args'][2], IForbiddenView)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
class TestRepozeWho1AuthenticationPolicyDirective(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
def _callFUT(self, context, **kw):
from repoze.bfg.zcml import repozewho1authenticationpolicy
return repozewho1authenticationpolicy(context, **kw)
def test_it_defaults(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IAuthenticationPolicy
context = DummyContext()
self._callFUT(context)
actions = context.actions
- from repoze.bfg.interfaces import IAuthenticationPolicy
- from repoze.bfg.zcml import handler
-
self.assertEqual(len(actions), 1)
-
regadapt = actions[0]
- regadapt_discriminator = 'authentication_policy'
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- policy = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IAuthenticationPolicy)
+ self.assertEqual(regadapt['callable'], None)
+ self.assertEqual(regadapt['args'], ())
+ policy = getUtility(IAuthenticationPolicy)
self.assertEqual(policy.callback, None)
self.assertEqual(policy.identifier_name, 'auth_tkt')
- self.assertEqual(regadapt['args'][2], IAuthenticationPolicy)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
def test_it(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IAuthenticationPolicy
context = DummyContext()
def callback(identity, request):
""" """
self._callFUT(context, identifier_name='something', callback=callback)
actions = context.actions
- from repoze.bfg.interfaces import IAuthenticationPolicy
- from repoze.bfg.zcml import handler
-
self.assertEqual(len(actions), 1)
-
regadapt = actions[0]
- regadapt_discriminator = 'authentication_policy'
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- policy = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IAuthenticationPolicy)
+ self.assertEqual(regadapt['callable'], None)
+ self.assertEqual(regadapt['args'], ())
+ policy = getUtility(IAuthenticationPolicy)
self.assertEqual(policy.callback, callback)
self.assertEqual(policy.identifier_name, 'something')
- self.assertEqual(regadapt['args'][2], IAuthenticationPolicy)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
class TestRemoteUserAuthenticationPolicyDirective(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
def _callFUT(self, context, **kw):
from repoze.bfg.zcml import remoteuserauthenticationpolicy
return remoteuserauthenticationpolicy(context, **kw)
def test_defaults(self):
+ from repoze.bfg.interfaces import IAuthenticationPolicy
+ from zope.component import getUtility
context = DummyContext()
def callback(identity, request):
""" """
self._callFUT(context)
actions = context.actions
- from repoze.bfg.interfaces import IAuthenticationPolicy
- from repoze.bfg.zcml import handler
-
self.assertEqual(len(actions), 1)
-
regadapt = actions[0]
regadapt_discriminator = 'authentication_policy'
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- policy = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IAuthenticationPolicy)
+ self.assertEqual(regadapt['callable'], None)
+ self.assertEqual(regadapt['args'], ())
+ policy = getUtility(IAuthenticationPolicy)
self.assertEqual(policy.environ_key, 'REMOTE_USER')
self.assertEqual(policy.callback, None)
- self.assertEqual(regadapt['args'][2], IAuthenticationPolicy)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
def test_it(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IAuthenticationPolicy
context = DummyContext()
def callback(identity, request):
""" """
self._callFUT(context, environ_key='BLAH', callback=callback)
actions = context.actions
- from repoze.bfg.interfaces import IAuthenticationPolicy
- from repoze.bfg.zcml import handler
-
self.assertEqual(len(actions), 1)
-
regadapt = actions[0]
- regadapt_discriminator = 'authentication_policy'
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- policy = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IAuthenticationPolicy)
+ self.assertEqual(regadapt['callable'], None)
+ self.assertEqual(regadapt['args'], ())
+ policy = getUtility(IAuthenticationPolicy)
self.assertEqual(policy.environ_key, 'BLAH')
self.assertEqual(policy.callback, callback)
- self.assertEqual(regadapt['args'][2], IAuthenticationPolicy)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
class TestAuthTktAuthenticationPolicyDirective(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
def _callFUT(self, context, secret, **kw):
from repoze.bfg.zcml import authtktauthenticationpolicy
return authtktauthenticationpolicy(context, secret, **kw)
def test_it_defaults(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IAuthenticationPolicy
context = DummyContext()
self._callFUT(context, 'sosecret')
actions = context.actions
- from repoze.bfg.interfaces import IAuthenticationPolicy
- from repoze.bfg.zcml import handler
-
self.assertEqual(len(actions), 1)
-
regadapt = actions[0]
- regadapt_discriminator = 'authentication_policy'
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- policy = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IAuthenticationPolicy)
+ self.assertEqual(regadapt['callable'], None)
+ self.assertEqual(regadapt['args'], ())
+ policy = getUtility(IAuthenticationPolicy)
self.assertEqual(policy.cookie.secret, 'sosecret')
self.assertEqual(policy.callback, None)
- self.assertEqual(regadapt['args'][2], IAuthenticationPolicy)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
def test_it_noconfigerror(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IAuthenticationPolicy
context = DummyContext()
def callback(identity, request):
""" """
@@ -715,22 +925,14 @@ class TestAuthTktAuthenticationPolicyDirective(unittest.TestCase):
secure=True, include_ip=True, timeout=100,
reissue_time=60)
actions = context.actions
- from repoze.bfg.interfaces import IAuthenticationPolicy
- from repoze.bfg.zcml import handler
-
self.assertEqual(len(actions), 1)
-
regadapt = actions[0]
- regadapt_discriminator = 'authentication_policy'
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- policy = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IAuthenticationPolicy)
+ self.assertEqual(regadapt['callable'], None)
+ self.assertEqual(regadapt['args'], ())
+ policy = getUtility(IAuthenticationPolicy)
self.assertEqual(policy.cookie.secret, 'sosecret')
self.assertEqual(policy.callback, callback)
- self.assertEqual(regadapt['args'][2], IAuthenticationPolicy)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
def test_it_configerror(self):
from zope.configuration.exceptions import ConfigurationError
@@ -745,43 +947,74 @@ class TestAuthTktAuthenticationPolicyDirective(unittest.TestCase):
reissue_time=500)
class TestACLAuthorizationPolicyDirective(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
def _callFUT(self, context, **kw):
from repoze.bfg.zcml import aclauthorizationpolicy
return aclauthorizationpolicy(context, **kw)
def test_it(self):
+ from zope.component import getUtility
from repoze.bfg.authorization import ACLAuthorizationPolicy
from repoze.bfg.interfaces import IAuthorizationPolicy
- from repoze.bfg.zcml import handler
context = DummyContext()
def callback(identity, request):
""" """
self._callFUT(context)
actions = context.actions
-
self.assertEqual(len(actions), 1)
-
regadapt = actions[0]
- regadapt_discriminator = 'authorization_policy'
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerUtility')
- policy = regadapt['args'][1]
+ self.assertEqual(regadapt['discriminator'], IAuthorizationPolicy)
+ self.assertEqual(regadapt['callable'], None)
+ self.assertEqual(regadapt['args'], ())
+ policy = getUtility(IAuthorizationPolicy)
self.assertEqual(policy.__class__, ACLAuthorizationPolicy)
- self.assertEqual(regadapt['args'][2], IAuthorizationPolicy)
- self.assertEqual(regadapt['args'][3], '')
- self.assertEqual(regadapt['args'][4], None)
class TestDeriveView(unittest.TestCase):
- def _callFUT(self, view):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
+ def _callFUT(self, view, *arg, **kw):
from repoze.bfg.zcml import derive_view
- return derive_view(view)
+ return derive_view(view, *arg, **kw)
+
+ def _registerLogger(self):
+ from repoze.bfg.interfaces import ILogger
+ from zope.component import getSiteManager
+ logger = DummyLogger()
+ sm = getSiteManager()
+ sm.registerUtility(logger, ILogger, 'repoze.bfg.debug')
+ return logger
+
+ def _registerSettings(self, **d):
+ from repoze.bfg.interfaces import ISettings
+ from zope.component import getSiteManager
+ settings = DummySettings(d)
+ sm = getSiteManager()
+ sm.registerUtility(settings, ISettings)
+
+ def _registerSecurityPolicy(self, permissive):
+ from repoze.bfg.interfaces import IAuthenticationPolicy
+ from repoze.bfg.interfaces import IAuthorizationPolicy
+ from zope.component import getSiteManager
+ policy = DummySecurityPolicy(permissive)
+ sm = getSiteManager()
+ sm.registerUtility(policy, IAuthenticationPolicy)
+ sm.registerUtility(policy, IAuthorizationPolicy)
def test_view_as_function_context_and_request(self):
def view(context, request):
return 'OK'
result = self._callFUT(view)
self.failUnless(result is view)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(view(None, None), 'OK')
def test_view_as_function_requestonly(self):
@@ -792,6 +1025,7 @@ class TestDeriveView(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_view_as_newstyle_class_context_and_request(self):
@@ -805,6 +1039,7 @@ class TestDeriveView(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_view_as_newstyle_class_requestonly(self):
@@ -818,6 +1053,7 @@ class TestDeriveView(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_view_as_oldstyle_class_context_and_request(self):
@@ -831,6 +1067,7 @@ class TestDeriveView(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_view_as_oldstyle_class_requestonly(self):
@@ -844,6 +1081,7 @@ class TestDeriveView(unittest.TestCase):
self.assertEqual(view.__module__, result.__module__)
self.assertEqual(view.__doc__, result.__doc__)
self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_view_as_instance_context_and_request(self):
@@ -853,6 +1091,7 @@ class TestDeriveView(unittest.TestCase):
view = View()
result = self._callFUT(view)
self.failUnless(result is view)
+ self.failIf(hasattr(result, '__call_permissive__'))
self.assertEqual(result(None, None), 'OK')
def test_view_as_instance_requestonly(self):
@@ -865,8 +1104,158 @@ class TestDeriveView(unittest.TestCase):
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_view_with_debug_authorization_no_authpol(self):
+ def view(context, request):
+ return 'OK'
+ self._registerSettings(debug_authorization=True)
+ logger = self._registerLogger()
+ result = self._callFUT(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 = DummyRequest()
+ 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_view_with_debug_authorization_no_permission(self):
+ def view(context, request):
+ return 'OK'
+ self._registerSettings(debug_authorization=True)
+ self._registerSecurityPolicy(True)
+ logger = self._registerLogger()
+ result = self._callFUT(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 = DummyRequest()
+ 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_view_with_debug_authorization_permission_authpol_permitted(self):
+ def view(context, request):
+ return 'OK'
+ self._registerSettings(debug_authorization=True)
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(True)
+ result = self._callFUT(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 = DummyRequest()
+ 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_view_with_debug_authorization_permission_authpol_denied(self):
+ from repoze.bfg.security import Unauthorized
+ def view(context, request):
+ """ """
+ self._registerSettings(debug_authorization=True)
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(False)
+ result = self._callFUT(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 = DummyRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertRaises(Unauthorized, 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_view_with_debug_authorization_permission_authpol_denied2(self):
+ def view(context, request):
+ """ """
+ self._registerSettings(debug_authorization=True)
+ logger = self._registerLogger()
+ self._registerSecurityPolicy(False)
+ result = self._callFUT(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = DummyRequest()
+ request.view_name = 'view_name'
+ request.url = 'url'
+ permitted = result.__permitted__(None, None)
+ self.assertEqual(permitted, False)
+
+ def test_view_with_predicates_all(self):
+ def view(context, request):
+ return '123'
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+ result = self._callFUT(view, predicates=[predicate1, predicate2])
+ request = DummyRequest()
+ request.method = 'POST'
+ next = result(None, None)
+ self.assertEqual(next, '123')
+ self.assertEqual(predicates, [True, True])
+
+ def test_view_with_predicates_notall(self):
+ from repoze.bfg.view import NotFound
+ def view(context, request):
+ """ """
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return False
+ result = self._callFUT(view, predicates=[predicate1, predicate2])
+ request = DummyRequest()
+ request.method = 'POST'
+ self.assertRaises(NotFound, result, None, None)
+ self.assertEqual(predicates, [True, True])
+
+ def test_view_with_predicates_checker(self):
+ def view(context, request):
+ """ """
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+ result = self._callFUT(view, predicates=[predicate1, predicate2])
+ request = DummyRequest()
+ request.method = 'POST'
+ next = result.__predicated__(None, None)
+ self.assertEqual(next, True)
+ self.assertEqual(predicates, [True, True])
+
class TestConnectRouteFunction(unittest.TestCase):
def setUp(self):
cleanUp()
@@ -903,103 +1292,119 @@ class TestRouteDirective(unittest.TestCase):
return route(*arg, **kw)
def test_defaults(self):
- from zope.component import getUtility
- from repoze.bfg.interfaces import IRequestFactories
+ from repoze.bfg.zcml import connect_route
context = DummyContext()
self._callFUT(context, 'name', 'path')
- self.failUnless(getUtility(IRequestFactories, name='name'))
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+
+ route_action = actions[0]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(len(route_discriminator), 2)
+ self.assertEqual(route_discriminator[0], 'route')
+ self.assertEqual(route_discriminator[1], 'name')
+ self.assertEqual(route_args, ('path', 'name', None))
def test_with_view(self):
- from zope.component import getUtility
- from repoze.bfg.interfaces import IRequestFactories
- from repoze.bfg.zcml import handler
+ from zope.interface import Interface
+ from zope.interface import implementedBy
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRouteRequest
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
context = DummyContext()
- view = Dummy()
+ def view(context, request):
+ return '123'
self._callFUT(context, 'name', 'path', view=view)
actions = context.actions
self.assertEqual(len(actions), 2)
- factories = getUtility(IRequestFactories, name='name')
- request_iface = factories[None]['interface']
-
view_action = actions[0]
- view_callable = view_action['callable']
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
view_discriminator = view_action['discriminator']
- view_args = view_action['args']
- self.assertEqual(view_callable, handler)
- self.assertEqual(len(view_discriminator), 5)
+ self.assertEqual(len(view_discriminator), 9)
self.assertEqual(view_discriminator[0], 'view')
self.assertEqual(view_discriminator[1], None)
self.assertEqual(view_discriminator[2],'')
- self.assertEqual(view_discriminator[3], request_iface)
+ self.assertEqual(view_discriminator[3], request_type)
self.assertEqual(view_discriminator[4], IView)
- self.assertEqual(view_args, ('registerAdapter', view,
- (None, request_iface), IView,
- '', None))
+ self.assertEqual(view_discriminator[5], None)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], None)
+ self.assertEqual(view_discriminator[8], 'name')
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ wrapped = sm.adapters.lookup((Interface, request_type), IView, name='')
+ request = DummyRequest()
+ self.assertEqual(wrapped(None, request), '123')
route_action = actions[1]
route_callable = route_action['callable']
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 4)
+ self.assertEqual(len(route_discriminator), 2)
self.assertEqual(route_discriminator[0], 'route')
self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_discriminator[2], None)
- self.assertEqual(route_discriminator[3], None)
self.assertEqual(route_args, ('path', 'name', None))
def test_with_view_and_view_for(self):
- from zope.component import getUtility
- from repoze.bfg.interfaces import IRequestFactories
- from repoze.bfg.zcml import handler
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
context = DummyContext()
- view = Dummy()
+ def view(context, request):
+ return '123'
self._callFUT(context, 'name', 'path', view=view, view_for=IDummy)
actions = context.actions
self.assertEqual(len(actions), 2)
- factories = getUtility(IRequestFactories, 'name')
- request_iface = factories[None]['interface']
-
view_action = actions[0]
- view_callable = view_action['callable']
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
view_discriminator = view_action['discriminator']
- view_args = view_action['args']
- self.assertEqual(view_callable, handler)
- self.assertEqual(len(view_discriminator), 5)
+ self.assertEqual(len(view_discriminator), 9)
self.assertEqual(view_discriminator[0], 'view')
self.assertEqual(view_discriminator[1], IDummy)
self.assertEqual(view_discriminator[2],'')
- self.assertEqual(view_discriminator[3], request_iface)
- self.assertEqual(view_discriminator[4], IView)
- self.assertEqual(view_args, ('registerAdapter', view,
- (IDummy, request_iface), IView,
- '', None))
+ self.assertEqual(view_discriminator[3], request_type)
+ self.assertEqual(view_discriminator[4], IView)
+ self.assertEqual(view_discriminator[5], None)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], None)
+ self.assertEqual(view_discriminator[8], 'name')
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ request = DummyRequest()
+ self.assertEqual(wrapped(None, request), '123')
route_action = actions[1]
route_callable = route_action['callable']
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 4)
+ self.assertEqual(len(route_discriminator), 2)
self.assertEqual(route_discriminator[0], 'route')
self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_discriminator[2], IDummy)
- self.assertEqual(route_discriminator[3], None)
self.assertEqual(route_args, ('path', 'name', None,))
def test_without_view(self):
from repoze.bfg.zcml import connect_route
-
context = DummyContext()
- view = Dummy()
self._callFUT(context, 'name', 'path')
actions = context.actions
self.assertEqual(len(actions), 1)
@@ -1009,32 +1414,275 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 4)
+ self.assertEqual(len(route_discriminator), 2)
self.assertEqual(route_discriminator[0], 'route')
self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_discriminator[2], None)
- self.assertEqual(route_discriminator[3], None)
self.assertEqual(route_args, ('path', 'name', None))
- def test_with_request_type(self):
+ def test_with_view_request_type(self):
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
context = DummyContext()
- view = Dummy()
- self._callFUT(context, 'name', 'path', request_type="GET")
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'name', 'path', view=view,
+ view_request_type="GET")
actions = context.actions
- self.assertEqual(len(actions), 1)
+ self.assertEqual(len(actions), 2)
- route_action = actions[0]
+ view_action = actions[0]
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ view_discriminator = view_action['discriminator']
+ self.assertEqual(len(view_discriminator), 9)
+ self.assertEqual(view_discriminator[0], 'view')
+ self.assertEqual(view_discriminator[1], None)
+ self.assertEqual(view_discriminator[2],'')
+ self.assertEqual(view_discriminator[3], request_type)
+ self.assertEqual(view_discriminator[4], IView)
+ self.assertEqual(view_discriminator[5], None)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], 'GET')
+ self.assertEqual(view_discriminator[8], 'name')
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ self.failUnless(wrapped)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(len(route_discriminator), 2)
+ self.assertEqual(route_discriminator[0], 'route')
+ self.assertEqual(route_discriminator[1], 'name')
+ self.assertEqual(route_args, ('path', 'name', None))
+
+ def test_with_view_request_type_alias(self):
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
+
+ context = DummyContext()
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'name', 'path', view=view, request_type="GET")
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ view_action = actions[0]
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ view_discriminator = view_action['discriminator']
+ self.assertEqual(len(view_discriminator), 9)
+ self.assertEqual(view_discriminator[0], 'view')
+ self.assertEqual(view_discriminator[1], None)
+ self.assertEqual(view_discriminator[2],'')
+ self.assertEqual(view_discriminator[3], request_type)
+ self.assertEqual(view_discriminator[4], IView)
+ self.assertEqual(view_discriminator[5], None)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], 'GET')
+ self.assertEqual(view_discriminator[8], 'name')
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ self.failUnless(wrapped)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(len(route_discriminator), 2)
+ self.assertEqual(route_discriminator[0], 'route')
+ self.assertEqual(route_discriminator[1], 'name')
+ self.assertEqual(route_args, ('path', 'name', None))
+
+ def test_with_view_request_method(self):
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
+
+ context = DummyContext()
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'name', 'path', view=view,
+ view_request_method="GET")
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ view_action = actions[0]
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ view_discriminator = view_action['discriminator']
+ self.assertEqual(len(view_discriminator), 9)
+ self.assertEqual(view_discriminator[0], 'view')
+ self.assertEqual(view_discriminator[1], None)
+ self.assertEqual(view_discriminator[2],'')
+ self.assertEqual(view_discriminator[3], request_type)
+ self.assertEqual(view_discriminator[4], IView)
+ self.assertEqual(view_discriminator[5], None)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], 'GET')
+ self.assertEqual(view_discriminator[8], 'name')
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ self.failUnless(wrapped)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(len(route_discriminator), 2)
+ self.assertEqual(route_discriminator[0], 'route')
+ self.assertEqual(route_discriminator[1], 'name')
+ self.assertEqual(route_args, ('path', 'name', None))
+
+ def test_with_view_request_method_alias(self):
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
+
+ context = DummyContext()
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'name', 'path', view=view, request_method="GET")
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ view_action = actions[0]
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ view_discriminator = view_action['discriminator']
+ self.assertEqual(len(view_discriminator), 9)
+ self.assertEqual(view_discriminator[0], 'view')
+ self.assertEqual(view_discriminator[1], None)
+ self.assertEqual(view_discriminator[2],'')
+ self.assertEqual(view_discriminator[3], request_type)
+ self.assertEqual(view_discriminator[4], IView)
+ self.assertEqual(view_discriminator[5], None)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], 'GET')
+ self.assertEqual(view_discriminator[8], 'name')
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ self.failUnless(wrapped)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(len(route_discriminator), 2)
+ self.assertEqual(route_discriminator[0], 'route')
+ self.assertEqual(route_discriminator[1], 'name')
+ self.assertEqual(route_args, ('path', 'name', None))
+
+ def test_with_view_containment(self):
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
+
+ context = DummyContext()
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'name', 'path', view=view, view_containment=True)
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ view_action = actions[0]
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ view_discriminator = view_action['discriminator']
+ self.assertEqual(len(view_discriminator), 9)
+ self.assertEqual(view_discriminator[0], 'view')
+ self.assertEqual(view_discriminator[1], None)
+ self.assertEqual(view_discriminator[2],'')
+ self.assertEqual(view_discriminator[3], request_type)
+ self.assertEqual(view_discriminator[4], IView)
+ self.assertEqual(view_discriminator[5], True)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], None)
+ self.assertEqual(view_discriminator[8], 'name')
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ self.failUnless(wrapped)
+
+ route_action = actions[1]
route_callable = route_action['callable']
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 4)
+ self.assertEqual(len(route_discriminator), 2)
+ self.assertEqual(route_discriminator[0], 'route')
+ self.assertEqual(route_discriminator[1], 'name')
+ self.assertEqual(route_args, ('path', 'name', None))
+
+ def test_with_view_containment_alias(self):
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
+
+ context = DummyContext()
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'name', 'path', view=view, containment=True)
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ view_action = actions[0]
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ view_discriminator = view_action['discriminator']
+ self.assertEqual(len(view_discriminator), 9)
+ self.assertEqual(view_discriminator[0], 'view')
+ self.assertEqual(view_discriminator[1], None)
+ self.assertEqual(view_discriminator[2],'')
+ self.assertEqual(view_discriminator[3], request_type)
+ self.assertEqual(view_discriminator[4], IView)
+ self.assertEqual(view_discriminator[5], True)
+ self.assertEqual(view_discriminator[6], None)
+ self.assertEqual(view_discriminator[7], None)
+ self.assertEqual(view_discriminator[8], 'name')
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ self.failUnless(wrapped)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(len(route_discriminator), 2)
self.assertEqual(route_discriminator[0], 'route')
self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_discriminator[2], None)
- self.assertEqual(route_discriminator[3], 'GET')
self.assertEqual(route_args, ('path', 'name', None))
class TestStaticDirective(unittest.TestCase):
@@ -1049,65 +1697,87 @@ class TestStaticDirective(unittest.TestCase):
return static(*arg, **kw)
def test_absolute(self):
+ from paste.urlparser import StaticURLParser
+ from zope.interface import implementedBy
+ from zope.component import getSiteManager
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.zcml import StaticRootFactory
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
import os
here = os.path.dirname(__file__)
static_path = os.path.join(here, 'fixtures', 'static')
- from repoze.bfg.zcml import handler
- from repoze.bfg.zcml import connect_route
- from repoze.bfg.interfaces import IView
context = DummyContext()
self._callFUT(context, 'name', static_path)
actions = context.actions
self.assertEqual(len(actions), 2)
action = actions[0]
- callable = action['callable']
discriminator = action['discriminator']
- args = action['args']
- self.assertEqual(callable, handler)
- self.assertEqual(discriminator[:3], ('view', None, ''))
+ self.assertEqual(discriminator[:3], ('view', StaticRootFactory, ''))
self.assertEqual(discriminator[4], IView)
- self.assertEqual(args[1].app.directory, static_path)
+ sm = getSiteManager()
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ iface = implementedBy(StaticRootFactory)
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ wrapped = sm.adapters.lookup((iface, request_type), IView, name='')
+ request = DummyRequest()
+ self.assertEqual(wrapped(None, request).__class__, StaticURLParser)
action = actions[1]
callable = action['callable']
discriminator = action['discriminator']
args = action['args']
self.assertEqual(callable, connect_route)
- self.assertEqual(discriminator, ('route', 'name', None, None))
+ self.assertEqual(discriminator, ('route', 'name'))
self.assertEqual(args[0], 'name*subpath')
def test_package_relative(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.static import PackageURLParser
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
from repoze.bfg.zcml import connect_route
+ from repoze.bfg.zcml import StaticRootFactory
from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
context = DummyContext()
self._callFUT(context, 'name', 'repoze.bfg.tests:fixtures/static')
actions = context.actions
self.assertEqual(len(actions), 2)
action = actions[0]
- callable = action['callable']
discriminator = action['discriminator']
- args = action['args']
- self.assertEqual(callable, handler)
- self.assertEqual(discriminator[:3], ('view', None, ''))
+ self.assertEqual(discriminator[:3], ('view', StaticRootFactory, ''))
self.assertEqual(discriminator[4], IView)
- self.assertEqual(args[1].app.package_name, 'repoze.bfg.tests')
- self.assertEqual(args[1].app.resource_name, 'fixtures/static')
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ iface = implementedBy(StaticRootFactory)
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ view = sm.adapters.lookup((iface, request_type), IView, name='')
+ request = DummyRequest()
+ self.assertEqual(view(None, request).__class__, PackageURLParser)
action = actions[1]
callable = action['callable']
discriminator = action['discriminator']
args = action['args']
self.assertEqual(callable, connect_route)
- self.assertEqual(discriminator, ('route', 'name', None, None))
+ self.assertEqual(discriminator, ('route', 'name'))
self.assertEqual(args[0], 'name*subpath')
def test_here_relative(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.static import PackageURLParser
+ from zope.component import getSiteManager
+ from zope.interface import implementedBy
from repoze.bfg.zcml import connect_route
+ from repoze.bfg.zcml import StaticRootFactory
from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
import repoze.bfg.tests
context = DummyContext(repoze.bfg.tests)
self._callFUT(context, 'name', 'fixtures/static')
@@ -1115,21 +1785,25 @@ class TestStaticDirective(unittest.TestCase):
self.assertEqual(len(actions), 2)
action = actions[0]
- callable = action['callable']
discriminator = action['discriminator']
- args = action['args']
- self.assertEqual(callable, handler)
- self.assertEqual(discriminator[:3], ('view', None, ''))
+ self.assertEqual(discriminator[:3], ('view', StaticRootFactory, ''))
self.assertEqual(discriminator[4], IView)
- self.assertEqual(args[1].app.package_name, 'repoze.bfg.tests')
- self.assertEqual(args[1].app.resource_name, 'fixtures/static')
+ register = action['callable']
+ register()
+ sm = getSiteManager()
+ iface = implementedBy(StaticRootFactory)
+ request_factory = sm.getUtility(IRouteRequest, 'name')
+ request_type = implementedBy(request_factory)
+ wrapped = sm.adapters.lookup((iface, request_type), IView, name='')
+ request = DummyRequest()
+ self.assertEqual(wrapped(None, request).__class__, PackageURLParser)
action = actions[1]
callable = action['callable']
discriminator = action['discriminator']
args = action['args']
self.assertEqual(callable, connect_route)
- self.assertEqual(discriminator, ('route', 'name', None, None))
+ self.assertEqual(discriminator, ('route', 'name'))
self.assertEqual(args[0], 'name*subpath')
class TestResourceDirective(unittest.TestCase):
@@ -1372,22 +2046,36 @@ class TestBFGViewFunctionGrokker(unittest.TestCase):
return self._getTargetClass()(*arg, **kw)
def test_grok_is_bfg_view(self):
+ from zope.component import getSiteManager
from repoze.bfg.interfaces import IRequest
+ from repoze.bfg.interfaces import IView
from zope.interface import Interface
grokker = self._makeOne()
class obj:
- pass
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
obj.__is_bfg_view__ = True
obj.__permission__ = 'foo'
obj.__for__ = Interface
obj.__view_name__ = 'foo.html'
obj.__request_type__ = IRequest
obj.__route_name__ = None
+ obj.__request_method__ = None
+ obj.__request_param__ = None
+ obj.__containment__ = None
context = DummyContext()
result = grokker.grok('name', obj, context=context)
self.assertEqual(result, True)
actions = context.actions
- self.assertEqual(len(actions), 2)
+ self.assertEqual(len(actions), 1)
+ register = actions[0]['callable']
+ register()
+ sm = getSiteManager()
+ wrapped = sm.adapters.lookup((Interface, IRequest), IView,
+ name='foo.html')
+ self.assertEqual(wrapped(None, None), 'OK')
def test_grok_is_not_bfg_view(self):
grokker = self._makeOne()
@@ -1436,152 +2124,17 @@ class TestExcludeFunction(unittest.TestCase):
self.assertEqual(self._callFUT('.foo'), True)
self.assertEqual(self._callFUT('foo'), False)
-class TestRequestOnly(unittest.TestCase):
- def _callFUT(self, arg):
- from repoze.bfg.zcml import requestonly
- return requestonly(arg)
-
- def test_newstyle_class_no_init(self):
- class foo(object):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_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):
- class foo(object):
- def __init__(self, request):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_newstyle_class_init_onearg_named_somethingelse(self):
- class foo(object):
- def __init__(self, req):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_newstyle_class_init_defaultargs_firstname_not_request(self):
- class foo(object):
- def __init__(self, context, request=None):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_newstyle_class_init_defaultargs_firstname_request(self):
- class foo(object):
- def __init__(self, request, foo=1, bar=2):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_newstyle_class_init_noargs(self):
- class foo(object):
- def __init__():
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_no_init(self):
- class foo:
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_init_toomanyargs(self):
- class foo:
- def __init__(self, context, request):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_init_onearg_named_request(self):
- class foo:
- def __init__(self, request):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_oldstyle_class_init_onearg_named_somethingelse(self):
- class foo:
- def __init__(self, req):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_oldstyle_class_init_defaultargs_firstname_not_request(self):
- class foo:
- def __init__(self, context, request=None):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_init_defaultargs_firstname_request(self):
- class foo:
- def __init__(self, request, foo=1, bar=2):
- """ """
- self.assertTrue(self._callFUT(foo), True)
-
- def test_oldstyle_class_init_noargs(self):
- class foo:
- def __init__():
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_function_toomanyargs(self):
- def foo(context, request):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_function_onearg_named_request(self):
- def foo(request):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_function_onearg_named_somethingelse(self):
- def foo(req):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_function_defaultargs_firstname_not_request(self):
- def foo(context, request=None):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_function_defaultargs_firstname_request(self):
- def foo(request, foo=1, bar=2):
- """ """
- self.assertTrue(self._callFUT(foo), True)
-
- def test_instance_toomanyargs(self):
- class Foo:
- def __call__(self, context, request):
- """ """
- foo = Foo()
- self.assertFalse(self._callFUT(foo))
-
- def test_instance_defaultargs_onearg_named_request(self):
- class Foo:
- def __call__(self, request):
- """ """
- foo = Foo()
- self.assertTrue(self._callFUT(foo))
-
- def test_instance_defaultargs_onearg_named_somethingelse(self):
- class Foo:
- def __call__(self, req):
- """ """
- foo = Foo()
- self.assertTrue(self._callFUT(foo))
-
- def test_instance_defaultargs_firstname_not_request(self):
- class Foo:
- def __call__(self, context, request=None):
- """ """
- foo = Foo()
- self.assertFalse(self._callFUT(foo))
+class TestAll(unittest.TestCase):
+ def test_it(self):
+ from repoze.bfg.zcml import all
+ self.assertEqual(all([True, True]), True)
+ self.assertEqual(all([False, False]), False)
+ self.assertEqual(all([False, True]), False)
- def test_instance_defaultargs_firstname_request(self):
- class Foo:
- def __call__(self, request, foo=1, bar=2):
- """ """
- foo = Foo()
- self.assertTrue(self._callFUT(foo), True)
+class TestStaticRootFactory(unittest.TestCase):
+ def test_it(self):
+ from repoze.bfg.zcml import StaticRootFactory
+ StaticRootFactory({}) # it just needs construction
class DummyModule:
__path__ = "foo"
@@ -1612,7 +2165,7 @@ class DummyContext:
self.info = None
self.resolved = resolved
- def action(self, discriminator, callable, args):
+ def action(self, discriminator, callable=None, args=(), kw={}, order=0):
self.actions.append(
{'discriminator':discriminator,
'callable':callable,
@@ -1639,9 +2192,6 @@ from zope.interface import Interface
class IDummy(Interface):
pass
-class DummySecurityPolicy:
- pass
-
class DummyLogger:
def __init__(self):
self.messages = []
@@ -1651,9 +2201,18 @@ class DummyLogger:
debug = info
class DummyRequest:
+ subpath = ()
+ def __init__(self, environ=None):
+ if environ is None:
+ environ = {}
+ self.environ = environ
+
def get_response(self, app):
return app
-
+
+ def copy(self):
+ return self
+
class DummyOverrides:
def __init__(self, package):
self.package = package
@@ -1666,3 +2225,17 @@ class DummyPackage:
def __init__(self, name):
self.__name__ = name
+class DummySettings(dict):
+ def __getattr__(self, name):
+ return self[name]
+
+class DummySecurityPolicy:
+ def __init__(self, permitted=True):
+ self.permitted = permitted
+
+ def effective_principals(self, request):
+ return []
+
+ def permits(self, context, principals, permission):
+ return self.permitted
+
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index 4fea8bf84..50bd7b86b 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -17,16 +17,20 @@ from webob import Response
from paste.urlparser import StaticURLParser
-from zope.component import queryMultiAdapter
from zope.component import queryUtility
+from zope.component import providedBy
+from zope.component import getSiteManager
+
+from zope.interface import implements
+
from zope.deprecation import deprecated
-from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import IResponseFactory
-from repoze.bfg.path import caller_path
+from repoze.bfg.interfaces import IView
+from repoze.bfg.interfaces import IMultiView
+
from repoze.bfg.path import caller_package
-from repoze.bfg.security import view_execution_permitted
-from repoze.bfg.security import Unauthorized
+
from repoze.bfg.static import PackageURLParser
deprecated('view_execution_permitted',
@@ -50,19 +54,21 @@ def render_view_to_response(context, request, name='', secure=True):
``repoze.bfg.security.Unauthorized`` exception will be raised; its
``args`` attribute explains why the view access was disallowed.
If ``secure`` is ``False``, no permission checking is done."""
- if secure:
- permitted = view_execution_permitted(context, request, name)
- if not permitted:
- raise Unauthorized(permitted)
-
- # It's no use trying to distinguish below whether response is None
- # because a) we were returned a default or b) because the view
- # function returned None: the zope.component/zope.interface
- # machinery doesn't distinguish a None returned from the view from
- # a sentinel None returned during queryMultiAdapter (even if we
- # pass a non-None default).
-
- return queryMultiAdapter((context, request), IView, name=name)
+ provides = map(providedBy, (context, request))
+ sm = getSiteManager()
+ view = sm.adapters.lookup(provides, IView, name=name)
+ if view is None:
+ return None
+
+ if not secure:
+ # the view will have a __permissive_view__ attribute if it's
+ # secured; otherwise it won't.
+ view = getattr(view, '__call_permissive__', view)
+
+ # if this view is secured, it will raise an Unauthorized
+ # appropriately if the executing user does not have the proper
+ # permission
+ return view(context, request)
def render_view_to_iterable(context, request, name='', secure=True):
""" Render the view named ``name`` against the specified
@@ -211,23 +217,53 @@ class bfg_view(object):
route_name='site1'
/>
- If ``name`` is not supplied, the empty string is used (implying
- the default view).
-
- If ``request_type`` is not supplied, the interface
- ``repoze.bfg.interfaces.IRequest`` is used.
+ The following arguments are supported: ``for_``, ``permission``,
+ ``name``, ``request_type``, ``route_name``, ``request_method``,
+ ``request_param``, and ``containment``.
If ``for_`` is not supplied, the interface
- ``zope.interface.Interface`` (implying *all* interfaces) is used.
+ ``zope.interface.Interface`` (matching any context) is used.
If ``permission`` is not supplied, no permission is registered for
this view (it's accessible by any caller).
+ If ``name`` is not supplied, the empty string is used (implying
+ the default view name).
+
+ If ``request_type`` is not supplied, the interface
+ ``repoze.bfg.interfaces.IRequest`` is used, implying the standard
+ request interface type.
+
If ``route_name`` is not supplied, the view declaration is
considered to be made against a URL that doesn't match any defined
:term:`route`. The use of a ``route_name`` is an advanced
feature, useful only if you're using :term:`url dispatch`.
+ If ``request_method`` is not supplied, this view will match a
+ request with any HTTP ``REQUEST_METHOD``
+ (GET/POST/PUT/HEAD/DELETE). If this parameter *is* supplied, it
+ must be a string naming an HTTP ``REQUEST_METHOD``, indicating
+ that this view will only match when the current request has a
+ ``REQUEST_METHOD`` that matches this value.
+
+ If ``request_param`` is not supplied, this view will be called
+ when a request with any (or no) request GET or POST parameters is
+ encountered. If the value is present, it must be a string. If
+ the value supplied to the parameter has no ``=`` sign in it, it
+ implies that the key must exist in the ``request.params``
+ dictionary for this view to'match' the current request. If the value
+ supplied to the parameter has a ``=`` sign in it, e.g.
+ ``request_params="foo=123"``, then the key (``foo``) must both exist
+ in the ``request.params`` dictionary, and the value must match the
+ right hand side of the expression (``123``) for the view to "match" the
+ current request.
+
+ If ``containment`` is not supplied, this view will be called when
+ the context of the request has any location lineage. If
+ ``containment`` *is* supplied, it must be a class or :term:`interface`,
+ denoting that the view 'matches' the current request only if any graph
+ lineage node possesses this class or interface.
+
Any individual or all parameters can be omitted. The simplest
bfg_view declaration then becomes::
@@ -239,7 +275,9 @@ class bfg_view(object):
``my_view``, registered for models with the
``zope.interface.Interface`` interface, using no permission,
registered against requests which implement the default IRequest
- interface when no urldispatch route matches.
+ interface when no urldispatch route matches, with any
+ REQUEST_METHOD, any set of request.params values, in any lineage
+ containment.
The ``bfg_view`` decorator can also be used as a class decorator
in Python 2.6 and better (Python 2.5 and below do not support
@@ -284,35 +322,28 @@ class bfg_view(object):
<scan package="."/>
"""
def __init__(self, name='', request_type=None, for_=None, permission=None,
- route_name=None):
+ route_name=None, request_method=None, request_param=None,
+ containment=None):
self.name = name
self.request_type = request_type
self.for_ = for_
self.permission = permission
self.route_name = route_name
+ self.request_method = request_method
+ self.request_param = request_param
+ self.containment = containment
def __call__(self, wrapped):
- _bfg_view = wrapped
- if inspect.isclass(_bfg_view):
- # If the object we're decorating is a class, turn it into
- # a function that operates like a Zope view (when it's
- # invoked, construct an instance using 'context' and
- # 'request' as position arguments, then immediately invoke
- # the __call__ method of the instance with no arguments;
- # __call__ should return an IResponse).
- def _bfg_class_view(context, request):
- inst = wrapped(context, request)
- return inst()
- _bfg_class_view.__module__ = wrapped.__module__
- _bfg_class_view.__name__ = wrapped.__name__
- _bfg_class_view.__doc__ = wrapped.__doc__
- _bfg_view = _bfg_class_view
+ _bfg_view = map_view(wrapped)
_bfg_view.__is_bfg_view__ = True
_bfg_view.__permission__ = self.permission
_bfg_view.__for__ = self.for_
_bfg_view.__view_name__ = self.name
_bfg_view.__request_type__ = self.request_type
_bfg_view.__route_name__ = self.route_name
+ _bfg_view.__request_method__ = self.request_method
+ _bfg_view.__request_param__ = self.request_param
+ _bfg_view.__containment__ = self.containment
return _bfg_view
def default_view(context, request, status):
@@ -342,3 +373,141 @@ def default_forbidden_view(context, request):
def default_notfound_view(context, request):
return default_view(context, request, '404 Not Found')
+class NotFound(Exception):
+ pass
+
+class MultiView(object):
+ implements(IMultiView)
+
+ def __init__(self, name):
+ self.name = name
+ self.views = []
+
+ def add(self, view, score):
+ self.views.append((score, view))
+ self.views.sort()
+
+ def match(self, context, request):
+ for score, view in self.views:
+ if not hasattr(view, '__predicated__'):
+ return view
+ if view.__predicated__(context, request):
+ return view
+ raise NotFound(self.name)
+
+ def __permitted__(self, context, request):
+ view = self.match(context, request)
+ if hasattr(view, '__permitted__'):
+ return view.__permitted__(context, request)
+ return True
+
+ def __call_permissive__(self, context, request):
+ view = self.match(context, request)
+ view = getattr(view, '__call_permissive__', view)
+ return view(context, request)
+
+ def __call__(self, context, request):
+ for score, view in self.views:
+ try:
+ return view(context, request)
+ except NotFound:
+ continue
+ raise NotFound(self.name)
+
+def map_view(view):
+ wrapped_view = view
+
+ if inspect.isclass(view):
+ # If the object we've located is a class, turn it into a
+ # function that operates like a Zope view (when it's invoked,
+ # construct an instance using 'context' and 'request' as
+ # position arguments, then immediately invoke the __call__
+ # method of the instance with no arguments; __call__ should
+ # return an IResponse).
+ if requestonly(view):
+ # its __init__ accepts only a single request argument,
+ # instead of both context and request
+ def _bfg_class_requestonly_view(context, request):
+ inst = view(request)
+ return inst()
+ wrapped_view = _bfg_class_requestonly_view
+ else:
+ # its __init__ accepts both context and request
+ def _bfg_class_view(context, request):
+ inst = view(context, request)
+ return inst()
+ wrapped_view = _bfg_class_view
+
+ elif requestonly(view):
+ # its __call__ accepts only a single request argument,
+ # instead of both context and request
+ def _bfg_requestonly_view(context, request):
+ return view(request)
+ wrapped_view = _bfg_requestonly_view
+
+ decorate_view(wrapped_view, view)
+ return wrapped_view
+
+def requestonly(class_or_callable):
+ """ Return true of the class or callable accepts only a request argument,
+ as opposed to something that accepts context, request """
+ if inspect.isfunction(class_or_callable):
+ fn = class_or_callable
+ elif inspect.isclass(class_or_callable):
+ try:
+ fn = class_or_callable.__init__
+ except AttributeError:
+ return False
+ else:
+ try:
+ fn = class_or_callable.__call__
+ except AttributeError:
+ return False
+
+ try:
+ argspec = inspect.getargspec(fn)
+ except TypeError:
+ 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:
+ return False
+
+ if len(args) == 1:
+ return True
+
+ elif args[0] == 'request':
+ if len(args) - len(defaults) == 1:
+ return True
+
+ return False
+
+def decorate_view(wrapped_view, original_view):
+ if wrapped_view is not original_view:
+ wrapped_view.__module__ = original_view.__module__
+ wrapped_view.__doc__ = original_view.__doc__
+ try:
+ wrapped_view.__name__ = original_view.__name__
+ except AttributeError:
+ wrapped_view.__name__ = repr(original_view)
+ try:
+ wrapped_view.__permitted__ = original_view.__permitted__
+ except AttributeError:
+ pass
+ try:
+ wrapped_view.__call_permissive__ = original_view.__call_permissive__
+ except AttributeError:
+ pass
+ try:
+ wrapped_view.__predicated__ = original_view.__predicated__
+ except AttributeError:
+ pass
+ return True
+ return False
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index 5a41babd1..fb4e8d720 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -1,5 +1,5 @@
import os
-import inspect
+import sys
import types
from zope.configuration import xmlconfig
@@ -14,6 +14,8 @@ from zope.configuration.exceptions import ConfigurationError
from zope.configuration.fields import GlobalObject
from zope.interface import Interface
+from zope.interface.interfaces import IInterface
+from zope.interface import implementedBy
from zope.schema import TextLine
from zope.schema import Bool
@@ -32,30 +34,45 @@ from repoze.bfg.interfaces import IForbiddenView
from repoze.bfg.interfaces import IAuthenticationPolicy
from repoze.bfg.interfaces import IAuthorizationPolicy
from repoze.bfg.interfaces import ISecurityPolicy
+from repoze.bfg.interfaces import ISecuredView
+from repoze.bfg.interfaces import IMultiView
from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import IUnauthorizedAppFactory
from repoze.bfg.interfaces import ILogger
-from repoze.bfg.interfaces import IRequestFactories
from repoze.bfg.interfaces import IPackageOverrides
+from repoze.bfg.interfaces import IRequest
+from repoze.bfg.interfaces import IRouteRequest
from repoze.bfg.path import package_name
from repoze.bfg.resource import PackageOverrides
-from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
-from repoze.bfg.request import named_request_factories
+from repoze.bfg.request import create_route_request_factory
-from repoze.bfg.security import ViewPermissionFactory
+from repoze.bfg.security import Unauthorized
from repoze.bfg.secpols import registerBBBAuthn
+from repoze.bfg.settings import get_settings
+
+from repoze.bfg.traversal import find_interface
from repoze.bfg.view import static as static_view
+from repoze.bfg.view import NotFound
+from repoze.bfg.view import MultiView
+from repoze.bfg.view import map_view
+from repoze.bfg.view import decorate_view
+
import martian
-def handler(methodName, *args, **kwargs):
- method = getattr(getSiteManager(), methodName)
- method(*args, **kwargs)
+try:
+ all = all
+except NameError: # pragma: no cover
+ def all(iterable):
+ for element in iterable:
+ if not element:
+ return False
+ return True
def view(
_context,
@@ -65,56 +82,154 @@ def view(
name="",
request_type=None,
route_name=None,
+ request_method=None,
+ request_param=None,
+ containment=None,
cacheable=True, # not used, here for b/w compat < 0.8
):
if not view:
raise ConfigurationError('"view" attribute was not specified')
- if route_name is None:
- request_factories = DEFAULT_REQUEST_FACTORIES
- else:
- request_factories = queryUtility(IRequestFactories, name=route_name)
- if request_factories is None:
- raise ConfigurationError(
- 'Unknown route_name "%s". <route> definitions must be ordered '
- 'before the view definition which mentions the route\'s name '
- 'within ZCML (or before the "scan" directive is invoked '
- 'within a bfg_view decorator).' % route_name)
-
- if request_type in request_factories:
- request_type = request_factories[request_type]['interface']
- else:
- request_type = _context.resolve(request_type)
+ sm = getSiteManager()
+
+ if request_type in ('GET', 'HEAD', 'PUT', 'POST', 'DELETE'):
+ # b/w compat for 1.0
+ request_method = request_type
+ request_type = None
- derived_view = derive_view(view)
+ if request_type is None:
+ if route_name is None:
+ request_type = IRequest
+ else:
+ request_type = queryUtility(IRouteRequest, name=route_name)
+ if request_type is None:
+ factory = create_route_request_factory(route_name)
+ request_type = implementedBy(factory)
+ sm.registerUtility(factory, IRouteRequest, name=route_name)
- if permission:
- pfactory = ViewPermissionFactory(permission)
- _context.action(
- discriminator = ('permission', for_, name, request_type,
- IViewPermission),
- callable = handler,
- args = ('registerAdapter',
- pfactory, (for_, request_type), IViewPermission, name,
- _context.info),
- )
+ if isinstance(request_type, basestring):
+ request_type = _context.resolve(request_type)
+ predicates = []
+ weight = sys.maxint
+
+ # Predicates are added to the predicate list in (presumed)
+ # computation expense order. All predicates associated with a
+ # view must evaluate true for the view to "match" a request.
+ # Elsewhere in the code, we evaluate them using a generator
+ # expression. The fastest predicate should be evaluated first,
+ # then the next fastest, and so on, as if one returns false, the
+ # remainder of the predicates won't need to be evaluated.
+
+ # Each predicate is associated with a weight value. The weight
+ # symbolizes the relative potential "importance" of the predicate
+ # to all other predicates. A larger weight indicates greater
+ # importance. These weights are subtracted from an aggregate
+ # 'weight' variable. The aggregate weight is then divided by the
+ # length of the predicate list to compute a "score" for this view.
+ # The score represents the ordering in which a "multiview" ( a
+ # collection of views that share the same context/request/name
+ # triad but differ in other ways via predicates) will attempt to
+ # call its set of views. Views with lower scores will be tried
+ # first. The intent is to a) ensure that views with more
+ # predicates are always evaluated before views with fewer
+ # predicates and b) to ensure a stable call ordering of views that
+ # share the same number of predicates.
+
+ # Views which do not have any predicates get a score of
+ # "sys.maxint", meaning that they will be tried very last.
+
+ if request_method is not None:
+ def request_method_predicate(context, request):
+ return request.method == request_method
+ weight = weight - 10
+ predicates.append(request_method_predicate)
+
+ if request_param is not None:
+ request_param_val = None
+ if '=' in request_param:
+ request_param, request_param_val = request_param.split('=', 1)
+ def request_param_predicate(context, request):
+ if request_param_val is None:
+ return request_param in request.params
+ return request.params.get(request_param) == request_param_val
+ weight = weight - 20
+ predicates.append(request_param_predicate)
+
+ if containment is not None:
+ def containment_predicate(context, request):
+ return find_interface(context, containment) is not None
+ weight = weight - 30
+ predicates.append(containment_predicate)
+
+ if predicates:
+ score = float(weight) / len(predicates)
+ else:
+ score = sys.maxint
+
+ def register():
+ derived_view = derive_view(view, permission, predicates)
+ r_for_ = for_
+ r_request_type = request_type
+ if r_for_ is None:
+ r_for_ = Interface
+ if not IInterface.providedBy(r_for_):
+ r_for_ = implementedBy(r_for_)
+ if not IInterface.providedBy(r_request_type):
+ r_request_type = implementedBy(r_request_type)
+ old_view = sm.adapters.lookup((r_for_, r_request_type), IView,name=name)
+ if old_view is None:
+ if hasattr(derived_view, '__call_permissive__'):
+ sm.registerAdapter(derived_view, (for_, request_type),
+ ISecuredView, name, _context.info)
+ if hasattr(derived_view, '__permitted__'):
+ # bw compat
+ sm.registerAdapter(derived_view.__permitted__,
+ (for_, request_type), IViewPermission,
+ name, _context.info)
+ else:
+ sm.registerAdapter(derived_view, (for_, request_type),
+ IView, name, _context.info)
+ else:
+ # XXX we could try to be more efficient here and register
+ # a non-secured view for a multiview if none of the
+ # multiview's consituent views have a permission
+ # associated with them, but this code is getting pretty
+ # rough already
+ if IMultiView.providedBy(old_view):
+ multiview = old_view
+ else:
+ multiview = MultiView(name)
+ multiview.add(old_view, sys.maxint)
+ multiview.add(derived_view, score)
+ for i in (IView, ISecuredView):
+ # unregister any existing views
+ sm.adapters.unregister((r_for_, r_request_type), i, name=name)
+ sm.registerAdapter(multiview, (for_, request_type), IMultiView,
+ name, _context.info)
+ # b/w compat
+ sm.registerAdapter(multiview.__permitted__,
+ (for_, request_type), IViewPermission,
+ name, _context.info)
_context.action(
- discriminator = ('view', for_, name, request_type, IView),
- callable = handler,
- args = ('registerAdapter',
- derived_view, (for_, request_type), IView, name, _context.info),
+ discriminator = ('view', for_, name, request_type, IView, containment,
+ request_param, request_method, route_name),
+ callable = register,
+ args = (),
)
_view = view # for directives that take a view arg
def view_utility(_context, view, iface):
- derived_view = derive_view(view)
+ def register():
+ derived_view = derive_view(view)
+ sm = getSiteManager()
+ sm.registerUtility(derived_view, iface, '', _context.info)
+
_context.action(
- discriminator = ('notfound_view',),
- callable = handler,
- args = ('registerUtility', derived_view, iface, '', _context.info),
+ discriminator = iface,
+ callable = register,
)
def notfound(_context, view):
@@ -123,46 +238,83 @@ def notfound(_context, view):
def forbidden(_context, view):
view_utility(_context, view, IForbiddenView)
-def derive_view(view):
- derived_view = view
- if inspect.isclass(view):
- # If the object we've located is a class, turn it into a
- # function that operates like a Zope view (when it's invoked,
- # construct an instance using 'context' and 'request' as
- # position arguments, then immediately invoke the __call__
- # method of the instance with no arguments; __call__ should
- # return an IResponse).
- if requestonly(view):
- # its __init__ accepts only a single request argument,
- # instead of both context and request
- def _bfg_class_requestonly_view(context, request):
- inst = view(request)
- return inst()
- derived_view = _bfg_class_requestonly_view
- else:
- # its __init__ accepts both context and request
- def _bfg_class_view(context, request):
- inst = view(context, request)
- return inst()
- derived_view = _bfg_class_view
-
- elif requestonly(view):
- # its __call__ accepts only a single request argument,
- # instead of both context and request
- def _bfg_requestonly_view(context, request):
- return view(request)
- derived_view = _bfg_requestonly_view
-
- if derived_view is not view:
- derived_view.__module__ = view.__module__
- derived_view.__doc__ = view.__doc__
- try:
- derived_view.__name__ = view.__name__
- except AttributeError:
- derived_view.__name__ = repr(view)
-
+def derive_view(original_view, permission=None, predicates=()):
+ mapped_view = map_view(original_view)
+ secured_view = secure_view(mapped_view, permission)
+ debug_view = authdebug_view(secured_view, permission)
+ derived_view = predicate_wrap(debug_view, predicates)
return derived_view
-
+
+def predicate_wrap(view, predicates):
+ if not predicates:
+ return view
+ def _wrapped(context, request):
+ if all((predicate(context, request) for predicate in predicates)):
+ return view(context, request)
+ raise NotFound('predicate mismatch for view %s' % view)
+ def checker(context, request):
+ return all((predicate(context, request) for predicate in predicates))
+ _wrapped.__predicated__ = checker
+ decorate_view(_wrapped, view)
+ return _wrapped
+
+def secure_view(view, permission):
+ wrapped_view = view
+ authn_policy = queryUtility(IAuthenticationPolicy)
+ authz_policy = queryUtility(IAuthorizationPolicy)
+ if authn_policy and authz_policy and (permission is not None):
+ def _secured_view(context, request):
+ principals = authn_policy.effective_principals(request)
+ if authz_policy.permits(context, principals, permission):
+ return view(context, request)
+ msg = getattr(request, 'authdebug_message',
+ 'Unauthorized: %s failed permission check' % view)
+ raise Unauthorized(msg)
+ _secured_view.__call_permissive__ = view
+ def _permitted(context, request):
+ principals = authn_policy.effective_principals(request)
+ return authz_policy.permits(context, principals, permission)
+ _secured_view.__permitted__ = _permitted
+ wrapped_view = _secured_view
+ decorate_view(wrapped_view, view)
+
+ return wrapped_view
+
+def authdebug_view(view, permission):
+ wrapped_view = view
+ authn_policy = queryUtility(IAuthenticationPolicy)
+ authz_policy = queryUtility(IAuthorizationPolicy)
+ settings = get_settings()
+ debug_authorization = getattr(settings, 'debug_authorization', False)
+ if debug_authorization:
+ def _authdebug_view(context, request):
+ view_name = getattr(request, 'view_name', None)
+
+ if authn_policy and authz_policy:
+ if permission is None:
+ msg = 'Allowed (no permission registered)'
+ else:
+ principals = authn_policy.effective_principals(request)
+ msg = str(authz_policy.permits(context, principals,
+ permission))
+ else:
+ msg = 'Allowed (no authorization policy in use)'
+
+ view_name = getattr(request, 'view_name', None)
+ url = getattr(request, 'url', None)
+ msg = ('debug_authorization of url %s (view name %r against '
+ 'context %r): %s' % (url, view_name, context, msg))
+ logger = getUtility(ILogger, 'repoze.bfg.debug')
+ logger and logger.debug(msg)
+ if request is not None:
+ request.authdebug_message = msg
+ return view(context, request)
+
+ wrapped_view = _authdebug_view
+ decorate_view(wrapped_view, view)
+
+ return wrapped_view
+
def scan(_context, package, martian=martian):
# martian overrideable only for unit tests
module_grokker = martian.ModuleGrokker()
@@ -240,12 +392,11 @@ def repozewho1authenticationpolicy(_context, identifier_name='auth_tkt',
callback=None):
policy = RepozeWho1AuthenticationPolicy(identifier_name=identifier_name,
callback=callback)
- _context.action(
- discriminator = 'authentication_policy',
- callable = handler,
- args = ('registerUtility', policy, IAuthenticationPolicy, '',
- _context.info),
- )
+ # authentication policies must be registered eagerly so they can
+ # be found by the view registration machinery
+ sm = getSiteManager()
+ sm.registerUtility(policy, IAuthenticationPolicy)
+ _context.action(discriminator=IAuthenticationPolicy)
class IRemoteUserAuthenticationPolicyDirective(Interface):
environ_key = TextLine(title=u'environ_key', required=False,
@@ -256,12 +407,11 @@ def remoteuserauthenticationpolicy(_context, environ_key='REMOTE_USER',
callback=None):
policy = RemoteUserAuthenticationPolicy(environ_key=environ_key,
callback=callback)
- _context.action(
- discriminator = 'authentication_policy',
- callable = handler,
- args = ('registerUtility', policy, IAuthenticationPolicy, '',
- _context.info),
- )
+ # authentication policies must be registered eagerly so they can
+ # be found by the view registration machinery
+ sm = getSiteManager()
+ sm.registerUtility(policy, IAuthenticationPolicy)
+ _context.action(discriminator=IAuthenticationPolicy)
class IAuthTktAuthenticationPolicyDirective(Interface):
secret = TextLine(title=u'secret', required=True)
@@ -291,49 +441,91 @@ def authtktauthenticationpolicy(_context,
reissue_time = reissue_time)
except ValueError, why:
raise ConfigurationError(str(why))
- _context.action(
- discriminator = 'authentication_policy',
- callable = handler,
- args = ('registerUtility', policy, IAuthenticationPolicy, '',
- _context.info),
- )
+ # authentication policies must be registered eagerly so they can
+ # be found by the view registration machinery
+ sm = getSiteManager()
+ sm.registerUtility(policy, IAuthenticationPolicy)
+ _context.action(discriminator=IAuthenticationPolicy)
class IACLAuthorizationPolicyDirective(Interface):
pass
def aclauthorizationpolicy(_context):
policy = ACLAuthorizationPolicy()
- _context.action(
- discriminator = 'authorization_policy',
- callable = handler,
- args = ('registerUtility', policy, IAuthorizationPolicy, '',
- _context.info),
- )
+ # authorization policies must be registered eagerly so they can be
+ # found by the view registration machinery
+ sm = getSiteManager()
+ sm.registerUtility(policy, IAuthorizationPolicy)
+ _context.action(discriminator=IAuthorizationPolicy)
class IRouteDirective(Interface):
""" The interface for the ``route`` ZCML directive
"""
name = TextLine(title=u'name', required=True)
path = TextLine(title=u'path', required=True)
+ factory = GlobalObject(title=u'context factory', required=False)
view = GlobalObject(title=u'view', required=False)
view_for = GlobalObject(title=u'view_for', required=False)
+ view_permission = TextLine(title=u'view_permission', required=False)
+ view_request_type = TextLine(title=u'view_request_type', required=False)
+ view_request_method = TextLine(title=u'view_request_method', required=False)
+ view_containment = GlobalObject(
+ title = u'Dotted name of a containment class or interface',
+ required=False)
+ # alias for "view_for"
+ for_ = GlobalObject(title=u'for', required=False)
+ # alias for "view_permission"
permission = TextLine(title=u'permission', required=False)
- factory = GlobalObject(title=u'context factory', required=False)
+ # alias for "view_request_type"
request_type = TextLine(title=u'request_type', required=False)
-
-def route(_context, name, path, view=None, view_for=None, permission=None,
- factory=None, request_type=None):
+ # alias for "view_request_method"
+ request_method = TextLine(title=u'request_method', required=False)
+ # alias for "view_request_param"
+ request_param = TextLine(title=u'request_param', required=False)
+ # alias for "view_containment"
+ containment = GlobalObject(
+ title = u'Dotted name of a containment class or interface',
+ required=False)
+
+def route(_context, name, path, view=None, view_for=None,
+ permission=None, factory=None, request_type=None, for_=None,
+ view_permission=None, view_request_type=None,
+ request_method=None, view_request_method=None,
+ request_param=None, view_request_param=None, containment=None,
+ view_containment=None):
""" Handle ``route`` ZCML directives
"""
+ # the strange ordering of the request kw args above is for b/w
+ # compatibility purposes.
+ for_ = view_for or for_
+ request_type = view_request_type or request_type
+ permission = view_permission or permission
+ request_method = view_request_method or request_method
+ request_param = view_request_param or request_param
+ containment = view_containment or containment
+
sm = getSiteManager()
- request_factories = named_request_factories(name)
- sm.registerUtility(request_factories, IRequestFactories, name=name)
+
+ if request_type in ('GET', 'HEAD', 'PUT', 'POST', 'DELETE'):
+ # b/w compat for 1.0
+ request_method = request_type
+ request_type = None
+
+ if request_type is None:
+ request_factory = queryUtility(IRouteRequest, name=name)
+ if request_factory is None:
+ request_factory = create_route_request_factory(name)
+ sm.registerUtility(request_factory, IRouteRequest, name=name)
+ request_type = implementedBy(request_factory)
if view:
- _view(_context, permission, view_for, view, '', request_type, name)
+ _view(_context, permission=permission, for_=for_, view=view, name='',
+ request_type=request_type, route_name=name,
+ request_method=request_method, request_param=request_param,
+ containment=containment)
_context.action(
- discriminator = ('route', name, view_for, request_type),
+ discriminator = ('route', name),
callable = connect_route,
args = (path, name, factory),
)
@@ -361,6 +553,10 @@ class IStaticDirective(Interface):
required=False,
default=None)
+class StaticRootFactory:
+ def __init__(self, environ):
+ pass
+
def static(_context, name, path, cache_max_age=3600):
""" Handle ``static`` ZCML directives
"""
@@ -371,7 +567,8 @@ def static(_context, name, path, cache_max_age=3600):
path = '%s:%s' % (package_name(_context.resolve('.')), path)
view = static_view(path, cache_max_age=cache_max_age)
- route(_context, name, "%s*subpath" % name, view=view)
+ route(_context, name, "%s*subpath" % name, view=view,
+ view_for=StaticRootFactory, factory=StaticRootFactory)
class IViewDirective(Interface):
for_ = GlobalObject(
@@ -394,8 +591,7 @@ class IViewDirective(Interface):
name = TextLine(
title=u"The name of the view",
description=u"""
- The name shows up in URLs/paths. For example 'foo' or
- 'foo.html'.""",
+ The name shows up in URLs/paths. For example 'foo' or 'foo.html'.""",
required=False,
)
@@ -411,6 +607,25 @@ class IViewDirective(Interface):
title = u'The route that must match for this view to be used',
required = False)
+ containment = GlobalObject(
+ title = u'Dotted name of a containment class or interface',
+ required=False)
+
+ request_method = TextLine(
+ title = u'Request method name that must be matched (e.g. GET/POST)',
+ description = (u'The view will be called if and only if the request '
+ 'method (``request.method``) matches this string. This'
+ 'functionality replaces the older ``request_type`` '
+ 'functionality.'),
+ required=False)
+
+ request_param = TextLine(
+ title = (u'Request parameter name that must exist in '
+ '``request.params`` for this view to match'),
+ description = (u'The view will be called if and only if the request '
+ 'parameter exists which matches this string.'),
+ required=False)
+
class INotFoundViewDirective(Interface):
view = GlobalObject(
title=u"",
@@ -523,10 +738,14 @@ class BFGViewFunctionGrokker(martian.InstanceGrokker):
name = obj.__view_name__
request_type = obj.__request_type__
route_name = obj.__route_name__
+ request_method = obj.__request_method__
+ request_param = obj.__request_param__
+ containment = obj.__containment__
context = kw['context']
view(context, permission=permission, for_=for_,
view=obj, name=name, request_type=request_type,
- route_name=route_name)
+ route_name=route_name, request_method=request_method,
+ request_param=request_param, containment=containment)
return True
return False
@@ -535,47 +754,6 @@ def exclude(name):
return True
return False
-def requestonly(class_or_callable):
- """ Return true of the class or callable accepts only a request argument,
- as opposed to something that accepts context, request """
- if inspect.isfunction(class_or_callable):
- fn = class_or_callable
- elif inspect.isclass(class_or_callable):
- try:
- fn = class_or_callable.__init__
- except AttributeError:
- return False
- else:
- try:
- fn = class_or_callable.__call__
- except AttributeError:
- return False
-
- try:
- argspec = inspect.getargspec(fn)
- except TypeError:
- 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:
- return False
-
- if len(args) == 1:
- return True
-
- elif args[0] == 'request':
- if len(args) - len(defaults) == 1:
- return True
-
- return False
-
class Uncacheable(object):
""" Include in discriminators of actions which are not cacheable;
this class only exists for backwards compatibility (<0.8.1)"""