Michael Merickel
2011-08-10 fecefff5f0c3a6aaafdd43d902aaed15edb8559e
Added the `pyramid.security.NO_PERMISSION_REQUIRED` constant.

Removed the undocumented version from pyramid.interfaces.
10 files modified
58 ■■■■■ changed files
docs/api/config.rst 2 ●●● patch | view | raw | blame | history
docs/api/security.rst 2 ●●●●● patch | view | raw | blame | history
docs/narr/security.rst 9 ●●●●● patch | view | raw | blame | history
pyramid/config.py 28 ●●●● patch | view | raw | blame | history
pyramid/interfaces.py 2 ●●●●● patch | view | raw | blame | history
pyramid/security.py 2 ●●●●● patch | view | raw | blame | history
pyramid/static.py 3 ●●●● patch | view | raw | blame | history
pyramid/tests/defpermbugapp/__init__.py 3 ●●●● patch | view | raw | blame | history
pyramid/tests/test_config.py 3 ●●●● patch | view | raw | blame | history
pyramid/tests/test_static.py 4 ●●●● patch | view | raw | blame | history
docs/api/config.rst
@@ -44,7 +44,7 @@
     .. automethod:: add_route
     .. automethod:: add_static_view(name, path, cache_max_age=3600, permission='__no_permission_required__')
     .. automethod:: add_static_view(name, path, cache_max_age=3600, permission=NO_PERMISSION_REQUIRED)
     .. automethod:: add_settings
docs/api/security.rst
@@ -57,6 +57,8 @@
    last ACE in an ACL in systems that use an "inheriting" security
    policy, representing the concept "don't inherit any other ACEs".
.. attribute:: NO_PERMISSION_REQUIRED
Return Values
-------------
docs/narr/security.rst
@@ -200,9 +200,9 @@
  permission is ignored for that view registration, and the
  view-configuration-named permission is used.
- If a view configuration names an explicit permission as the string
  ``__no_permission_required__``, the default permission is ignored,
  and the view is registered *without* a permission (making it
- If a view configuration names the permission
  :data:`pyramid.security.NO_PERMISSION_REQUIRED`, the default permission
  is ignored, and the view is registered *without* a permission (making it
  available to all callers regardless of their credentials).
.. warning::
@@ -210,7 +210,8 @@
   When you register a default permission, *all* views (even :term:`exception
   view` views) are protected by a permission.  For all views which are truly
   meant to be anonymously accessible, you will need to associate the view's
   configuration with the ``__no_permission_required__`` permission.
   configuration with the :data:`pyramid.security.NO_PERMISSION_REQUIRED`
   permission.
.. index::
   single: ACL
pyramid/config.py
@@ -71,6 +71,7 @@
from pyramid.request import route_request_iface
from pyramid.asset import PackageOverrides
from pyramid.asset import resolve_asset_spec
from pyramid.security import NO_PERMISSION_REQUIRED
from pyramid.settings import Settings
from pyramid.static import StaticURLInfo
from pyramid.threadlocal import get_current_registry
@@ -1170,10 +1171,10 @@
          ``default_permission`` argument, or if
          :meth:`pyramid.config.Configurator.set_default_permission`
          was used prior to this view registration.  Pass the string
          ``__no_permission_required__`` as the permission argument to
          explicitly indicate that the view should always be
          executable by entirely anonymous users, regardless of the
          default permission, bypassing any :term:`authorization
          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the
          permission argument to explicitly indicate that the view should
          always be executable by entirely anonymous users, regardless of
          the default permission, bypassing any :term:`authorization
          policy` that may be in effect.
        attr
@@ -2400,10 +2401,11 @@
          If a default permission is in effect, view configurations meant to
          create a truly anonymously accessible view (even :term:`exception
          view` views) *must* use the explicit permission string
          ``__no_permission_required__`` as the permission.  When this string
          is used as the ``permission`` for a view configuration, the default
          permission is ignored, and the view is registered, making it
          available to all callers regardless of their credentials.
          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission.
          When this string is used as the ``permission`` for a view
          configuration, the default permission is ignored, and the view is
          registered, making it available to all callers regardless of their
          credentials.
        See also :ref:`setting_a_default_permission`.
@@ -2530,10 +2532,10 @@
        The ``permission`` keyword argument is used to specify the
        :term:`permission` required by a user to execute the static view.  By
        default, it is the string ``__no_permission_required__``.  The
        ``__no_permission_required__`` string is a special sentinel which
        indicates that, even if a :term:`default permission` exists for the
        current application, the static view should be renderered to
        default, it is the string
        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel
        which indicates that, even if a :term:`default permission` exists for
        the current application, the static view should be renderered to
        completely anonymous users.  This default value is permissive
        because, in most web apps, static assets seldom need protection from
        viewing.  If ``permission`` is specified, the security checking will
@@ -3132,7 +3134,7 @@
    @wraps_view
    def secured_view(self, view):
        permission = self.kw.get('permission')
        if permission == '__no_permission_required__':
        if permission == NO_PERMISSION_REQUIRED:
            # allow views registered within configurations that have a
            # default permission to explicitly override the default
            # permission, replacing it with no permission at all
pyramid/interfaces.py
@@ -866,8 +866,6 @@
    def __contains__(key):
        """Return true if a key exists in the mapping."""
NO_PERMISSION_REQUIRED = '__no_permission_required__'
class IRendererInfo(Interface):
    """ An object implementing this interface is passed to every
    :term:`renderer factory` constructor as its only argument (conventionally
pyramid/security.py
@@ -24,6 +24,8 @@
ALL_PERMISSIONS = AllPermissionsList()
DENY_ALL = (Deny, Everyone, ALL_PERMISSIONS)
NO_PERMISSION_REQUIRED = '__no_permission_required__'
def has_permission(permission, context, request):
    """ Provided a permission (a string or unicode object), a context
    (a :term:`resource` instance) and a request object, return an
pyramid/static.py
@@ -14,6 +14,7 @@
from pyramid.interfaces import IStaticURLInfo
from pyramid.path import caller_package
from pyramid.request import call_app_with_subpath_as_path_info
from pyramid.security import NO_PERMISSION_REQUIRED
from pyramid.url import route_url
class PackageURLParser(StaticURLParser):
@@ -149,7 +150,7 @@
            if permission is None:
                permission = extra.pop('permission', None)
            if permission is None:
                permission = '__no_permission_required__'
                permission = NO_PERMISSION_REQUIRED
            context = extra.pop('view_context', None)
            if context is None:
pyramid/tests/defpermbugapp/__init__.py
@@ -1,4 +1,5 @@
from webob import Response
from pyramid.security import NO_PERMISSION_REQUIRED
from pyramid.view import view_config
@view_config(name='x')
@@ -9,7 +10,7 @@
def y_view(request): # pragma: no cover
     return Response('this is private too!')
     
@view_config(name='z', permission='__no_permission_required__')
@view_config(name='z', permission=NO_PERMISSION_REQUIRED)
def z_view(request):
     return Response('this is public')
pyramid/tests/test_config.py
@@ -4166,13 +4166,14 @@
        self.assertEqual(permitted, False)
    def test_debug_auth_permission_authpol_overridden(self):
        from pyramid.security import NO_PERMISSION_REQUIRED
        response = DummyResponse()
        view = lambda *arg: response
        self.config.registry.settings = dict(
            debug_authorization=True, reload_templates=True)
        logger = self._registerLogger()
        self._registerSecurityPolicy(False)
        deriver = self._makeOne(permission='__no_permission_required__')
        deriver = self._makeOne(permission=NO_PERMISSION_REQUIRED)
        result = deriver(view)
        self.assertEqual(view.__module__, result.__module__)
        self.assertEqual(view.__doc__, result.__doc__)
pyramid/tests/test_static.py
@@ -410,6 +410,7 @@
        self.assertEqual(inst.registrations, expected)
    def test_add_viewname(self):
        from pyramid.security import NO_PERMISSION_REQUIRED
        from pyramid.static import static_view
        config = DummyConfig()
        inst = self._makeOne(config)
@@ -417,8 +418,7 @@
        expected = [('view/', 'anotherpackage:path/', False)]
        self.assertEqual(inst.registrations, expected)
        self.assertEqual(config.route_args, ('view/', 'view/*subpath'))
        self.assertEqual(config.view_kw['permission'],
                         '__no_permission_required__')
        self.assertEqual(config.view_kw['permission'], NO_PERMISSION_REQUIRED)
        self.assertEqual(config.view_kw['view'].__class__, static_view)
        self.assertEqual(config.view_kw['view'].app.cache_max_age, 1)