64 ``level`` specifies the initial indent level. Used if ``indent > 0``. |
64 ``level`` specifies the initial indent level. Used if ``indent > 0``. |
65 """ |
65 """ |
66 |
66 |
67 if isinstance(o, bytes): |
67 if isinstance(o, bytes): |
68 if bprefix: |
68 if bprefix: |
69 yield "b'%s'" % escapestr(o) |
69 yield b"b'%s'" % escapestr(o) |
70 else: |
70 else: |
71 yield "'%s'" % escapestr(o) |
71 yield b"'%s'" % escapestr(o) |
72 elif isinstance(o, bytearray): |
72 elif isinstance(o, bytearray): |
73 # codecs.escape_encode() can't handle bytearray, so escapestr fails |
73 # codecs.escape_encode() can't handle bytearray, so escapestr fails |
74 # without coercion. |
74 # without coercion. |
75 yield "bytearray['%s']" % escapestr(bytes(o)) |
75 yield b"bytearray['%s']" % escapestr(bytes(o)) |
76 elif isinstance(o, list): |
76 elif isinstance(o, list): |
77 if not o: |
77 if not o: |
78 yield '[]' |
78 yield b'[]' |
79 return |
79 return |
80 |
80 |
81 yield '[' |
81 yield b'[' |
82 |
82 |
83 if indent: |
83 if indent: |
84 level += 1 |
84 level += 1 |
85 yield '\n' |
85 yield b'\n' |
86 yield ' ' * (level * indent) |
86 yield b' ' * (level * indent) |
87 |
87 |
88 for i, a in enumerate(o): |
88 for i, a in enumerate(o): |
89 for chunk in pprintgen( |
89 for chunk in pprintgen( |
90 a, bprefix=bprefix, indent=indent, level=level |
90 a, bprefix=bprefix, indent=indent, level=level |
91 ): |
91 ): |
92 yield chunk |
92 yield chunk |
93 |
93 |
94 if i + 1 < len(o): |
94 if i + 1 < len(o): |
95 if indent: |
95 if indent: |
96 yield ',\n' |
96 yield b',\n' |
97 yield ' ' * (level * indent) |
97 yield b' ' * (level * indent) |
98 else: |
98 else: |
99 yield ', ' |
99 yield b', ' |
100 |
100 |
101 if indent: |
101 if indent: |
102 level -= 1 |
102 level -= 1 |
103 yield '\n' |
103 yield b'\n' |
104 yield ' ' * (level * indent) |
104 yield b' ' * (level * indent) |
105 |
105 |
106 yield ']' |
106 yield b']' |
107 elif isinstance(o, dict): |
107 elif isinstance(o, dict): |
108 if not o: |
108 if not o: |
109 yield '{}' |
109 yield b'{}' |
110 return |
110 return |
111 |
111 |
112 yield '{' |
112 yield b'{' |
113 |
113 |
114 if indent: |
114 if indent: |
115 level += 1 |
115 level += 1 |
116 yield '\n' |
116 yield b'\n' |
117 yield ' ' * (level * indent) |
117 yield b' ' * (level * indent) |
118 |
118 |
119 for i, (k, v) in enumerate(sorted(o.items())): |
119 for i, (k, v) in enumerate(sorted(o.items())): |
120 for chunk in pprintgen( |
120 for chunk in pprintgen( |
121 k, bprefix=bprefix, indent=indent, level=level |
121 k, bprefix=bprefix, indent=indent, level=level |
122 ): |
122 ): |
123 yield chunk |
123 yield chunk |
124 |
124 |
125 yield ': ' |
125 yield b': ' |
126 |
126 |
127 for chunk in pprintgen( |
127 for chunk in pprintgen( |
128 v, bprefix=bprefix, indent=indent, level=level |
128 v, bprefix=bprefix, indent=indent, level=level |
129 ): |
129 ): |
130 yield chunk |
130 yield chunk |
131 |
131 |
132 if i + 1 < len(o): |
132 if i + 1 < len(o): |
133 if indent: |
133 if indent: |
134 yield ',\n' |
134 yield b',\n' |
135 yield ' ' * (level * indent) |
135 yield b' ' * (level * indent) |
136 else: |
136 else: |
137 yield ', ' |
137 yield b', ' |
138 |
138 |
139 if indent: |
139 if indent: |
140 level -= 1 |
140 level -= 1 |
141 yield '\n' |
141 yield b'\n' |
142 yield ' ' * (level * indent) |
142 yield b' ' * (level * indent) |
143 |
143 |
144 yield '}' |
144 yield b'}' |
145 elif isinstance(o, set): |
145 elif isinstance(o, set): |
146 if not o: |
146 if not o: |
147 yield 'set([])' |
147 yield b'set([])' |
148 return |
148 return |
149 |
149 |
150 yield 'set([' |
150 yield b'set([' |
151 |
151 |
152 if indent: |
152 if indent: |
153 level += 1 |
153 level += 1 |
154 yield '\n' |
154 yield b'\n' |
155 yield ' ' * (level * indent) |
155 yield b' ' * (level * indent) |
156 |
156 |
157 for i, k in enumerate(sorted(o)): |
157 for i, k in enumerate(sorted(o)): |
158 for chunk in pprintgen( |
158 for chunk in pprintgen( |
159 k, bprefix=bprefix, indent=indent, level=level |
159 k, bprefix=bprefix, indent=indent, level=level |
160 ): |
160 ): |
161 yield chunk |
161 yield chunk |
162 |
162 |
163 if i + 1 < len(o): |
163 if i + 1 < len(o): |
164 if indent: |
164 if indent: |
165 yield ',\n' |
165 yield b',\n' |
166 yield ' ' * (level * indent) |
166 yield b' ' * (level * indent) |
167 else: |
167 else: |
168 yield ', ' |
168 yield b', ' |
169 |
169 |
170 if indent: |
170 if indent: |
171 level -= 1 |
171 level -= 1 |
172 yield '\n' |
172 yield b'\n' |
173 yield ' ' * (level * indent) |
173 yield b' ' * (level * indent) |
174 |
174 |
175 yield '])' |
175 yield b'])' |
176 elif isinstance(o, tuple): |
176 elif isinstance(o, tuple): |
177 if not o: |
177 if not o: |
178 yield '()' |
178 yield b'()' |
179 return |
179 return |
180 |
180 |
181 yield '(' |
181 yield b'(' |
182 |
182 |
183 if indent: |
183 if indent: |
184 level += 1 |
184 level += 1 |
185 yield '\n' |
185 yield b'\n' |
186 yield ' ' * (level * indent) |
186 yield b' ' * (level * indent) |
187 |
187 |
188 for i, a in enumerate(o): |
188 for i, a in enumerate(o): |
189 for chunk in pprintgen( |
189 for chunk in pprintgen( |
190 a, bprefix=bprefix, indent=indent, level=level |
190 a, bprefix=bprefix, indent=indent, level=level |
191 ): |
191 ): |
192 yield chunk |
192 yield chunk |
193 |
193 |
194 if i + 1 < len(o): |
194 if i + 1 < len(o): |
195 if indent: |
195 if indent: |
196 yield ',\n' |
196 yield b',\n' |
197 yield ' ' * (level * indent) |
197 yield b' ' * (level * indent) |
198 else: |
198 else: |
199 yield ', ' |
199 yield b', ' |
200 |
200 |
201 if indent: |
201 if indent: |
202 level -= 1 |
202 level -= 1 |
203 yield '\n' |
203 yield b'\n' |
204 yield ' ' * (level * indent) |
204 yield b' ' * (level * indent) |
205 |
205 |
206 yield ')' |
206 yield b')' |
207 elif isinstance(o, types.GeneratorType): |
207 elif isinstance(o, types.GeneratorType): |
208 # Special case of empty generator. |
208 # Special case of empty generator. |
209 try: |
209 try: |
210 nextitem = next(o) |
210 nextitem = next(o) |
211 except StopIteration: |
211 except StopIteration: |
212 yield 'gen[]' |
212 yield b'gen[]' |
213 return |
213 return |
214 |
214 |
215 yield 'gen[' |
215 yield b'gen[' |
216 |
216 |
217 if indent: |
217 if indent: |
218 level += 1 |
218 level += 1 |
219 yield '\n' |
219 yield b'\n' |
220 yield ' ' * (level * indent) |
220 yield b' ' * (level * indent) |
221 |
221 |
222 last = False |
222 last = False |
223 |
223 |
224 while not last: |
224 while not last: |
225 current = nextitem |
225 current = nextitem |
259 while p0 < len(rs): |
259 while p0 < len(rs): |
260 # '... field=<type ... field=<type ...' |
260 # '... field=<type ... field=<type ...' |
261 # ~~~~~~~~~~~~~~~~ |
261 # ~~~~~~~~~~~~~~~~ |
262 # p0 p1 q0 q1 |
262 # p0 p1 q0 q1 |
263 q0 = -1 |
263 q0 = -1 |
264 q1 = rs.find('<', p1 + 1) |
264 q1 = rs.find(b'<', p1 + 1) |
265 if q1 < 0: |
265 if q1 < 0: |
266 q1 = len(rs) |
266 q1 = len(rs) |
267 elif q1 > p1 + 1 and rs.startswith('=', q1 - 1): |
267 elif q1 > p1 + 1 and rs.startswith(b'=', q1 - 1): |
268 # backtrack for ' field=<' |
268 # backtrack for ' field=<' |
269 q0 = rs.rfind(' ', p1 + 1, q1 - 1) |
269 q0 = rs.rfind(b' ', p1 + 1, q1 - 1) |
270 if q0 < 0: |
270 if q0 < 0: |
271 q0 = q1 |
271 q0 = q1 |
272 else: |
272 else: |
273 q0 += 1 # skip ' ' |
273 q0 += 1 # skip ' ' |
274 l = rs.count('<', 0, p0) - rs.count('>', 0, p0) |
274 l = rs.count(b'<', 0, p0) - rs.count(b'>', 0, p0) |
275 assert l >= 0 |
275 assert l >= 0 |
276 lines.append((l, rs[p0:q0].rstrip())) |
276 lines.append((l, rs[p0:q0].rstrip())) |
277 p0, p1 = q0, q1 |
277 p0, p1 = q0, q1 |
278 return '\n'.join(' ' * l + s for l, s in lines) |
278 return b'\n'.join(b' ' * l + s for l, s in lines) |
279 |
279 |
280 |
280 |
281 def buildrepr(r): |
281 def buildrepr(r): |
282 """Format an optional printable representation from unexpanded bits |
282 """Format an optional printable representation from unexpanded bits |
283 |
283 |
343 |
343 |
344 case insensitive literal matches |
344 case insensitive literal matches |
345 >>> itest(b'ABCDEFG', b'abc', b'def', b'abcdefg') |
345 >>> itest(b'ABCDEFG', b'abc', b'def', b'abcdefg') |
346 ('literal', 'ABCDEFG', [False, False, True]) |
346 ('literal', 'ABCDEFG', [False, False, True]) |
347 """ |
347 """ |
348 if pattern.startswith('re:'): |
348 if pattern.startswith(b're:'): |
349 pattern = pattern[3:] |
349 pattern = pattern[3:] |
350 try: |
350 try: |
351 flags = 0 |
351 flags = 0 |
352 if not casesensitive: |
352 if not casesensitive: |
353 flags = remod.I |
353 flags = remod.I |
354 regex = remod.compile(pattern, flags) |
354 regex = remod.compile(pattern, flags) |
355 except remod.error as e: |
355 except remod.error as e: |
356 raise error.ParseError(_('invalid regular expression: %s') % e) |
356 raise error.ParseError(_(b'invalid regular expression: %s') % e) |
357 return 're', pattern, regex.search |
357 return b're', pattern, regex.search |
358 elif pattern.startswith('literal:'): |
358 elif pattern.startswith(b'literal:'): |
359 pattern = pattern[8:] |
359 pattern = pattern[8:] |
360 |
360 |
361 match = pattern.__eq__ |
361 match = pattern.__eq__ |
362 |
362 |
363 if not casesensitive: |
363 if not casesensitive: |
364 ipat = encoding.lower(pattern) |
364 ipat = encoding.lower(pattern) |
365 match = lambda s: ipat == encoding.lower(s) |
365 match = lambda s: ipat == encoding.lower(s) |
366 return 'literal', pattern, match |
366 return b'literal', pattern, match |
367 |
367 |
368 |
368 |
369 def shortuser(user): |
369 def shortuser(user): |
370 """Return a short representation of a user name or email address.""" |
370 """Return a short representation of a user name or email address.""" |
371 f = user.find('@') |
371 f = user.find(b'@') |
372 if f >= 0: |
372 if f >= 0: |
373 user = user[:f] |
373 user = user[:f] |
374 f = user.find('<') |
374 f = user.find(b'<') |
375 if f >= 0: |
375 if f >= 0: |
376 user = user[f + 1 :] |
376 user = user[f + 1 :] |
377 f = user.find(' ') |
377 f = user.find(b' ') |
378 if f >= 0: |
378 if f >= 0: |
379 user = user[:f] |
379 user = user[:f] |
380 f = user.find('.') |
380 f = user.find(b'.') |
381 if f >= 0: |
381 if f >= 0: |
382 user = user[:f] |
382 user = user[:f] |
383 return user |
383 return user |
384 |
384 |
385 |
385 |
386 def emailuser(user): |
386 def emailuser(user): |
387 """Return the user portion of an email address.""" |
387 """Return the user portion of an email address.""" |
388 f = user.find('@') |
388 f = user.find(b'@') |
389 if f >= 0: |
389 if f >= 0: |
390 user = user[:f] |
390 user = user[:f] |
391 f = user.find('<') |
391 f = user.find(b'<') |
392 if f >= 0: |
392 if f >= 0: |
393 user = user[f + 1 :] |
393 user = user[f + 1 :] |
394 return user |
394 return user |
395 |
395 |
396 |
396 |
397 def email(author): |
397 def email(author): |
398 '''get email of author.''' |
398 '''get email of author.''' |
399 r = author.find('>') |
399 r = author.find(b'>') |
400 if r == -1: |
400 if r == -1: |
401 r = None |
401 r = None |
402 return author[author.find('<') + 1 : r] |
402 return author[author.find(b'<') + 1 : r] |
403 |
403 |
404 |
404 |
405 def person(author): |
405 def person(author): |
406 """Returns the name before an email address, |
406 """Returns the name before an email address, |
407 interpreting it as per RFC 5322 |
407 interpreting it as per RFC 5322 |
495 |
495 |
496 for line in mailmapcontent.splitlines(): |
496 for line in mailmapcontent.splitlines(): |
497 |
497 |
498 # Don't bother checking the line if it is a comment or |
498 # Don't bother checking the line if it is a comment or |
499 # is an improperly formed author field |
499 # is an improperly formed author field |
500 if line.lstrip().startswith('#'): |
500 if line.lstrip().startswith(b'#'): |
501 continue |
501 continue |
502 |
502 |
503 # names, emails hold the parsed emails and names for each line |
503 # names, emails hold the parsed emails and names for each line |
504 # name_builder holds the words in a persons name |
504 # name_builder holds the words in a persons name |
505 names, emails = [], [] |
505 names, emails = [], [] |
506 namebuilder = [] |
506 namebuilder = [] |
507 |
507 |
508 for element in line.split(): |
508 for element in line.split(): |
509 if element.startswith('#'): |
509 if element.startswith(b'#'): |
510 # If we reach a comment in the mailmap file, move on |
510 # If we reach a comment in the mailmap file, move on |
511 break |
511 break |
512 |
512 |
513 elif element.startswith('<') and element.endswith('>'): |
513 elif element.startswith(b'<') and element.endswith(b'>'): |
514 # We have found an email. |
514 # We have found an email. |
515 # Parse it, and finalize any names from earlier |
515 # Parse it, and finalize any names from earlier |
516 emails.append(element[1:-1]) # Slice off the "<>" |
516 emails.append(element[1:-1]) # Slice off the "<>" |
517 |
517 |
518 if namebuilder: |
518 if namebuilder: |
519 names.append(' '.join(namebuilder)) |
519 names.append(b' '.join(namebuilder)) |
520 namebuilder = [] |
520 namebuilder = [] |
521 |
521 |
522 # Break if we have found a second email, any other |
522 # Break if we have found a second email, any other |
523 # data does not fit the spec for .mailmap |
523 # data does not fit the spec for .mailmap |
524 if len(emails) > 1: |
524 if len(emails) > 1: |