For sets with cyclical reprs, emit '...' instead of recursing.
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index 422cc41..dedd1fb 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -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
 
diff --git a/Misc/NEWS b/Misc/NEWS
index 9acc771..7ab30ed 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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().
 
diff --git a/Objects/setobject.c b/Objects/setobject.c
index d33fff9..507a07b 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -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;
 }