[Python-checkins] bpo-28850: Fix PrettyPrinter.format overrides ignored for contents of small containers (GH-22120)
taleinat
webhook-mailer at python.org
Mon Nov 23 08:32:05 EST 2020
https://github.com/python/cpython/commit/ff420f0e08a2443339da0df7ace95e14177bac53
commit: ff420f0e08a2443339da0df7ace95e14177bac53
branch: master
author: Irit Katriel <iritkatriel at yahoo.com>
committer: taleinat <532281+taleinat at users.noreply.github.com>
date: 2020-11-23T15:31:31+02:00
summary:
bpo-28850: Fix PrettyPrinter.format overrides ignored for contents of small containers (GH-22120)
files:
A Misc/NEWS.d/next/Library/2020-09-06-21-55-44.bpo-28850.HJNggD.rst
M Lib/pprint.py
M Lib/test/test_pprint.py
diff --git a/Lib/pprint.py b/Lib/pprint.py
index 213998e3491ef..a8af50e5a6861 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -64,15 +64,15 @@ def pp(object, *args, sort_dicts=False, **kwargs):
def saferepr(object):
"""Version of repr() which can handle recursive data structures."""
- return _safe_repr(object, {}, None, 0, True)[0]
+ return PrettyPrinter()._safe_repr(object, {}, None, 0)[0]
def isreadable(object):
"""Determine if saferepr(object) is readable by eval()."""
- return _safe_repr(object, {}, None, 0, True)[1]
+ return PrettyPrinter()._safe_repr(object, {}, None, 0)[1]
def isrecursive(object):
"""Determine if object requires a recursive representation."""
- return _safe_repr(object, {}, None, 0, True)[2]
+ return PrettyPrinter()._safe_repr(object, {}, None, 0)[2]
class _safe_key:
"""Helper function for key functions when sorting unorderable objects.
@@ -435,7 +435,7 @@ def format(self, object, context, maxlevels, level):
and flags indicating whether the representation is 'readable'
and whether the object represents a recursive construct.
"""
- return _safe_repr(object, context, maxlevels, level, self._sort_dicts)
+ return self._safe_repr(object, context, maxlevels, level)
def _pprint_default_dict(self, object, stream, indent, allowance, context, level):
if not len(object):
@@ -518,77 +518,79 @@ def _pprint_user_string(self, object, stream, indent, allowance, context, level)
_dispatch[_collections.UserString.__repr__] = _pprint_user_string
-# Return triple (repr_string, isreadable, isrecursive).
+ def _safe_repr(self, object, context, maxlevels, level):
+ # Return triple (repr_string, isreadable, isrecursive).
+ typ = type(object)
+ if typ in _builtin_scalars:
+ return repr(object), True, False
-def _safe_repr(object, context, maxlevels, level, sort_dicts):
- typ = type(object)
- if typ in _builtin_scalars:
- return repr(object), True, False
-
- r = getattr(typ, "__repr__", None)
- if issubclass(typ, dict) and r is dict.__repr__:
- if not object:
- return "{}", True, False
- objid = id(object)
- if maxlevels and level >= maxlevels:
- return "{...}", False, objid in context
- if objid in context:
- return _recursion(object), False, True
- context[objid] = 1
- readable = True
- recursive = False
- components = []
- append = components.append
- level += 1
- if sort_dicts:
- items = sorted(object.items(), key=_safe_tuple)
- else:
- items = object.items()
- for k, v in items:
- krepr, kreadable, krecur = _safe_repr(k, context, maxlevels, level, sort_dicts)
- vrepr, vreadable, vrecur = _safe_repr(v, context, maxlevels, level, sort_dicts)
- append("%s: %s" % (krepr, vrepr))
- readable = readable and kreadable and vreadable
- if krecur or vrecur:
- recursive = True
- del context[objid]
- return "{%s}" % ", ".join(components), readable, recursive
-
- if (issubclass(typ, list) and r is list.__repr__) or \
- (issubclass(typ, tuple) and r is tuple.__repr__):
- if issubclass(typ, list):
+ r = getattr(typ, "__repr__", None)
+ if issubclass(typ, dict) and r is dict.__repr__:
if not object:
- return "[]", True, False
- format = "[%s]"
- elif len(object) == 1:
- format = "(%s,)"
- else:
- if not object:
- return "()", True, False
- format = "(%s)"
- objid = id(object)
- if maxlevels and level >= maxlevels:
- return format % "...", False, objid in context
- if objid in context:
- return _recursion(object), False, True
- context[objid] = 1
- readable = True
- recursive = False
- components = []
- append = components.append
- level += 1
- for o in object:
- orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level, sort_dicts)
- append(orepr)
- if not oreadable:
- readable = False
- if orecur:
- recursive = True
- del context[objid]
- return format % ", ".join(components), readable, recursive
-
- rep = repr(object)
- return rep, (rep and not rep.startswith('<')), False
+ return "{}", True, False
+ objid = id(object)
+ if maxlevels and level >= maxlevels:
+ return "{...}", False, objid in context
+ if objid in context:
+ return _recursion(object), False, True
+ context[objid] = 1
+ readable = True
+ recursive = False
+ components = []
+ append = components.append
+ level += 1
+ if self._sort_dicts:
+ items = sorted(object.items(), key=_safe_tuple)
+ else:
+ items = object.items()
+ for k, v in items:
+ krepr, kreadable, krecur = self.format(
+ k, context, maxlevels, level)
+ vrepr, vreadable, vrecur = self.format(
+ v, context, maxlevels, level)
+ append("%s: %s" % (krepr, vrepr))
+ readable = readable and kreadable and vreadable
+ if krecur or vrecur:
+ recursive = True
+ del context[objid]
+ return "{%s}" % ", ".join(components), readable, recursive
+
+ if (issubclass(typ, list) and r is list.__repr__) or \
+ (issubclass(typ, tuple) and r is tuple.__repr__):
+ if issubclass(typ, list):
+ if not object:
+ return "[]", True, False
+ format = "[%s]"
+ elif len(object) == 1:
+ format = "(%s,)"
+ else:
+ if not object:
+ return "()", True, False
+ format = "(%s)"
+ objid = id(object)
+ if maxlevels and level >= maxlevels:
+ return format % "...", False, objid in context
+ if objid in context:
+ return _recursion(object), False, True
+ context[objid] = 1
+ readable = True
+ recursive = False
+ components = []
+ append = components.append
+ level += 1
+ for o in object:
+ orepr, oreadable, orecur = self.format(
+ o, context, maxlevels, level)
+ append(orepr)
+ if not oreadable:
+ readable = False
+ if orecur:
+ recursive = True
+ del context[objid]
+ return format % ", ".join(components), readable, recursive
+
+ rep = repr(object)
+ return rep, (rep and not rep.startswith('<')), False
_builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
bool, type(None)})
@@ -604,7 +606,7 @@ def _perfcheck(object=None):
object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000
p = PrettyPrinter()
t1 = time.perf_counter()
- _safe_repr(object, {}, None, 0, True)
+ p._safe_repr(object, {}, None, 0, True)
t2 = time.perf_counter()
p.pformat(object)
t3 = time.perf_counter()
diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py
index 8ee18e8fef84f..c4a8578a9fc8f 100644
--- a/Lib/test/test_pprint.py
+++ b/Lib/test/test_pprint.py
@@ -453,12 +453,23 @@ class AdvancedNamespace(types.SimpleNamespace): pass
dog=8)""")
def test_subclassing(self):
+ # length(repr(obj)) > width
o = {'names with spaces': 'should be presented using repr()',
'others.should.not.be': 'like.this'}
exp = """\
{'names with spaces': 'should be presented using repr()',
others.should.not.be: like.this}"""
- self.assertEqual(DottedPrettyPrinter().pformat(o), exp)
+
+ dotted_printer = DottedPrettyPrinter()
+ self.assertEqual(dotted_printer.pformat(o), exp)
+
+ # length(repr(obj)) < width
+ o1 = ['with space']
+ exp1 = "['with space']"
+ self.assertEqual(dotted_printer.pformat(o1), exp1)
+ o2 = ['without.space']
+ exp2 = "[without.space]"
+ self.assertEqual(dotted_printer.pformat(o2), exp2)
def test_set_reprs(self):
self.assertEqual(pprint.pformat(set()), 'set()')
diff --git a/Misc/NEWS.d/next/Library/2020-09-06-21-55-44.bpo-28850.HJNggD.rst b/Misc/NEWS.d/next/Library/2020-09-06-21-55-44.bpo-28850.HJNggD.rst
new file mode 100644
index 0000000000000..fc6bd1d57e2ae
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-09-06-21-55-44.bpo-28850.HJNggD.rst
@@ -0,0 +1 @@
+Fix :meth:`pprint.PrettyPrinter.format` overrides being ignored for contents of small containers. The :func:`pprint._safe_repr` function was removed.
More information about the Python-checkins
mailing list