summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2020-02-06 06:09:29 -0600
committerJason Madden <jamadden@gmail.com>2020-02-06 06:09:29 -0600
commitfb5fa208565a462470f7884c6d9cf73adad886c5 (patch)
tree0aafb30c4d99d06475d6ecbf62205704084f8e1a
parent944e79ae6ec5214323372e518b8198d9540ed992 (diff)
downloadzope-security-fb5fa208565a462470f7884c6d9cf73adad886c5.tar.gz
Let interfaces be iterated on Python 3
Fixes https://github.com/zopefoundation/zope.interface/issues/141
-rw-r--r--CHANGES.rst12
-rw-r--r--setup.py2
-rw-r--r--src/zope/security/checker.py10
-rw-r--r--src/zope/security/tests/test_proxy.py27
4 files changed, 40 insertions, 11 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 18cdfef..86a6a70 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -2,14 +2,16 @@
Changes
=========
-5.1 (unreleased)
-================
+5.1.0 (unreleased)
+==================
-- Nothing changed yet.
+- Let proxied interfaces be iterated on Python 3. This worked on
+ Python 2, but raised ``ForbiddenAttribute`` an Python 3. See
+ `zope.interface issue 141 <https://github.com/zopefoundation/zope.interface/issues/141>`_.
-5.0 (2019-11-11)
-================
+5.0.0 (2019-11-11)
+==================
- Drop support for Python 3.4.
diff --git a/setup.py b/setup.py
index 91b59c6..59a69fa 100644
--- a/setup.py
+++ b/setup.py
@@ -132,7 +132,7 @@ TESTS_REQUIRE = [
setup(name='zope.security',
- version='5.1.dev0',
+ version='5.1.0.dev0',
author='Zope Foundation and Contributors',
author_email='zope-dev@zope.org',
description='Zope Security Framework',
diff --git a/src/zope/security/checker.py b/src/zope/security/checker.py
index f5541a7..8fbf3ec 100644
--- a/src/zope/security/checker.py
+++ b/src/zope/security/checker.py
@@ -858,8 +858,14 @@ _default_checkers = {
type(f()): _iteratorChecker,
type(Interface): InterfaceChecker(
IInterface,
- __str__=CheckerPublic, _implied=CheckerPublic, subscribe=CheckerPublic,
- ),
+ __str__=CheckerPublic,
+ _implied=CheckerPublic,
+ subscribe=CheckerPublic,
+ # To iterate, Python calls __len__ as a hint.
+ # Python 2 ignores AttributeErrors, but Python 3
+ # lets them pass.
+ __len__=CheckerPublic,
+ ),
zope.interface.interface.Method: InterfaceChecker(
zope.interface.interfaces.IMethod),
zope.interface.declarations.ProvidesClass: _Declaration_checker,
diff --git a/src/zope/security/tests/test_proxy.py b/src/zope/security/tests/test_proxy.py
index 55d6d43..cecac86 100644
--- a/src/zope/security/tests/test_proxy.py
+++ b/src/zope/security/tests/test_proxy.py
@@ -27,6 +27,7 @@ if not PYTHON2: # pragma: no cover (Python 3)
raise NotImplementedError("Not on Python 3")
cmp = coerce
long = int
+ unicode = str
class AbstractProxyTestBase(object):
@@ -1770,7 +1771,7 @@ class Something:
return x == 42
-class ProxyTests(unittest.TestCase):
+class ProxyFactoryTests(unittest.TestCase):
def setUp(self):
from zope.security.proxy import ProxyFactory
@@ -1958,6 +1959,11 @@ class ProxyTests(unittest.TestCase):
if PYTHON2:
unops.append("long(x)")
+ def _make_eval(self, expr, locs):
+ def _eval(*args):
+ eval(expr, globals(), locs)
+ return _eval
+
def test_unops(self):
# We want the starting value of the expressions to be a proxy,
# but we don't want to create new proxies as a result of
@@ -1968,6 +1974,7 @@ class ProxyTests(unittest.TestCase):
self.c.unproxied_types = {str, int, float}
if PYTHON2:
self.c.unproxied_types.add(long)
+
for expr in self.unops:
x = 1
y = eval(expr)
@@ -1976,7 +1983,7 @@ class ProxyTests(unittest.TestCase):
z = eval(expr)
self.assertEqual(removeSecurityProxy(z), y,
"x=%r; expr=%r" % (x, expr))
- self.shouldFail(lambda x: eval(expr), x)
+ self.shouldFail(self._make_eval(expr, locals()), x)
@_skip_if_not_Py2
def test_odd_unops(self):
@@ -2007,7 +2014,7 @@ class ProxyTests(unittest.TestCase):
else:
self.assertEqual(removeSecurityProxy(eval(expr)), z,
"x=%r; y=%r; expr=%r" % (x, y, expr))
- self.shouldFail(lambda x, y: eval(expr), x, y)
+ self.shouldFail(self._make_eval(expr, locals()), x, y)
def test_inplace(self):
# TODO: should test all inplace operators...
@@ -2101,6 +2108,20 @@ class ProxyTests(unittest.TestCase):
self.assertIs(type(removeSecurityProxy(a)), float)
self.assertIs(b, y)
+ def test_iterate_interface(self):
+ # This used to work on Python 2, but fail on Python 3.
+ # See https://github.com/zopefoundation/zope.interface/issues/141
+ from zope.interface import Interface
+ from zope.security.proxy import ProxyFactory
+
+ class IFoo(Interface):
+ def x():
+ """A method"""
+
+ proxy = ProxyFactory(IFoo)
+ self.assertEqual(list(IFoo), ['x'])
+ self.assertEqual(list(proxy), list(IFoo))
+
def test_using_mapping_slots_hack():
"""The security proxy will use mapping slots, on the checker to go faster