SF bug[ #423781: pprint.isrecursive() broken.

This commit is contained in:
Tim Peters 2001-05-14 07:05:58 +00:00
parent 2a0af79269
commit a814db579d
4 changed files with 93 additions and 30 deletions

View File

@ -49,26 +49,21 @@ def pprint(object, stream=None):
printer = PrettyPrinter(stream=stream)
printer.pprint(object)
def pformat(object):
"""Format a Python object into a pretty-printed representation."""
return PrettyPrinter().pformat(object)
def isreadable(object):
"""Determine if saferepr(object) is readable by eval()."""
return PrettyPrinter().isreadable(object)
def isrecursive(object):
"""Determine if object requires a recursive representation."""
return PrettyPrinter().isrecursive(object)
def saferepr(object):
"""Version of repr() which can handle recursive data structures."""
return _safe_repr(object, {})[0]
def isreadable(object):
"""Determine if saferepr(object) is readable by eval()."""
return _safe_repr(object, {})[1]
def isrecursive(object):
"""Determine if object requires a recursive representation."""
return _safe_repr(object, {})[2]
class PrettyPrinter:
def __init__(self, indent=1, width=80, depth=None, stream=None):
@ -92,7 +87,7 @@ class PrettyPrinter:
indent = int(indent)
width = int(width)
assert indent >= 0
assert (not depth) or depth > 0, "depth may not be negative"
assert depth is None or depth > 0, "depth must be > 0"
assert width
self.__depth = depth
self.__indent_per_level = indent
@ -182,23 +177,28 @@ class PrettyPrinter:
del context[objid]
def __repr(self, object, context, level):
repr, readable = _safe_repr(object, context, self.__depth, level)
repr, readable, recursive = _safe_repr(object, context,
self.__depth, level)
if not readable:
self.__readable = 0
if recursive:
self.__recursive = 1
return repr
# Return triple (repr_string, isreadable, isrecursive).
def _safe_repr(object, context, maxlevels=None, level=0):
level = level + 1
typ = type(object)
if not (typ in (DictType, ListType, TupleType) and object):
rep = `object`
return rep, (rep and (rep[0] != '<'))
return rep, (rep and (rep[0] != '<')), 0
if context.has_key(id(object)):
return `_Recursion(object)`, 0
return `_Recursion(object)`, 0, 1
objid = id(object)
context[objid] = 1
readable = 1
recursive = 0
if typ is DictType:
if maxlevels and level >= maxlevels:
s = "{...}"
@ -206,14 +206,20 @@ def _safe_repr(object, context, maxlevels=None, level=0):
else:
items = object.items()
k, v = items[0]
krepr, kreadable = _safe_repr(k, context, maxlevels, level)
vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
krepr, kreadable, krecur = _safe_repr(k, context, maxlevels,
level)
vrepr, vreadable, vrecur = _safe_repr(v, context, maxlevels,
level)
readable = readable and kreadable and vreadable
recursive = recursive or krecur or vrecur
s = "{%s: %s" % (krepr, vrepr)
for k, v in items[1:]:
krepr, kreadable = _safe_repr(k, context, maxlevels, level)
vrepr, vreadable = _safe_repr(v, context, maxlevels, level)
krepr, kreadable, krecur = _safe_repr(k, context, maxlevels,
level)
vrepr, vreadable, vrecur = _safe_repr(v, context, maxlevels,
level)
readable = readable and kreadable and vreadable
recursive = recursive or krecur or vrecur
s = "%s, %s: %s" % (s, krepr, vrepr)
s = s + "}"
else:
@ -222,22 +228,24 @@ def _safe_repr(object, context, maxlevels=None, level=0):
s = s + "..."
readable = 0
else:
subrepr, subreadable = _safe_repr(
subrepr, subreadable, subrecur = _safe_repr(
object[0], context, maxlevels, level)
readable = readable and subreadable
recursive = recursive or subrecur
s = s + subrepr
tail = object[1:]
if not tail:
if typ is TupleType:
s = s + ','
for ent in tail:
subrepr, subreadable = _safe_repr(
subrepr, subreadable, subrecur = _safe_repr(
ent, context, maxlevels, level)
readable = readable and subreadable
recursive = recursive or subrecur
s = "%s, %s" % (s, subrepr)
s = s + term
del context[objid]
return s, readable
return s, readable and not recursive, recursive
class _Recursion:

View File

@ -0,0 +1 @@
test_pprint

36
Lib/test/test_pprint.py Normal file
View File

@ -0,0 +1,36 @@
from test_support import verify
import pprint
# Verify that .isrecursive() and .isreadable() work.
a = range(100)
b = range(200)
a[-12] = b
for safe in 2, 2.0, 2j, "abc", [3], (2,2), {3: 3}, u"yaddayadda", a, b:
verify(pprint.isrecursive(safe) == 0, "expected isrecursive == 0")
verify(pprint.isreadable(safe) == 1, "expected isreadable == 1")
# Tie a knot.
b[67] = a
# Messy dict.
d = {}
d[0] = d[1] = d[2] = d
for icky in a, b, d, (d, d):
verify(pprint.isrecursive(icky) == 1, "expected isrecursive == 1")
verify(pprint.isreadable(icky) == 0, "expected isreadable == 0")
# Break the cycles.
d.clear()
del a[:]
del b[:]
for safe in a, b, d, (d, d):
verify(pprint.isrecursive(safe) == 0, "expected isrecursive == 0")
verify(pprint.isreadable(safe) == 1, "expected isreadable == 1")
# Not recursive but not readable anyway.
for unreadable in type(3), pprint, pprint.isrecursive:
verify(pprint.isrecursive(unreadable) == 0, "expected isrecursive == 0")
verify(pprint.isreadable(unreadable) ==0, "expected isreadable == 0")

View File

@ -2,22 +2,23 @@ What's New in Python 2.2a0?
===========================
Core
- Some operating systems now support the concept of a default Unicode
encoding for file system operations. Notably, Windows supports 'mbcs'
as the default. The Macintosh will also adopt this concept in the medium
term, altough the default encoding for that platform will be other than
term, altough the default encoding for that platform will be other than
'mbcs'.
On operating system that support non-ascii filenames, it is common for
On operating system that support non-ascii filenames, it is common for
functions that return filenames (such as os.listdir()) to return Python
string objects pre-encoded using the default file system encoding for
the platform. As this encoding is likely to be different from Python's
default encoding, converting this name to a Unicode object before passing
it back to the Operating System would result in a Unicode error, as Python
would attempt to use it's default encoding (generally ASCII) rather
than the default encoding for the file system.
In general, this change simply removes surprises when working with
Unicode and the file system, making these operations work as
you expect, increasing the transparency of Unicode objects in this context.
would attempt to use its default encoding (generally ASCII) rather than
the default encoding for the file system.
In general, this change simply removes surprises when working with
Unicode and the file system, making these operations work as you expect,
increasing the transparency of Unicode objects in this context.
See [????] for more details, including examples.
- Float (and complex) literals in source code were evaluated to full
@ -82,6 +83,23 @@ Core
to crash if the element comparison routines for the dict keys and/or
values mutated the dicts. Making the code bulletproof slowed it down.
Library
- Cookie.py now sorts key+value pairs by key in output strings.
- pprint.isrecursive(object) didn't correctly identify recursive objects.
Now it does.
Tests
- New test_mutants.py runs dict comparisons where the key and value
comparison operators mutute the dicts randomly during comparison. This
rapidly causes Python to crash under earlier releases (not for the faint
of heart: it can also cause Win9x to freeze or reboot!).
- New test_pprint.py verfies that pprint.isrecursive() and
pprint.isreadable() return sensible results.
What's New in Python 2.1 (final)?
=================================