Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/utils/stringutil.py @ 39405:0f549da54379
stringutil: teach pprint() to indent
This will make data structure dumping in various places a bit
easier to read and diff. Since I wanted this for `hg debugwireproto`
output, I added indentation to it.
A more advanced pretty printer implementation would conditionally
add newlines if output is too long. But it is vastly simpler to
be consistent and always add newlines when indenting.
Again, I'm not crazy about the verbosity of the code and there is
room to consolidate logic for "print a collection." But this isn't
the most complicated code in the world and I'm not convinced it is
worth doing.
Differential Revision: https://phab.mercurial-scm.org/D4399
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 27 Aug 2018 09:13:58 -0700 |
parents | 5ed7c6caf24d |
children | f2fbd32c7664 |
comparison
equal
deleted
inserted
replaced
39404:b4e7e1f09c09 | 39405:0f549da54379 |
---|---|
41 pat = pat.translate(_regexescapemap) | 41 pat = pat.translate(_regexescapemap) |
42 if wantuni: | 42 if wantuni: |
43 return pat | 43 return pat |
44 return pat.encode('latin1') | 44 return pat.encode('latin1') |
45 | 45 |
46 def pprint(o, bprefix=False): | 46 def pprint(o, bprefix=False, indent=0): |
47 """Pretty print an object.""" | 47 """Pretty print an object.""" |
48 return b''.join(pprintgen(o, bprefix=bprefix)) | 48 return b''.join(pprintgen(o, bprefix=bprefix, indent=indent)) |
49 | 49 |
50 def pprintgen(o, bprefix=False): | 50 def pprintgen(o, bprefix=False, indent=0, _level=1): |
51 """Pretty print an object to a generator of atoms.""" | 51 """Pretty print an object to a generator of atoms. |
52 | |
53 ``bprefix`` is a flag influencing whether bytestrings are preferred with | |
54 a ``b''`` prefix. | |
55 | |
56 ``indent`` controls whether collections and nested data structures | |
57 span multiple lines via the indentation amount in spaces. By default, | |
58 no newlines are emitted. | |
59 """ | |
52 | 60 |
53 if isinstance(o, bytes): | 61 if isinstance(o, bytes): |
54 if bprefix: | 62 if bprefix: |
55 yield "b'%s'" % escapestr(o) | 63 yield "b'%s'" % escapestr(o) |
56 else: | 64 else: |
64 yield '[]' | 72 yield '[]' |
65 return | 73 return |
66 | 74 |
67 yield '[' | 75 yield '[' |
68 | 76 |
77 if indent: | |
78 yield '\n' | |
79 yield ' ' * (_level * indent) | |
80 | |
69 for i, a in enumerate(o): | 81 for i, a in enumerate(o): |
70 for chunk in pprintgen(a, bprefix=bprefix): | 82 for chunk in pprintgen(a, bprefix=bprefix, indent=indent, |
83 _level=_level + 1): | |
71 yield chunk | 84 yield chunk |
72 | 85 |
73 if i + 1 < len(o): | 86 if i + 1 < len(o): |
74 yield ', ' | 87 if indent: |
88 yield ',\n' | |
89 yield ' ' * (_level * indent) | |
90 else: | |
91 yield ', ' | |
92 | |
93 if indent: | |
94 yield '\n' | |
95 yield ' ' * ((_level - 1) * indent) | |
75 | 96 |
76 yield ']' | 97 yield ']' |
77 elif isinstance(o, dict): | 98 elif isinstance(o, dict): |
78 if not o: | 99 if not o: |
79 yield '{}' | 100 yield '{}' |
80 return | 101 return |
81 | 102 |
82 yield '{' | 103 yield '{' |
83 | 104 |
105 if indent: | |
106 yield '\n' | |
107 yield ' ' * (_level * indent) | |
108 | |
84 for i, (k, v) in enumerate(sorted(o.items())): | 109 for i, (k, v) in enumerate(sorted(o.items())): |
85 for chunk in pprintgen(k, bprefix=bprefix): | 110 for chunk in pprintgen(k, bprefix=bprefix, indent=indent, |
111 _level=_level + 1): | |
86 yield chunk | 112 yield chunk |
87 | 113 |
88 yield ': ' | 114 yield ': ' |
89 | 115 |
90 for chunk in pprintgen(v, bprefix=bprefix): | 116 for chunk in pprintgen(v, bprefix=bprefix, indent=indent, |
117 _level=_level + 1): | |
91 yield chunk | 118 yield chunk |
92 | 119 |
93 if i + 1 < len(o): | 120 if i + 1 < len(o): |
94 yield ', ' | 121 if indent: |
122 yield ',\n' | |
123 yield ' ' * (_level * indent) | |
124 else: | |
125 yield ', ' | |
126 | |
127 if indent: | |
128 yield '\n' | |
129 yield ' ' * ((_level - 1) * indent) | |
95 | 130 |
96 yield '}' | 131 yield '}' |
97 elif isinstance(o, set): | 132 elif isinstance(o, set): |
98 if not o: | 133 if not o: |
99 yield 'set([])' | 134 yield 'set([])' |
100 return | 135 return |
101 | 136 |
102 yield 'set([' | 137 yield 'set([' |
103 | 138 |
139 if indent: | |
140 yield '\n' | |
141 yield ' ' * (_level * indent) | |
142 | |
104 for i, k in enumerate(sorted(o)): | 143 for i, k in enumerate(sorted(o)): |
105 for chunk in pprintgen(k, bprefix=bprefix): | 144 for chunk in pprintgen(k, bprefix=bprefix, indent=indent, |
145 _level=_level + 1): | |
106 yield chunk | 146 yield chunk |
107 | 147 |
108 if i + 1 < len(o): | 148 if i + 1 < len(o): |
109 yield ', ' | 149 if indent: |
150 yield ',\n' | |
151 yield ' ' * (_level * indent) | |
152 else: | |
153 yield ', ' | |
154 | |
155 if indent: | |
156 yield '\n' | |
157 yield ' ' * ((_level - 1) * indent) | |
110 | 158 |
111 yield '])' | 159 yield '])' |
112 elif isinstance(o, tuple): | 160 elif isinstance(o, tuple): |
113 if not o: | 161 if not o: |
114 yield '()' | 162 yield '()' |
115 return | 163 return |
116 | 164 |
117 yield '(' | 165 yield '(' |
118 | 166 |
167 if indent: | |
168 yield '\n' | |
169 yield ' ' * (_level * indent) | |
170 | |
119 for i, a in enumerate(o): | 171 for i, a in enumerate(o): |
120 for chunk in pprintgen(a, bprefix=bprefix): | 172 for chunk in pprintgen(a, bprefix=bprefix, indent=indent, |
173 _level=_level + 1): | |
121 yield chunk | 174 yield chunk |
122 | 175 |
123 if i + 1 < len(o): | 176 if i + 1 < len(o): |
124 yield ', ' | 177 if indent: |
178 yield ',\n' | |
179 yield ' ' * (_level * indent) | |
180 else: | |
181 yield ', ' | |
182 | |
183 if indent: | |
184 yield '\n' | |
185 yield ' ' * ((_level - 1) * indent) | |
125 | 186 |
126 yield ')' | 187 yield ')' |
127 elif isinstance(o, types.GeneratorType): | 188 elif isinstance(o, types.GeneratorType): |
128 # Special case of empty generator. | 189 # Special case of empty generator. |
129 try: | 190 try: |
132 yield 'gen[]' | 193 yield 'gen[]' |
133 return | 194 return |
134 | 195 |
135 yield 'gen[' | 196 yield 'gen[' |
136 | 197 |
198 if indent: | |
199 yield '\n' | |
200 yield ' ' * (_level * indent) | |
201 | |
137 last = False | 202 last = False |
138 | 203 |
139 while not last: | 204 while not last: |
140 current = nextitem | 205 current = nextitem |
141 | 206 |
142 try: | 207 try: |
143 nextitem = next(o) | 208 nextitem = next(o) |
144 except StopIteration: | 209 except StopIteration: |
145 last = True | 210 last = True |
146 | 211 |
147 for chunk in pprintgen(current, bprefix=bprefix): | 212 for chunk in pprintgen(current, bprefix=bprefix, indent=indent, |
213 _level=_level + 1): | |
148 yield chunk | 214 yield chunk |
149 | 215 |
150 if not last: | 216 if not last: |
151 yield ', ' | 217 if indent: |
218 yield ',\n' | |
219 yield ' ' * (_level * indent) | |
220 else: | |
221 yield ', ' | |
222 | |
223 if indent: | |
224 yield '\n' | |
225 yield ' ' * ((_level -1) * indent) | |
152 | 226 |
153 yield ']' | 227 yield ']' |
154 else: | 228 else: |
155 yield pycompat.byterepr(o) | 229 yield pycompat.byterepr(o) |
156 | 230 |