bpo-43080: pprint for dataclass instances (GH-24389)

* Added pprint support for dataclass instances which don't have a custom __repr__.
diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py
index e5d2ac5..6c714fd 100644
--- a/Lib/test/test_pprint.py
+++ b/Lib/test/test_pprint.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 
 import collections
+import dataclasses
 import io
 import itertools
 import pprint
@@ -66,6 +67,38 @@ class dict_custom_repr(dict):
     def __repr__(self):
         return '*'*len(dict.__repr__(self))
 
+@dataclasses.dataclass
+class dataclass1:
+    field1: str
+    field2: int
+    field3: bool = False
+    field4: int = dataclasses.field(default=1, repr=False)
+
+@dataclasses.dataclass
+class dataclass2:
+    a: int = 1
+    def __repr__(self):
+        return "custom repr that doesn't fit within pprint width"
+
+@dataclasses.dataclass(repr=False)
+class dataclass3:
+    a: int = 1
+
+@dataclasses.dataclass
+class dataclass4:
+    a: "dataclass4"
+    b: int = 1
+
+@dataclasses.dataclass
+class dataclass5:
+    a: "dataclass6"
+    b: int = 1
+
+@dataclasses.dataclass
+class dataclass6:
+    c: "dataclass5"
+    d: int = 1
+
 class Unorderable:
     def __repr__(self):
         return str(id(self))
@@ -428,7 +461,7 @@ def test_simple_namespace(self):
             lazy=7,
             dog=8,
         )
-        formatted = pprint.pformat(ns, width=60)
+        formatted = pprint.pformat(ns, width=60, indent=4)
         self.assertEqual(formatted, """\
 namespace(the=0,
           quick=1,
@@ -465,6 +498,56 @@ class AdvancedNamespace(types.SimpleNamespace): pass
                   lazy=7,
                   dog=8)""")
 
+    def test_empty_dataclass(self):
+        dc = dataclasses.make_dataclass("MyDataclass", ())()
+        formatted = pprint.pformat(dc)
+        self.assertEqual(formatted, "MyDataclass()")
+
+    def test_small_dataclass(self):
+        dc = dataclass1("text", 123)
+        formatted = pprint.pformat(dc)
+        self.assertEqual(formatted, "dataclass1(field1='text', field2=123, field3=False)")
+
+    def test_larger_dataclass(self):
+        dc = dataclass1("some fairly long text", int(1e10), True)
+        formatted = pprint.pformat([dc, dc], width=60, indent=4)
+        self.assertEqual(formatted, """\
+[   dataclass1(field1='some fairly long text',
+               field2=10000000000,
+               field3=True),
+    dataclass1(field1='some fairly long text',
+               field2=10000000000,
+               field3=True)]""")
+
+    def test_dataclass_with_repr(self):
+        dc = dataclass2()
+        formatted = pprint.pformat(dc, width=20)
+        self.assertEqual(formatted, "custom repr that doesn't fit within pprint width")
+
+    def test_dataclass_no_repr(self):
+        dc = dataclass3()
+        formatted = pprint.pformat(dc, width=10)
+        self.assertRegex(formatted, r"<test.test_pprint.dataclass3 object at \w+>")
+
+    def test_recursive_dataclass(self):
+        dc = dataclass4(None)
+        dc.a = dc
+        formatted = pprint.pformat(dc, width=10)
+        self.assertEqual(formatted, """\
+dataclass4(a=...,
+           b=1)""")
+
+    def test_cyclic_dataclass(self):
+        dc5 = dataclass5(None)
+        dc6 = dataclass6(None)
+        dc5.a = dc6
+        dc6.c = dc5
+        formatted = pprint.pformat(dc5, width=10)
+        self.assertEqual(formatted, """\
+dataclass5(a=dataclass6(c=...,
+                        d=1),
+           b=1)""")
+
     def test_subclassing(self):
         # length(repr(obj)) > width
         o = {'names with spaces': 'should be presented using repr()',