diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/zope/security/proxy.py | 46 | ||||
-rw-r--r-- | src/zope/security/tests/test_proxy.py | 110 |
2 files changed, 134 insertions, 22 deletions
diff --git a/src/zope/security/proxy.py b/src/zope/security/proxy.py index 9e7333d..3416419 100644 --- a/src/zope/security/proxy.py +++ b/src/zope/security/proxy.py @@ -17,7 +17,8 @@ import functools import sys from zope.proxy import PyProxyBase -from zope.security._compat import PYPY, PURE_PYTHON +from zope.security._compat import PURE_PYTHON +from zope.security._compat import _BUILTINS from zope.security.interfaces import ForbiddenAttribute def _check_name(meth, wrap_result=True): @@ -139,19 +140,21 @@ class ProxyPy(PyProxyBase): @_check_name def __getslice__(self, start, end): + wrapped = object.__getattribute__(self, '_wrapped') try: - return self._wrapped.__getslice__(start, end) - except: - getitem = PyProxyBase.__getattribute__(self, '__getitem__') - return getitem(slice(start, end)) + getslice = wrapped.__getslice__ + except AttributeError: + return wrapped.__getitem__(slice(start, end)) + return getslice(start, end) @_check_name - def __setslice__(self, i, j, value): + def __setslice__(self, start, end, value): + wrapped = object.__getattribute__(self, '_wrapped') try: - return self._wrapped.__setslice__(i, j, value) - except: - setitem = PyProxyBase.__getattribute__(self, '__setitem__') - return setitem(slice(i, j), value) + setslice = wrapped.__setslice__ + except AttributeError: + return wrapped.__setitem__(slice(start, end), value) + return setslice(start, end, value) def __cmp__(self, other): # no check @@ -311,8 +314,9 @@ for name in ['__call__', meth = getattr(PyProxyBase, name) setattr(ProxyPy, name, _check_name(meth)) -for name in ['__len__', - ]: +for name in ( + '__len__', +): meth = getattr(PyProxyBase, name) setattr(ProxyPy, name, _check_name(meth, False)) @@ -336,16 +340,15 @@ for name in ['__iadd__', def getCheckerPy(proxy): return super(PyProxyBase, proxy).__getattribute__('_checker') -if PYPY: - _builtin_isinstance = __builtins__.isinstance -else: - _builtin_isinstance = __builtins__['isinstance'] + +_builtin_isinstance = sys.modules[_BUILTINS].isinstance def getObjectPy(proxy): if not _builtin_isinstance(proxy, ProxyPy): return proxy return super(PyProxyBase, proxy).__getattribute__('_wrapped') + _c_available = not PURE_PYTHON if _c_available: try: @@ -353,11 +356,12 @@ if _c_available: except (ImportError, AttributeError): #pragma NO COVER PyPy / PURE_PYTHON _c_available = False -if not _c_available: - getChecker = getCheckerPy - getObject = getObjectPy - Proxy = ProxyPy -else: #pragma NO COVER CPython + +getChecker = getCheckerPy +getObject = getObjectPy +Proxy = ProxyPy + +if _c_available: from zope.security._proxy import getChecker from zope.security._proxy import getObject Proxy = _Proxy diff --git a/src/zope/security/tests/test_proxy.py b/src/zope/security/tests/test_proxy.py index ee9200f..077023f 100644 --- a/src/zope/security/tests/test_proxy.py +++ b/src/zope/security/tests/test_proxy.py @@ -38,6 +38,8 @@ class AbstractProxyTestBase(object): idiv = itruediv div = '__truediv__' if not PYTHON2 else '__div__' truediv = div + getslice = '__getitem__' if not PYTHON2 else '__getslice__' + setslice = '__setitem__' if not PYTHON2 else '__setslice__' def _getTargetClass(self): raise NotImplementedError("Subclass responsibility") @@ -278,6 +280,24 @@ class AbstractProxyTestBase(object): o_proxy = self._makeOne(target, checker) self.assertEqual(cmp(proxy, o_proxy), 0) + def test__le__(self): + target = 1 + checker = object() # checker not consulted + proxy = self._makeOne(target, checker) + self.assertTrue(proxy <= 1) + + def test__ne__(self): + target = 1 + checker = object() # checker not consulted + proxy = self._makeOne(target, checker) + self.assertFalse(proxy != 1) + + def test__ge__(self): + target = 1 + checker = object() # checker not consulted + proxy = self._makeOne(target, checker) + self.assertTrue(proxy >= 1) + def test___hash___w_self(self): target = object() checker = object() # checker not consulted @@ -1169,6 +1189,20 @@ class AbstractProxyTestBase(object): self.assertRaises(ForbiddenAttribute, len, proxy) self.assertEqual(checker._checked, '__len__') + def test__length_hint_w_checker_allows(self): + target = iter([0, 1, 2]) + checker = DummyChecker() + proxy = self._makeOne(target, checker) + hint = object.__getattribute__(proxy, '__length_hint__') + self.assertEqual(3, hint()) + + def test__length_hint_dne(self): + target = object() + checker = DummyChecker() + proxy = self._makeOne(target, checker) + hint = object.__getattribute__(proxy, '__length_hint__') + self.assertEqual(NotImplemented, hint()) + def test___contains___hit_w_checker_allows(self): target = [0, 1, 2] checker = DummyChecker() @@ -1246,7 +1280,46 @@ class AbstractProxyTestBase(object): checker = DummyChecker() proxy = self._makeOne(target, checker) self.assertEqual(proxy[1:3], [1, 2]) - self.assertEqual(checker._checked, '__getslice__') + self.assertEqual(checker._checked, self.getslice) + + @_skip_if_not_Py2 + def test___getslice___error_propagates(self): + # This is currently broken on Python 3 because + # https://github.com/zopefoundation/zope.proxy/issues/21 + class Missing(Exception): + pass + class Get(object): + def __getitem__(self, x): + raise Missing('__getitem__') + def __getslice__(self, start, stop): + raise Missing("__getslice__") + target = Get() + checker = DummyChecker() + proxy = self._makeOne(target, checker) + with self.assertRaisesRegexp(Missing, + self.getslice): + proxy[1:2] + + self.assertEqual(checker._checked, self.getslice) + + @_skip_if_not_Py2 + def test___getslice___dne_uses_getitem(self): + # This is currently broken on Python 3 because + # https://github.com/zopefoundation/zope.proxy/issues/21 + class Missing(Exception): + pass + class Get(object): + def __getitem__(self, x): + raise Missing('__getitem__') + + target = Get() + checker = DummyChecker() + proxy = self._makeOne(target, checker) + with self.assertRaisesRegexp(Missing, + '__getitem__'): + proxy[1:2] + + self.assertEqual(checker._checked, self.getslice) @_skip_if_not_Py2 def test___getslice___w_checker_forbids(self): @@ -1277,6 +1350,41 @@ class AbstractProxyTestBase(object): self.assertRaises(ForbiddenAttribute, _try) self.assertEqual(checker._checked, '__setslice__') + def test___setslice___error_propagates(self): + class Missing(Exception): + pass + class Set(object): + def __setitem__(self, k, v): + raise Missing('__setitem__') + def __setslice__(self, start, stop, value): + raise Missing("__setslice__") + target = Set() + checker = DummyChecker() + proxy = self._makeOne(target, checker) + with self.assertRaisesRegexp(Missing, + self.setslice): + proxy[1:2] = 1 + + self.assertEqual(checker._checked, self.setslice) + + def test___setslice___dne_uses_getitem(self): + # This is currently broken on Python 3 because + # https://github.com/zopefoundation/zope.proxy/issues/21 + class Missing(Exception): + pass + class Set(object): + def __setitem__(self, k, v): + raise Missing('__setitem__') + + target = Set() + checker = DummyChecker() + proxy = self._makeOne(target, checker) + with self.assertRaisesRegexp(Missing, + '__setitem__'): + proxy[1:2] = 1 + + self.assertEqual(checker._checked, self.setslice) + def test___getitem___mapping_hit_w_checker_allows(self): target = {'a': 0, 'b': 1, 'c': 2} checker = DummyChecker() |