Issue 9840:  Add reprlib.recursive_repr(), a decorator for handling recursive calls to __repr__ methods.
diff --git a/Lib/reprlib.py b/Lib/reprlib.py
index 9893c71..c44c75c 100644
--- a/Lib/reprlib.py
+++ b/Lib/reprlib.py
@@ -1,9 +1,38 @@
 """Redo the builtin repr() (representation) but with limits on most sizes."""
 
-__all__ = ["Repr","repr"]
+__all__ = ["Repr", "repr", "recursive_repr"]
 
 import builtins
 from itertools import islice
+try:
+    from _thread import get_ident
+except AttributeError:
+    from _dummy_thread import get_ident
+
+def recursive_repr(fillvalue='...'):
+    'Decorator to make a repr function return fillvalue for a recursive call'
+
+    def decorating_function(user_function):
+        repr_running = set()
+
+        def wrapper(self):
+            key = id(self), get_ident()
+            if key in repr_running:
+                return fillvalue
+            repr_running.add(key)
+            try:
+                result = user_function(self)
+            finally:
+                repr_running.discard(key)
+            return result
+
+        # Can't use functools.wraps() here because of bootstrap issues
+        wrapper.__module__ = getattr(user_function, '__module__')
+        wrapper.__doc__ = getattr(user_function, '__doc__')
+        wrapper.__name__ = getattr(user_function, '__name__')
+        return wrapper
+
+    return decorating_function
 
 class Repr: