New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pprint._safe_repr is not general enough in one instance #48226
Comments
I've run into a case where pprint isn't able to print out a particular import pprint
class A:
pass pprint.pprint({A(): 1, A(): 2}) Which throws this exception: Traceback (most recent call last):
File
"/opt/local/Library/Frameworks/Python.framework/Versions/3.0/lib/python3
.0/pprint.py", line 272, in _safe_repr
items = sorted(items)
TypeError: unorderable types: A() < A()
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "foo.py", line 6, in <module>
pprint.pprint({A(): 1, A(): 2})
File
"/opt/local/Library/Frameworks/Python.framework/Versions/3.0/lib/python3
.0/pprint.py", line 55, in pprint
printer.pprint(object)
File
"/opt/local/Library/Frameworks/Python.framework/Versions/3.0/lib/python3
.0/pprint.py", line 106, in pprint
self._format(object, self._stream, 0, 0, {}, 0)
File
"/opt/local/Library/Frameworks/Python.framework/Versions/3.0/lib/python3
.0/pprint.py", line 129, in _format
rep = self._repr(object, context, level - 1)
File
"/opt/local/Library/Frameworks/Python.framework/Versions/3.0/lib/python3
.0/pprint.py", line 216, in _repr
self._depth, level)
File
"/opt/local/Library/Frameworks/Python.framework/Versions/3.0/lib/python3
.0/pprint.py", line 228, in format
return _safe_repr(object, context, maxlevels, level)
File
"/opt/local/Library/Frameworks/Python.framework/Versions/3.0/lib/python3
.0/pprint.py", line 277, in _safe_repr
items = sorted(items, key=sortkey)
TypeError: unorderable types: A() < A() This is happening because of this block of code:
The exception block is trying to sort the items again, but in this
That would at least give some ordering to the output. Unfortunately, in |
Another solution would be to separate the dict items by key type, try to |
fyi, I found another case where pprint needs a "safe sort", this is --- /opt/local/lib/python3.0/pprint.py 2008-09-26 09:35:21.000000000 -0700
+++ /tmp/pprint.py 2008-09-26 09:35:13.000000000 -0700
@@ -145,7 +145,7 @@
if length:
context[objid] = 1
indent = indent + self._indent_per_level
- items = sorted(object.items())
+ items = _safe_sorted(object.items())
key, ent = items[0]
rep = self._repr(key, context, level)
write(rep)
@@ -267,14 +267,7 @@
append = components.append
level += 1
saferepr = _safe_repr
- items = object.items()
- try:
- items = sorted(items)
- except TypeError:
- def sortkey(item):
- key, value = item
- return str(type(key)), key, value
- items = sorted(items, key=sortkey)
+ items = _safe_sorted(object.items())
for k, v in items:
krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
@@ -321,6 +314,20 @@
rep = repr(object)
return rep, (rep and not rep.startswith('<')), False +def _safe_sorted(items): def _recursion(object):
return ("<Recursion on %s with id=%s>" One other thing to note is that I'm also aware that the yaml project |
For this to be integrated, it should also add an unit test. |
The proposed patch appears to give up sorting by key,value altogether if |
Also note that this patch will not sort sequences of mixed types where {1:2, 2:3, 'a':4, 1.5: 5} the 1.5 key will not be placed between the 1 and 2 keys. I'm not aware of a way to implement that behavior without support for a |
I'm thinking that pprint should not try to sort unsortable items. try: |
OK, there *is* a way. Consider this: class safe_key(object):
__slots__ = ('obj',)
def __init__(self, obj):
self.obj = obj
def __eq__(self, other):
return self.obj.__eq__(other.obj)
def __lt__(self, other):
try:
return self.obj < other.obj
except TypeError:
return id(type(self.obj)) < id(type(other.obj))
ls = [2, 1, 1.0, 1.5, 'a', 'c', 'b']
print(sorted(ls, key=safe_key)) |
@georg: Instead of catching a TypeError i would rather call __gt__ / |
Eg, something like this: class safe_key(object):
__slots__ = ('obj',)
def __init__(self, obj):
self.obj = obj
def __eq__(self, other):
return self.obj.__eq__(other.obj)
def __lt__(self, other):
rv = self.obj.__lt__(other.obj)
if rv is NotImplemented:
rv = id(type(self.obj)) < id(type(other.obj))
return rv
ls = [2, 1, 1.0, 1.5, 'a', 'c', 'b']
print(sorted(ls, key=safe_key)) |
Fixed. See r76389 and r76390. |
Armin: this has the problem that, if the object you're trying to compare is a class, self.obj.__lt__ expects a different number of parameters (i.e., it expects the instance). See bpo-10017 . Testing with "<" works. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: