[Zope3-checkins] SVN: Zope3/trunk/ Refactored zope.decorator into
zope.proxy.decorator and zope.security.decorator
Wolfgang Schnerring
wosc at wosc.de
Fri Sep 22 02:40:32 EDT 2006
Log message for revision 70320:
Refactored zope.decorator into zope.proxy.decorator and zope.security.decorator
as discussed in http://article.gmane.org/gmane.comp.web.zope.zope3/18586
Changed:
U Zope3/trunk/doc/CHANGES.txt
D Zope3/trunk/src/zope/decorator/DEPENDENCIES.cfg
U Zope3/trunk/src/zope/decorator/__init__.py
D Zope3/trunk/src/zope/decorator/tests.py
U Zope3/trunk/src/zope/location/location.py
A Zope3/trunk/src/zope/proxy/decorator.py
A Zope3/trunk/src/zope/proxy/tests/test_decorator.py
A Zope3/trunk/src/zope/security/decorator.py
-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/doc/CHANGES.txt 2006-09-22 06:40:31 UTC (rev 70320)
@@ -59,6 +59,9 @@
Restructuring
+ - Refactored zope.decorator into zope.proxy.decorator and
+ zope.security.decorator.
+
- Deprecated directive <zope:localUtility>, replaced by <zope:class>.
- Removed deprecated directive <zope:defaultLayer>.
Deleted: Zope3/trunk/src/zope/decorator/DEPENDENCIES.cfg
===================================================================
--- Zope3/trunk/src/zope/decorator/DEPENDENCIES.cfg 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/src/zope/decorator/DEPENDENCIES.cfg 2006-09-22 06:40:31 UTC (rev 70320)
@@ -1,3 +0,0 @@
-zope.proxy
-zope.interface
-zope.security
Modified: Zope3/trunk/src/zope/decorator/__init__.py
===================================================================
--- Zope3/trunk/src/zope/decorator/__init__.py 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/src/zope/decorator/__init__.py 2006-09-22 06:40:31 UTC (rev 70320)
@@ -1,249 +1,11 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Decorator support
+import zope.deprecation
+zope.deprecation.moved(
+ "zope.proxy.decorator",
+ "Zope 3.6",
+ )
+zope.deprecation.moved(
+ "zope.security.decorator",
+ "Zope 3.6",
+ )
-Decorators are proxies that are mostly transparent but that may provide
-additional features.
-
-$Id$
-"""
-__docformat__ = "reStructuredText"
-
-from zope.proxy import getProxiedObject, ProxyBase
-from zope.security.checker import selectChecker, CombinedChecker
-from zope.security.proxy import Proxy, getChecker
-from zope.interface.declarations import ObjectSpecificationDescriptor
-from zope.interface.declarations import getObjectSpecification
-from zope.interface.declarations import ObjectSpecification
-from zope.interface import providedBy
-
-class DecoratorSpecificationDescriptor(ObjectSpecificationDescriptor):
- """Support for interface declarations on decorators
-
- >>> from zope.interface import *
- >>> class I1(Interface):
- ... pass
- >>> class I2(Interface):
- ... pass
- >>> class I3(Interface):
- ... pass
- >>> class I4(Interface):
- ... pass
-
- >>> class D1(Decorator):
- ... implements(I1)
-
-
- >>> class D2(Decorator):
- ... implements(I2)
-
- >>> class X(object):
- ... implements(I3)
-
- >>> x = X()
- >>> directlyProvides(x, I4)
-
- Interfaces of X are ordered with the directly-provided interfaces first
-
- >>> [interface.getName() for interface in list(providedBy(x))]
- ['I4', 'I3']
-
- When we decorate objects, what order should the interfaces come
- in? One could argue that decorators are less specific, so they
- should come last.
-
- >>> [interface.getName() for interface in list(providedBy(D1(x)))]
- ['I4', 'I3', 'I1']
-
- >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))]
- ['I4', 'I3', 'I1', 'I2']
- """
- def __get__(self, inst, cls=None):
- if inst is None:
- return getObjectSpecification(cls)
- else:
- provided = providedBy(getProxiedObject(inst))
-
- # Use type rather than __class__ because inst is a proxy and
- # will return the proxied object's class.
- cls = type(inst)
- return ObjectSpecification(provided, cls)
-
- def __set__(self, inst, value):
- raise TypeError("Can't set __providedBy__ on a decorated object")
-
-class DecoratedSecurityCheckerDescriptor(object):
- """Descriptor for a Decorator that provides a decorated security checker.
-
- To illustrate, we'll create a class that will be proxied:
-
- >>> class Foo(object):
- ... a = 'a'
-
- and a class to proxy it that uses a decorated security checker:
-
- >>> class Wrapper(ProxyBase):
- ... b = 'b'
- ... __Security_checker__ = DecoratedSecurityCheckerDescriptor()
-
- Next we'll create and register a checker for `Foo`:
-
- >>> from zope.security.checker import NamesChecker, defineChecker
- >>> fooChecker = NamesChecker(['a'])
- >>> defineChecker(Foo, fooChecker)
-
- along with a checker for `Wrapper`:
-
- >>> wrapperChecker = NamesChecker(['b'])
- >>> defineChecker(Wrapper, wrapperChecker)
-
- Using `selectChecker()`, we can confirm that a `Foo` object uses
- `fooChecker`:
-
- >>> foo = Foo()
- >>> selectChecker(foo) is fooChecker
- True
- >>> fooChecker.check(foo, 'a')
- >>> fooChecker.check(foo, 'b') # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ForbiddenAttribute: ('b', <zope.decorator.Foo object ...>)
-
- and that a `Wrapper` object uses `wrappeChecker`:
-
- >>> wrapper = Wrapper(foo)
- >>> selectChecker(wrapper) is wrapperChecker
- True
- >>> wrapperChecker.check(wrapper, 'b')
- >>> wrapperChecker.check(wrapper, 'a') # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ForbiddenAttribute: ('a', <zope.decorator.Foo object ...>)
-
- (Note that the object description says `Foo` because the object is a
- proxy and generally looks and acts like the object it's proxying.)
-
- When we access wrapper's ``__Security_checker__`` attribute, we invoke
- the decorated security checker descriptor. The decorator's job is to make
- sure checkers from both objects are used when available. In this case,
- because both objects have checkers, we get a combined checker:
-
- >>> checker = wrapper.__Security_checker__
- >>> type(checker)
- <class 'zope.security.checker.CombinedChecker'>
- >>> checker.check(wrapper, 'a')
- >>> checker.check(wrapper, 'b')
-
- The decorator checker will work even with security proxied objects. To
- illustrate, we'll proxify `foo`:
-
- >>> from zope.security.proxy import ProxyFactory
- >>> secure_foo = ProxyFactory(foo)
- >>> secure_foo.a
- 'a'
- >>> secure_foo.b # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ForbiddenAttribute: ('b', <zope.decorator.Foo object ...>)
-
- when we wrap the secured `foo`:
-
- >>> wrapper = Wrapper(secure_foo)
-
- we still get a combined checker:
-
- >>> checker = wrapper.__Security_checker__
- >>> type(checker)
- <class 'zope.security.checker.CombinedChecker'>
- >>> checker.check(wrapper, 'a')
- >>> checker.check(wrapper, 'b')
-
- The decorator checker has three other scenarios:
-
- - the wrapper has a checker but the proxied object doesn't
- - the proxied object has a checker but the wrapper doesn't
- - neither the wrapper nor the proxied object have checkers
-
- When the wrapper has a checker but the proxied object doesn't:
-
- >>> from zope.security.checker import NoProxy, _checkers
- >>> del _checkers[Foo]
- >>> defineChecker(Foo, NoProxy)
- >>> selectChecker(foo) is None
- True
- >>> selectChecker(wrapper) is wrapperChecker
- True
-
- the decorator uses only the wrapper checker:
-
- >>> wrapper = Wrapper(foo)
- >>> wrapper.__Security_checker__ is wrapperChecker
- True
-
- When the proxied object has a checker but the wrapper doesn't:
-
- >>> del _checkers[Wrapper]
- >>> defineChecker(Wrapper, NoProxy)
- >>> selectChecker(wrapper) is None
- True
- >>> del _checkers[Foo]
- >>> defineChecker(Foo, fooChecker)
- >>> selectChecker(foo) is fooChecker
- True
-
- the decorator uses only the proxied object checker:
-
- >>> wrapper.__Security_checker__ is fooChecker
- True
-
- Finally, if neither the wrapper not the proxied have checkers:
-
- >>> del _checkers[Foo]
- >>> defineChecker(Foo, NoProxy)
- >>> selectChecker(foo) is None
- True
- >>> selectChecker(wrapper) is None
- True
-
- the decorator doesn't have a checker:
-
- >>> wrapper.__Security_checker__ is None
- True
-
- """
- def __get__(self, inst, cls=None):
- if inst is None:
- return self
- else:
- proxied_object = getProxiedObject(inst)
- if type(proxied_object) is Proxy:
- checker = getChecker(proxied_object)
- else:
- checker = getattr(proxied_object, '__Security_checker__', None)
- if checker is None:
- checker = selectChecker(proxied_object)
- wrapper_checker = selectChecker(inst)
- if wrapper_checker is None:
- return checker
- elif checker is None:
- return wrapper_checker
- else:
- return CombinedChecker(wrapper_checker, checker)
-
- def __set__(self, inst, value):
- raise TypeError("Can't set __Security_checker__ on a decorated object")
-
-class Decorator(ProxyBase):
- """Decorator base class"""
-
- __providedBy__ = DecoratorSpecificationDescriptor()
- __Security_checker__ = DecoratedSecurityCheckerDescriptor()
-
+Decorator = DecoratorBase
Deleted: Zope3/trunk/src/zope/decorator/tests.py
===================================================================
--- Zope3/trunk/src/zope/decorator/tests.py 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/src/zope/decorator/tests.py 2006-09-22 06:40:31 UTC (rev 70320)
@@ -1,92 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Context Tests
-
-$Id$
-"""
-import pickle
-import unittest
-from zope.decorator import Decorator
-from zope.interface import Interface, implements, directlyProvides, providedBy
-from zope.interface import directlyProvidedBy, implementedBy
-from zope.testing.doctestunit import DocTestSuite
-from zope.security.interfaces import ForbiddenAttribute
-
-class I1(Interface):
- pass
-class I2(Interface):
- pass
-class I3(Interface):
- pass
-class I4(Interface):
- pass
-
-class D1(Decorator):
- implements(I1)
-
-class D2(Decorator):
- implements(I2)
-
-
-def check_forbidden_call(callable, *args):
- try:
- return callable(*args)
- except ForbiddenAttribute, e:
- return 'ForbiddenAttribute: %s' % e[0]
-
-
-def test_providedBy_iter_w_new_style_class():
- """
- >>> class X(object):
- ... implements(I3)
-
- >>> x = X()
- >>> directlyProvides(x, I4)
-
- >>> [interface.getName() for interface in list(providedBy(x))]
- ['I4', 'I3']
-
- >>> [interface.getName() for interface in list(providedBy(D1(x)))]
- ['I4', 'I3', 'I1']
-
- >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))]
- ['I4', 'I3', 'I1', 'I2']
- """
-
-def test_providedBy_iter_w_classic_class():
- """
- >>> class X(object):
- ... implements(I3)
-
- >>> x = X()
- >>> directlyProvides(x, I4)
-
- >>> [interface.getName() for interface in list(providedBy(x))]
- ['I4', 'I3']
-
- >>> [interface.getName() for interface in list(providedBy(D1(x)))]
- ['I4', 'I3', 'I1']
-
- >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))]
- ['I4', 'I3', 'I1', 'I2']
- """
-
-def test_suite():
- suite = DocTestSuite()
- suite.addTest(DocTestSuite('zope.decorator'))
- return suite
-
-
-if __name__ == '__main__':
- unittest.main()
Modified: Zope3/trunk/src/zope/location/location.py
===================================================================
--- Zope3/trunk/src/zope/location/location.py 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/src/zope/location/location.py 2006-09-22 06:40:31 UTC (rev 70320)
@@ -20,8 +20,7 @@
import zope.interface
from zope.location.interfaces import ILocation
from zope.proxy import ProxyBase, getProxiedObject, non_overridable
-from zope.decorator import DecoratorSpecificationDescriptor
-from zope.decorator import DecoratedSecurityCheckerDescriptor
+from zope.security.decorator import DecoratorBase
class Location(object):
"""Stupid mix-in that defines `__parent__` and `__name__` attributes
@@ -120,7 +119,7 @@
return self.funcs[1](cls)
return self.funcs[0](inst)
-class LocationProxy(ProxyBase):
+class LocationProxy(DecoratorBase):
__doc__ = """Location-object proxy
This is a non-picklable proxy that can be put around objects that
@@ -172,7 +171,3 @@
)
__reduce_ex__ = __reduce__
-
- __providedBy__ = DecoratorSpecificationDescriptor()
-
- __Security_checker__ = DecoratedSecurityCheckerDescriptor()
Added: Zope3/trunk/src/zope/proxy/decorator.py
===================================================================
--- Zope3/trunk/src/zope/proxy/decorator.py 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/src/zope/proxy/decorator.py 2006-09-22 06:40:31 UTC (rev 70320)
@@ -0,0 +1,108 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Decorator support
+
+Decorators are proxies that are mostly transparent but that may provide
+additional features.
+
+$Id: __init__.py 66343 2006-04-03 04:59:49Z philikon $
+"""
+__docformat__ = "reStructuredText"
+
+from zope.proxy import getProxiedObject, ProxyBase
+from zope.security.checker import selectChecker, CombinedChecker
+from zope.security.proxy import Proxy, getChecker
+from zope.interface.declarations import ObjectSpecificationDescriptor
+from zope.interface.declarations import getObjectSpecification
+from zope.interface.declarations import ObjectSpecification
+from zope.interface import providedBy
+
+class DecoratorSpecificationDescriptor(ObjectSpecificationDescriptor):
+ """Support for interface declarations on decorators
+
+ >>> from zope.interface import *
+ >>> class I1(Interface):
+ ... pass
+ >>> class I2(Interface):
+ ... pass
+ >>> class I3(Interface):
+ ... pass
+ >>> class I4(Interface):
+ ... pass
+
+ >>> class D1(SpecificationDecoratorBase):
+ ... implements(I1)
+
+
+ >>> class D2(SpecificationDecoratorBase):
+ ... implements(I2)
+
+ >>> class X(object):
+ ... implements(I3)
+
+ >>> x = X()
+ >>> directlyProvides(x, I4)
+
+ Interfaces of X are ordered with the directly-provided interfaces first
+
+ >>> [interface.getName() for interface in list(providedBy(x))]
+ ['I4', 'I3']
+
+ When we decorate objects, what order should the interfaces come
+ in? One could argue that decorators are less specific, so they
+ should come last.
+
+ >>> [interface.getName() for interface in list(providedBy(D1(x)))]
+ ['I4', 'I3', 'I1']
+
+ >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))]
+ ['I4', 'I3', 'I1', 'I2']
+
+ SpecificationDecorators also work with old-style classes:
+
+ >>> class X:
+ ... implements(I3)
+
+ >>> x = X()
+ >>> directlyProvides(x, I4)
+
+ >>> [interface.getName() for interface in list(providedBy(x))]
+ ['I4', 'I3']
+
+ >>> [interface.getName() for interface in list(providedBy(D1(x)))]
+ ['I4', 'I3', 'I1']
+
+ >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))]
+ ['I4', 'I3', 'I1', 'I2']
+ """
+ def __get__(self, inst, cls=None):
+ if inst is None:
+ return getObjectSpecification(cls)
+ else:
+ provided = providedBy(getProxiedObject(inst))
+
+ # Use type rather than __class__ because inst is a proxy and
+ # will return the proxied object's class.
+ cls = type(inst)
+ return ObjectSpecification(provided, cls)
+
+ def __set__(self, inst, value):
+ raise TypeError("Can't set __providedBy__ on a decorated object")
+
+
+class SpecificationDecoratorBase(ProxyBase):
+ """Base class for a proxy that provides additional interfaces."""
+
+ __providedBy__ = DecoratorSpecificationDescriptor()
+
Added: Zope3/trunk/src/zope/proxy/tests/test_decorator.py
===================================================================
--- Zope3/trunk/src/zope/proxy/tests/test_decorator.py 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/src/zope/proxy/tests/test_decorator.py 2006-09-22 06:40:31 UTC (rev 70320)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test Harness
+
+$Id: tests.py 66343 2006-04-03 04:59:49Z philikon $
+"""
+from zope.testing.doctestunit import DocTestSuite
+
+
+def test_suite():
+ suite = DocTestSuite()
+ suite.addTest(DocTestSuite('zope.proxy.decorator'))
+ return suite
Added: Zope3/trunk/src/zope/security/decorator.py
===================================================================
--- Zope3/trunk/src/zope/security/decorator.py 2006-09-22 05:29:49 UTC (rev 70319)
+++ Zope3/trunk/src/zope/security/decorator.py 2006-09-22 06:40:31 UTC (rev 70320)
@@ -0,0 +1,201 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Decorator support
+
+Decorators are proxies that are mostly transparent but that may provide
+additional features.
+
+$Id: __init__.py 66343 2006-04-03 04:59:49Z philikon $
+"""
+__docformat__ = "reStructuredText"
+
+from zope.proxy import getProxiedObject, ProxyBase
+from zope.proxy.decorator import SpecificationDecoratorBase
+from zope.security.checker import selectChecker, CombinedChecker
+from zope.security.proxy import Proxy, getChecker
+from zope.interface.declarations import ObjectSpecificationDescriptor
+from zope.interface.declarations import getObjectSpecification
+from zope.interface.declarations import ObjectSpecification
+from zope.interface import providedBy
+
+class DecoratedSecurityCheckerDescriptor(object):
+ """Descriptor for a Decorator that provides a decorated security checker.
+
+ To illustrate, we'll create a class that will be proxied:
+
+ >>> class Foo(object):
+ ... a = 'a'
+
+ and a class to proxy it that uses a decorated security checker:
+
+ >>> class Wrapper(ProxyBase):
+ ... b = 'b'
+ ... __Security_checker__ = DecoratedSecurityCheckerDescriptor()
+
+ Next we'll create and register a checker for `Foo`:
+
+ >>> from zope.security.checker import NamesChecker, defineChecker
+ >>> fooChecker = NamesChecker(['a'])
+ >>> defineChecker(Foo, fooChecker)
+
+ along with a checker for `Wrapper`:
+
+ >>> wrapperChecker = NamesChecker(['b'])
+ >>> defineChecker(Wrapper, wrapperChecker)
+
+ Using `selectChecker()`, we can confirm that a `Foo` object uses
+ `fooChecker`:
+
+ >>> foo = Foo()
+ >>> selectChecker(foo) is fooChecker
+ True
+ >>> fooChecker.check(foo, 'a')
+ >>> fooChecker.check(foo, 'b') # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ForbiddenAttribute: ('b', <zope.decorator.Foo object ...>)
+
+ and that a `Wrapper` object uses `wrappeChecker`:
+
+ >>> wrapper = Wrapper(foo)
+ >>> selectChecker(wrapper) is wrapperChecker
+ True
+ >>> wrapperChecker.check(wrapper, 'b')
+ >>> wrapperChecker.check(wrapper, 'a') # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ForbiddenAttribute: ('a', <zope.decorator.Foo object ...>)
+
+ (Note that the object description says `Foo` because the object is a
+ proxy and generally looks and acts like the object it's proxying.)
+
+ When we access wrapper's ``__Security_checker__`` attribute, we invoke
+ the decorated security checker descriptor. The decorator's job is to make
+ sure checkers from both objects are used when available. In this case,
+ because both objects have checkers, we get a combined checker:
+
+ >>> checker = wrapper.__Security_checker__
+ >>> type(checker)
+ <class 'zope.security.checker.CombinedChecker'>
+ >>> checker.check(wrapper, 'a')
+ >>> checker.check(wrapper, 'b')
+
+ The decorator checker will work even with security proxied objects. To
+ illustrate, we'll proxify `foo`:
+
+ >>> from zope.security.proxy import ProxyFactory
+ >>> secure_foo = ProxyFactory(foo)
+ >>> secure_foo.a
+ 'a'
+ >>> secure_foo.b # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ForbiddenAttribute: ('b', <zope.decorator.Foo object ...>)
+
+ when we wrap the secured `foo`:
+
+ >>> wrapper = Wrapper(secure_foo)
+
+ we still get a combined checker:
+
+ >>> checker = wrapper.__Security_checker__
+ >>> type(checker)
+ <class 'zope.security.checker.CombinedChecker'>
+ >>> checker.check(wrapper, 'a')
+ >>> checker.check(wrapper, 'b')
+
+ The decorator checker has three other scenarios:
+
+ - the wrapper has a checker but the proxied object doesn't
+ - the proxied object has a checker but the wrapper doesn't
+ - neither the wrapper nor the proxied object have checkers
+
+ When the wrapper has a checker but the proxied object doesn't:
+
+ >>> from zope.security.checker import NoProxy, _checkers
+ >>> del _checkers[Foo]
+ >>> defineChecker(Foo, NoProxy)
+ >>> selectChecker(foo) is None
+ True
+ >>> selectChecker(wrapper) is wrapperChecker
+ True
+
+ the decorator uses only the wrapper checker:
+
+ >>> wrapper = Wrapper(foo)
+ >>> wrapper.__Security_checker__ is wrapperChecker
+ True
+
+ When the proxied object has a checker but the wrapper doesn't:
+
+ >>> del _checkers[Wrapper]
+ >>> defineChecker(Wrapper, NoProxy)
+ >>> selectChecker(wrapper) is None
+ True
+ >>> del _checkers[Foo]
+ >>> defineChecker(Foo, fooChecker)
+ >>> selectChecker(foo) is fooChecker
+ True
+
+ the decorator uses only the proxied object checker:
+
+ >>> wrapper.__Security_checker__ is fooChecker
+ True
+
+ Finally, if neither the wrapper not the proxied have checkers:
+
+ >>> del _checkers[Foo]
+ >>> defineChecker(Foo, NoProxy)
+ >>> selectChecker(foo) is None
+ True
+ >>> selectChecker(wrapper) is None
+ True
+
+ the decorator doesn't have a checker:
+
+ >>> wrapper.__Security_checker__ is None
+ True
+
+ """
+ def __get__(self, inst, cls=None):
+ if inst is None:
+ return self
+ else:
+ proxied_object = getProxiedObject(inst)
+ if type(proxied_object) is Proxy:
+ checker = getChecker(proxied_object)
+ else:
+ checker = getattr(proxied_object, '__Security_checker__', None)
+ if checker is None:
+ checker = selectChecker(proxied_object)
+ wrapper_checker = selectChecker(inst)
+ if wrapper_checker is None:
+ return checker
+ elif checker is None:
+ return wrapper_checker
+ else:
+ return CombinedChecker(wrapper_checker, checker)
+
+ def __set__(self, inst, value):
+ raise TypeError("Can't set __Security_checker__ on a decorated object")
+
+
+class SecurityCheckerDecoratorBase(ProxyBase):
+ """Base class for a proxy that provides additional security declarations."""
+
+ __Security_checker__ = DecoratedSecurityCheckerDescriptor()
+
+
+class DecoratorBase(SpecificationDecoratorBase, SecurityCheckerDecoratorBase):
+ """Base class for a proxy that provides both additional interfaces and
+ security declarations."""
+
+
More information about the Zope3-Checkins
mailing list