← mined_oracle

rich_2524

failed WRONG_FIX UNSUBMITTED wrong_fix_unsubmitted(None) · None tool calls · 0 s · Textualize/rich

Task input

(not found in data/tasks.jsonl)

Tool calls (0)

#ToolArgumentsResult
No trace captured.

Patch

--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Handle stdout/stderr being null https://github.com/Textualize/rich/pull/2513
 - Fix NO_COLOR support on legacy Windows https://github.com/Textualize/rich/pull/2458
+- Fix pretty printer handling of cyclic references https://github.com/Textualize/rich/pull/2524
 - Fix missing `mode` property on file wrapper breaking uploads via `requests` https://github.com/Textualize/rich/pull/2495
 
 ### Changed
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -8,6 +8,7 @@ The following people have contributed to the development of Rich:
 - [Gregory Beauregard](https://github.com/GBeauregard/pyffstream)
 - [Dennis Brakhane](https://github.com/brakhane)
 - [Darren Burns](https://github.com/darrenburns)
+- [Jim Crist-Harif](https://github.com/jcrist)
 - [Ed Davis](https://github.com/davised)
 - [Pete Davison](https://github.com/pd93)
 - [James Estevez](https://github.com/jstvz)
--- a/rich/pretty.py
+++ b/rich/pretty.py
@@ -636,6 +636,11 @@ def traverse(
     def _traverse(obj: Any, root: bool = False, depth: int = 0) -> Node:
         """Walk the object depth first."""
 
+        obj_id = id(obj)
+        if obj_id in visited_ids:
+            # Recursion detected
+            return Node(value_repr="...")
+
         obj_type = type(obj)
         py_version = (sys.version_info.major, sys.version_info.minor)
         children: List[Node]
@@ -673,6 +678,7 @@ def traverse(
                 pass
 
         if rich_repr_result is not None:
+            push_visited(obj_id)
             angular = getattr(obj.__rich_repr__, "angular", False)
             args = list(iter_rich_args(rich_repr_result))
             class_name = obj.__class__.__name__
@@ -720,7 +726,9 @@ def traverse(
                     children=[],
                     last=root,
                 )
+            pop_visited(obj_id)
         elif _is_attr_object(obj) and not fake_attributes:
+            push_visited(obj_id)
             children = []
             append = children.append
 
@@ -767,19 +775,14 @@ def traverse(
                 node = Node(
                     value_repr=f"{obj.__class__.__name__}()", children=[], last=root
                 )
-
+            pop_visited(obj_id)
         elif (
             is_dataclass(obj)
             and not _safe_isinstance(obj, type)
             and not fake_attributes
             and (_is_dataclass_repr(obj) or py_version == (3, 6))
         ):
-            obj_id = id(obj)
-            if obj_id in visited_ids:
-                # Recursion detected
-                return Node(value_repr="...")
             push_visited(obj_id)
-
             children = []
             append = children.append
             if reached_max_depth:
@@ -801,8 +804,9 @@ def traverse(
                     child_node.key_separator = "="
                     append(child_node)
 
-                pop_visited(obj_id)
+            pop_visited(obj_id)
         elif _is_namedtuple(obj) and _has_default_namedtuple_repr(obj):
+            push_visited(obj_id)
             class_name = obj.__class__.__name__
             if reached_max_depth:
                 # If we've reached the max depth, we still show the class name, but not its contents
@@ -824,16 +828,13 @@ def traverse(
                     child_node.last = last
                     child_node.key_separator = "="
                     append(child_node)
+            pop_visited(obj_id)
         elif _safe_isinstance(obj, _CONTAINERS):
             for container_type in _CONTAINERS:
                 if _safe_isinstance(obj, container_type):
                     obj_type = container_type
                     break
 
-            obj_id = id(obj)
-            if obj_id in visited_ids:
-                # Recursion detected
-                return Node(value_repr="...")
             push_visited(obj_id)
 
             open_brace, close_brace, empty = _BRACES[obj_type](obj)

Test output

show
.........F
=================================== FAILURES ===================================
____________________________ test_pretty_dataclass _____________________________

    def test_pretty_dataclass():
        dc = ExampleDataclass(1000, "Hello, World", 999, ["foo", "bar", "baz"])
        result = pretty_repr(dc, max_width=80)
        print(repr(result))
        assert (
            result
            == "ExampleDataclass(foo=1000, bar='Hello, World', baz=['foo', 'bar', 'baz'])"
        )
        result = pretty_repr(dc, max_width=16)
        print(repr(result))
>       assert (
            result
            == "ExampleDataclass(\n    foo=1000,\n    bar='Hello, World',\n    baz=[\n        'foo',\n        'bar',\n        'baz'\n    ]\n)"
        )
E       assert "ExampleDatac...bar', 'baz'])" == "ExampleDatac...az'\n    ]\n)"
E         
E         + ExampleDataclass(foo=1000, bar='Hello, World', baz=['foo', 'bar', 'baz'])
E         - ExampleDataclass(
E         -     foo=1000,
E         -     bar='Hello, World',
E         -     baz=[
E         -         'foo',...
E         
E         ...Full output truncated (4 lines hidden), use '-vv' to show

tests/test_pretty.py:193: AssertionError
----------------------------- Captured stdout call -----------------------------
"ExampleDataclass(foo=1000, bar='Hello, World', baz=['foo', 'bar', 'baz'])"
"ExampleDataclass(foo=1000, bar='Hello, World', baz=['foo', 'bar', 'baz'])"
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 9 passed in 0.17s