From 66d0c3d72b7066783762218c7e6b4c933d275a30 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Tue, 28 Feb 2023 21:05:59 +0000 Subject: Use PEP 3114 __next__ methods I got very confused recently when I had a security-proxied iterator using this sort of pattern: class Foo: def __iter__(self): return self def __next__(self): ... The value returned from `__iter__` is wrapped in a security proxy, and I found that unless I used `PURE_PYTHON=1` I got a `ForbiddenAttribute` exception trying to get the Python-2-style `next` method. This probably ought to have been noticed and fixed before we dropped support for Python 2, in which case a transition period of supporting both method names would have made sense. Now that we only support Python 3, I expect that any proxied objects that actually work as iterators will have a `__next__` method (and perhaps a vestigial `next` alias for compatibility), so I think we can just jump straight to only supporting `__next__` for both the C case and the pure-Python case. The C case is not actually being tested properly at the moment due to an oversight around the exact handling of the `PURE_PYTHON` environment variable, but fixing that will require coordinated changes to both `zope.security` and `zope.proxy`. I'll deal with that separately. --- CHANGES.rst | 4 ++++ src/zope/security/_proxy.c | 6 +++--- src/zope/security/proxy.py | 1 - src/zope/security/tests/test_checker.py | 2 -- src/zope/security/tests/test_proxy.py | 9 +++++---- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 7391d96..7d9d8b3 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,10 @@ 6.2 (unreleased) ---------------- +- Make ``next()`` on C proxies call ``__next__`` rather than ``next`` (see + PEP 3114), and drop support for the Python 2 ``next`` method name from + pure-Python proxies. + 6.1 (2023-01-18) ================ diff --git a/src/zope/security/_proxy.c b/src/zope/security/_proxy.c index 6d9f298..d38eaeb 100644 --- a/src/zope/security/_proxy.c +++ b/src/zope/security/_proxy.c @@ -58,7 +58,7 @@ DECLARE_STRING(__getitem__); DECLARE_STRING(__hash__); DECLARE_STRING(__iter__); DECLARE_STRING(__len__); -DECLARE_STRING(next); +DECLARE_STRING(__next__); DECLARE_STRING(op_abs); DECLARE_STRING(op_add); DECLARE_STRING(op_and); @@ -351,7 +351,7 @@ proxy_iternext(SecurityProxy *self) { PyObject *result = NULL; - if (check(self, str_check_getattr, str_next) >= 0) + if (check(self, str_check_getattr, str___next__) >= 0) { result = PyIter_Next(self->proxy.proxy_object); PROXY_RESULT(self, result); @@ -878,7 +878,7 @@ if((str_op_##S = INTERN("__" #S "__")) == NULL) return MOD_ERROR_VAL INIT_STRING(__hash__); INIT_STRING(__iter__); INIT_STRING(__len__); - INIT_STRING(next); + INIT_STRING(__next__); INIT_STRING_OP(abs); INIT_STRING_OP(add); INIT_STRING_OP(and); diff --git a/src/zope/security/proxy.py b/src/zope/security/proxy.py index 8b7ebf5..66a4cb7 100644 --- a/src/zope/security/proxy.py +++ b/src/zope/security/proxy.py @@ -274,7 +274,6 @@ for name in ['__call__', '__delitem__', '__iter__', '__next__', - 'next', '__contains__', '__neg__', '__pos__', diff --git a/src/zope/security/tests/test_checker.py b/src/zope/security/tests/test_checker.py index a0ee8bd..22e9a1e 100644 --- a/src/zope/security/tests/test_checker.py +++ b/src/zope/security/tests/test_checker.py @@ -586,8 +586,6 @@ class CheckerTestsBase(QuietWatchingChecker): finally: self.index += 1 - next = __next__ - def __length_hint__(self): self.hint_called = True return self.hint diff --git a/src/zope/security/tests/test_proxy.py b/src/zope/security/tests/test_proxy.py index 38126fc..90e9fc3 100644 --- a/src/zope/security/tests/test_proxy.py +++ b/src/zope/security/tests/test_proxy.py @@ -1490,7 +1490,9 @@ class Checker: unproxied_types = {str, } def check_getattr(self, _object, name): - if name not in ("foo", "next", "__class__", "__name__", "__module__"): + if name in ("__class__", "__name__", "__module__"): + return + if not self.ok or name not in ("__next__", "foo"): raise RuntimeError def check_setattr(self, _object, name): @@ -1535,7 +1537,6 @@ class Something: def __next__(self): return 42 # Infinite sequence - next = __next__ def __len__(self): return 42 @@ -1651,10 +1652,10 @@ class ProxyFactoryTests(unittest.TestCase): self.shouldFail(iter, self.p) def testNextOK(self): - self.assertEqual(self.p.next(), 42) + self.assertEqual(next(self.p), 42) def testNextFail(self): - self.shouldFail(self.p.next) + self.shouldFail(next, self.p) def testHashOK(self): self.assertEqual(hash(self.p), hash(self.x)) -- cgit v1.2.1