[Checkins] SVN: Acquisition/trunk/ fix iteration proxying to pass `self` acquisition-wrapped into `__iter__` and `__getitem__` (fixes https://bugs.launchpad.net/zope2/+bug/360761)

Andreas Zeidler az at zitc.de
Thu Oct 29 05:18:47 EDT 2009


Log message for revision 105350:
  fix iteration proxying to pass `self` acquisition-wrapped into `__iter__` and `__getitem__` (fixes https://bugs.launchpad.net/zope2/+bug/360761)

Changed:
  U   Acquisition/trunk/CHANGES.txt
  U   Acquisition/trunk/src/Acquisition/_Acquisition.c
  U   Acquisition/trunk/src/Acquisition/tests.py

-=-
Modified: Acquisition/trunk/CHANGES.txt
===================================================================
--- Acquisition/trunk/CHANGES.txt	2009-10-29 09:18:40 UTC (rev 105349)
+++ Acquisition/trunk/CHANGES.txt	2009-10-29 09:18:46 UTC (rev 105350)
@@ -4,6 +4,10 @@
 2.12.4 (unreleased)
 -------------------
 
+- Fix iteration proxying to pass `self` acquisition-wrapped into both
+  `__iter__` as well as `__getitem__` (this fixes
+  https://bugs.launchpad.net/zope2/+bug/360761).
+
 - Add tests for the __getslice__ proxying, including open-ended slicing.
 
 2.12.3 (2009-08-08)

Modified: Acquisition/trunk/src/Acquisition/_Acquisition.c
===================================================================
--- Acquisition/trunk/src/Acquisition/_Acquisition.c	2009-10-29 09:18:40 UTC (rev 105349)
+++ Acquisition/trunk/src/Acquisition/_Acquisition.c	2009-10-29 09:18:46 UTC (rev 105350)
@@ -942,10 +942,35 @@
   return c;
 }
 
+/* Support for iteration cannot rely on the internal implementation of
+   `PyObject_GetIter`, since the `self` passed into `__iter__` and
+   `__getitem__` should be acquisition-wrapped (also see LP 360761): The
+   wrapper obviously supports the iterator protocol so simply calling
+   `PyObject_GetIter(OBJECT(self))` results in an infinite recursion.
+   Instead the base object needs to be checked and the wrapper must only
+   be used when actually calling `__getitem__` or setting up a sequence
+   iterator. */
 static PyObject * 
 Wrapper_iter(Wrapper *self)
 {
-  return PyObject_GetIter(self->obj);
+  PyObject *obj = self->obj;
+  PyObject *res;
+  if ((res=PyObject_GetAttr(OBJECT(self),py__iter__))) {
+      ASSIGN(res,PyObject_CallFunction(res,NULL,NULL));
+      if (res != NULL && !PyIter_Check(res)) {
+          PyErr_Format(PyExc_TypeError,
+                   "iter() returned non-iterator "
+                   "of type '%.100s'",
+                   res->ob_type->tp_name);
+          Py_DECREF(res);
+          res = NULL;
+      }
+  } else if (PySequence_Check(obj)) {
+      ASSIGN(res,PySeqIter_New(OBJECT(self)));
+  } else {
+      res = PyErr_Format(PyExc_TypeError, "iteration over non-sequence");
+  }
+  return res;
 }
 
 static PySequenceMethods Wrapper_as_sequence = {

Modified: Acquisition/trunk/src/Acquisition/tests.py
===================================================================
--- Acquisition/trunk/src/Acquisition/tests.py	2009-10-29 09:18:40 UTC (rev 105349)
+++ Acquisition/trunk/src/Acquisition/tests.py	2009-10-29 09:18:46 UTC (rev 105350)
@@ -1813,7 +1813,7 @@
     slicing...
     True
 
-    Finally let's check that the wrapper's __iter__ proxy falls back
+    Next let's check that the wrapper's __iter__ proxy falls back
     to using the object's __getitem__ if it has no __iter__.  See
     https://bugs.launchpad.net/zope2/+bug/360761 .
 



More information about the checkins mailing list