[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