Skip to content

Commit

Permalink
pythongh-118761: Improve import time of pprint (python#122725)
Browse files Browse the repository at this point in the history
Co-authored-by: Adam Turner <[email protected]>
  • Loading branch information
2 people authored and blhsing committed Aug 22, 2024
1 parent c2db627 commit 0549dc7
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 4 deletions.
25 changes: 21 additions & 4 deletions Lib/pprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
"""

import collections as _collections
import dataclasses as _dataclasses
import re
import sys as _sys
import types as _types
from io import StringIO as _StringIO
Expand All @@ -54,29 +52,35 @@ def pprint(object, stream=None, indent=1, width=80, depth=None, *,
underscore_numbers=underscore_numbers)
printer.pprint(object)


def pformat(object, indent=1, width=80, depth=None, *,
compact=False, sort_dicts=True, underscore_numbers=False):
"""Format a Python object into a pretty-printed representation."""
return PrettyPrinter(indent=indent, width=width, depth=depth,
compact=compact, sort_dicts=sort_dicts,
underscore_numbers=underscore_numbers).pformat(object)


def pp(object, *args, sort_dicts=False, **kwargs):
"""Pretty-print a Python object"""
pprint(object, *args, sort_dicts=sort_dicts, **kwargs)


def saferepr(object):
"""Version of repr() which can handle recursive data structures."""
return PrettyPrinter()._safe_repr(object, {}, None, 0)[0]


def isreadable(object):
"""Determine if saferepr(object) is readable by eval()."""
return PrettyPrinter()._safe_repr(object, {}, None, 0)[1]


def isrecursive(object):
"""Determine if object requires a recursive representation."""
return PrettyPrinter()._safe_repr(object, {}, None, 0)[2]


class _safe_key:
"""Helper function for key functions when sorting unorderable objects.
Expand All @@ -99,10 +103,12 @@ def __lt__(self, other):
return ((str(type(self.obj)), id(self.obj)) < \
(str(type(other.obj)), id(other.obj)))


def _safe_tuple(t):
"Helper function for comparing 2-tuples"
return _safe_key(t[0]), _safe_key(t[1])


class PrettyPrinter:
def __init__(self, indent=1, width=80, depth=None, stream=None, *,
compact=False, sort_dicts=True, underscore_numbers=False):
Expand Down Expand Up @@ -179,12 +185,15 @@ def _format(self, object, stream, indent, allowance, context, level):
max_width = self._width - indent - allowance
if len(rep) > max_width:
p = self._dispatch.get(type(object).__repr__, None)
# Lazy import to improve module import time
from dataclasses import is_dataclass

if p is not None:
context[objid] = 1
p(self, object, stream, indent, allowance, context, level + 1)
del context[objid]
return
elif (_dataclasses.is_dataclass(object) and
elif (is_dataclass(object) and
not isinstance(object, type) and
object.__dataclass_params__.repr and
# Check dataclass has generated repr method.
Expand All @@ -197,9 +206,12 @@ def _format(self, object, stream, indent, allowance, context, level):
stream.write(rep)

def _pprint_dataclass(self, object, stream, indent, allowance, context, level):
# Lazy import to improve module import time
from dataclasses import fields as dataclass_fields

cls_name = object.__class__.__name__
indent += len(cls_name) + 1
items = [(f.name, getattr(object, f.name)) for f in _dataclasses.fields(object) if f.repr]
items = [(f.name, getattr(object, f.name)) for f in dataclass_fields(object) if f.repr]
stream.write(cls_name + '(')
self._format_namespace_items(items, stream, indent, allowance, context, level)
stream.write(')')
Expand Down Expand Up @@ -291,6 +303,9 @@ def _pprint_str(self, object, stream, indent, allowance, context, level):
if len(rep) <= max_width1:
chunks.append(rep)
else:
# Lazy import to improve module import time
import re

# A list of alternating (non-space, space) strings
parts = re.findall(r'\S*\s*', line)
assert parts
Expand Down Expand Up @@ -632,9 +647,11 @@ def _safe_repr(self, object, context, maxlevels, level):
rep = repr(object)
return rep, (rep and not rep.startswith('<')), False


_builtin_scalars = frozenset({str, bytes, bytearray, float, complex,
bool, type(None)})


def _recursion(object):
return ("<Recursion on %s with id=%s>"
% (type(object).__name__, id(object)))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve import time of :mod:`pprint` by around seven times. Patch by Hugo
van Kemenade.

0 comments on commit 0549dc7

Please sign in to comment.