github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/pprint.py (about)

     1  #  Author:      Fred L. Drake, Jr.
     2  #               fdrake@acm.org
     3  #
     4  #  This is a simple little module I wrote to make life easier.  I didn't
     5  #  see anything quite like it in the library, though I may have overlooked
     6  #  something.  I wrote this when I was trying to read some heavily nested
     7  #  tuples with fairly non-descriptive content.  This is modeled very much
     8  #  after Lisp/Scheme - style pretty-printing of lists.  If you find it
     9  #  useful, thank small children who sleep at night.
    10  
    11  """Support to pretty-print lists, tuples, & dictionaries recursively.
    12  
    13  Very simple, but useful, especially in debugging data structures.
    14  
    15  Classes
    16  -------
    17  
    18  PrettyPrinter()
    19      Handle pretty-printing operations onto a stream using a configured
    20      set of formatting parameters.
    21  
    22  Functions
    23  ---------
    24  
    25  pformat()
    26      Format a Python object into a pretty-printed representation.
    27  
    28  pprint()
    29      Pretty-print a Python object to a stream [default is sys.stdout].
    30  
    31  saferepr()
    32      Generate a 'standard' repr()-like value, but protect against recursive
    33      data structures.
    34  
    35  """
    36  
    37  import sys as _sys
    38  import warnings
    39  import StringIO
    40  _StringIO = StringIO.StringIO
    41  
    42  # try:
    43  #     from cStringIO import StringIO as _StringIO
    44  # except ImportError:
    45  #     from StringIO import StringIO as _StringIO
    46  
    47  __all__ = ["pprint","pformat","isreadable","isrecursive","saferepr",
    48             "PrettyPrinter"]
    49  
    50  # cache these for faster access:
    51  _commajoin = ", ".join
    52  _id = id
    53  _len = len
    54  _type = type
    55  
    56  
    57  def pprint(o, stream=None, indent=1, width=80, depth=None):
    58      """Pretty-print a Python o to a stream [default is sys.stdout]."""
    59      printer = PrettyPrinter(
    60          stream=stream, indent=indent, width=width, depth=depth)
    61      printer.pprint(o)
    62  
    63  def pformat(o, indent=1, width=80, depth=None):
    64      """Format a Python o into a pretty-printed representation."""
    65      return PrettyPrinter(indent=indent, width=width, depth=depth).pformat(o)
    66  
    67  def saferepr(o):
    68      """Version of repr() which can handle recursive data structures."""
    69      return _safe_repr(o, {}, None, 0)[0]
    70  
    71  def isreadable(o):
    72      """Determine if saferepr(o) is readable by eval()."""
    73      return _safe_repr(o, {}, None, 0)[1]
    74  
    75  def isrecursive(o):
    76      """Determine if o requires a recursive representation."""
    77      return _safe_repr(o, {}, None, 0)[2]
    78  
    79  def _sorted(iterable):
    80      with warnings.catch_warnings():
    81          if _sys.py3kwarning:
    82              warnings.filterwarnings("ignore", "comparing unequal types "
    83                                      "not supported", DeprecationWarning)
    84          return sorted(iterable)
    85  
    86  class PrettyPrinter(object):
    87      def __init__(self, indent=1, width=80, depth=None, stream=None):
    88          """Handle pretty printing operations onto a stream using a set of
    89          configured parameters.
    90  
    91          indent
    92              Number of spaces to indent for each level of nesting.
    93  
    94          width
    95              Attempted maximum number of columns in the output.
    96  
    97          depth
    98              The maximum depth to print out nested structures.
    99  
   100          stream
   101              The desired output stream.  If omitted (or false), the standard
   102              output stream available at construction will be used.
   103  
   104          """
   105          indent = int(indent)
   106          width = int(width)
   107          assert indent >= 0, "indent must be >= 0"
   108          assert depth is None or depth > 0, "depth must be > 0"
   109          assert width, "width must be != 0"
   110          self._depth = depth
   111          self._indent_per_level = indent
   112          self._width = width
   113          if stream is not None:
   114              self._stream = stream
   115          else:
   116              self._stream = _sys.stdout
   117  
   118      def pprint(self, o):
   119          self._format(o, self._stream, 0, 0, {}, 0)
   120          self._stream.write("\n")
   121  
   122      def pformat(self, o):
   123          sio = _StringIO()
   124          self._format(o, sio, 0, 0, {}, 0)
   125          return sio.getvalue()
   126  
   127      def isrecursive(self, o):
   128          return self.format(o, {}, 0, 0)[2]
   129  
   130      def isreadable(self, o):
   131          s, readable, recursive = self.format(o, {}, 0, 0)
   132          return readable and not recursive
   133  
   134      def _format(self, o, stream, indent, allowance, context, level):
   135          level = level + 1
   136          objid = _id(o)
   137          if objid in context:
   138              stream.write(_recursion(o))
   139              self._recursive = True
   140              self._readable = False
   141              return
   142          rep = self._repr(o, context, level - 1)
   143          typ = _type(o)
   144          sepLines = _len(rep) > (self._width - 1 - indent - allowance)
   145          write = stream.write
   146  
   147          if self._depth and level > self._depth:
   148              write(rep)
   149              return
   150  
   151          r = getattr(typ, "__repr__", None)
   152          if issubclass(typ, dict):# and r == dict.__repr__:
   153              write('{')
   154              if self._indent_per_level > 1:
   155                  write((self._indent_per_level - 1) * ' ')
   156              length = _len(o)
   157              if length:
   158                  context[objid] = 1
   159                  indent = indent + self._indent_per_level
   160                  items = _sorted(o.items())
   161                  key, ent = items[0]
   162                  rep = self._repr(key, context, level)
   163                  write(rep)
   164                  write(': ')
   165                  self._format(ent, stream, indent + _len(rep) + 2,
   166                                allowance + 1, context, level)
   167                  if length > 1:
   168                      for key, ent in items[1:]:
   169                          rep = self._repr(key, context, level)
   170                          if sepLines:
   171                              write(',\n%s%s: ' % (' '*indent, rep))
   172                          else:
   173                              write(', %s: ' % rep)
   174                          self._format(ent, stream, indent + _len(rep) + 2,
   175                                        allowance + 1, context, level)
   176                  indent = indent - self._indent_per_level
   177                  del context[objid]
   178              write('}')
   179              return
   180  
   181          # if ((issubclass(typ, list) and r == list.__repr__) or
   182          #     (issubclass(typ, tuple) and r == tuple.__repr__) or
   183          #     (issubclass(typ, set) and r == set.__repr__) or
   184          #     (issubclass(typ, frozenset) and r == frozenset.__repr__)
   185          if ((issubclass(typ, list)) or
   186              (issubclass(typ, tuple)) or
   187              (issubclass(typ, set)) or
   188              (issubclass(typ, frozenset))
   189             ):
   190              length = _len(o)
   191              if issubclass(typ, list):
   192                  write('[')
   193                  endchar = ']'
   194              elif issubclass(typ, tuple):
   195                  write('(')
   196                  endchar = ')'
   197              else:
   198                  if not length:
   199                      write(rep)
   200                      return
   201                  write(typ.__name__)
   202                  write('([')
   203                  endchar = '])'
   204                  indent += len(typ.__name__) + 1
   205                  o = _sorted(o)
   206              if self._indent_per_level > 1 and sepLines:
   207                  write((self._indent_per_level - 1) * ' ')
   208              if length:
   209                  context[objid] = 1
   210                  indent = indent + self._indent_per_level
   211                  self._format(o[0], stream, indent, allowance + 1,
   212                               context, level)
   213                  if length > 1:
   214                      for ent in o[1:]:
   215                          if sepLines:
   216                              write(',\n' + ' '*indent)
   217                          else:
   218                              write(', ')
   219                          self._format(ent, stream, indent,
   220                                        allowance + 1, context, level)
   221                  indent = indent - self._indent_per_level
   222                  del context[objid]
   223              if issubclass(typ, tuple) and length == 1:
   224                  write(',')
   225              write(endchar)
   226              return
   227  
   228          write(rep)
   229  
   230      def _repr(self, o, context, level):
   231          repr1, readable, recursive = self.format(o, dict(context),
   232                                                  self._depth, level)
   233          if not readable:
   234              self._readable = False
   235          if recursive:
   236              self._recursive = True
   237          return repr1
   238  
   239      def format(self, o, context, maxlevels, level):
   240          """Format o for a specific context, returning a string
   241          and flags indicating whether the representation is 'readable'
   242          and whether the o represents a recursive construct.
   243          """
   244          return _safe_repr(o, context, maxlevels, level)
   245  
   246  
   247  # Return triple (repr_string, isreadable, isrecursive).
   248  
   249  def _safe_repr(o, context, maxlevels, level):
   250      typ = _type(o)
   251      if typ is str:
   252          # if 'locale' not in _sys.modules:
   253          #     return repr(o), True, False
   254          if "'" in o and '"' not in o:
   255              closure = '"'
   256              quotes = {'"': '\\"'}
   257          else:
   258              closure = "'"
   259              quotes = {"'": "\\'"}
   260          qget = quotes.get
   261          sio = _StringIO()
   262          write = sio.write
   263          for char in o:
   264              # if char.isalpha():
   265              if 'a' <= char <= 'z' or 'A' <= char <= 'Z':
   266                  write(char)
   267              else:
   268                  write(qget(char, repr(char)[1:-1]))
   269          return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False
   270  
   271      r = getattr(typ, "__repr__", None)
   272      if issubclass(typ, dict):# and r == dict.__repr__:
   273          if not o:
   274              return "{}", True, False
   275          objid = _id(o)
   276          if maxlevels and level >= maxlevels:
   277              return "{...}", False, objid in context
   278          if objid in context:
   279              return _recursion(o), False, True
   280          context[objid] = 1
   281          readable = True
   282          recursive = False
   283          components = []
   284          append = components.append
   285          level += 1
   286          saferepr = _safe_repr
   287          for k, v in _sorted(o.items()):
   288              krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
   289              vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
   290              append("%s: %s" % (krepr, vrepr))
   291              readable = readable and kreadable and vreadable
   292              if krecur or vrecur:
   293                  recursive = True
   294          del context[objid]
   295          return "{%s}" % _commajoin(components), readable, recursive
   296  
   297      # if (issubclass(typ, list) and r == list.__repr__) or \
   298      #    (issubclass(typ, tuple) and r == tuple.__repr__):
   299      if (issubclass(typ, list)) or \
   300         (issubclass(typ, tuple)):
   301          if issubclass(typ, list):
   302              if not o:
   303                  return "[]", True, False
   304              format = "[%s]"
   305          elif _len(o) == 1:
   306              format = "(%s,)"
   307          else:
   308              if not o:
   309                  return "()", True, False
   310              format = "(%s)"
   311          objid = _id(o)
   312          if maxlevels and level >= maxlevels:
   313              return format % "...", False, objid in context
   314          if objid in context:
   315              return _recursion(o), False, True
   316          context[objid] = 1
   317          readable = True
   318          recursive = False
   319          components = []
   320          append = components.append
   321          level += 1
   322          for x in o:
   323              orepr, oreadable, orecur = _safe_repr(x, context, maxlevels, level)
   324              append(orepr)
   325              if not oreadable:
   326                  readable = False
   327              if orecur:
   328                  recursive = True
   329          del context[objid]
   330          return format % _commajoin(components), readable, recursive
   331  
   332      rep = repr(o)
   333      return rep, (rep and not rep.startswith('<')), False
   334  
   335  
   336  def _recursion(o):
   337      return ("<Recursion on %s with id=%s>"
   338              % (_type(o).__name__, _id(o)))
   339  
   340  
   341  # def _perfcheck(o=None):
   342  #     import time
   343  #     if o is None:
   344  #         o = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
   345  #     p = PrettyPrinter()
   346  #     t1 = time.time()
   347  #     _safe_repr(o, {}, None, 0)
   348  #     t2 = time.time()
   349  #     p.pformat(o)
   350  #     t3 = time.time()
   351  #     print "_safe_repr:", t2 - t1
   352  #     print "pformat:", t3 - t2
   353  
   354  # if __name__ == "__main__":
   355  #     _perfcheck()