• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: utf-8 -*-
2
3import collections
4import contextlib
5import dataclasses
6import io
7import itertools
8import pprint
9import random
10import re
11import test.support
12import types
13import unittest
14
15# list, tuple and dict subclasses that do or don't overwrite __repr__
16class list2(list):
17    pass
18
19class list3(list):
20    def __repr__(self):
21        return list.__repr__(self)
22
23class list_custom_repr(list):
24    def __repr__(self):
25        return '*'*len(list.__repr__(self))
26
27class tuple2(tuple):
28    pass
29
30class tuple3(tuple):
31    def __repr__(self):
32        return tuple.__repr__(self)
33
34class tuple_custom_repr(tuple):
35    def __repr__(self):
36        return '*'*len(tuple.__repr__(self))
37
38class set2(set):
39    pass
40
41class set3(set):
42    def __repr__(self):
43        return set.__repr__(self)
44
45class set_custom_repr(set):
46    def __repr__(self):
47        return '*'*len(set.__repr__(self))
48
49class frozenset2(frozenset):
50    pass
51
52class frozenset3(frozenset):
53    def __repr__(self):
54        return frozenset.__repr__(self)
55
56class frozenset_custom_repr(frozenset):
57    def __repr__(self):
58        return '*'*len(frozenset.__repr__(self))
59
60class dict2(dict):
61    pass
62
63class dict3(dict):
64    def __repr__(self):
65        return dict.__repr__(self)
66
67class dict_custom_repr(dict):
68    def __repr__(self):
69        return '*'*len(dict.__repr__(self))
70
71@dataclasses.dataclass
72class dataclass1:
73    field1: str
74    field2: int
75    field3: bool = False
76    field4: int = dataclasses.field(default=1, repr=False)
77
78@dataclasses.dataclass
79class dataclass2:
80    a: int = 1
81    def __repr__(self):
82        return "custom repr that doesn't fit within pprint width"
83
84@dataclasses.dataclass(repr=False)
85class dataclass3:
86    a: int = 1
87
88@dataclasses.dataclass
89class dataclass4:
90    a: "dataclass4"
91    b: int = 1
92
93@dataclasses.dataclass
94class dataclass5:
95    a: "dataclass6"
96    b: int = 1
97
98@dataclasses.dataclass
99class dataclass6:
100    c: "dataclass5"
101    d: int = 1
102
103class Unorderable:
104    def __repr__(self):
105        return str(id(self))
106
107# Class Orderable is orderable with any type
108class Orderable:
109    def __init__(self, hash):
110        self._hash = hash
111    def __lt__(self, other):
112        return False
113    def __gt__(self, other):
114        return self != other
115    def __le__(self, other):
116        return self == other
117    def __ge__(self, other):
118        return True
119    def __eq__(self, other):
120        return self is other
121    def __ne__(self, other):
122        return self is not other
123    def __hash__(self):
124        return self._hash
125
126class QueryTestCase(unittest.TestCase):
127
128    def setUp(self):
129        self.a = list(range(100))
130        self.b = list(range(200))
131        self.a[-12] = self.b
132
133    def test_init(self):
134        pp = pprint.PrettyPrinter()
135        pp = pprint.PrettyPrinter(indent=4, width=40, depth=5,
136                                  stream=io.StringIO(), compact=True)
137        pp = pprint.PrettyPrinter(4, 40, 5, io.StringIO())
138        pp = pprint.PrettyPrinter(sort_dicts=False)
139        with self.assertRaises(TypeError):
140            pp = pprint.PrettyPrinter(4, 40, 5, io.StringIO(), True)
141        self.assertRaises(ValueError, pprint.PrettyPrinter, indent=-1)
142        self.assertRaises(ValueError, pprint.PrettyPrinter, depth=0)
143        self.assertRaises(ValueError, pprint.PrettyPrinter, depth=-1)
144        self.assertRaises(ValueError, pprint.PrettyPrinter, width=0)
145
146    def test_basic(self):
147        # Verify .isrecursive() and .isreadable() w/o recursion
148        pp = pprint.PrettyPrinter()
149        for safe in (2, 2.0, 2j, "abc", [3], (2,2), {3: 3}, b"def",
150                     bytearray(b"ghi"), True, False, None, ...,
151                     self.a, self.b):
152            # module-level convenience functions
153            self.assertFalse(pprint.isrecursive(safe),
154                             "expected not isrecursive for %r" % (safe,))
155            self.assertTrue(pprint.isreadable(safe),
156                            "expected isreadable for %r" % (safe,))
157            # PrettyPrinter methods
158            self.assertFalse(pp.isrecursive(safe),
159                             "expected not isrecursive for %r" % (safe,))
160            self.assertTrue(pp.isreadable(safe),
161                            "expected isreadable for %r" % (safe,))
162
163    def test_stdout_is_None(self):
164        with contextlib.redirect_stdout(None):
165            # smoke test - there is no output to check
166            value = 'this should not fail'
167            pprint.pprint(value)
168            pprint.PrettyPrinter().pprint(value)
169
170    def test_knotted(self):
171        # Verify .isrecursive() and .isreadable() w/ recursion
172        # Tie a knot.
173        self.b[67] = self.a
174        # Messy dict.
175        self.d = {}
176        self.d[0] = self.d[1] = self.d[2] = self.d
177
178        pp = pprint.PrettyPrinter()
179
180        for icky in self.a, self.b, self.d, (self.d, self.d):
181            self.assertTrue(pprint.isrecursive(icky), "expected isrecursive")
182            self.assertFalse(pprint.isreadable(icky), "expected not isreadable")
183            self.assertTrue(pp.isrecursive(icky), "expected isrecursive")
184            self.assertFalse(pp.isreadable(icky), "expected not isreadable")
185
186        # Break the cycles.
187        self.d.clear()
188        del self.a[:]
189        del self.b[:]
190
191        for safe in self.a, self.b, self.d, (self.d, self.d):
192            # module-level convenience functions
193            self.assertFalse(pprint.isrecursive(safe),
194                             "expected not isrecursive for %r" % (safe,))
195            self.assertTrue(pprint.isreadable(safe),
196                            "expected isreadable for %r" % (safe,))
197            # PrettyPrinter methods
198            self.assertFalse(pp.isrecursive(safe),
199                             "expected not isrecursive for %r" % (safe,))
200            self.assertTrue(pp.isreadable(safe),
201                            "expected isreadable for %r" % (safe,))
202
203    def test_unreadable(self):
204        # Not recursive but not readable anyway
205        pp = pprint.PrettyPrinter()
206        for unreadable in object(), int, pprint, pprint.isrecursive:
207            # module-level convenience functions
208            self.assertFalse(pprint.isrecursive(unreadable),
209                             "expected not isrecursive for %r" % (unreadable,))
210            self.assertFalse(pprint.isreadable(unreadable),
211                             "expected not isreadable for %r" % (unreadable,))
212            # PrettyPrinter methods
213            self.assertFalse(pp.isrecursive(unreadable),
214                             "expected not isrecursive for %r" % (unreadable,))
215            self.assertFalse(pp.isreadable(unreadable),
216                             "expected not isreadable for %r" % (unreadable,))
217
218    def test_same_as_repr(self):
219        # Simple objects, small containers and classes that override __repr__
220        # to directly call super's __repr__.
221        # For those the result should be the same as repr().
222        # Ahem.  The docs don't say anything about that -- this appears to
223        # be testing an implementation quirk.  Starting in Python 2.5, it's
224        # not true for dicts:  pprint always sorts dicts by key now; before,
225        # it sorted a dict display if and only if the display required
226        # multiple lines.  For that reason, dicts with more than one element
227        # aren't tested here.
228        for simple in (0, 0, 0+0j, 0.0, "", b"", bytearray(),
229                       (), tuple2(), tuple3(),
230                       [], list2(), list3(),
231                       set(), set2(), set3(),
232                       frozenset(), frozenset2(), frozenset3(),
233                       {}, dict2(), dict3(),
234                       self.assertTrue, pprint,
235                       -6, -6, -6-6j, -1.5, "x", b"x", bytearray(b"x"),
236                       (3,), [3], {3: 6},
237                       (1,2), [3,4], {5: 6},
238                       tuple2((1,2)), tuple3((1,2)), tuple3(range(100)),
239                       [3,4], list2([3,4]), list3([3,4]), list3(range(100)),
240                       set({7}), set2({7}), set3({7}),
241                       frozenset({8}), frozenset2({8}), frozenset3({8}),
242                       dict2({5: 6}), dict3({5: 6}),
243                       range(10, -11, -1),
244                       True, False, None, ...,
245                      ):
246            native = repr(simple)
247            self.assertEqual(pprint.pformat(simple), native)
248            self.assertEqual(pprint.pformat(simple, width=1, indent=0)
249                             .replace('\n', ' '), native)
250            self.assertEqual(pprint.pformat(simple, underscore_numbers=True), native)
251            self.assertEqual(pprint.saferepr(simple), native)
252
253    def test_container_repr_override_called(self):
254        N = 1000
255        # Ensure that __repr__ override is called for subclasses of containers
256
257        for cont in (list_custom_repr(),
258                     list_custom_repr([1,2,3]),
259                     list_custom_repr(range(N)),
260                     tuple_custom_repr(),
261                     tuple_custom_repr([1,2,3]),
262                     tuple_custom_repr(range(N)),
263                     set_custom_repr(),
264                     set_custom_repr([1,2,3]),
265                     set_custom_repr(range(N)),
266                     frozenset_custom_repr(),
267                     frozenset_custom_repr([1,2,3]),
268                     frozenset_custom_repr(range(N)),
269                     dict_custom_repr(),
270                     dict_custom_repr({5: 6}),
271                     dict_custom_repr(zip(range(N),range(N))),
272                    ):
273            native = repr(cont)
274            expected = '*' * len(native)
275            self.assertEqual(pprint.pformat(cont), expected)
276            self.assertEqual(pprint.pformat(cont, width=1, indent=0), expected)
277            self.assertEqual(pprint.saferepr(cont), expected)
278
279    def test_basic_line_wrap(self):
280        # verify basic line-wrapping operation
281        o = {'RPM_cal': 0,
282             'RPM_cal2': 48059,
283             'Speed_cal': 0,
284             'controldesk_runtime_us': 0,
285             'main_code_runtime_us': 0,
286             'read_io_runtime_us': 0,
287             'write_io_runtime_us': 43690}
288        exp = """\
289{'RPM_cal': 0,
290 'RPM_cal2': 48059,
291 'Speed_cal': 0,
292 'controldesk_runtime_us': 0,
293 'main_code_runtime_us': 0,
294 'read_io_runtime_us': 0,
295 'write_io_runtime_us': 43690}"""
296        for type in [dict, dict2]:
297            self.assertEqual(pprint.pformat(type(o)), exp)
298
299        o = range(100)
300        exp = '[%s]' % ',\n '.join(map(str, o))
301        for type in [list, list2]:
302            self.assertEqual(pprint.pformat(type(o)), exp)
303
304        o = tuple(range(100))
305        exp = '(%s)' % ',\n '.join(map(str, o))
306        for type in [tuple, tuple2]:
307            self.assertEqual(pprint.pformat(type(o)), exp)
308
309        # indent parameter
310        o = range(100)
311        exp = '[   %s]' % ',\n    '.join(map(str, o))
312        for type in [list, list2]:
313            self.assertEqual(pprint.pformat(type(o), indent=4), exp)
314
315    def test_nested_indentations(self):
316        o1 = list(range(10))
317        o2 = dict(first=1, second=2, third=3)
318        o = [o1, o2]
319        expected = """\
320[   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
321    {'first': 1, 'second': 2, 'third': 3}]"""
322        self.assertEqual(pprint.pformat(o, indent=4, width=42), expected)
323        expected = """\
324[   [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
325    {   'first': 1,
326        'second': 2,
327        'third': 3}]"""
328        self.assertEqual(pprint.pformat(o, indent=4, width=41), expected)
329
330    def test_width(self):
331        expected = """\
332[[[[[[1, 2, 3],
333     '1 2']]]],
334 {1: [1, 2, 3],
335  2: [12, 34]},
336 'abc def ghi',
337 ('ab cd ef',),
338 set2({1, 23}),
339 [[[[[1, 2, 3],
340     '1 2']]]]]"""
341        o = eval(expected)
342        self.assertEqual(pprint.pformat(o, width=15), expected)
343        self.assertEqual(pprint.pformat(o, width=16), expected)
344        self.assertEqual(pprint.pformat(o, width=25), expected)
345        self.assertEqual(pprint.pformat(o, width=14), """\
346[[[[[[1,
347      2,
348      3],
349     '1 '
350     '2']]]],
351 {1: [1,
352      2,
353      3],
354  2: [12,
355      34]},
356 'abc def '
357 'ghi',
358 ('ab cd '
359  'ef',),
360 set2({1,
361       23}),
362 [[[[[1,
363      2,
364      3],
365     '1 '
366     '2']]]]]""")
367
368    def test_integer(self):
369        self.assertEqual(pprint.pformat(1234567), '1234567')
370        self.assertEqual(pprint.pformat(1234567, underscore_numbers=True), '1_234_567')
371
372        class Temperature(int):
373            def __new__(cls, celsius_degrees):
374                return super().__new__(Temperature, celsius_degrees)
375            def __repr__(self):
376                kelvin_degrees = self + 273.15
377                return f"{kelvin_degrees}°K"
378        self.assertEqual(pprint.pformat(Temperature(1000)), '1273.15°K')
379
380    def test_sorted_dict(self):
381        # Starting in Python 2.5, pprint sorts dict displays by key regardless
382        # of how small the dictionary may be.
383        # Before the change, on 32-bit Windows pformat() gave order
384        # 'a', 'c', 'b' here, so this test failed.
385        d = {'a': 1, 'b': 1, 'c': 1}
386        self.assertEqual(pprint.pformat(d), "{'a': 1, 'b': 1, 'c': 1}")
387        self.assertEqual(pprint.pformat([d, d]),
388            "[{'a': 1, 'b': 1, 'c': 1}, {'a': 1, 'b': 1, 'c': 1}]")
389
390        # The next one is kind of goofy.  The sorted order depends on the
391        # alphabetic order of type names:  "int" < "str" < "tuple".  Before
392        # Python 2.5, this was in the test_same_as_repr() test.  It's worth
393        # keeping around for now because it's one of few tests of pprint
394        # against a crazy mix of types.
395        self.assertEqual(pprint.pformat({"xy\tab\n": (3,), 5: [[]], (): {}}),
396            r"{5: [[]], 'xy\tab\n': (3,), (): {}}")
397
398    def test_sort_dict(self):
399        d = dict.fromkeys('cba')
400        self.assertEqual(pprint.pformat(d, sort_dicts=False), "{'c': None, 'b': None, 'a': None}")
401        self.assertEqual(pprint.pformat([d, d], sort_dicts=False),
402            "[{'c': None, 'b': None, 'a': None}, {'c': None, 'b': None, 'a': None}]")
403
404    def test_ordered_dict(self):
405        d = collections.OrderedDict()
406        self.assertEqual(pprint.pformat(d, width=1), 'OrderedDict()')
407        d = collections.OrderedDict([])
408        self.assertEqual(pprint.pformat(d, width=1), 'OrderedDict()')
409        words = 'the quick brown fox jumped over a lazy dog'.split()
410        d = collections.OrderedDict(zip(words, itertools.count()))
411        self.assertEqual(pprint.pformat(d),
412"""\
413OrderedDict([('the', 0),
414             ('quick', 1),
415             ('brown', 2),
416             ('fox', 3),
417             ('jumped', 4),
418             ('over', 5),
419             ('a', 6),
420             ('lazy', 7),
421             ('dog', 8)])""")
422
423    def test_mapping_proxy(self):
424        words = 'the quick brown fox jumped over a lazy dog'.split()
425        d = dict(zip(words, itertools.count()))
426        m = types.MappingProxyType(d)
427        self.assertEqual(pprint.pformat(m), """\
428mappingproxy({'a': 6,
429              'brown': 2,
430              'dog': 8,
431              'fox': 3,
432              'jumped': 4,
433              'lazy': 7,
434              'over': 5,
435              'quick': 1,
436              'the': 0})""")
437        d = collections.OrderedDict(zip(words, itertools.count()))
438        m = types.MappingProxyType(d)
439        self.assertEqual(pprint.pformat(m), """\
440mappingproxy(OrderedDict([('the', 0),
441                          ('quick', 1),
442                          ('brown', 2),
443                          ('fox', 3),
444                          ('jumped', 4),
445                          ('over', 5),
446                          ('a', 6),
447                          ('lazy', 7),
448                          ('dog', 8)]))""")
449
450    def test_empty_simple_namespace(self):
451        ns = types.SimpleNamespace()
452        formatted = pprint.pformat(ns)
453        self.assertEqual(formatted, "namespace()")
454
455    def test_small_simple_namespace(self):
456        ns = types.SimpleNamespace(a=1, b=2)
457        formatted = pprint.pformat(ns)
458        self.assertEqual(formatted, "namespace(a=1, b=2)")
459
460    def test_simple_namespace(self):
461        ns = types.SimpleNamespace(
462            the=0,
463            quick=1,
464            brown=2,
465            fox=3,
466            jumped=4,
467            over=5,
468            a=6,
469            lazy=7,
470            dog=8,
471        )
472        formatted = pprint.pformat(ns, width=60, indent=4)
473        self.assertEqual(formatted, """\
474namespace(the=0,
475          quick=1,
476          brown=2,
477          fox=3,
478          jumped=4,
479          over=5,
480          a=6,
481          lazy=7,
482          dog=8)""")
483
484    def test_simple_namespace_subclass(self):
485        class AdvancedNamespace(types.SimpleNamespace): pass
486        ns = AdvancedNamespace(
487            the=0,
488            quick=1,
489            brown=2,
490            fox=3,
491            jumped=4,
492            over=5,
493            a=6,
494            lazy=7,
495            dog=8,
496        )
497        formatted = pprint.pformat(ns, width=60)
498        self.assertEqual(formatted, """\
499AdvancedNamespace(the=0,
500                  quick=1,
501                  brown=2,
502                  fox=3,
503                  jumped=4,
504                  over=5,
505                  a=6,
506                  lazy=7,
507                  dog=8)""")
508
509    def test_empty_dataclass(self):
510        dc = dataclasses.make_dataclass("MyDataclass", ())()
511        formatted = pprint.pformat(dc)
512        self.assertEqual(formatted, "MyDataclass()")
513
514    def test_small_dataclass(self):
515        dc = dataclass1("text", 123)
516        formatted = pprint.pformat(dc)
517        self.assertEqual(formatted, "dataclass1(field1='text', field2=123, field3=False)")
518
519    def test_larger_dataclass(self):
520        dc = dataclass1("some fairly long text", int(1e10), True)
521        formatted = pprint.pformat([dc, dc], width=60, indent=4)
522        self.assertEqual(formatted, """\
523[   dataclass1(field1='some fairly long text',
524               field2=10000000000,
525               field3=True),
526    dataclass1(field1='some fairly long text',
527               field2=10000000000,
528               field3=True)]""")
529
530    def test_dataclass_with_repr(self):
531        dc = dataclass2()
532        formatted = pprint.pformat(dc, width=20)
533        self.assertEqual(formatted, "custom repr that doesn't fit within pprint width")
534
535    def test_dataclass_no_repr(self):
536        dc = dataclass3()
537        formatted = pprint.pformat(dc, width=10)
538        self.assertRegex(
539            formatted,
540            fr"<{re.escape(__name__)}.dataclass3 object at \w+>",
541        )
542
543    def test_recursive_dataclass(self):
544        dc = dataclass4(None)
545        dc.a = dc
546        formatted = pprint.pformat(dc, width=10)
547        self.assertEqual(formatted, """\
548dataclass4(a=...,
549           b=1)""")
550
551    def test_cyclic_dataclass(self):
552        dc5 = dataclass5(None)
553        dc6 = dataclass6(None)
554        dc5.a = dc6
555        dc6.c = dc5
556        formatted = pprint.pformat(dc5, width=10)
557        self.assertEqual(formatted, """\
558dataclass5(a=dataclass6(c=...,
559                        d=1),
560           b=1)""")
561
562    def test_subclassing(self):
563        # length(repr(obj)) > width
564        o = {'names with spaces': 'should be presented using repr()',
565             'others.should.not.be': 'like.this'}
566        exp = """\
567{'names with spaces': 'should be presented using repr()',
568 others.should.not.be: like.this}"""
569
570        dotted_printer = DottedPrettyPrinter()
571        self.assertEqual(dotted_printer.pformat(o), exp)
572
573        # length(repr(obj)) < width
574        o1 = ['with space']
575        exp1 = "['with space']"
576        self.assertEqual(dotted_printer.pformat(o1), exp1)
577        o2 = ['without.space']
578        exp2 = "[without.space]"
579        self.assertEqual(dotted_printer.pformat(o2), exp2)
580
581    def test_set_reprs(self):
582        self.assertEqual(pprint.pformat(set()), 'set()')
583        self.assertEqual(pprint.pformat(set(range(3))), '{0, 1, 2}')
584        self.assertEqual(pprint.pformat(set(range(7)), width=20), '''\
585{0,
586 1,
587 2,
588 3,
589 4,
590 5,
591 6}''')
592        self.assertEqual(pprint.pformat(set2(range(7)), width=20), '''\
593set2({0,
594      1,
595      2,
596      3,
597      4,
598      5,
599      6})''')
600        self.assertEqual(pprint.pformat(set3(range(7)), width=20),
601                         'set3({0, 1, 2, 3, 4, 5, 6})')
602
603        self.assertEqual(pprint.pformat(frozenset()), 'frozenset()')
604        self.assertEqual(pprint.pformat(frozenset(range(3))),
605                         'frozenset({0, 1, 2})')
606        self.assertEqual(pprint.pformat(frozenset(range(7)), width=20), '''\
607frozenset({0,
608           1,
609           2,
610           3,
611           4,
612           5,
613           6})''')
614        self.assertEqual(pprint.pformat(frozenset2(range(7)), width=20), '''\
615frozenset2({0,
616            1,
617            2,
618            3,
619            4,
620            5,
621            6})''')
622        self.assertEqual(pprint.pformat(frozenset3(range(7)), width=20),
623                         'frozenset3({0, 1, 2, 3, 4, 5, 6})')
624
625    def test_set_of_sets_reprs(self):
626        # This test creates a complex arrangement of frozensets and
627        # compares the pretty-printed repr against a string hard-coded in
628        # the test.  The hard-coded repr depends on the sort order of
629        # frozensets.
630        #
631        # However, as the docs point out: "Since sets only define
632        # partial ordering (subset relationships), the output of the
633        # list.sort() method is undefined for lists of sets."
634        #
635        # >>> frozenset({0}) < frozenset({1})
636        # False
637        # >>> frozenset({1}) < frozenset({0})
638        # False
639        #
640        # In this test we list all possible invariants of the result
641        # for unordered frozensets.
642        #
643        # This test has a long history, see:
644        # - https://github.com/python/cpython/commit/969fe57baa0eb80332990f9cda936a33e13fabef
645        # - https://github.com/python/cpython/issues/58115
646        # - https://github.com/python/cpython/issues/111147
647
648        import textwrap
649
650        # Single-line, always ordered:
651        fs0 = frozenset()
652        fs1 = frozenset(('abc', 'xyz'))
653        data = frozenset((fs0, fs1))
654        self.assertEqual(pprint.pformat(data),
655                         'frozenset({%r, %r})' % (fs0, fs1))
656        self.assertEqual(pprint.pformat(data), repr(data))
657
658        fs2 = frozenset(('one', 'two'))
659        data = {fs2: frozenset((fs0, fs1))}
660        self.assertEqual(pprint.pformat(data),
661                         "{%r: frozenset({%r, %r})}" % (fs2, fs0, fs1))
662        self.assertEqual(pprint.pformat(data), repr(data))
663
664        # Single-line, unordered:
665        fs1 = frozenset(("xyz", "qwerty"))
666        fs2 = frozenset(("abcd", "spam"))
667        fs = frozenset((fs1, fs2))
668        self.assertEqual(pprint.pformat(fs), repr(fs))
669
670        # Multiline, unordered:
671        def check(res, invariants):
672            self.assertIn(res, [textwrap.dedent(i).strip() for i in invariants])
673
674        # Inner-most frozensets are singleline, result is multiline, unordered:
675        fs1 = frozenset(('regular string', 'other string'))
676        fs2 = frozenset(('third string', 'one more string'))
677        check(
678            pprint.pformat(frozenset((fs1, fs2))),
679            [
680                """
681                frozenset({%r,
682                           %r})
683                """ % (fs1, fs2),
684                """
685                frozenset({%r,
686                           %r})
687                """ % (fs2, fs1),
688            ],
689        )
690
691        # Everything is multiline, unordered:
692        check(
693            pprint.pformat(
694                frozenset((
695                    frozenset((
696                        "xyz very-very long string",
697                        "qwerty is also absurdly long",
698                    )),
699                    frozenset((
700                        "abcd is even longer that before",
701                        "spam is not so long",
702                    )),
703                )),
704            ),
705            [
706                """
707                frozenset({frozenset({'abcd is even longer that before',
708                                      'spam is not so long'}),
709                           frozenset({'qwerty is also absurdly long',
710                                      'xyz very-very long string'})})
711                """,
712
713                """
714                frozenset({frozenset({'abcd is even longer that before',
715                                      'spam is not so long'}),
716                           frozenset({'xyz very-very long string',
717                                      'qwerty is also absurdly long'})})
718                """,
719
720                """
721                frozenset({frozenset({'qwerty is also absurdly long',
722                                      'xyz very-very long string'}),
723                           frozenset({'abcd is even longer that before',
724                                      'spam is not so long'})})
725                """,
726
727                """
728                frozenset({frozenset({'qwerty is also absurdly long',
729                                      'xyz very-very long string'}),
730                           frozenset({'spam is not so long',
731                                      'abcd is even longer that before'})})
732                """,
733            ],
734        )
735
736    def test_depth(self):
737        nested_tuple = (1, (2, (3, (4, (5, 6)))))
738        nested_dict = {1: {2: {3: {4: {5: {6: 6}}}}}}
739        nested_list = [1, [2, [3, [4, [5, [6, []]]]]]]
740        self.assertEqual(pprint.pformat(nested_tuple), repr(nested_tuple))
741        self.assertEqual(pprint.pformat(nested_dict), repr(nested_dict))
742        self.assertEqual(pprint.pformat(nested_list), repr(nested_list))
743
744        lv1_tuple = '(1, (...))'
745        lv1_dict = '{1: {...}}'
746        lv1_list = '[1, [...]]'
747        self.assertEqual(pprint.pformat(nested_tuple, depth=1), lv1_tuple)
748        self.assertEqual(pprint.pformat(nested_dict, depth=1), lv1_dict)
749        self.assertEqual(pprint.pformat(nested_list, depth=1), lv1_list)
750
751    def test_sort_unorderable_values(self):
752        # Issue 3976:  sorted pprints fail for unorderable values.
753        n = 20
754        keys = [Unorderable() for i in range(n)]
755        random.shuffle(keys)
756        skeys = sorted(keys, key=id)
757        clean = lambda s: s.replace(' ', '').replace('\n','')
758
759        self.assertEqual(clean(pprint.pformat(set(keys))),
760            '{' + ','.join(map(repr, skeys)) + '}')
761        self.assertEqual(clean(pprint.pformat(frozenset(keys))),
762            'frozenset({' + ','.join(map(repr, skeys)) + '})')
763        self.assertEqual(clean(pprint.pformat(dict.fromkeys(keys))),
764            '{' + ','.join('%r:None' % k for k in skeys) + '}')
765
766        # Issue 10017: TypeError on user-defined types as dict keys.
767        self.assertEqual(pprint.pformat({Unorderable: 0, 1: 0}),
768                         '{1: 0, ' + repr(Unorderable) +': 0}')
769
770        # Issue 14998: TypeError on tuples with NoneTypes as dict keys.
771        keys = [(1,), (None,)]
772        self.assertEqual(pprint.pformat(dict.fromkeys(keys, 0)),
773                         '{%r: 0, %r: 0}' % tuple(sorted(keys, key=id)))
774
775    def test_sort_orderable_and_unorderable_values(self):
776        # Issue 22721:  sorted pprints is not stable
777        a = Unorderable()
778        b = Orderable(hash(a))  # should have the same hash value
779        # self-test
780        self.assertLess(a, b)
781        self.assertLess(str(type(b)), str(type(a)))
782        self.assertEqual(sorted([b, a]), [a, b])
783        self.assertEqual(sorted([a, b]), [a, b])
784        # set
785        self.assertEqual(pprint.pformat(set([b, a]), width=1),
786                         '{%r,\n %r}' % (a, b))
787        self.assertEqual(pprint.pformat(set([a, b]), width=1),
788                         '{%r,\n %r}' % (a, b))
789        # dict
790        self.assertEqual(pprint.pformat(dict.fromkeys([b, a]), width=1),
791                         '{%r: None,\n %r: None}' % (a, b))
792        self.assertEqual(pprint.pformat(dict.fromkeys([a, b]), width=1),
793                         '{%r: None,\n %r: None}' % (a, b))
794
795    def test_str_wrap(self):
796        # pprint tries to wrap strings intelligently
797        fox = 'the quick brown fox jumped over a lazy dog'
798        self.assertEqual(pprint.pformat(fox, width=19), """\
799('the quick brown '
800 'fox jumped over '
801 'a lazy dog')""")
802        self.assertEqual(pprint.pformat({'a': 1, 'b': fox, 'c': 2},
803                                        width=25), """\
804{'a': 1,
805 'b': 'the quick brown '
806      'fox jumped over '
807      'a lazy dog',
808 'c': 2}""")
809        # With some special characters
810        # - \n always triggers a new line in the pprint
811        # - \t and \n are escaped
812        # - non-ASCII is allowed
813        # - an apostrophe doesn't disrupt the pprint
814        special = "Portons dix bons \"whiskys\"\nà l'avocat goujat\t qui fumait au zoo"
815        self.assertEqual(pprint.pformat(special, width=68), repr(special))
816        self.assertEqual(pprint.pformat(special, width=31), """\
817('Portons dix bons "whiskys"\\n'
818 "à l'avocat goujat\\t qui "
819 'fumait au zoo')""")
820        self.assertEqual(pprint.pformat(special, width=20), """\
821('Portons dix bons '
822 '"whiskys"\\n'
823 "à l'avocat "
824 'goujat\\t qui '
825 'fumait au zoo')""")
826        self.assertEqual(pprint.pformat([[[[[special]]]]], width=35), """\
827[[[[['Portons dix bons "whiskys"\\n'
828     "à l'avocat goujat\\t qui "
829     'fumait au zoo']]]]]""")
830        self.assertEqual(pprint.pformat([[[[[special]]]]], width=25), """\
831[[[[['Portons dix bons '
832     '"whiskys"\\n'
833     "à l'avocat "
834     'goujat\\t qui '
835     'fumait au zoo']]]]]""")
836        self.assertEqual(pprint.pformat([[[[[special]]]]], width=23), """\
837[[[[['Portons dix '
838     'bons "whiskys"\\n'
839     "à l'avocat "
840     'goujat\\t qui '
841     'fumait au '
842     'zoo']]]]]""")
843        # An unwrappable string is formatted as its repr
844        unwrappable = "x" * 100
845        self.assertEqual(pprint.pformat(unwrappable, width=80), repr(unwrappable))
846        self.assertEqual(pprint.pformat(''), "''")
847        # Check that the pprint is a usable repr
848        special *= 10
849        for width in range(3, 40):
850            formatted = pprint.pformat(special, width=width)
851            self.assertEqual(eval(formatted), special)
852            formatted = pprint.pformat([special] * 2, width=width)
853            self.assertEqual(eval(formatted), [special] * 2)
854
855    def test_compact(self):
856        o = ([list(range(i * i)) for i in range(5)] +
857             [list(range(i)) for i in range(6)])
858        expected = """\
859[[], [0], [0, 1, 2, 3],
860 [0, 1, 2, 3, 4, 5, 6, 7, 8],
861 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
862  14, 15],
863 [], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3],
864 [0, 1, 2, 3, 4]]"""
865        self.assertEqual(pprint.pformat(o, width=47, compact=True), expected)
866
867    def test_compact_width(self):
868        levels = 20
869        number = 10
870        o = [0] * number
871        for i in range(levels - 1):
872            o = [o]
873        for w in range(levels * 2 + 1, levels + 3 * number - 1):
874            lines = pprint.pformat(o, width=w, compact=True).splitlines()
875            maxwidth = max(map(len, lines))
876            self.assertLessEqual(maxwidth, w)
877            self.assertGreater(maxwidth, w - 3)
878
879    def test_bytes_wrap(self):
880        self.assertEqual(pprint.pformat(b'', width=1), "b''")
881        self.assertEqual(pprint.pformat(b'abcd', width=1), "b'abcd'")
882        letters = b'abcdefghijklmnopqrstuvwxyz'
883        self.assertEqual(pprint.pformat(letters, width=29), repr(letters))
884        self.assertEqual(pprint.pformat(letters, width=19), """\
885(b'abcdefghijkl'
886 b'mnopqrstuvwxyz')""")
887        self.assertEqual(pprint.pformat(letters, width=18), """\
888(b'abcdefghijkl'
889 b'mnopqrstuvwx'
890 b'yz')""")
891        self.assertEqual(pprint.pformat(letters, width=16), """\
892(b'abcdefghijkl'
893 b'mnopqrstuvwx'
894 b'yz')""")
895        special = bytes(range(16))
896        self.assertEqual(pprint.pformat(special, width=61), repr(special))
897        self.assertEqual(pprint.pformat(special, width=48), """\
898(b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b'
899 b'\\x0c\\r\\x0e\\x0f')""")
900        self.assertEqual(pprint.pformat(special, width=32), """\
901(b'\\x00\\x01\\x02\\x03'
902 b'\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b'
903 b'\\x0c\\r\\x0e\\x0f')""")
904        self.assertEqual(pprint.pformat(special, width=1), """\
905(b'\\x00\\x01\\x02\\x03'
906 b'\\x04\\x05\\x06\\x07'
907 b'\\x08\\t\\n\\x0b'
908 b'\\x0c\\r\\x0e\\x0f')""")
909        self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2},
910                                        width=21), """\
911{'a': 1,
912 'b': b'abcdefghijkl'
913      b'mnopqrstuvwx'
914      b'yz',
915 'c': 2}""")
916        self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2},
917                                        width=20), """\
918{'a': 1,
919 'b': b'abcdefgh'
920      b'ijklmnop'
921      b'qrstuvwxyz',
922 'c': 2}""")
923        self.assertEqual(pprint.pformat([[[[[[letters]]]]]], width=25), """\
924[[[[[[b'abcdefghijklmnop'
925      b'qrstuvwxyz']]]]]]""")
926        self.assertEqual(pprint.pformat([[[[[[special]]]]]], width=41), """\
927[[[[[[b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07'
928      b'\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f']]]]]]""")
929        # Check that the pprint is a usable repr
930        for width in range(1, 64):
931            formatted = pprint.pformat(special, width=width)
932            self.assertEqual(eval(formatted), special)
933            formatted = pprint.pformat([special] * 2, width=width)
934            self.assertEqual(eval(formatted), [special] * 2)
935
936    def test_bytearray_wrap(self):
937        self.assertEqual(pprint.pformat(bytearray(), width=1), "bytearray(b'')")
938        letters = bytearray(b'abcdefghijklmnopqrstuvwxyz')
939        self.assertEqual(pprint.pformat(letters, width=40), repr(letters))
940        self.assertEqual(pprint.pformat(letters, width=28), """\
941bytearray(b'abcdefghijkl'
942          b'mnopqrstuvwxyz')""")
943        self.assertEqual(pprint.pformat(letters, width=27), """\
944bytearray(b'abcdefghijkl'
945          b'mnopqrstuvwx'
946          b'yz')""")
947        self.assertEqual(pprint.pformat(letters, width=25), """\
948bytearray(b'abcdefghijkl'
949          b'mnopqrstuvwx'
950          b'yz')""")
951        special = bytearray(range(16))
952        self.assertEqual(pprint.pformat(special, width=72), repr(special))
953        self.assertEqual(pprint.pformat(special, width=57), """\
954bytearray(b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b'
955          b'\\x0c\\r\\x0e\\x0f')""")
956        self.assertEqual(pprint.pformat(special, width=41), """\
957bytearray(b'\\x00\\x01\\x02\\x03'
958          b'\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b'
959          b'\\x0c\\r\\x0e\\x0f')""")
960        self.assertEqual(pprint.pformat(special, width=1), """\
961bytearray(b'\\x00\\x01\\x02\\x03'
962          b'\\x04\\x05\\x06\\x07'
963          b'\\x08\\t\\n\\x0b'
964          b'\\x0c\\r\\x0e\\x0f')""")
965        self.assertEqual(pprint.pformat({'a': 1, 'b': letters, 'c': 2},
966                                        width=31), """\
967{'a': 1,
968 'b': bytearray(b'abcdefghijkl'
969                b'mnopqrstuvwx'
970                b'yz'),
971 'c': 2}""")
972        self.assertEqual(pprint.pformat([[[[[letters]]]]], width=37), """\
973[[[[[bytearray(b'abcdefghijklmnop'
974               b'qrstuvwxyz')]]]]]""")
975        self.assertEqual(pprint.pformat([[[[[special]]]]], width=50), """\
976[[[[[bytearray(b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07'
977               b'\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f')]]]]]""")
978
979    def test_default_dict(self):
980        d = collections.defaultdict(int)
981        self.assertEqual(pprint.pformat(d, width=1), "defaultdict(<class 'int'>, {})")
982        words = 'the quick brown fox jumped over a lazy dog'.split()
983        d = collections.defaultdict(int, zip(words, itertools.count()))
984        self.assertEqual(pprint.pformat(d),
985"""\
986defaultdict(<class 'int'>,
987            {'a': 6,
988             'brown': 2,
989             'dog': 8,
990             'fox': 3,
991             'jumped': 4,
992             'lazy': 7,
993             'over': 5,
994             'quick': 1,
995             'the': 0})""")
996
997    def test_counter(self):
998        d = collections.Counter()
999        self.assertEqual(pprint.pformat(d, width=1), "Counter()")
1000        d = collections.Counter('senselessness')
1001        self.assertEqual(pprint.pformat(d, width=40),
1002"""\
1003Counter({'s': 6,
1004         'e': 4,
1005         'n': 2,
1006         'l': 1})""")
1007
1008    def test_chainmap(self):
1009        d = collections.ChainMap()
1010        self.assertEqual(pprint.pformat(d, width=1), "ChainMap({})")
1011        words = 'the quick brown fox jumped over a lazy dog'.split()
1012        items = list(zip(words, itertools.count()))
1013        d = collections.ChainMap(dict(items))
1014        self.assertEqual(pprint.pformat(d),
1015"""\
1016ChainMap({'a': 6,
1017          'brown': 2,
1018          'dog': 8,
1019          'fox': 3,
1020          'jumped': 4,
1021          'lazy': 7,
1022          'over': 5,
1023          'quick': 1,
1024          'the': 0})""")
1025        d = collections.ChainMap(dict(items), collections.OrderedDict(items))
1026        self.assertEqual(pprint.pformat(d),
1027"""\
1028ChainMap({'a': 6,
1029          'brown': 2,
1030          'dog': 8,
1031          'fox': 3,
1032          'jumped': 4,
1033          'lazy': 7,
1034          'over': 5,
1035          'quick': 1,
1036          'the': 0},
1037         OrderedDict([('the', 0),
1038                      ('quick', 1),
1039                      ('brown', 2),
1040                      ('fox', 3),
1041                      ('jumped', 4),
1042                      ('over', 5),
1043                      ('a', 6),
1044                      ('lazy', 7),
1045                      ('dog', 8)]))""")
1046
1047    def test_deque(self):
1048        d = collections.deque()
1049        self.assertEqual(pprint.pformat(d, width=1), "deque([])")
1050        d = collections.deque(maxlen=7)
1051        self.assertEqual(pprint.pformat(d, width=1), "deque([], maxlen=7)")
1052        words = 'the quick brown fox jumped over a lazy dog'.split()
1053        d = collections.deque(zip(words, itertools.count()))
1054        self.assertEqual(pprint.pformat(d),
1055"""\
1056deque([('the', 0),
1057       ('quick', 1),
1058       ('brown', 2),
1059       ('fox', 3),
1060       ('jumped', 4),
1061       ('over', 5),
1062       ('a', 6),
1063       ('lazy', 7),
1064       ('dog', 8)])""")
1065        d = collections.deque(zip(words, itertools.count()), maxlen=7)
1066        self.assertEqual(pprint.pformat(d),
1067"""\
1068deque([('brown', 2),
1069       ('fox', 3),
1070       ('jumped', 4),
1071       ('over', 5),
1072       ('a', 6),
1073       ('lazy', 7),
1074       ('dog', 8)],
1075      maxlen=7)""")
1076
1077    def test_user_dict(self):
1078        d = collections.UserDict()
1079        self.assertEqual(pprint.pformat(d, width=1), "{}")
1080        words = 'the quick brown fox jumped over a lazy dog'.split()
1081        d = collections.UserDict(zip(words, itertools.count()))
1082        self.assertEqual(pprint.pformat(d),
1083"""\
1084{'a': 6,
1085 'brown': 2,
1086 'dog': 8,
1087 'fox': 3,
1088 'jumped': 4,
1089 'lazy': 7,
1090 'over': 5,
1091 'quick': 1,
1092 'the': 0}""")
1093
1094    def test_user_list(self):
1095        d = collections.UserList()
1096        self.assertEqual(pprint.pformat(d, width=1), "[]")
1097        words = 'the quick brown fox jumped over a lazy dog'.split()
1098        d = collections.UserList(zip(words, itertools.count()))
1099        self.assertEqual(pprint.pformat(d),
1100"""\
1101[('the', 0),
1102 ('quick', 1),
1103 ('brown', 2),
1104 ('fox', 3),
1105 ('jumped', 4),
1106 ('over', 5),
1107 ('a', 6),
1108 ('lazy', 7),
1109 ('dog', 8)]""")
1110
1111    def test_user_string(self):
1112        d = collections.UserString('')
1113        self.assertEqual(pprint.pformat(d, width=1), "''")
1114        d = collections.UserString('the quick brown fox jumped over a lazy dog')
1115        self.assertEqual(pprint.pformat(d, width=20),
1116"""\
1117('the quick brown '
1118 'fox jumped over '
1119 'a lazy dog')""")
1120        self.assertEqual(pprint.pformat({1: d}, width=20),
1121"""\
1122{1: 'the quick '
1123    'brown fox '
1124    'jumped over a '
1125    'lazy dog'}""")
1126
1127
1128class DottedPrettyPrinter(pprint.PrettyPrinter):
1129
1130    def format(self, object, context, maxlevels, level):
1131        if isinstance(object, str):
1132            if ' ' in object:
1133                return repr(object), 1, 0
1134            else:
1135                return object, 0, 0
1136        else:
1137            return pprint.PrettyPrinter.format(
1138                self, object, context, maxlevels, level)
1139
1140
1141if __name__ == "__main__":
1142    unittest.main()
1143