summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-09-30 03:27:28 +0000
committerChris McDonough <chrism@agendaless.com>2009-09-30 03:27:28 +0000
commitd75fe70228c89e3606e51a4d5775faf549252a90 (patch)
tree043a7334d49a7455b80789f1aab56e4238dbd6b0
parent4be6ce73f41e09bf0f3e5df01d7f5aaf4f3137a6 (diff)
downloadpyramid-d75fe70228c89e3606e51a4d5775faf549252a90.tar.gz
pyramid-d75fe70228c89e3606e51a4d5775faf549252a90.tar.bz2
pyramid-d75fe70228c89e3606e51a4d5775faf549252a90.zip
- The import of ``repoze.bfg.view.NotFound`` is deprecated in favor of
``repoze.bfg.exceptions.NotFound``. The old location still functions, but emits a deprecation warning. - The import of ``repoze.bfg.security.Unauthorized`` is deprecated in favor of ``repoze.bfg.exceptions.Forbidden``. The old location still functions but emits a deprecation warning. The rename from ``Unauthorized`` to ``Forbidden`` brings parity to the the name of the exception and the system view it invokes when raised. - New ``repoze.bfg.exceptions`` module was created to house exceptions that were previously sprinkled through various modules. - An ``exceptions`` API chapter was added, documenting the new ``repoze.bfg.exceptions`` module.
-rw-r--r--CHANGES.txt19
-rw-r--r--docs/api/exceptions.rst11
-rw-r--r--docs/index.rst1
-rw-r--r--docs/narr/views.rst4
-rw-r--r--repoze/bfg/exceptions.py24
-rw-r--r--repoze/bfg/interfaces.py6
-rw-r--r--repoze/bfg/router.py6
-rw-r--r--repoze/bfg/security.py14
-rw-r--r--repoze/bfg/testing.py4
-rw-r--r--repoze/bfg/tests/test_router.py6
-rw-r--r--repoze/bfg/tests/test_testing.py4
-rw-r--r--repoze/bfg/tests/test_view.py18
-rw-r--r--repoze/bfg/tests/test_zcml.py8
-rw-r--r--repoze/bfg/view.py26
14 files changed, 111 insertions, 40 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 347d0292f..981483e25 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -7,6 +7,9 @@ Documentation
- Added a diagram of model graph traversal to the "Traversal"
narrative chapter of the documentation.
+- An ``exceptions`` API chapter was added, documenting the new
+ ``repoze.bfg.exceptions`` module.
+
Features
--------
@@ -30,12 +33,28 @@ Features
- Minor speedup of ``repoze.bfg.router.Router.__call__``.
+- New ``repoze.bfg.exceptions`` module was created to house exceptions
+ that were previously sprinkled through various modules.
+
Internal
--------
- Move ``repoze.bfg.traversal._url_quote`` into ``repoze.bfg.encode``
as ``url_quote``.
+Deprecations
+------------
+
+- The import of ``repoze.bfg.view.NotFound`` is deprecated in favor of
+ ``repoze.bfg.exceptions.NotFound``. The old location still
+ functions, but emits a deprecation warning.
+
+- The import of ``repoze.bfg.security.Unauthorized`` is deprecated in
+ favor of ``repoze.bfg.exceptions.Forbidden``. The old location
+ still functions but emits a deprecation warning. The rename from
+ ``Unauthorized`` to ``Forbidden`` brings parity to the the name of
+ the exception and the system view it invokes when raised.
+
Backwards Incompatibilities
---------------------------
diff --git a/docs/api/exceptions.rst b/docs/api/exceptions.rst
new file mode 100644
index 000000000..63a3916ae
--- /dev/null
+++ b/docs/api/exceptions.rst
@@ -0,0 +1,11 @@
+.. _exceptions_module:
+
+:mod:`repoze.bfg.exceptions`
+----------------------------
+
+.. automodule:: repoze.bfg.exceptions
+
+ .. autoclass:: NotFound
+
+ .. autoclass:: Forbidden
+
diff --git a/docs/index.rst b/docs/index.rst
index 6b85f1440..1305104c4 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -57,6 +57,7 @@ Per-module :mod:`repoze.bfg` API documentation.
api/chameleon_text
api/chameleon_zpt
api/events
+ api/exceptions
api/location
api/paster
api/router
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index 5fe66dc63..b45221e71 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -680,7 +680,7 @@ 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
+the current context, processing stops, and an ``Forbidden`` error
is raised, usually resulting in a "forbidden" view being shown to the
invoking user. No further view narrowing or view lookup is done.
@@ -989,7 +989,7 @@ user does not possess the ``add`` permission relative to the current
.. note::
Packages such as :term:`repoze.who` are capable of intercepting an
- ``Unauthorized`` response and displaying a form that asks a user to
+ ``Forbidden`` response and displaying a form that asks a user to
authenticate. Use this kind of package to ask the user for
authentication credentials.
diff --git a/repoze/bfg/exceptions.py b/repoze/bfg/exceptions.py
new file mode 100644
index 000000000..afd617a2c
--- /dev/null
+++ b/repoze/bfg/exceptions.py
@@ -0,0 +1,24 @@
+class Forbidden(Exception):
+ """\
+ Raise this exception within :term:`view` code to immediately
+ return the Forbidden view to the invoking user. Usually this is a
+ basic ``401`` page, but the Forbidden view can be customized as
+ necessary. See :ref:`changing_the_forbidden_view`.
+
+ This exception's constructor accepts a single positional argument,
+ which should be a string. The value of this string will be placed
+ into the WSGI environment under the ``repoze.bfg.message`` key,
+ for availability to the Forbidden view."""
+
+class NotFound(Exception):
+ """\
+ Raise this exception within :term:`view` code to immediately
+ return the Not Found view to the invoking user. Usually this is a
+ basic ``404`` page, but the Not Found view can be customized as
+ necessary. See :ref:`changing_the_notfound_view`.
+
+ This exception's constructor accepts a single positional argument,
+ which should be a string. The value of this string will be placed
+ into the WSGI environment under the ``repoze.bfg.message`` key,
+ for availability to the Not Found view."""
+
diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py
index 8896c883e..5d8394484 100644
--- a/repoze/bfg/interfaces.py
+++ b/repoze/bfg/interfaces.py
@@ -26,8 +26,10 @@ class IResponse(Interface):
class IView(Interface):
def __call__(context, request):
""" Must return an object that implements IResponse. May
- optionally raise ``repoze.bfg.security.Unauthorized`` if an
- authorization failure is detected during view execution."""
+ optionally raise ``repoze.bfg.exceptions.Forbidden`` if an
+ authorization failure is detected during view execution or
+ ``repoze.bfg.exceptions.NotFound`` if the not found page is
+ meant to be returned."""
class ISecuredView(IView):
""" *Internal only* interface. Not an API. """
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index ec6c5969a..e2b2b6830 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -23,18 +23,18 @@ from repoze.bfg.authorization import ACLAuthorizationPolicy
from repoze.bfg.events import NewRequest
from repoze.bfg.events import NewResponse
from repoze.bfg.events import WSGIApplicationCreatedEvent
+from repoze.bfg.exceptions import Forbidden
+from repoze.bfg.exceptions import NotFound
from repoze.bfg.log import make_stream_logger
from repoze.bfg.registry import Registry
from repoze.bfg.registry import populateRegistry
from repoze.bfg.request import request_factory
-from repoze.bfg.security import Unauthorized
from repoze.bfg.settings import Settings
from repoze.bfg.settings import get_options
from repoze.bfg.threadlocal import manager
from repoze.bfg.traversal import ModelGraphTraverser
from repoze.bfg.traversal import _traverse
from repoze.bfg.urldispatch import RoutesRootFactory
-from repoze.bfg.view import NotFound
from repoze.bfg.view import default_forbidden_view
from repoze.bfg.view import default_notfound_view
@@ -118,7 +118,7 @@ class Router(object):
else:
try:
response = view_callable(context, request)
- except Unauthorized, why:
+ except Forbidden, why:
msg = why[0]
environ = getattr(request, 'environ', {})
environ['repoze.bfg.message'] = msg
diff --git a/repoze/bfg/security.py b/repoze/bfg/security.py
index 466c33da3..e0873a0ad 100644
--- a/repoze/bfg/security.py
+++ b/repoze/bfg/security.py
@@ -2,10 +2,21 @@ from zope.component import getSiteManager
from zope.component import providedBy
from zope.component import queryUtility
+from zope.deprecation import deprecated
+
from repoze.bfg.interfaces import IAuthenticationPolicy
from repoze.bfg.interfaces import IAuthorizationPolicy
from repoze.bfg.interfaces import ISecuredView
+# b/c import
+from repoze.bfg.exceptions import Forbidden as Unauthorized
+
+deprecated('Unauthorized',
+ "('from repoze.bfg.security import Unauthorized' was "
+ "deprecated as of repoze.bfg 1.1; instead use 'from "
+ "repoze.bfg.exceptions import Forbidden')",
+ )
+
Everyone = 'system.Everyone'
Authenticated = 'system.Authenticated'
Allow = 'Allow'
@@ -229,6 +240,3 @@ class ACLAllowed(ACLPermitsResult):
as the ``msg`` attribute."""
boolval = 1
-class Unauthorized(Exception):
- pass
-
diff --git a/repoze/bfg/testing.py b/repoze/bfg/testing.py
index 92bb4399a..2e31afce6 100644
--- a/repoze/bfg/testing.py
+++ b/repoze/bfg/testing.py
@@ -101,7 +101,7 @@ def registerView(name, result='', view=None, for_=(Interface, Interface),
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
+ from repoze.bfg.exceptions import Forbidden
if view is None:
def view(context, request):
from webob import Response
@@ -111,7 +111,7 @@ def registerView(name, result='', view=None, for_=(Interface, Interface),
else:
def _secure(context, request):
if not has_permission(permission, context, request):
- raise Unauthorized('no permission')
+ raise Forbidden('no permission')
else:
return view(context, request)
_secure.__call_permissive__ = view
diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py
index 3116d2572..5c39b65f0 100644
--- a/repoze/bfg/tests/test_router.py
+++ b/repoze/bfg/tests/test_router.py
@@ -672,10 +672,10 @@ class DummyView:
def __call__(self, context, request):
if self.raise_unauthorized:
- from repoze.bfg.security import Unauthorized
- raise Unauthorized('unauthorized')
+ from repoze.bfg.exceptions import Forbidden
+ raise Forbidden('unauthorized')
if self.raise_notfound:
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
raise NotFound('notfound')
return self.response
diff --git a/repoze/bfg/tests/test_testing.py b/repoze/bfg/tests/test_testing.py
index c302bd9f5..938115ecd 100644
--- a/repoze/bfg/tests/test_testing.py
+++ b/repoze/bfg/tests/test_testing.py
@@ -149,7 +149,7 @@ class TestTestingFunctions(unittest.TestCase):
def test_registerView_with_permission_denying(self):
from repoze.bfg import testing
- from repoze.bfg.security import Unauthorized
+ from repoze.bfg.exceptions import Forbidden
def view(context, request):
""" """
view = testing.registerView('moo.html', view=view, permission='bar')
@@ -157,7 +157,7 @@ class TestTestingFunctions(unittest.TestCase):
import types
self.failUnless(isinstance(view, types.FunctionType))
from repoze.bfg.view import render_view_to_response
- self.assertRaises(Unauthorized, render_view_to_response,
+ self.assertRaises(Forbidden, render_view_to_response,
None, None, 'moo.html')
def test_registerView_with_permission_denying2(self):
diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py
index edbfa120f..32c9d391b 100644
--- a/repoze/bfg/tests/test_view.py
+++ b/repoze/bfg/tests/test_view.py
@@ -467,14 +467,14 @@ class TestMultiView(unittest.TestCase):
self.assertEqual(mv.views, [(99, 'view2'), (100, 'view')])
def test_match_not_found(self):
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions 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
+ from repoze.bfg.exceptions import NotFound
mv = self._makeOne()
def view(context, request):
""" """
@@ -496,7 +496,7 @@ class TestMultiView(unittest.TestCase):
self.assertEqual(result, view)
def test_permitted_no_views(self):
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
mv = self._makeOne()
context = DummyContext()
request = DummyRequest()
@@ -527,14 +527,14 @@ class TestMultiView(unittest.TestCase):
self.assertEqual(result, False)
def test__call__not_found(self):
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions 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
+ from repoze.bfg.exceptions import NotFound
mv = self._makeOne()
context = DummyContext()
request = DummyRequest()
@@ -561,7 +561,7 @@ class TestMultiView(unittest.TestCase):
self.assertEqual(response, expected_response)
def test__call_permissive__not_found(self):
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
mv = self._makeOne()
context = DummyContext()
request = DummyRequest()
@@ -1408,7 +1408,7 @@ class TestDeriveView(unittest.TestCase):
"'view_name' against context None): True")
def test_view_with_debug_authorization_permission_authpol_denied(self):
- from repoze.bfg.security import Unauthorized
+ from repoze.bfg.exceptions import Forbidden
def view(context, request):
""" """
self._registerSettings(debug_authorization=True, reload_templates=True)
@@ -1422,7 +1422,7 @@ class TestDeriveView(unittest.TestCase):
request = DummyRequest()
request.view_name = 'view_name'
request.url = 'url'
- self.assertRaises(Unauthorized, result, None, request)
+ self.assertRaises(Forbidden, result, None, request)
self.assertEqual(len(logger.messages), 1)
self.assertEqual(logger.messages[0],
"debug_authorization of url url (view name "
@@ -1462,7 +1462,7 @@ class TestDeriveView(unittest.TestCase):
self.assertEqual(predicates, [True, True])
def test_view_with_predicates_notall(self):
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
def view(context, request):
""" """
predicates = []
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index 89ad71cac..35584f301 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -573,7 +573,7 @@ class TestViewDirective(unittest.TestCase):
from zope.interface import Interface
from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IView
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
context = DummyContext()
class IFoo(Interface):
pass
@@ -626,7 +626,7 @@ class TestViewDirective(unittest.TestCase):
from zope.interface import Interface
from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IView
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
context = DummyContext()
class IFoo(Interface):
pass
@@ -679,7 +679,7 @@ class TestViewDirective(unittest.TestCase):
from zope.interface import Interface
from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IView
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
context = DummyContext()
class IFoo(Interface):
pass
@@ -735,7 +735,7 @@ class TestViewDirective(unittest.TestCase):
from zope.interface import Interface
from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IView
- from repoze.bfg.view import NotFound
+ from repoze.bfg.exceptions import NotFound
context = DummyContext()
class IFoo(Interface):
pass
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index 8d8d6baa0..91ccad57d 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -31,13 +31,17 @@ from repoze.bfg.interfaces import IRendererFactory
from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import IView
+from repoze.bfg.exceptions import NotFound
+from repoze.bfg.exceptions import Forbidden
from repoze.bfg.path import caller_package
from repoze.bfg.renderers import renderer_from_name
from repoze.bfg.resource import resource_spec
-from repoze.bfg.security import Unauthorized
from repoze.bfg.settings import get_settings
from repoze.bfg.static import PackageURLParser
+# b/c imports
+from repoze.bfg.security import view_execution_permitted
+
try:
all = all
except NameError: # pragma: no cover
@@ -53,6 +57,12 @@ deprecated('view_execution_permitted',
"repoze.bfg.security import view_execution_permitted')",
)
+deprecated('NotFound',
+ "('from repoze.bfg.view import NotFound' was "
+ "deprecated as of repoze.bfg 1.1; instead use 'from "
+ "repoze.bfg.exceptions import NotFound')",
+ )
+
_marker = object()
def render_view_to_response(context, request, name='', secure=True):
@@ -64,7 +74,7 @@ def render_view_to_response(context, request, name='', secure=True):
protected by a permission, the permission will be checked before
calling the view function. If the permission check disallows view
execution (based on the current security policy), a
- ``repoze.bfg.security.Unauthorized`` exception will be raised; its
+ ``repoze.bfg.exceptions.Forbidden`` exception will be raised; its
``args`` attribute explains why the view access was disallowed.
If ``secure`` is ``False``, no permission checking is done."""
provides = map(providedBy, (context, request))
@@ -78,7 +88,7 @@ def render_view_to_response(context, request, name='', secure=True):
# secured; otherwise it won't.
view = getattr(view, '__call_permissive__', view)
- # if this view is secured, it will raise an Unauthorized
+ # if this view is secured, it will raise a Forbidden
# appropriately if the executing user does not have the proper
# permission
return view(context, request)
@@ -98,7 +108,7 @@ def render_view_to_iterable(context, request, name='', secure=True):
a permission, the permission will be checked before calling the
view function. If the permission check disallows view execution
(based on the current security policy), a
- ``repoze.bfg.security.Unauthorized`` exception will be raised; its
+ ``repoze.bfg.exceptions.Forbidden`` exception will be raised; its
``args`` attribute explains why the view access was disallowed.
If ``secure`` is ``False``, no permission checking is done."""
response = render_view_to_response(context, request, name, secure)
@@ -119,7 +129,7 @@ def render_view(context, request, name='', secure=True):
permission, the permission will be checked before calling the view
function. If the permission check disallows view execution (based
on the current security policy), a
- ``repoze.bfg.security.Unauthorized`` exception will be raised; its
+ ``repoze.bfg.exceptions.Forbidden`` exception will be raised; its
``args`` attribute explains why the view access was disallowed.
If ``secure`` is ``False``, no permission checking is done."""
iterable = render_view_to_iterable(context, request, name, secure)
@@ -386,9 +396,6 @@ 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)
@@ -664,7 +671,7 @@ def secure_view(view, permission):
return view(context, request)
msg = getattr(request, 'authdebug_message',
'Unauthorized: %s failed permission check' % view)
- raise Unauthorized(msg)
+ raise Forbidden(msg)
_secured_view.__call_permissive__ = view
def _permitted(context, request):
principals = authn_policy.effective_principals(request)
@@ -711,4 +718,3 @@ def authdebug_view(view, permission):
decorate_view(wrapped_view, view)
return wrapped_view
-