[Python-checkins] r53197 - in python/branches/release25-maint: Lib/test/test_set.py Misc/NEWS Objects/setobject.c

raymond.hettinger python-checkins at python.org
Fri Dec 29 19:49:14 CET 2006


Author: raymond.hettinger
Date: Fri Dec 29 19:49:13 2006
New Revision: 53197

Modified:
   python/branches/release25-maint/Lib/test/test_set.py
   python/branches/release25-maint/Misc/NEWS
   python/branches/release25-maint/Objects/setobject.c
Log:
For sets with cyclical reprs, emit '...' instead of recursing.

Modified: python/branches/release25-maint/Lib/test/test_set.py
==============================================================================
--- python/branches/release25-maint/Lib/test/test_set.py	(original)
+++ python/branches/release25-maint/Lib/test/test_set.py	Fri Dec 29 19:49:13 2006
@@ -21,6 +21,11 @@
     def __cmp__(self, other):
         raise RuntimeError
 
+class ReprWrapper:
+    'Used to test self-referential repr() calls'
+    def __repr__(self):
+        return repr(self.value)
+
 class TestJointOps(unittest.TestCase):
     # Tests common to both set and frozenset
 
@@ -244,6 +249,27 @@
             self.assertRaises(RuntimeError, s.discard, BadCmp())
             self.assertRaises(RuntimeError, s.remove, BadCmp())
 
+    def test_cyclical_repr(self):
+        w = ReprWrapper()
+        s = self.thetype([w])
+        w.value = s
+        name = repr(s).partition('(')[0]    # strip class name from repr string
+        self.assertEqual(repr(s), '%s([%s(...)])' % (name, name))
+
+    def test_cyclical_print(self):
+        w = ReprWrapper()
+        s = self.thetype([w])
+        w.value = s
+        try:
+            fo = open(test_support.TESTFN, "wb")
+            print >> fo, s,
+            fo.close()
+            fo = open(test_support.TESTFN, "rb")
+            self.assertEqual(fo.read(), repr(s))
+        finally:
+            fo.close()
+            os.remove(test_support.TESTFN)
+
 class TestSet(TestJointOps):
     thetype = set
 

Modified: python/branches/release25-maint/Misc/NEWS
==============================================================================
--- python/branches/release25-maint/Misc/NEWS	(original)
+++ python/branches/release25-maint/Misc/NEWS	Fri Dec 29 19:49:13 2006
@@ -18,6 +18,9 @@
   custom ``__eq__()`` method to confuse set internals when class instances
   were used as a set's elements and the ``__eq__()`` method mutated the set.
 
+- The repr for self-referential sets and fronzensets now shows "..." instead
+  of falling into infinite recursion.
+
 - Eliminated unnecessary repeated calls to hash() by set.intersection() and
   set.symmetric_difference_update().
 

Modified: python/branches/release25-maint/Objects/setobject.c
==============================================================================
--- python/branches/release25-maint/Objects/setobject.c	(original)
+++ python/branches/release25-maint/Objects/setobject.c	Fri Dec 29 19:49:13 2006
@@ -572,34 +572,54 @@
 	Py_ssize_t pos=0;
 	char *emit = "";	/* No separator emitted on first pass */
 	char *separator = ", ";
+	int status = Py_ReprEnter((PyObject*)so);
+
+	if (status != 0) {
+		if (status < 0)
+			return status;
+		fprintf(fp, "%s(...)", so->ob_type->tp_name);
+		return 0;
+	}        
 
 	fprintf(fp, "%s([", so->ob_type->tp_name);
 	while (set_next(so, &pos, &entry)) {
 		fputs(emit, fp);
 		emit = separator;
-		if (PyObject_Print(entry->key, fp, 0) != 0)
+		if (PyObject_Print(entry->key, fp, 0) != 0) {
+			Py_ReprLeave((PyObject*)so);
 			return -1;
+		}
 	}
 	fputs("])", fp);
+	Py_ReprLeave((PyObject*)so);        
 	return 0;
 }
 
 static PyObject *
 set_repr(PySetObject *so)
 {
-	PyObject *keys, *result, *listrepr;
+	PyObject *keys, *result=NULL, *listrepr;
+	int status = Py_ReprEnter((PyObject*)so);
+
+	if (status != 0) {
+		if (status < 0)
+			return NULL;
+		return PyString_FromFormat("%s(...)", so->ob_type->tp_name);
+	}
 
 	keys = PySequence_List((PyObject *)so);
 	if (keys == NULL)
-		return NULL;
+		goto done;
 	listrepr = PyObject_Repr(keys);
 	Py_DECREF(keys);
 	if (listrepr == NULL)
-		return NULL;
+		goto done;
 
 	result = PyString_FromFormat("%s(%s)", so->ob_type->tp_name,
 		PyString_AS_STRING(listrepr));
 	Py_DECREF(listrepr);
+done:
+	Py_ReprLeave((PyObject*)so);
 	return result;
 }
 


More information about the Python-checkins mailing list