Path 1: 162 calls (1.0)

1 (45) Layout (18) dict (16) 0 (14) Console (7) test_broken_call_attr..NotCallable (4) list (4) (1,) (4) ExampleDataclass (3) test_reference_c...

None (155) 10 (5) 2 (2)

None (156) 60 (4) 8 (1) 80 (1)

None (151) 2 (4) 1 (3) 0 (1) 3 (1) 4 (1) 5 (1)

Node (162)

1def traverse(
2    _object: Any,
3    max_length: Optional[int] = None,
4    max_string: Optional[int] = None,
5    max_depth: Optional[int] = None,
6) -> Node:
7    """Traverse object and generate a tree.
8
9    Args:
10        _object (Any): Object to be traversed.
11        max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
12            Defaults to None.
13        max_string (int, optional): Maximum length of string before truncating, or None to disable truncating.
14            Defaults to None.
15        max_depth (int, optional): Maximum depth of data structures, or None for no maximum.
16            Defaults to None.
17
18    Returns:
19        Node: The root of a tree structure which can be used to render a pretty repr.
20    """
21
22    def to_repr(obj: Any) -> str:
23        """Get repr string for an object, but catch errors."""
24        if (
25            max_string is not None
26            and _safe_isinstance(obj, (bytes, str))
27            and len(obj) > max_string
28        ):
29            truncated = len(obj) - max_string
30            obj_repr = f"{obj[:max_string]!r}+{truncated}"
31        else:
32            try:
33                obj_repr = repr(obj)
34            except Exception as error:
35                obj_repr = f"<repr-error {str(error)!r}>"
36        return obj_repr
37
38    visited_ids: Set[int] = set()
39    push_visited = visited_ids.add
40    pop_visited = visited_ids.remove
41
42    def _traverse(obj: Any, root: bool = False, depth: int = 0) -> Node:
43        """Walk the object depth first."""
44
45        obj_id = id(obj)
46        if obj_id in visited_ids:
47            # Recursion detected
48            return Node(value_repr="...")
49
50        obj_type = type(obj)
51        py_version = (sys.version_info.major, sys.version_info.minor)
52        children: List[Node]
53        reached_max_depth = max_depth is not None and depth >= max_depth
54
55        def iter_rich_args(rich_args: Any) -> Iterable[Union[Any, Tuple[str, Any]]]:
56            for arg in rich_args:
57                if _safe_isinstance(arg, tuple):
58                    if len(arg) == 3:
59                        key, child, default = arg
60                        if default == child:
61                            continue
62                        yield key, child
63                    elif len(arg) == 2:
64                        key, child = arg
65                        yield key, child
66                    elif len(arg) == 1:
67                        yield arg[0]
68                else:
69                    yield arg
70
71        try:
72            fake_attributes = hasattr(
73                obj, "awehoi234_wdfjwljet234_234wdfoijsdfmmnxpi492"
74            )
75        except Exception:
76            fake_attributes = False
77
78        rich_repr_result: Optional[RichReprResult] = None
79        if not fake_attributes:
80            try:
81                if hasattr(obj, "__rich_repr__") and not isclass(obj):
82                    rich_repr_result = obj.__rich_repr__()
83            except Exception:
84                pass
85
86        if rich_repr_result is not None:
87            push_visited(obj_id)
88            angular = getattr(obj.__rich_repr__, "angular", False)
89            args = list(iter_rich_args(rich_repr_result))
90            class_name = obj.__class__.__name__
91
92            if args:
93                children = []
94                append = children.append
95
96                if reached_max_depth:
97                    if angular:
98                        node = Node(value_repr=f"<{class_name}...>")
99                    else:
100                        node = Node(value_repr=f"{class_name}(...)")
101                else:
102                    if angular:
103                        node = Node(
104                            open_brace=f"<{class_name} ",
105                            close_brace=">",
106                            children=children,
107                            last=root,
108                            separator=" ",
109                        )
110                    else:
111                        node = Node(
112                            open_brace=f"{class_name}(",
113                            close_brace=")",
114                            children=children,
115                            last=root,
116                        )
117                    for last, arg in loop_last(args):
118                        if _safe_isinstance(arg, tuple):
119                            key, child = arg
120                            child_node = _traverse(child, depth=depth + 1)
121                            child_node.last = last
122                            child_node.key_repr = key
123                            child_node.key_separator = "="
124                            append(child_node)
125                        else:
126                            child_node = _traverse(arg, depth=depth + 1)
127                            child_node.last = last
128                            append(child_node)
129            else:
130                node = Node(
131                    value_repr=f"<{class_name}>" if angular else f"{class_name}()",
132                    children=[],
133                    last=root,
134                )
135            pop_visited(obj_id)
136        elif _is_attr_object(obj) and not fake_attributes:
137            push_visited(obj_id)
138            children = []
139            append = children.append
140
141            attr_fields = _get_attr_fields(obj)
142            if attr_fields:
143                if reached_max_depth:
144                    node = Node(value_repr=f"{obj.__class__.__name__}(...)")
145                else:
146                    node = Node(
147                        open_brace=f"{obj.__class__.__name__}(",
148                        close_brace=")",
149                        children=children,
150                        last=root,
151                    )
152
153                    def iter_attrs() -> Iterable[
154                        Tuple[str, Any, Optional[Callable[[Any], str]]]
155                    ]:
156                        """Iterate over attr fields and values."""
157                        for attr in attr_fields:
158                            if attr.repr:
159                                try:
160                                    value = getattr(obj, attr.name)
161                                except Exception as error:
162                                    # Can happen, albeit rarely
163                                    yield (attr.name, error, None)
164                                else:
165                                    yield (
166                                        attr.name,
167                                        value,
168                                        attr.repr if callable(attr.repr) else None,
169                                    )
170
171                    for last, (name, value, repr_callable) in loop_last(iter_attrs()):
172                        if repr_callable:
173                            child_node = Node(value_repr=str(repr_callable(value)))
174                        else:
175                            child_node = _traverse(value, depth=depth + 1)
176                        child_node.last = last
177                        child_node.key_repr = name
178                        child_node.key_separator = "="
179                        append(child_node)
180            else:
181                node = Node(
182                    value_repr=f"{obj.__class__.__name__}()", children=[], last=root
183                )
184            pop_visited(obj_id)
185        elif (
186            is_dataclass(obj)
187            and not _safe_isinstance(obj, type)
188            and not fake_attributes
189            and (_is_dataclass_repr(obj) or py_version == (3, 6))
190        ):
191            push_visited(obj_id)
192            children = []
193            append = children.append
194            if reached_max_depth:
195                node = Node(value_repr=f"{obj.__class__.__name__}(...)")
196            else:
197                node = Node(
198                    open_brace=f"{obj.__class__.__name__}(",
199                    close_brace=")",
200                    children=children,
201                    last=root,
202                )
203
204                for last, field in loop_last(
205                    field for field in fields(obj) if field.repr
206                ):
207                    child_node = _traverse(getattr(obj, field.name), depth=depth + 1)
208                    child_node.key_repr = field.name
209                    child_node.last = last
210                    child_node.key_separator = "="
211                    append(child_node)
212
213            pop_visited(obj_id)
214        elif _is_namedtuple(obj) and _has_default_namedtuple_repr(obj):
215            push_visited(obj_id)
216            class_name = obj.__class__.__name__
217            if reached_max_depth:
218                # If we've reached the max depth, we still show the class name, but not its contents
219                node = Node(
220                    value_repr=f"{class_name}(...)",
221                )
222            else:
223                children = []
224                append = children.append
225                node = Node(
226                    open_brace=f"{class_name}(",
227                    close_brace=")",
228                    children=children,
229                    empty=f"{class_name}()",
230                )
231                for last, (key, value) in loop_last(obj._asdict().items()):
232                    child_node = _traverse(value, depth=depth + 1)
233                    child_node.key_repr = key
234                    child_node.last = last
235                    child_node.key_separator = "="
236                    append(child_node)
237            pop_visited(obj_id)
238        elif _safe_isinstance(obj, _CONTAINERS):
239            for container_type in _CONTAINERS:
240                if _safe_isinstance(obj, container_type):
241                    obj_type = container_type
242                    break
243
244            push_visited(obj_id)
245
246            open_brace, close_brace, empty = _BRACES[obj_type](obj)
247
248            if reached_max_depth:
249                node = Node(value_repr=f"{open_brace}...{close_brace}")
250            elif obj_type.__repr__ != type(obj).__repr__:
251                node = Node(value_repr=to_repr(obj), last=root)
252            elif obj:
253                children = []
254                node = Node(
255                    open_brace=open_brace,
256                    close_brace=close_brace,
257                    children=children,
258                    last=root,
259                )
260                append = children.append
261                num_items = len(obj)
262                last_item_index = num_items - 1
263
264                if _safe_isinstance(obj, _MAPPING_CONTAINERS):
265                    iter_items = iter(obj.items())
266                    if max_length is not None:
267                        iter_items = islice(iter_items, max_length)
268                    for index, (key, child) in enumerate(iter_items):
269                        child_node = _traverse(child, depth=depth + 1)
270                        child_node.key_repr = to_repr(key)
271                        child_node.last = index == last_item_index
272                        append(child_node)
273                else:
274                    iter_values = iter(obj)
275                    if max_length is not None:
276                        iter_values = islice(iter_values, max_length)
277                    for index, child in enumerate(iter_values):
278                        child_node = _traverse(child, depth=depth + 1)
279                        child_node.last = index == last_item_index
280                        append(child_node)
281                if max_length is not None and num_items > max_length:
282                    append(Node(value_repr=f"... +{num_items - max_length}", last=True))
283            else:
284                node = Node(empty=empty, children=[], last=root)
285
286            pop_visited(obj_id)
287        else:
288            node = Node(value_repr=to_repr(obj), last=root)
289        node.is_tuple = _safe_isinstance(obj, tuple)
290        node.is_namedtuple = _is_namedtuple(obj)
291        return node
292
293    node = _traverse(_object, root=True)
294    return node