changeset: 95457:c8815035116b user: Serhiy Storchaka date: Mon Apr 06 22:52:44 2015 +0300 files: Lib/pprint.py Lib/test/test_pprint.py Misc/NEWS description: 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. diff -r f46454229cf5 -r c8815035116b Lib/pprint.py --- a/Lib/pprint.py Mon Apr 06 20:37:34 2015 +0300 +++ b/Lib/pprint.py Mon Apr 06 22:52:44 2015 +0300 @@ -86,14 +86,10 @@ 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 -r f46454229cf5 -r c8815035116b Lib/test/test_pprint.py --- a/Lib/test/test_pprint.py Mon Apr 06 20:37:34 2015 +0300 +++ b/Lib/test/test_pprint.py Mon Apr 06 22:52:44 2015 +0300 @@ -50,6 +50,25 @@ 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 @@ 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 -r f46454229cf5 -r c8815035116b Misc/NEWS --- a/Misc/NEWS Mon Apr 06 20:37:34 2015 +0300 +++ b/Misc/NEWS Mon Apr 06 22:52:44 2015 +0300 @@ -19,6 +19,10 @@ 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.