1# -*- coding: utf-8 -*-
2"""
3Python advanced pretty printer.  This pretty printer is intended to
4replace the old `pprint` python module which does not allow developers
5to provide their own pretty print callbacks.
6
7This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
8
9The following implementations were forked from the IPython project:
10* Copyright (c) 2008-2014, IPython Development Team
11* Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
12* Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13* Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14
15Example Usage
16-------------
17
18To directly print the representation of an object use `pprint`::
19
20    from pretty import pretty_print
21    pretty_pprint(complex_object)
22
23To get a string of the output use `pretty`::
24
25    from pretty import pretty
26    string = pretty(complex_object)
27
28
29Extending
30---------
31
32The pretty library allows developers to add pretty printing rules for their
33own objects.  This process is straightforward.  All you have to do is to
34add a `_repr_pretty_` method to your object and call the methods on the
35pretty printer passed::
36
37    class MyObject(object):
38
39        def _repr_pretty_(self, p, cycle):
40            ...
41
42Here is an example implementation of a `_repr_pretty_` method for a list
43subclass::
44
45    class MyList(list):
46
47        def _repr_pretty_(self, p, cycle):
48            if cycle:
49                p.text('MyList(...)')
50            else:
51                with p.group(8, 'MyList([', '])'):
52                    for idx, item in enumerate(self):
53                        if idx:
54                            p.text(',')
55                            p.breakable()
56                        p.pretty(item)
57
58The `cycle` parameter is `True` if pretty detected a cycle.  You *have* to
59react to that or the result is an infinite loop.  `p.text()` just adds
60non breaking text to the output, `p.breakable()` either adds a whitespace
61or breaks here.  If you pass it an argument it's used instead of the
62default space.  `p.pretty` prettyprints another object using the pretty print
63method.
64
65The first parameter to the `group` function specifies the extra indentation
66of the next line.  In this example the next item will either be on the same
67line (if the items are short enough) or aligned with the right edge of the
68opening bracket of `MyList`.
69
70If you just want to indent something you can use the group function
71without open / close parameters.  You can also use this code::
72
73    with p.indent(2):
74        ...
75
76
77:copyright: 2007 by Armin Ronacher.
78            Portions (c) 2009 by Robert Kern.
79:license: BSD License.
80"""
81import io
82import re
83import sys
84import types
85import datetime
86import contextlib
87import collections
88
89from xonsh.lazyasd import LazyObject, lazyobject
90
91__all__ = [
92    "pretty",
93    "pretty_print",
94    "PrettyPrinter",
95    "RepresentationPrinter",
96    "for_type",
97    "for_type_by_name",
98]
99
100
101MAX_SEQ_LENGTH = 1000
102
103
104def _safe_getattr(obj, attr, default=None):
105    """Safe version of getattr.
106
107    Same as getattr, but will return ``default`` on any Exception,
108    rather than raising.
109    """
110    try:
111        return getattr(obj, attr, default)
112    except Exception:
113        return default
114
115
116CUnicodeIO = io.StringIO
117
118
119def pretty(
120    obj, verbose=False, max_width=79, newline="\n", max_seq_length=MAX_SEQ_LENGTH
121):
122    """
123    Pretty print the object's representation.
124    """
125    if hasattr(obj, "xonsh_display"):
126        return obj.xonsh_display()
127
128    stream = CUnicodeIO()
129    printer = RepresentationPrinter(
130        stream, verbose, max_width, newline, max_seq_length=max_seq_length
131    )
132    printer.pretty(obj)
133    printer.flush()
134    return stream.getvalue()
135
136
137def pretty_print(
138    obj, verbose=False, max_width=79, newline="\n", max_seq_length=MAX_SEQ_LENGTH
139):
140    """
141    Like pretty() but print to stdout.
142    """
143    printer = RepresentationPrinter(
144        sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length
145    )
146    printer.pretty(obj)
147    printer.flush()
148    sys.stdout.write(newline)
149    sys.stdout.flush()
150
151
152class _PrettyPrinterBase(object):
153    @contextlib.contextmanager
154    def indent(self, indent):
155        """with statement support for indenting/dedenting."""
156        self.indentation += indent
157        try:
158            yield
159        finally:
160            self.indentation -= indent
161
162    @contextlib.contextmanager
163    def group(self, indent=0, open="", close=""):
164        """like begin_group / end_group but for the with statement."""
165        self.begin_group(indent, open)
166        try:
167            yield
168        finally:
169            self.end_group(indent, close)
170
171
172class PrettyPrinter(_PrettyPrinterBase):
173    """
174    Baseclass for the `RepresentationPrinter` prettyprinter that is used to
175    generate pretty reprs of objects.  Contrary to the `RepresentationPrinter`
176    this printer knows nothing about the default pprinters or the `_repr_pretty_`
177    callback method.
178    """
179
180    def __init__(
181        self, output, max_width=79, newline="\n", max_seq_length=MAX_SEQ_LENGTH
182    ):
183        self.output = output
184        self.max_width = max_width
185        self.newline = newline
186        self.max_seq_length = max_seq_length
187        self.output_width = 0
188        self.buffer_width = 0
189        self.buffer = collections.deque()
190
191        root_group = Group(0)
192        self.group_stack = [root_group]
193        self.group_queue = GroupQueue(root_group)
194        self.indentation = 0
195
196    def _break_outer_groups(self):
197        while self.max_width < self.output_width + self.buffer_width:
198            group = self.group_queue.deq()
199            if not group:
200                return
201            while group.breakables:
202                x = self.buffer.popleft()
203                self.output_width = x.output(self.output, self.output_width)
204                self.buffer_width -= x.width
205            while self.buffer and isinstance(self.buffer[0], Text):
206                x = self.buffer.popleft()
207                self.output_width = x.output(self.output, self.output_width)
208                self.buffer_width -= x.width
209
210    def text(self, obj):
211        """Add literal text to the output."""
212        width = len(obj)
213        if self.buffer:
214            text = self.buffer[-1]
215            if not isinstance(text, Text):
216                text = Text()
217                self.buffer.append(text)
218            text.add(obj, width)
219            self.buffer_width += width
220            self._break_outer_groups()
221        else:
222            self.output.write(obj)
223            self.output_width += width
224
225    def breakable(self, sep=" "):
226        """
227        Add a breakable separator to the output.  This does not mean that it
228        will automatically break here.  If no breaking on this position takes
229        place the `sep` is inserted which default to one space.
230        """
231        width = len(sep)
232        group = self.group_stack[-1]
233        if group.want_break:
234            self.flush()
235            self.output.write(self.newline)
236            self.output.write(" " * self.indentation)
237            self.output_width = self.indentation
238            self.buffer_width = 0
239        else:
240            self.buffer.append(Breakable(sep, width, self))
241            self.buffer_width += width
242            self._break_outer_groups()
243
244    def break_(self):
245        """
246        Explicitly insert a newline into the output, maintaining correct indentation.
247        """
248        self.flush()
249        self.output.write(self.newline)
250        self.output.write(" " * self.indentation)
251        self.output_width = self.indentation
252        self.buffer_width = 0
253
254    def begin_group(self, indent=0, open=""):
255        """
256        Begin a group.  If you want support for python < 2.5 which doesn't has
257        the with statement this is the preferred way:
258
259            p.begin_group(1, '{')
260            ...
261            p.end_group(1, '}')
262
263        The python 2.5 expression would be this:
264
265            with p.group(1, '{', '}'):
266                ...
267
268        The first parameter specifies the indentation for the next line (usually
269        the width of the opening text), the second the opening text.  All
270        parameters are optional.
271        """
272        if open:
273            self.text(open)
274        group = Group(self.group_stack[-1].depth + 1)
275        self.group_stack.append(group)
276        self.group_queue.enq(group)
277        self.indentation += indent
278
279    def _enumerate(self, seq):
280        """like enumerate, but with an upper limit on the number of items"""
281        for idx, x in enumerate(seq):
282            if self.max_seq_length and idx >= self.max_seq_length:
283                self.text(",")
284                self.breakable()
285                self.text("...")
286                return
287            yield idx, x
288
289    def end_group(self, dedent=0, close=""):
290        """End a group. See `begin_group` for more details."""
291        self.indentation -= dedent
292        group = self.group_stack.pop()
293        if not group.breakables:
294            self.group_queue.remove(group)
295        if close:
296            self.text(close)
297
298    def flush(self):
299        """Flush data that is left in the buffer."""
300        for data in self.buffer:
301            self.output_width += data.output(self.output, self.output_width)
302        self.buffer.clear()
303        self.buffer_width = 0
304
305
306def _get_mro(obj_class):
307    """ Get a reasonable method resolution order of a class and its superclasses
308    for both old-style and new-style classes.
309    """
310    if not hasattr(obj_class, "__mro__"):
311        # Old-style class. Mix in object to make a fake new-style class.
312        try:
313            obj_class = type(obj_class.__name__, (obj_class, object), {})
314        except TypeError:
315            # Old-style extension type that does not descend from object.
316            # FIXME: try to construct a more thorough MRO.
317            mro = [obj_class]
318        else:
319            mro = obj_class.__mro__[1:-1]
320    else:
321        mro = obj_class.__mro__
322    return mro
323
324
325class RepresentationPrinter(PrettyPrinter):
326    """
327    Special pretty printer that has a `pretty` method that calls the pretty
328    printer for a python object.
329
330    This class stores processing data on `self` so you must *never* use
331    this class in a threaded environment.  Always lock it or reinstantiate
332    it.
333
334    Instances also have a verbose flag callbacks can access to control their
335    output.  For example the default instance repr prints all attributes and
336    methods that are not prefixed by an underscore if the printer is in
337    verbose mode.
338    """
339
340    def __init__(
341        self,
342        output,
343        verbose=False,
344        max_width=79,
345        newline="\n",
346        singleton_pprinters=None,
347        type_pprinters=None,
348        deferred_pprinters=None,
349        max_seq_length=MAX_SEQ_LENGTH,
350    ):
351
352        PrettyPrinter.__init__(
353            self, output, max_width, newline, max_seq_length=max_seq_length
354        )
355        self.verbose = verbose
356        self.stack = []
357        if singleton_pprinters is None:
358            singleton_pprinters = _singleton_pprinters.copy()
359        self.singleton_pprinters = singleton_pprinters
360        if type_pprinters is None:
361            type_pprinters = _type_pprinters.copy()
362        self.type_pprinters = type_pprinters
363        if deferred_pprinters is None:
364            deferred_pprinters = _deferred_type_pprinters.copy()
365        self.deferred_pprinters = deferred_pprinters
366
367    def pretty(self, obj):
368        """Pretty print the given object."""
369        obj_id = id(obj)
370        cycle = obj_id in self.stack
371        self.stack.append(obj_id)
372        self.begin_group()
373        try:
374            obj_class = _safe_getattr(obj, "__class__", None) or type(obj)
375            # First try to find registered singleton printers for the type.
376            try:
377                printer = self.singleton_pprinters[obj_id]
378            except (TypeError, KeyError):
379                pass
380            else:
381                return printer(obj, self, cycle)
382            # Next walk the mro and check for either:
383            #   1) a registered printer
384            #   2) a _repr_pretty_ method
385            for cls in _get_mro(obj_class):
386                if cls in self.type_pprinters:
387                    # printer registered in self.type_pprinters
388                    return self.type_pprinters[cls](obj, self, cycle)
389                else:
390                    # deferred printer
391                    printer = self._in_deferred_types(cls)
392                    if printer is not None:
393                        return printer(obj, self, cycle)
394                    else:
395                        # Finally look for special method names.
396                        # Some objects automatically create any requested
397                        # attribute. Try to ignore most of them by checking for
398                        # callability.
399                        if "_repr_pretty_" in cls.__dict__:
400                            meth = cls._repr_pretty_
401                            if callable(meth):
402                                return meth(obj, self, cycle)
403            return _default_pprint(obj, self, cycle)
404        finally:
405            self.end_group()
406            self.stack.pop()
407
408    def _in_deferred_types(self, cls):
409        """
410        Check if the given class is specified in the deferred type registry.
411
412        Returns the printer from the registry if it exists, and None if the
413        class is not in the registry. Successful matches will be moved to the
414        regular type registry for future use.
415        """
416        mod = _safe_getattr(cls, "__module__", None)
417        name = _safe_getattr(cls, "__name__", None)
418        key = (mod, name)
419        printer = None
420        if key in self.deferred_pprinters:
421            # Move the printer over to the regular registry.
422            printer = self.deferred_pprinters.pop(key)
423            self.type_pprinters[cls] = printer
424        return printer
425
426
427class Printable(object):
428    def output(self, stream, output_width):
429        return output_width
430
431
432class Text(Printable):
433    def __init__(self):
434        self.objs = []
435        self.width = 0
436
437    def output(self, stream, output_width):
438        for obj in self.objs:
439            stream.write(obj)
440        return output_width + self.width
441
442    def add(self, obj, width):
443        self.objs.append(obj)
444        self.width += width
445
446
447class Breakable(Printable):
448    def __init__(self, seq, width, pretty):
449        self.obj = seq
450        self.width = width
451        self.pretty = pretty
452        self.indentation = pretty.indentation
453        self.group = pretty.group_stack[-1]
454        self.group.breakables.append(self)
455
456    def output(self, stream, output_width):
457        self.group.breakables.popleft()
458        if self.group.want_break:
459            stream.write(self.pretty.newline)
460            stream.write(" " * self.indentation)
461            return self.indentation
462        if not self.group.breakables:
463            self.pretty.group_queue.remove(self.group)
464        stream.write(self.obj)
465        return output_width + self.width
466
467
468class Group(Printable):
469    def __init__(self, depth):
470        self.depth = depth
471        self.breakables = collections.deque()
472        self.want_break = False
473
474
475class GroupQueue(object):
476    def __init__(self, *groups):
477        self.queue = []
478        for group in groups:
479            self.enq(group)
480
481    def enq(self, group):
482        depth = group.depth
483        while depth > len(self.queue) - 1:
484            self.queue.append([])
485        self.queue[depth].append(group)
486
487    def deq(self):
488        for stack in self.queue:
489            for idx, group in enumerate(reversed(stack)):
490                if group.breakables:
491                    del stack[idx]
492                    group.want_break = True
493                    return group
494            for group in stack:
495                group.want_break = True
496            del stack[:]
497
498    def remove(self, group):
499        try:
500            self.queue[group.depth].remove(group)
501        except ValueError:
502            pass
503
504
505@lazyobject
506def _baseclass_reprs():
507    try:
508        br = (object.__repr__, types.InstanceType.__repr__)
509    except AttributeError:  # Python 3
510        br = (object.__repr__,)
511    return br
512
513
514def _default_pprint(obj, p, cycle):
515    """
516    The default print function.  Used if an object does not provide one and
517    it's none of the builtin objects.
518    """
519    klass = _safe_getattr(obj, "__class__", None) or type(obj)
520    if _safe_getattr(klass, "__repr__", None) not in _baseclass_reprs:
521        # A user-provided repr. Find newlines and replace them with p.break_()
522        _repr_pprint(obj, p, cycle)
523        return
524    p.begin_group(1, "<")
525    p.pretty(klass)
526    p.text(" at 0x%x" % id(obj))
527    if cycle:
528        p.text(" ...")
529    elif p.verbose:
530        first = True
531        for key in dir(obj):
532            if not key.startswith("_"):
533                try:
534                    value = getattr(obj, key)
535                except AttributeError:
536                    continue
537                if isinstance(value, types.MethodType):
538                    continue
539                if not first:
540                    p.text(",")
541                p.breakable()
542                p.text(key)
543                p.text("=")
544                step = len(key) + 1
545                p.indentation += step
546                p.pretty(value)
547                p.indentation -= step
548                first = False
549    p.end_group(1, ">")
550
551
552def _seq_pprinter_factory(start, end, basetype):
553    """
554    Factory that returns a pprint function useful for sequences.  Used by
555    the default pprint for tuples, dicts, and lists.
556    """
557
558    def inner(obj, p, cycle):
559        typ = type(obj)
560        if (
561            basetype is not None
562            and typ is not basetype
563            and typ.__repr__ != basetype.__repr__
564        ):
565            # If the subclass provides its own repr, use it instead.
566            return p.text(typ.__repr__(obj))
567
568        if cycle:
569            return p.text(start + "..." + end)
570        step = len(start)
571        p.begin_group(step, start)
572        for idx, x in p._enumerate(obj):
573            if idx:
574                p.text(",")
575                p.breakable()
576            p.pretty(x)
577        if len(obj) == 1 and type(obj) is tuple:
578            # Special case for 1-item tuples.
579            p.text(",")
580        p.end_group(step, end)
581
582    return inner
583
584
585def _set_pprinter_factory(start, end, basetype):
586    """
587    Factory that returns a pprint function useful for sets and frozensets.
588    """
589
590    def inner(obj, p, cycle):
591        typ = type(obj)
592        if (
593            basetype is not None
594            and typ is not basetype
595            and typ.__repr__ != basetype.__repr__
596        ):
597            # If the subclass provides its own repr, use it instead.
598            return p.text(typ.__repr__(obj))
599
600        if cycle:
601            return p.text(start + "..." + end)
602        if len(obj) == 0:
603            # Special case.
604            p.text(basetype.__name__ + "()")
605        else:
606            step = len(start)
607            p.begin_group(step, start)
608            # Like dictionary keys, we will try to sort the items if there aren't too many
609            items = obj
610            if not (p.max_seq_length and len(obj) >= p.max_seq_length):
611                try:
612                    items = sorted(obj)
613                except Exception:
614                    # Sometimes the items don't sort.
615                    pass
616            for idx, x in p._enumerate(items):
617                if idx:
618                    p.text(",")
619                    p.breakable()
620                p.pretty(x)
621            p.end_group(step, end)
622
623    return inner
624
625
626def _dict_pprinter_factory(start, end, basetype=None):
627    """
628    Factory that returns a pprint function used by the default pprint of
629    dicts and dict proxies.
630    """
631
632    def inner(obj, p, cycle):
633        typ = type(obj)
634        if (
635            basetype is not None
636            and typ is not basetype
637            and typ.__repr__ != basetype.__repr__
638        ):
639            # If the subclass provides its own repr, use it instead.
640            return p.text(typ.__repr__(obj))
641
642        if cycle:
643            return p.text("{...}")
644        p.begin_group(1, start)
645        keys = obj.keys()
646        # if dict isn't large enough to be truncated, sort keys before displaying
647        if not (p.max_seq_length and len(obj) >= p.max_seq_length):
648            try:
649                keys = sorted(keys)
650            except Exception:
651                # Sometimes the keys don't sort.
652                pass
653        for idx, key in p._enumerate(keys):
654            if idx:
655                p.text(",")
656                p.breakable()
657            p.pretty(key)
658            p.text(": ")
659            p.pretty(obj[key])
660        p.end_group(1, end)
661
662    return inner
663
664
665def _super_pprint(obj, p, cycle):
666    """The pprint for the super type."""
667    p.begin_group(8, "<super: ")
668    p.pretty(obj.__thisclass__)
669    p.text(",")
670    p.breakable()
671    p.pretty(obj.__self__)
672    p.end_group(8, ">")
673
674
675def _re_pattern_pprint(obj, p, cycle):
676    """The pprint function for regular expression patterns."""
677    p.text("re.compile(")
678    pattern = repr(obj.pattern)
679    if pattern[:1] in "uU":
680        pattern = pattern[1:]
681        prefix = "ur"
682    else:
683        prefix = "r"
684    pattern = prefix + pattern.replace("\\\\", "\\")
685    p.text(pattern)
686    if obj.flags:
687        p.text(",")
688        p.breakable()
689        done_one = False
690        for flag in (
691            "TEMPLATE",
692            "IGNORECASE",
693            "LOCALE",
694            "MULTILINE",
695            "DOTALL",
696            "UNICODE",
697            "VERBOSE",
698            "DEBUG",
699        ):
700            if obj.flags & getattr(re, flag):
701                if done_one:
702                    p.text("|")
703                p.text("re." + flag)
704                done_one = True
705    p.text(")")
706
707
708def _type_pprint(obj, p, cycle):
709    """The pprint for classes and types."""
710    # Heap allocated types might not have the module attribute,
711    # and others may set it to None.
712
713    # Checks for a __repr__ override in the metaclass
714    if type(obj).__repr__ is not type.__repr__:
715        _repr_pprint(obj, p, cycle)
716        return
717
718    mod = _safe_getattr(obj, "__module__", None)
719    try:
720        name = obj.__qualname__
721        if not isinstance(name, str):
722            # This can happen if the type implements __qualname__ as a property
723            # or other descriptor in Python 2.
724            raise Exception("Try __name__")
725    except Exception:
726        name = obj.__name__
727        if not isinstance(name, str):
728            name = "<unknown type>"
729
730    if mod in (None, "__builtin__", "builtins", "exceptions"):
731        p.text(name)
732    else:
733        p.text(mod + "." + name)
734
735
736def _repr_pprint(obj, p, cycle):
737    """A pprint that just redirects to the normal repr function."""
738    # Find newlines and replace them with p.break_()
739    output = repr(obj)
740    for idx, output_line in enumerate(output.splitlines()):
741        if idx:
742            p.break_()
743        p.text(output_line)
744
745
746def _function_pprint(obj, p, cycle):
747    """Base pprint for all functions and builtin functions."""
748    name = _safe_getattr(obj, "__qualname__", obj.__name__)
749    mod = obj.__module__
750    if mod and mod not in ("__builtin__", "builtins", "exceptions"):
751        name = mod + "." + name
752    p.text("<function %s>" % name)
753
754
755def _exception_pprint(obj, p, cycle):
756    """Base pprint for all exceptions."""
757    name = getattr(obj.__class__, "__qualname__", obj.__class__.__name__)
758    if obj.__class__.__module__ not in ("exceptions", "builtins"):
759        name = "%s.%s" % (obj.__class__.__module__, name)
760    step = len(name) + 1
761    p.begin_group(step, name + "(")
762    for idx, arg in enumerate(getattr(obj, "args", ())):
763        if idx:
764            p.text(",")
765            p.breakable()
766        p.pretty(arg)
767    p.end_group(step, ")")
768
769
770@lazyobject
771def _type_pprinters():
772    #: printers for builtin types
773    tp = {
774        int: _repr_pprint,
775        float: _repr_pprint,
776        str: _repr_pprint,
777        tuple: _seq_pprinter_factory("(", ")", tuple),
778        list: _seq_pprinter_factory("[", "]", list),
779        dict: _dict_pprinter_factory("{", "}", dict),
780        set: _set_pprinter_factory("{", "}", set),
781        frozenset: _set_pprinter_factory("frozenset({", "})", frozenset),
782        super: _super_pprint,
783        type(re.compile("")): _re_pattern_pprint,
784        type: _type_pprint,
785        types.FunctionType: _function_pprint,
786        types.BuiltinFunctionType: _function_pprint,
787        types.MethodType: _repr_pprint,
788        datetime.datetime: _repr_pprint,
789        datetime.timedelta: _repr_pprint,
790    }
791    #: the exception base
792    try:
793        _exception_base = BaseException
794    except NameError:
795        _exception_base = Exception
796    tp[_exception_base] = _exception_pprint
797    try:
798        tp[types.DictProxyType] = _dict_pprinter_factory("<dictproxy {", "}>")
799        tp[types.ClassType] = _type_pprint
800        tp[types.SliceType] = _repr_pprint
801    except AttributeError:  # Python 3
802        tp[slice] = _repr_pprint
803    try:
804        tp[xrange] = _repr_pprint
805        tp[long] = _repr_pprint
806        tp[unicode] = _repr_pprint
807    except NameError:
808        tp[range] = _repr_pprint
809        tp[bytes] = _repr_pprint
810    return tp
811
812
813#: printers for types specified by name
814@lazyobject
815def _deferred_type_pprinters():
816    dtp = {}
817    for_type_by_name("collections", "defaultdict", _defaultdict_pprint, dtp=dtp)
818    for_type_by_name("collections", "OrderedDict", _ordereddict_pprint, dtp=dtp)
819    for_type_by_name("collections", "deque", _deque_pprint, dtp=dtp)
820    for_type_by_name("collections", "Counter", _counter_pprint, dtp=dtp)
821    return dtp
822
823
824def for_type(typ, func):
825    """
826    Add a pretty printer for a given type.
827    """
828    oldfunc = _type_pprinters.get(typ, None)
829    if func is not None:
830        # To support easy restoration of old pprinters, we need to ignore Nones.
831        _type_pprinters[typ] = func
832    return oldfunc
833
834
835def for_type_by_name(type_module, type_name, func, dtp=None):
836    """
837    Add a pretty printer for a type specified by the module and name of a type
838    rather than the type object itself.
839    """
840    if dtp is None:
841        dtp = _deferred_type_pprinters
842    key = (type_module, type_name)
843    oldfunc = dtp.get(key, None)
844    if func is not None:
845        # To support easy restoration of old pprinters, we need to ignore Nones.
846        dtp[key] = func
847    return oldfunc
848
849
850#: printers for the default singletons
851_singleton_pprinters = LazyObject(
852    lambda: dict.fromkeys(
853        map(id, [None, True, False, Ellipsis, NotImplemented]), _repr_pprint
854    ),
855    globals(),
856    "_singleton_pprinters",
857)
858
859
860def _defaultdict_pprint(obj, p, cycle):
861    name = obj.__class__.__name__
862    with p.group(len(name) + 1, name + "(", ")"):
863        if cycle:
864            p.text("...")
865        else:
866            p.pretty(obj.default_factory)
867            p.text(",")
868            p.breakable()
869            p.pretty(dict(obj))
870
871
872def _ordereddict_pprint(obj, p, cycle):
873    name = obj.__class__.__name__
874    with p.group(len(name) + 1, name + "(", ")"):
875        if cycle:
876            p.text("...")
877        elif len(obj):
878            p.pretty(list(obj.items()))
879
880
881def _deque_pprint(obj, p, cycle):
882    name = obj.__class__.__name__
883    with p.group(len(name) + 1, name + "(", ")"):
884        if cycle:
885            p.text("...")
886        else:
887            p.pretty(list(obj))
888
889
890def _counter_pprint(obj, p, cycle):
891    name = obj.__class__.__name__
892    with p.group(len(name) + 1, name + "(", ")"):
893        if cycle:
894            p.text("...")
895        elif len(obj):
896            p.pretty(dict(obj))
897