From c9533e6bb7f5302c2e5989ed39de889d239571cc Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:40:43 +0300 Subject: [PATCH 1/5] Improve import time of pprint --- Lib/pprint.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index 9314701db340c7..afc83d0e12ee7a 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -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 @@ -179,6 +177,9 @@ 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 + import dataclasses as _dataclasses + if p is not None: context[objid] = 1 p(self, object, stream, indent, allowance, context, level + 1) @@ -197,6 +198,9 @@ 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 + import dataclasses as _dataclasses + 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] @@ -291,6 +295,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 From f65cb1e42a762952b5abc91c470896c215ecd2d6 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:42:07 +0300 Subject: [PATCH 2/5] Add blurb --- .../next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst diff --git a/Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst b/Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst new file mode 100644 index 00000000000000..3f3e870b0b9565 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-06-10-36-55.gh-issue-118761.q_x_1A.rst @@ -0,0 +1,2 @@ +Improve import time of :mod:`pprint` by around seven times. Patch by Hugo +van Kemenade. From 40f6d2e3368d05f49d60416885085a997ded589f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:43:16 +0300 Subject: [PATCH 3/5] PEP 8: add whitespace --- Lib/pprint.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/pprint.py b/Lib/pprint.py index afc83d0e12ee7a..ff0dafd7466926 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -52,6 +52,7 @@ 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.""" @@ -59,22 +60,27 @@ def pformat(object, indent=1, width=80, depth=None, *, 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. @@ -97,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): @@ -639,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 ("" % (type(object).__name__, id(object))) From 07cffca9a441c6f696e2133dd5139ea7b4d5e26e Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:30:15 +0300 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Lib/pprint.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index ff0dafd7466926..b692704e41748c 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -186,7 +186,7 @@ def _format(self, object, stream, indent, allowance, context, level): if len(rep) > max_width: p = self._dispatch.get(type(object).__repr__, None) # Lazy import to improve module import time - import dataclasses as _dataclasses + from dataclasses import is_dataclass if p is not None: context[objid] = 1 @@ -207,11 +207,11 @@ def _format(self, object, stream, indent, allowance, context, level): def _pprint_dataclass(self, object, stream, indent, allowance, context, level): # Lazy import to improve module import time - import dataclasses as _dataclasses + 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(')') From 397f05bb51af5e78d237bd9e1f098021762ba69c Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:31:28 +0300 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Lib/pprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index b692704e41748c..dc0953cec67a58 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -193,7 +193,7 @@ def _format(self, object, stream, indent, allowance, context, level): 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.