Skip to content

Commit

Permalink
Merge pull request #4148 from HypothesisWorks/DRMacIver/use-provided-…
Browse files Browse the repository at this point in the history
…pretty

Always use a repr_pretty if provided
  • Loading branch information
Zac-HD authored Oct 26, 2024
2 parents b9d41db + 558db3c commit 21502ba
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 10 deletions.
5 changes: 5 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
RELEASE_TYPE: patch

This patch changes the priority order of pretty printing logic so that a user
provided pretty printing method will always be used in preference to e.g.
printing it like a dataclass.
18 changes: 10 additions & 8 deletions hypothesis-python/src/hypothesis/vendor/pretty.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ def pretty(self, obj):
pass
else:
return printer(obj, self, cycle)

# Look for the _repr_pretty_ method which allows users
# to define custom pretty printing.
# Some objects automatically create any requested
# attribute. Try to ignore most of them by checking for
# callability.
pretty_method = _safe_getattr(obj, "_repr_pretty_", None)
if callable(pretty_method):
return pretty_method(self, cycle)

# Next walk the mro and check for either:
# 1) a registered printer
# 2) a _repr_pretty_ method
Expand All @@ -206,14 +216,6 @@ def pretty(self, obj):
self.type_pprinters[cls] = printer
return printer(obj, self, cycle)
else:
# Finally look for special method names.
# Some objects automatically create any requested
# attribute. Try to ignore most of them by checking for
# callability.
if "_repr_pretty_" in cls.__dict__:
meth = cls._repr_pretty_
if callable(meth):
return meth(obj, self, cycle)
if hasattr(cls, "__attrs_attrs__"):
return pprint_fields(
obj,
Expand Down
34 changes: 32 additions & 2 deletions hypothesis-python/tests/cover/test_pretty.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""

import io
import re
import struct
import sys
Expand Down Expand Up @@ -100,9 +101,12 @@ def _repr_pretty_(self, p, cycle):
p.text("Dummy1(...)")


class Dummy2(Dummy1):
class Dummy2:
_repr_pretty_ = None

def __repr__(self):
return "Dummy2()"


class NoModule:
pass
Expand Down Expand Up @@ -207,7 +211,7 @@ def test_callability_checking():
"""Test that the _repr_pretty_ method is tested for callability and skipped
if not."""
gotoutput = pretty.pretty(Dummy2())
expectedoutput = "Dummy1(...)"
expectedoutput = "Dummy2()"

assert gotoutput == expectedoutput

Expand Down Expand Up @@ -901,3 +905,29 @@ class E(Enum):
@pytest.mark.parametrize("obj", NAMESPACED_VALUES, ids=map(repr, NAMESPACED_VALUES))
def test_includes_namespace_classes_in_pretty(obj):
assert pretty.pretty(obj).startswith("Namespace.")


class Banana:
def _repr_pretty_(self, p, cycle):
p.text("I am a banana")


@dataclass
class InheritsPretty(Banana):
x: int
y: int


def test_uses_defined_pretty_printing_method():
assert pretty.pretty(InheritsPretty(x=1, y=2)) == pretty.pretty(Banana())


def test_prefers_singleton_printing_to_repr_pretty():
out = io.StringIO()
printer = pretty.RepresentationPrinter(out)
banana = Banana()
printer.singleton_pprinters[id(banana)] = lambda obj, p, cycle: p.text(
"Actually a fish"
)
printer.pretty(banana)
assert "Actually a fish" in out.getvalue()

0 comments on commit 21502ba

Please sign in to comment.