Skip to content

Commit 092bd38

Browse files
Issue #19137: The pprint module now correctly formats instances of set and
frozenset subclasses.
2 parents 75f65e3 + 5184438 commit 092bd38

3 files changed

Lines changed: 83 additions & 27 deletions

File tree

Lib/pprint.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -203,24 +203,22 @@ def _format(self, object, stream, indent, allowance, context, level):
203203
if issubclass(typ, list):
204204
write('[')
205205
endchar = ']'
206-
elif issubclass(typ, set):
207-
if not length:
208-
write('set()')
209-
return
210-
write('{')
211-
endchar = '}'
212-
object = sorted(object, key=_safe_key)
213-
elif issubclass(typ, frozenset):
206+
elif issubclass(typ, tuple):
207+
write('(')
208+
endchar = ')'
209+
else:
214210
if not length:
215-
write('frozenset()')
211+
write(rep)
216212
return
217-
write('frozenset({')
218-
endchar = '})'
213+
if typ is set:
214+
write('{')
215+
endchar = '}'
216+
else:
217+
write(typ.__name__)
218+
write('({')
219+
endchar = '})'
220+
indent += len(typ.__name__) + 1
219221
object = sorted(object, key=_safe_key)
220-
indent += 10
221-
else:
222-
write('(')
223-
endchar = ')'
224222
if self._indent_per_level > 1:
225223
write((self._indent_per_level - 1) * ' ')
226224
if length:

Lib/test/test_pprint.py

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ class tuple3(tuple):
2323
def __repr__(self):
2424
return tuple.__repr__(self)
2525

26+
class set2(set):
27+
pass
28+
29+
class set3(set):
30+
def __repr__(self):
31+
return set.__repr__(self)
32+
33+
class frozenset2(frozenset):
34+
pass
35+
36+
class frozenset3(frozenset):
37+
def __repr__(self):
38+
return frozenset.__repr__(self)
39+
2640
class dict2(dict):
2741
pass
2842

@@ -117,22 +131,24 @@ def test_same_as_repr(self):
117131
for simple in (0, 0, 0+0j, 0.0, "", b"",
118132
(), tuple2(), tuple3(),
119133
[], list2(), list3(),
134+
set(), set2(), set3(),
135+
frozenset(), frozenset2(), frozenset3(),
120136
{}, dict2(), dict3(),
121137
self.assertTrue, pprint,
122138
-6, -6, -6-6j, -1.5, "x", b"x", (3,), [3], {3: 6},
123139
(1,2), [3,4], {5: 6},
124140
tuple2((1,2)), tuple3((1,2)), tuple3(range(100)),
125141
[3,4], list2([3,4]), list3([3,4]), list3(range(100)),
142+
set({7}), set2({7}), set3({7}),
143+
frozenset({8}), frozenset2({8}), frozenset3({8}),
126144
dict2({5: 6}), dict3({5: 6}),
127145
range(10, -11, -1)
128146
):
129147
native = repr(simple)
130-
for function in "pformat", "saferepr":
131-
f = getattr(pprint, function)
132-
got = f(simple)
133-
self.assertEqual(native, got,
134-
"expected %s got %s from pprint.%s" %
135-
(native, got, function))
148+
self.assertEqual(pprint.pformat(simple), native)
149+
self.assertEqual(pprint.pformat(simple, width=1, indent=0)
150+
.replace('\n', ' '), native)
151+
self.assertEqual(pprint.saferepr(simple), native)
136152

137153
def test_basic_line_wrap(self):
138154
# verify basic line-wrapping operation
@@ -221,10 +237,54 @@ def test_subclassing(self):
221237
others.should.not.be: like.this}"""
222238
self.assertEqual(DottedPrettyPrinter().pformat(o), exp)
223239

240+
def test_set_reprs(self):
241+
self.assertEqual(pprint.pformat(set()), 'set()')
242+
self.assertEqual(pprint.pformat(set(range(3))), '{0, 1, 2}')
243+
self.assertEqual(pprint.pformat(set(range(7)), width=20), '''\
244+
{0,
245+
1,
246+
2,
247+
3,
248+
4,
249+
5,
250+
6}''')
251+
self.assertEqual(pprint.pformat(set2(range(7)), width=20), '''\
252+
set2({0,
253+
1,
254+
2,
255+
3,
256+
4,
257+
5,
258+
6})''')
259+
self.assertEqual(pprint.pformat(set3(range(7)), width=20),
260+
'set3({0, 1, 2, 3, 4, 5, 6})')
261+
262+
self.assertEqual(pprint.pformat(frozenset()), 'frozenset()')
263+
self.assertEqual(pprint.pformat(frozenset(range(3))),
264+
'frozenset({0, 1, 2})')
265+
self.assertEqual(pprint.pformat(frozenset(range(7)), width=20), '''\
266+
frozenset({0,
267+
1,
268+
2,
269+
3,
270+
4,
271+
5,
272+
6})''')
273+
self.assertEqual(pprint.pformat(frozenset2(range(7)), width=20), '''\
274+
frozenset2({0,
275+
1,
276+
2,
277+
3,
278+
4,
279+
5,
280+
6})''')
281+
self.assertEqual(pprint.pformat(frozenset3(range(7)), width=20),
282+
'frozenset3({0, 1, 2, 3, 4, 5, 6})')
283+
224284
@unittest.expectedFailure
225285
#See http://bugs.python.org/issue13907
226286
@test.support.cpython_only
227-
def test_set_reprs(self):
287+
def test_set_of_sets_reprs(self):
228288
# This test creates a complex arrangement of frozensets and
229289
# compares the pretty-printed repr against a string hard-coded in
230290
# the test. The hard-coded repr depends on the sort order of
@@ -247,11 +307,6 @@ def test_set_reprs(self):
247307
# algorithm cause the test to fail when it should pass.
248308
# XXX Or changes to the dictionary implmentation...
249309

250-
self.assertEqual(pprint.pformat(set()), 'set()')
251-
self.assertEqual(pprint.pformat(set(range(3))), '{0, 1, 2}')
252-
self.assertEqual(pprint.pformat(frozenset()), 'frozenset()')
253-
254-
self.assertEqual(pprint.pformat(frozenset(range(3))), 'frozenset({0, 1, 2})')
255310
cube_repr_tgt = """\
256311
{frozenset(): frozenset({frozenset({2}), frozenset({0}), frozenset({1})}),
257312
frozenset({0}): frozenset({frozenset(),

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Core and Builtins
1313
Library
1414
-------
1515

16+
- Issue #19137: The pprint module now correctly formats instances of set and
17+
frozenset subclasses.
18+
1619
- Issue #10042: functools.total_ordering now correctly handles
1720
NotImplemented being returned by the underlying comparison function (Patch
1821
by Katie Miller)

0 commit comments

Comments
 (0)