Repository navigation
Expand file tree
/
Copy pathtest_recursion.py
More file actions
120 lines (86 loc) · 3.4 KB
/
Copy pathtest_recursion.py
File metadata and controls
120 lines (86 loc) · 3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from collections.abc import Callable, Iterator
from dataclasses import dataclass
from typing import Any
import pytest
from devtools import Debug
from devtools.prettier import PrettyFormat, pformat
def test_recursive_dict():
value: dict[str, Any] = {'before': 1}
value['self'] = value
value['after'] = 2
expected = "{\n 'before': 1,\n 'self': <Recursion on dict>,\n 'after': 2,\n}"
assert pformat(value) == expected
assert pformat(value) == expected
@pytest.mark.parametrize('cutoff', [0, 10])
def test_recursive_list(cutoff: int):
value: list[Any] = [1, 2]
value.append(value)
assert PrettyFormat(simple_cutoff=cutoff)(value) == '[\n 1,\n 2,\n <Recursion on list>,\n]'
@pytest.mark.parametrize('cutoff', [0, 10])
def test_short_recursive_list(cutoff: int):
value: list[Any] = []
value.append(value)
expected = '[\n <Recursion on list>,\n]' if cutoff == 0 else '[[...]]'
assert PrettyFormat(simple_cutoff=cutoff)(value) == expected
@pytest.mark.parametrize('cutoff', [0, 100])
def test_compact_recursive_dict(cutoff: int):
value: dict[str, Any] = {}
value['self'] = value
expected = "{\n 'self': <Recursion on dict>,\n}" if cutoff == 0 else "{'self': {...}}"
assert PrettyFormat(simple_cutoff=cutoff)(value) == expected
def test_mutually_recursive_containers():
value: dict[str, Any] = {}
value['child'] = [value, 1]
assert pformat(value) == "{\n 'child': [\n <Recursion on dict>,\n 1,\n ],\n}"
@pytest.mark.parametrize('slots', [False, True])
def test_recursive_dataclass(slots: bool):
@dataclass(slots=slots)
class Node:
child: Any = None
value = Node()
value.child = value
assert pformat(value) == 'Node(\n child=<Recursion on Node>,\n)'
def test_recursive_pretty():
class Pretty:
def __pretty__(self, fmt: Callable[[Any], Any], skip_exc: type[Exception]) -> Iterator[Any]:
yield 'Pretty('
yield fmt(self)
yield ')'
assert pformat(Pretty()) == 'Pretty(<Recursion on Pretty>)'
def test_recursive_generator():
def generate() -> Iterator[Any]:
yield value
yield 1
value = generate()
assert pformat(value) == '(\n <Recursion on generator>,\n 1,\n)'
def test_recursive_reentrant_repr():
formatter = PrettyFormat()
class Reentrant:
def __repr__(self) -> str:
return formatter(self)
assert formatter(Reentrant()) == '<Recursion on Reentrant>'
assert formatter(1) == '1'
def test_shared_child_is_not_recursive():
child = {'value': 1}
assert PrettyFormat(simple_cutoff=0)([child, child]) == (
"[\n {\n 'value': 1,\n },\n {\n 'value': 1,\n },\n]"
)
def test_formatting_error_does_not_mark_value_as_recursive():
formatter = PrettyFormat()
class Broken:
fail = True
def __repr__(self) -> str:
if self.fail:
raise ValueError('broken repr')
return 'recovered'
value = Broken()
with pytest.raises(ValueError, match='broken repr'):
formatter(value)
value.fail = False
assert formatter(value) == 'recovered'
def test_debug_recursive_value():
value: dict[str, Any] = {'before': 1}
value['self'] = value
output = str(Debug(highlight=False).format(value))
assert "'before': 1" in output
assert "'self': <Recursion on dict>" in output