summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/pprint.py10
-rw-r--r--Lib/test/test_pprint.py39
-rw-r--r--Misc/NEWS4
3 files changed, 46 insertions, 7 deletions
diff --git a/Lib/pprint.py b/Lib/pprint.py
index c79c713..723ea9c 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -86,14 +86,10 @@ class _safe_key:
def __lt__(self, other):
try:
- rv = self.obj.__lt__(other.obj)
+ return self.obj < other.obj
except TypeError:
- rv = NotImplemented
-
- if rv is NotImplemented:
- rv = (str(type(self.obj)), id(self.obj)) < \
- (str(type(other.obj)), id(other.obj))
- return rv
+ 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"
diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py
index 428e77e..ef2a8a5 100644
--- a/Lib/test/test_pprint.py
+++ b/Lib/test/test_pprint.py
@@ -50,6 +50,25 @@ class Unorderable:
def __repr__(self):
return str(id(self))
+# Class Orderable is orderable with any type
+class Orderable:
+ def __init__(self, hash):
+ self._hash = hash
+ def __lt__(self, other):
+ return False
+ def __gt__(self, other):
+ return self != other
+ def __le__(self, other):
+ return self == other
+ def __ge__(self, other):
+ return True
+ def __eq__(self, other):
+ return self is other
+ def __ne__(self, other):
+ return self is not other
+ def __hash__(self):
+ return self._hash
+
class QueryTestCase(unittest.TestCase):
def setUp(self):
@@ -620,6 +639,26 @@ frozenset2({0,
self.assertEqual(pprint.pformat(dict.fromkeys(keys, 0)),
'{%r: 0, %r: 0}' % tuple(sorted(keys, key=id)))
+ def test_sort_orderable_and_unorderable_values(self):
+ # Issue 22721: sorted pprints is not stable
+ a = Unorderable()
+ b = Orderable(hash(a)) # should have the same hash value
+ # self-test
+ self.assertLess(a, b)
+ self.assertLess(str(type(b)), str(type(a)))
+ self.assertEqual(sorted([b, a]), [a, b])
+ self.assertEqual(sorted([a, b]), [a, b])
+ # set
+ self.assertEqual(pprint.pformat(set([b, a]), width=1),
+ '{%r,\n %r}' % (a, b))
+ self.assertEqual(pprint.pformat(set([a, b]), width=1),
+ '{%r,\n %r}' % (a, b))
+ # dict
+ self.assertEqual(pprint.pformat(dict.fromkeys([b, a]), width=1),
+ '{%r: None,\n %r: None}' % (a, b))
+ self.assertEqual(pprint.pformat(dict.fromkeys([a, b]), width=1),
+ '{%r: None,\n %r: None}' % (a, b))
+
def test_str_wrap(self):
# pprint tries to wrap strings intelligently
fox = 'the quick brown fox jumped over a lazy dog'
diff --git a/Misc/NEWS b/Misc/NEWS
index 2c58f16..8bacc13 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -19,6 +19,10 @@ Core and Builtins
Library
-------
+- Issue #22721: An order of multiline pprint output of set or dict containing
+ orderable and non-orderable elements no longer depends on iteration order of
+ set or dict.
+
- Issue #15133: _tkinter.tkapp.getboolean() now supports Tcl_Obj and always
returns bool. tkinter.BooleanVar now validates input values (accepted bool,
int, str, and Tcl_Obj). tkinter.BooleanVar.get() now always returns bool.