diff options
author | Jason Madden <jamadden@gmail.com> | 2017-09-12 08:49:43 -0500 |
---|---|---|
committer | Jason Madden <jamadden@gmail.com> | 2017-09-12 08:49:43 -0500 |
commit | 673974bf6c0c13a737d53bac40fd1037fa5a0392 (patch) | |
tree | 51a67969ed3db5a822b11497db59ad6e855dc063 | |
parent | 12ce0b541c080b286673f314df517ee0fd135257 (diff) | |
download | zope-security-673974bf6c0c13a737d53bac40fd1037fa5a0392.tar.gz |
Coverage for get/setslice, length_hint, and comparison methods in proxy.py
-rw-r--r-- | .coveragerc | 1 | ||||
-rw-r--r-- | CHANGES.rst | 7 | ||||
-rw-r--r-- | src/zope/security/proxy.py | 46 | ||||
-rw-r--r-- | src/zope/security/tests/test_proxy.py | 110 |
4 files changed, 141 insertions, 23 deletions
diff --git a/.coveragerc b/.coveragerc index bb46267..6bd02c1 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,6 @@ [run] source = zope.security +omit = */flycheck_*.py [report] precision = 2 diff --git a/CHANGES.rst b/CHANGES.rst index fb06cc5..beea49e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -46,7 +46,12 @@ - Remove unused internal files from ``tests/``. -- Remove ``zope.security.setup``. It was unused and did not work anyway. +- Remove ``zope.security.setup``. It was unused and did not work + anyway. + +- Fix the pure-Python proxy on Python 2 letting ``__getslice__`` and + ``__setslice__`` fall through to ``__getitem__`` or ``__setitem__``, + respectively, if it raised an error. 4.1.1 (2017-05-17) ================== 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() |