Skip to content

Commit

Permalink
Let interfaces be iterated on Python 3
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Feb 6, 2020
1 parent 944e79a commit fb5fa20
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 11 deletions.
12 changes: 7 additions & 5 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def __str__(self):


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',
Expand Down
10 changes: 8 additions & 2 deletions src/zope/security/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,8 +858,14 @@ def f(): # pragma: no cover
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,
Expand Down
27 changes: 24 additions & 3 deletions src/zope/security/tests/test_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def coerce(*args):
raise NotImplementedError("Not on Python 3")
cmp = coerce
long = int
unicode = str

class AbstractProxyTestBase(object):

Expand Down Expand Up @@ -1770,7 +1771,7 @@ def __contains__(self, x):
return x == 42


class ProxyTests(unittest.TestCase):
class ProxyFactoryTests(unittest.TestCase):

def setUp(self):
from zope.security.proxy import ProxyFactory
Expand Down Expand Up @@ -1958,6 +1959,11 @@ class C(object):
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
Expand All @@ -1968,6 +1974,7 @@ def test_unops(self):
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)
Expand All @@ -1976,7 +1983,7 @@ def test_unops(self):
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):
Expand Down Expand Up @@ -2007,7 +2014,7 @@ def test_binops(self):
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...
Expand Down Expand Up @@ -2101,6 +2108,20 @@ def test_coerce(self):
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
Expand Down

0 comments on commit fb5fa20

Please sign in to comment.