comparison mercurial/templateutil.py @ 43077:687b865b95ad

formatting: byteify all mercurial/ and hgext/ string literals Done with python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py') black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**') # skip-blame mass-reformatting only Differential Revision: https://phab.mercurial-scm.org/D6972
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:48:39 -0400
parents 2372284d9457
children c59eb1560c44
comparison
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
128 item = stringify(context, mapping, item) 128 item = stringify(context, mapping, item)
129 return item in self._value 129 return item in self._value
130 130
131 def getmember(self, context, mapping, key): 131 def getmember(self, context, mapping, key):
132 raise error.ParseError( 132 raise error.ParseError(
133 _('%r is not a dictionary') % pycompat.bytestr(self._value) 133 _(b'%r is not a dictionary') % pycompat.bytestr(self._value)
134 ) 134 )
135 135
136 def getmin(self, context, mapping): 136 def getmin(self, context, mapping):
137 return self._getby(context, mapping, min) 137 return self._getby(context, mapping, min)
138 138
139 def getmax(self, context, mapping): 139 def getmax(self, context, mapping):
140 return self._getby(context, mapping, max) 140 return self._getby(context, mapping, max)
141 141
142 def _getby(self, context, mapping, func): 142 def _getby(self, context, mapping, func):
143 if not self._value: 143 if not self._value:
144 raise error.ParseError(_('empty string')) 144 raise error.ParseError(_(b'empty string'))
145 return func(pycompat.iterbytestr(self._value)) 145 return func(pycompat.iterbytestr(self._value))
146 146
147 def filter(self, context, mapping, select): 147 def filter(self, context, mapping, select):
148 raise error.ParseError( 148 raise error.ParseError(
149 _('%r is not filterable') % pycompat.bytestr(self._value) 149 _(b'%r is not filterable') % pycompat.bytestr(self._value)
150 ) 150 )
151 151
152 def itermaps(self, context): 152 def itermaps(self, context):
153 raise error.ParseError( 153 raise error.ParseError(
154 _('%r is not iterable of mappings') % pycompat.bytestr(self._value) 154 _(b'%r is not iterable of mappings') % pycompat.bytestr(self._value)
155 ) 155 )
156 156
157 def join(self, context, mapping, sep): 157 def join(self, context, mapping, sep):
158 return joinitems(pycompat.iterbytestr(self._value), sep) 158 return joinitems(pycompat.iterbytestr(self._value), sep)
159 159
172 172
173 def __init__(self, value): 173 def __init__(self, value):
174 self._value = value 174 self._value = value
175 175
176 def contains(self, context, mapping, item): 176 def contains(self, context, mapping, item):
177 raise error.ParseError(_("%r is not iterable") % self._value) 177 raise error.ParseError(_(b"%r is not iterable") % self._value)
178 178
179 def getmember(self, context, mapping, key): 179 def getmember(self, context, mapping, key):
180 raise error.ParseError(_('%r is not a dictionary') % self._value) 180 raise error.ParseError(_(b'%r is not a dictionary') % self._value)
181 181
182 def getmin(self, context, mapping): 182 def getmin(self, context, mapping):
183 raise error.ParseError(_("%r is not iterable") % self._value) 183 raise error.ParseError(_(b"%r is not iterable") % self._value)
184 184
185 def getmax(self, context, mapping): 185 def getmax(self, context, mapping):
186 raise error.ParseError(_("%r is not iterable") % self._value) 186 raise error.ParseError(_(b"%r is not iterable") % self._value)
187 187
188 def filter(self, context, mapping, select): 188 def filter(self, context, mapping, select):
189 raise error.ParseError(_("%r is not iterable") % self._value) 189 raise error.ParseError(_(b"%r is not iterable") % self._value)
190 190
191 def itermaps(self, context): 191 def itermaps(self, context):
192 raise error.ParseError( 192 raise error.ParseError(
193 _('%r is not iterable of mappings') % self._value 193 _(b'%r is not iterable of mappings') % self._value
194 ) 194 )
195 195
196 def join(self, context, mapping, sep): 196 def join(self, context, mapping, sep):
197 raise error.ParseError(_('%r is not iterable') % self._value) 197 raise error.ParseError(_(b'%r is not iterable') % self._value)
198 198
199 def show(self, context, mapping): 199 def show(self, context, mapping):
200 if self._value is None: 200 if self._value is None:
201 return b'' 201 return b''
202 return pycompat.bytestr(self._value) 202 return pycompat.bytestr(self._value)
214 214
215 215
216 class date(mappable, wrapped): 216 class date(mappable, wrapped):
217 """Wrapper for date tuple""" 217 """Wrapper for date tuple"""
218 218
219 def __init__(self, value, showfmt='%d %d'): 219 def __init__(self, value, showfmt=b'%d %d'):
220 # value may be (float, int), but public interface shouldn't support 220 # value may be (float, int), but public interface shouldn't support
221 # floating-point timestamp 221 # floating-point timestamp
222 self._unixtime, self._tzoffset = map(int, value) 222 self._unixtime, self._tzoffset = map(int, value)
223 self._showfmt = showfmt 223 self._showfmt = showfmt
224 224
225 def contains(self, context, mapping, item): 225 def contains(self, context, mapping, item):
226 raise error.ParseError(_('date is not iterable')) 226 raise error.ParseError(_(b'date is not iterable'))
227 227
228 def getmember(self, context, mapping, key): 228 def getmember(self, context, mapping, key):
229 raise error.ParseError(_('date is not a dictionary')) 229 raise error.ParseError(_(b'date is not a dictionary'))
230 230
231 def getmin(self, context, mapping): 231 def getmin(self, context, mapping):
232 raise error.ParseError(_('date is not iterable')) 232 raise error.ParseError(_(b'date is not iterable'))
233 233
234 def getmax(self, context, mapping): 234 def getmax(self, context, mapping):
235 raise error.ParseError(_('date is not iterable')) 235 raise error.ParseError(_(b'date is not iterable'))
236 236
237 def filter(self, context, mapping, select): 237 def filter(self, context, mapping, select):
238 raise error.ParseError(_('date is not iterable')) 238 raise error.ParseError(_(b'date is not iterable'))
239 239
240 def join(self, context, mapping, sep): 240 def join(self, context, mapping, sep):
241 raise error.ParseError(_("date is not iterable")) 241 raise error.ParseError(_(b"date is not iterable"))
242 242
243 def show(self, context, mapping): 243 def show(self, context, mapping):
244 return self._showfmt % (self._unixtime, self._tzoffset) 244 return self._showfmt % (self._unixtime, self._tzoffset)
245 245
246 def tomap(self, context): 246 def tomap(self, context):
247 return {'unixtime': self._unixtime, 'tzoffset': self._tzoffset} 247 return {b'unixtime': self._unixtime, b'tzoffset': self._tzoffset}
248 248
249 def tobool(self, context, mapping): 249 def tobool(self, context, mapping):
250 return True 250 return True
251 251
252 def tovalue(self, context, mapping): 252 def tovalue(self, context, mapping):
276 item = unwrapastype(context, mapping, item, self._keytype) 276 item = unwrapastype(context, mapping, item, self._keytype)
277 return item in self._values 277 return item in self._values
278 278
279 def getmember(self, context, mapping, key): 279 def getmember(self, context, mapping, key):
280 # TODO: maybe split hybrid list/dict types? 280 # TODO: maybe split hybrid list/dict types?
281 if not util.safehasattr(self._values, 'get'): 281 if not util.safehasattr(self._values, b'get'):
282 raise error.ParseError(_('not a dictionary')) 282 raise error.ParseError(_(b'not a dictionary'))
283 key = unwrapastype(context, mapping, key, self._keytype) 283 key = unwrapastype(context, mapping, key, self._keytype)
284 return self._wrapvalue(key, self._values.get(key)) 284 return self._wrapvalue(key, self._values.get(key))
285 285
286 def getmin(self, context, mapping): 286 def getmin(self, context, mapping):
287 return self._getby(context, mapping, min) 287 return self._getby(context, mapping, min)
289 def getmax(self, context, mapping): 289 def getmax(self, context, mapping):
290 return self._getby(context, mapping, max) 290 return self._getby(context, mapping, max)
291 291
292 def _getby(self, context, mapping, func): 292 def _getby(self, context, mapping, func):
293 if not self._values: 293 if not self._values:
294 raise error.ParseError(_('empty sequence')) 294 raise error.ParseError(_(b'empty sequence'))
295 val = func(self._values) 295 val = func(self._values)
296 return self._wrapvalue(val, val) 296 return self._wrapvalue(val, val)
297 297
298 def _wrapvalue(self, key, val): 298 def _wrapvalue(self, key, val):
299 if val is None: 299 if val is None:
300 return 300 return
301 if util.safehasattr(val, '_makemap'): 301 if util.safehasattr(val, b'_makemap'):
302 # a nested hybrid list/dict, which has its own way of map operation 302 # a nested hybrid list/dict, which has its own way of map operation
303 return val 303 return val
304 return hybriditem(None, key, val, self._makemap) 304 return hybriditem(None, key, val, self._makemap)
305 305
306 def filter(self, context, mapping, select): 306 def filter(self, context, mapping, select):
307 if util.safehasattr(self._values, 'get'): 307 if util.safehasattr(self._values, b'get'):
308 values = { 308 values = {
309 k: v 309 k: v
310 for k, v in self._values.iteritems() 310 for k, v in self._values.iteritems()
311 if select(self._wrapvalue(k, v)) 311 if select(self._wrapvalue(k, v))
312 } 312 }
325 325
326 def show(self, context, mapping): 326 def show(self, context, mapping):
327 # TODO: switch gen to (context, mapping) API? 327 # TODO: switch gen to (context, mapping) API?
328 gen = self._gen 328 gen = self._gen
329 if gen is None: 329 if gen is None:
330 return self.join(context, mapping, ' ') 330 return self.join(context, mapping, b' ')
331 if callable(gen): 331 if callable(gen):
332 return gen() 332 return gen()
333 return gen 333 return gen
334 334
335 def tobool(self, context, mapping): 335 def tobool(self, context, mapping):
336 return bool(self._values) 336 return bool(self._values)
337 337
338 def tovalue(self, context, mapping): 338 def tovalue(self, context, mapping):
339 # TODO: make it non-recursive for trivial lists/dicts 339 # TODO: make it non-recursive for trivial lists/dicts
340 xs = self._values 340 xs = self._values
341 if util.safehasattr(xs, 'get'): 341 if util.safehasattr(xs, b'get'):
342 return { 342 return {
343 k: unwrapvalue(context, mapping, v) for k, v in xs.iteritems() 343 k: unwrapvalue(context, mapping, v) for k, v in xs.iteritems()
344 } 344 }
345 return [unwrapvalue(context, mapping, x) for x in xs] 345 return [unwrapvalue(context, mapping, x) for x in xs]
346 346
411 which can also be rendered by the specified named/literal template. 411 which can also be rendered by the specified named/literal template.
412 412
413 Template mappings may be nested. 413 Template mappings may be nested.
414 """ 414 """
415 415
416 def __init__(self, name=None, tmpl=None, sep=''): 416 def __init__(self, name=None, tmpl=None, sep=b''):
417 if name is not None and tmpl is not None: 417 if name is not None and tmpl is not None:
418 raise error.ProgrammingError('name and tmpl are mutually exclusive') 418 raise error.ProgrammingError(
419 b'name and tmpl are mutually exclusive'
420 )
419 self._name = name 421 self._name = name
420 self._tmpl = tmpl 422 self._tmpl = tmpl
421 self._defaultsep = sep 423 self._defaultsep = sep
422 424
423 def contains(self, context, mapping, item): 425 def contains(self, context, mapping, item):
424 raise error.ParseError(_('not comparable')) 426 raise error.ParseError(_(b'not comparable'))
425 427
426 def getmember(self, context, mapping, key): 428 def getmember(self, context, mapping, key):
427 raise error.ParseError(_('not a dictionary')) 429 raise error.ParseError(_(b'not a dictionary'))
428 430
429 def getmin(self, context, mapping): 431 def getmin(self, context, mapping):
430 raise error.ParseError(_('not comparable')) 432 raise error.ParseError(_(b'not comparable'))
431 433
432 def getmax(self, context, mapping): 434 def getmax(self, context, mapping):
433 raise error.ParseError(_('not comparable')) 435 raise error.ParseError(_(b'not comparable'))
434 436
435 def filter(self, context, mapping, select): 437 def filter(self, context, mapping, select):
436 # implement if necessary; we'll need a wrapped type for a mapping dict 438 # implement if necessary; we'll need a wrapped type for a mapping dict
437 raise error.ParseError(_('not filterable without template')) 439 raise error.ParseError(_(b'not filterable without template'))
438 440
439 def join(self, context, mapping, sep): 441 def join(self, context, mapping, sep):
440 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context)) 442 mapsiter = _iteroverlaymaps(context, mapping, self.itermaps(context))
441 if self._name: 443 if self._name:
442 itemiter = (context.process(self._name, m) for m in mapsiter) 444 itemiter = (context.process(self._name, m) for m in mapsiter)
443 elif self._tmpl: 445 elif self._tmpl:
444 itemiter = (context.expand(self._tmpl, m) for m in mapsiter) 446 itemiter = (context.expand(self._tmpl, m) for m in mapsiter)
445 else: 447 else:
446 raise error.ParseError(_('not displayable without template')) 448 raise error.ParseError(_(b'not displayable without template'))
447 return joinitems(itemiter, sep) 449 return joinitems(itemiter, sep)
448 450
449 def show(self, context, mapping): 451 def show(self, context, mapping):
450 return self.join(context, mapping, self._defaultsep) 452 return self.join(context, mapping, self._defaultsep)
451 453
470 472
471 The function ``make(context, *args)`` should return a generator of 473 The function ``make(context, *args)`` should return a generator of
472 mapping dicts. 474 mapping dicts.
473 """ 475 """
474 476
475 def __init__(self, make, args=(), name=None, tmpl=None, sep=''): 477 def __init__(self, make, args=(), name=None, tmpl=None, sep=b''):
476 super(mappinggenerator, self).__init__(name, tmpl, sep) 478 super(mappinggenerator, self).__init__(name, tmpl, sep)
477 self._make = make 479 self._make = make
478 self._args = args 480 self._args = args
479 481
480 def itermaps(self, context): 482 def itermaps(self, context):
485 487
486 488
487 class mappinglist(_mappingsequence): 489 class mappinglist(_mappingsequence):
488 """Wrapper for list of template mappings""" 490 """Wrapper for list of template mappings"""
489 491
490 def __init__(self, mappings, name=None, tmpl=None, sep=''): 492 def __init__(self, mappings, name=None, tmpl=None, sep=b''):
491 super(mappinglist, self).__init__(name, tmpl, sep) 493 super(mappinglist, self).__init__(name, tmpl, sep)
492 self._mappings = mappings 494 self._mappings = mappings
493 495
494 def itermaps(self, context): 496 def itermaps(self, context):
495 return iter(self._mappings) 497 return iter(self._mappings)
554 556
555 def _gen(self, context): 557 def _gen(self, context):
556 return self._make(context, *self._args) 558 return self._make(context, *self._args)
557 559
558 def getmember(self, context, mapping, key): 560 def getmember(self, context, mapping, key):
559 raise error.ParseError(_('not a dictionary')) 561 raise error.ParseError(_(b'not a dictionary'))
560 562
561 def getmin(self, context, mapping): 563 def getmin(self, context, mapping):
562 return self._getby(context, mapping, min) 564 return self._getby(context, mapping, min)
563 565
564 def getmax(self, context, mapping): 566 def getmax(self, context, mapping):
565 return self._getby(context, mapping, max) 567 return self._getby(context, mapping, max)
566 568
567 def _getby(self, context, mapping, func): 569 def _getby(self, context, mapping, func):
568 xs = self.tovalue(context, mapping) 570 xs = self.tovalue(context, mapping)
569 if not xs: 571 if not xs:
570 raise error.ParseError(_('empty sequence')) 572 raise error.ParseError(_(b'empty sequence'))
571 return func(xs) 573 return func(xs)
572 574
573 @staticmethod 575 @staticmethod
574 def _filteredgen(context, mapping, make, args, select): 576 def _filteredgen(context, mapping, make, args, select):
575 for x in make(context, *args): 577 for x in make(context, *args):
580 def filter(self, context, mapping, select): 582 def filter(self, context, mapping, select):
581 args = (mapping, self._make, self._args, select) 583 args = (mapping, self._make, self._args, select)
582 return mappedgenerator(self._filteredgen, args) 584 return mappedgenerator(self._filteredgen, args)
583 585
584 def itermaps(self, context): 586 def itermaps(self, context):
585 raise error.ParseError(_('list of strings is not mappable')) 587 raise error.ParseError(_(b'list of strings is not mappable'))
586 588
587 def join(self, context, mapping, sep): 589 def join(self, context, mapping, sep):
588 return joinitems(self._gen(context), sep) 590 return joinitems(self._gen(context), sep)
589 591
590 def show(self, context, mapping): 592 def show(self, context, mapping):
591 return self.join(context, mapping, '') 593 return self.join(context, mapping, b'')
592 594
593 def tobool(self, context, mapping): 595 def tobool(self, context, mapping):
594 return _nonempty(self._gen(context)) 596 return _nonempty(self._gen(context))
595 597
596 def tovalue(self, context, mapping): 598 def tovalue(self, context, mapping):
597 return [stringify(context, mapping, x) for x in self._gen(context)] 599 return [stringify(context, mapping, x) for x in self._gen(context)]
598 600
599 601
600 def hybriddict(data, key='key', value='value', fmt=None, gen=None): 602 def hybriddict(data, key=b'key', value=b'value', fmt=None, gen=None):
601 """Wrap data to support both dict-like and string-like operations""" 603 """Wrap data to support both dict-like and string-like operations"""
602 prefmt = pycompat.identity 604 prefmt = pycompat.identity
603 if fmt is None: 605 if fmt is None:
604 fmt = '%s=%s' 606 fmt = b'%s=%s'
605 prefmt = pycompat.bytestr 607 prefmt = pycompat.bytestr
606 return hybrid( 608 return hybrid(
607 gen, 609 gen,
608 data, 610 data,
609 lambda k: {key: k, value: data[k]}, 611 lambda k: {key: k, value: data[k]},
613 615
614 def hybridlist(data, name, fmt=None, gen=None): 616 def hybridlist(data, name, fmt=None, gen=None):
615 """Wrap data to support both list-like and string-like operations""" 617 """Wrap data to support both list-like and string-like operations"""
616 prefmt = pycompat.identity 618 prefmt = pycompat.identity
617 if fmt is None: 619 if fmt is None:
618 fmt = '%s' 620 fmt = b'%s'
619 prefmt = pycompat.bytestr 621 prefmt = pycompat.bytestr
620 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x)) 622 return hybrid(gen, data, lambda x: {name: x}, lambda x: fmt % prefmt(x))
621 623
622 624
623 def compatdict( 625 def compatdict(
624 context, 626 context,
625 mapping, 627 mapping,
626 name, 628 name,
627 data, 629 data,
628 key='key', 630 key=b'key',
629 value='value', 631 value=b'value',
630 fmt=None, 632 fmt=None,
631 plural=None, 633 plural=None,
632 separator=' ', 634 separator=b' ',
633 ): 635 ):
634 """Wrap data like hybriddict(), but also supports old-style list template 636 """Wrap data like hybriddict(), but also supports old-style list template
635 637
636 This exists for backward compatibility with the old-style template. Use 638 This exists for backward compatibility with the old-style template. Use
637 hybriddict() for new template keywords. 639 hybriddict() for new template keywords.
647 name, 649 name,
648 data, 650 data,
649 element=None, 651 element=None,
650 fmt=None, 652 fmt=None,
651 plural=None, 653 plural=None,
652 separator=' ', 654 separator=b' ',
653 ): 655 ):
654 """Wrap data like hybridlist(), but also supports old-style list template 656 """Wrap data like hybridlist(), but also supports old-style list template
655 657
656 This exists for backward compatibility with the old-style template. Use 658 This exists for backward compatibility with the old-style template. Use
657 hybridlist() for new template keywords. 659 hybridlist() for new template keywords.
666 668
667 This exists for backward compatibility. Use hybriddict for new template 669 This exists for backward compatibility. Use hybriddict for new template
668 keywords. 670 keywords.
669 """ 671 """
670 # no need to provide {path} to old-style list template 672 # no need to provide {path} to old-style list template
671 c = [{'name': k, 'source': v} for k, v in copies] 673 c = [{b'name': k, b'source': v} for k, v in copies]
672 f = _showcompatlist(context, mapping, name, c, plural='file_copies') 674 f = _showcompatlist(context, mapping, name, c, plural=b'file_copies')
673 copies = util.sortdict(copies) 675 copies = util.sortdict(copies)
674 return hybrid( 676 return hybrid(
675 f, 677 f,
676 copies, 678 copies,
677 lambda k: {'name': k, 'path': k, 'source': copies[k]}, 679 lambda k: {b'name': k, b'path': k, b'source': copies[k]},
678 lambda k: '%s (%s)' % (k, copies[k]), 680 lambda k: b'%s (%s)' % (k, copies[k]),
679 ) 681 )
680 682
681 683
682 def compatfileslist(context, mapping, name, files): 684 def compatfileslist(context, mapping, name, files):
683 """Wrap list of file names to support old-style list template and field 685 """Wrap list of file names to support old-style list template and field
685 687
686 This exists for backward compatibility. Use hybridlist for new template 688 This exists for backward compatibility. Use hybridlist for new template
687 keywords. 689 keywords.
688 """ 690 """
689 f = _showcompatlist(context, mapping, name, files) 691 f = _showcompatlist(context, mapping, name, files)
690 return hybrid(f, files, lambda x: {'file': x, 'path': x}, pycompat.identity) 692 return hybrid(
691 693 f, files, lambda x: {b'file': x, b'path': x}, pycompat.identity
692 694 )
693 def _showcompatlist(context, mapping, name, values, plural=None, separator=' '): 695
696
697 def _showcompatlist(
698 context, mapping, name, values, plural=None, separator=b' '
699 ):
694 """Return a generator that renders old-style list template 700 """Return a generator that renders old-style list template
695 701
696 name is name of key in template map. 702 name is name of key in template map.
697 values is list of strings or dicts. 703 values is list of strings or dicts.
698 plural is plural of name, if not simply name + 's'. 704 plural is plural of name, if not simply name + 's'.
711 map, expand it instead of 'foo' for last key. 717 map, expand it instead of 'foo' for last key.
712 718
713 expand 'end_foos'. 719 expand 'end_foos'.
714 """ 720 """
715 if not plural: 721 if not plural:
716 plural = name + 's' 722 plural = name + b's'
717 if not values: 723 if not values:
718 noname = 'no_' + plural 724 noname = b'no_' + plural
719 if context.preload(noname): 725 if context.preload(noname):
720 yield context.process(noname, mapping) 726 yield context.process(noname, mapping)
721 return 727 return
722 if not context.preload(name): 728 if not context.preload(name):
723 if isinstance(values[0], bytes): 729 if isinstance(values[0], bytes):
726 for v in values: 732 for v in values:
727 r = dict(v) 733 r = dict(v)
728 r.update(mapping) 734 r.update(mapping)
729 yield r 735 yield r
730 return 736 return
731 startname = 'start_' + plural 737 startname = b'start_' + plural
732 if context.preload(startname): 738 if context.preload(startname):
733 yield context.process(startname, mapping) 739 yield context.process(startname, mapping)
734 740
735 def one(v, tag=name): 741 def one(v, tag=name):
736 vmapping = {} 742 vmapping = {}
747 except (TypeError, ValueError): 753 except (TypeError, ValueError):
748 vmapping[name] = v 754 vmapping[name] = v
749 vmapping = context.overlaymap(mapping, vmapping) 755 vmapping = context.overlaymap(mapping, vmapping)
750 return context.process(tag, vmapping) 756 return context.process(tag, vmapping)
751 757
752 lastname = 'last_' + name 758 lastname = b'last_' + name
753 if context.preload(lastname): 759 if context.preload(lastname):
754 last = values.pop() 760 last = values.pop()
755 else: 761 else:
756 last = None 762 last = None
757 for v in values: 763 for v in values:
758 yield one(v) 764 yield one(v)
759 if last is not None: 765 if last is not None:
760 yield one(last, tag=lastname) 766 yield one(last, tag=lastname)
761 endname = 'end_' + plural 767 endname = b'end_' + plural
762 if context.preload(endname): 768 if context.preload(endname):
763 yield context.process(endname, mapping) 769 yield context.process(endname, mapping)
764 770
765 771
766 def flatten(context, mapping, thing): 772 def flatten(context, mapping, thing):
771 yield thing 777 yield thing
772 elif isinstance(thing, str): 778 elif isinstance(thing, str):
773 # We can only hit this on Python 3, and it's here to guard 779 # We can only hit this on Python 3, and it's here to guard
774 # against infinite recursion. 780 # against infinite recursion.
775 raise error.ProgrammingError( 781 raise error.ProgrammingError(
776 'Mercurial IO including templates is done' 782 b'Mercurial IO including templates is done'
777 ' with bytes, not strings, got %r' % thing 783 b' with bytes, not strings, got %r' % thing
778 ) 784 )
779 elif thing is None: 785 elif thing is None:
780 pass 786 pass
781 elif not util.safehasattr(thing, '__iter__'): 787 elif not util.safehasattr(thing, b'__iter__'):
782 yield pycompat.bytestr(thing) 788 yield pycompat.bytestr(thing)
783 else: 789 else:
784 for i in thing: 790 for i in thing:
785 if isinstance(i, wrapped): 791 if isinstance(i, wrapped):
786 i = i.show(context, mapping) 792 i = i.show(context, mapping)
787 if isinstance(i, bytes): 793 if isinstance(i, bytes):
788 yield i 794 yield i
789 elif i is None: 795 elif i is None:
790 pass 796 pass
791 elif not util.safehasattr(i, '__iter__'): 797 elif not util.safehasattr(i, b'__iter__'):
792 yield pycompat.bytestr(i) 798 yield pycompat.bytestr(i)
793 else: 799 else:
794 for j in flatten(context, mapping, i): 800 for j in flatten(context, mapping, i):
795 yield j 801 yield j
796 802
893 # TODO: update hgweb to not return bare tuple; then just stringify 'thing' 899 # TODO: update hgweb to not return bare tuple; then just stringify 'thing'
894 thing = unwrapvalue(context, mapping, thing) 900 thing = unwrapvalue(context, mapping, thing)
895 try: 901 try:
896 return dateutil.parsedate(thing) 902 return dateutil.parsedate(thing)
897 except AttributeError: 903 except AttributeError:
898 raise error.ParseError(err or _('not a date tuple nor a string')) 904 raise error.ParseError(err or _(b'not a date tuple nor a string'))
899 except error.ParseError: 905 except error.ParseError:
900 if not err: 906 if not err:
901 raise 907 raise
902 raise error.ParseError(err) 908 raise error.ParseError(err)
903 909
910 def unwrapinteger(context, mapping, thing, err=None): 916 def unwrapinteger(context, mapping, thing, err=None):
911 thing = unwrapvalue(context, mapping, thing) 917 thing = unwrapvalue(context, mapping, thing)
912 try: 918 try:
913 return int(thing) 919 return int(thing)
914 except (TypeError, ValueError): 920 except (TypeError, ValueError):
915 raise error.ParseError(err or _('not an integer')) 921 raise error.ParseError(err or _(b'not an integer'))
916 922
917 923
918 def evalstring(context, mapping, arg): 924 def evalstring(context, mapping, arg):
919 return stringify(context, mapping, evalrawexp(context, mapping, arg)) 925 return stringify(context, mapping, evalrawexp(context, mapping, arg))
920 926
941 def unwrapastype(context, mapping, thing, typ): 947 def unwrapastype(context, mapping, thing, typ):
942 """Move the inner value object out of the wrapper and coerce its type""" 948 """Move the inner value object out of the wrapper and coerce its type"""
943 try: 949 try:
944 f = _unwrapfuncbytype[typ] 950 f = _unwrapfuncbytype[typ]
945 except KeyError: 951 except KeyError:
946 raise error.ProgrammingError('invalid type specified: %r' % typ) 952 raise error.ProgrammingError(b'invalid type specified: %r' % typ)
947 return f(context, mapping, thing) 953 return f(context, mapping, thing)
948 954
949 955
950 def runinteger(context, mapping, data): 956 def runinteger(context, mapping, data):
951 return int(data) 957 return int(data)
955 return data 961 return data
956 962
957 963
958 def _recursivesymbolblocker(key): 964 def _recursivesymbolblocker(key):
959 def showrecursion(context, mapping): 965 def showrecursion(context, mapping):
960 raise error.Abort(_("recursive reference '%s' in template") % key) 966 raise error.Abort(_(b"recursive reference '%s' in template") % key)
961 967
962 return showrecursion 968 return showrecursion
963 969
964 970
965 def runsymbol(context, mapping, key, default=''): 971 def runsymbol(context, mapping, key, default=b''):
966 v = context.symbol(mapping, key) 972 v = context.symbol(mapping, key)
967 if v is None: 973 if v is None:
968 # put poison to cut recursion. we can't move this to parsing phase 974 # put poison to cut recursion. we can't move this to parsing phase
969 # because "x = {x}" is allowed if "x" is a keyword. (issue4758) 975 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
970 safemapping = mapping.copy() 976 safemapping = mapping.copy()
1001 1007
1002 def _formatfiltererror(arg, filt): 1008 def _formatfiltererror(arg, filt):
1003 fn = pycompat.sysbytes(filt.__name__) 1009 fn = pycompat.sysbytes(filt.__name__)
1004 sym = findsymbolicname(arg) 1010 sym = findsymbolicname(arg)
1005 if not sym: 1011 if not sym:
1006 return _("incompatible use of template filter '%s'") % fn 1012 return _(b"incompatible use of template filter '%s'") % fn
1007 return _("template filter '%s' is not compatible with keyword '%s'") % ( 1013 return _(b"template filter '%s' is not compatible with keyword '%s'") % (
1008 fn, 1014 fn,
1009 sym, 1015 sym,
1010 ) 1016 )
1011 1017
1012 1018
1013 def _iteroverlaymaps(context, origmapping, newmappings): 1019 def _iteroverlaymaps(context, origmapping, newmappings):
1014 """Generate combined mappings from the original mapping and an iterable 1020 """Generate combined mappings from the original mapping and an iterable
1015 of partial mappings to override the original""" 1021 of partial mappings to override the original"""
1016 for i, nm in enumerate(newmappings): 1022 for i, nm in enumerate(newmappings):
1017 lm = context.overlaymap(origmapping, nm) 1023 lm = context.overlaymap(origmapping, nm)
1018 lm['index'] = i 1024 lm[b'index'] = i
1019 yield lm 1025 yield lm
1020 1026
1021 1027
1022 def _applymap(context, mapping, d, darg, targ): 1028 def _applymap(context, mapping, d, darg, targ):
1023 try: 1029 try:
1024 diter = d.itermaps(context) 1030 diter = d.itermaps(context)
1025 except error.ParseError as err: 1031 except error.ParseError as err:
1026 sym = findsymbolicname(darg) 1032 sym = findsymbolicname(darg)
1027 if not sym: 1033 if not sym:
1028 raise 1034 raise
1029 hint = _("keyword '%s' does not support map operation") % sym 1035 hint = _(b"keyword '%s' does not support map operation") % sym
1030 raise error.ParseError(bytes(err), hint=hint) 1036 raise error.ParseError(bytes(err), hint=hint)
1031 for lm in _iteroverlaymaps(context, mapping, diter): 1037 for lm in _iteroverlaymaps(context, mapping, diter):
1032 yield evalrawexp(context, lm, targ) 1038 yield evalrawexp(context, lm, targ)
1033 1039
1034 1040
1048 return d.getmember(context, mapping, memb) 1054 return d.getmember(context, mapping, memb)
1049 except error.ParseError as err: 1055 except error.ParseError as err:
1050 sym = findsymbolicname(darg) 1056 sym = findsymbolicname(darg)
1051 if not sym: 1057 if not sym:
1052 raise 1058 raise
1053 hint = _("keyword '%s' does not support member operation") % sym 1059 hint = _(b"keyword '%s' does not support member operation") % sym
1054 raise error.ParseError(bytes(err), hint=hint) 1060 raise error.ParseError(bytes(err), hint=hint)
1055 1061
1056 1062
1057 def runnegate(context, mapping, data): 1063 def runnegate(context, mapping, data):
1058 data = evalinteger( 1064 data = evalinteger(
1059 context, mapping, data, _('negation needs an integer argument') 1065 context, mapping, data, _(b'negation needs an integer argument')
1060 ) 1066 )
1061 return -data 1067 return -data
1062 1068
1063 1069
1064 def runarithmetic(context, mapping, data): 1070 def runarithmetic(context, mapping, data):
1065 func, left, right = data 1071 func, left, right = data
1066 left = evalinteger( 1072 left = evalinteger(
1067 context, mapping, left, _('arithmetic only defined on integers') 1073 context, mapping, left, _(b'arithmetic only defined on integers')
1068 ) 1074 )
1069 right = evalinteger( 1075 right = evalinteger(
1070 context, mapping, right, _('arithmetic only defined on integers') 1076 context, mapping, right, _(b'arithmetic only defined on integers')
1071 ) 1077 )
1072 try: 1078 try:
1073 return func(left, right) 1079 return func(left, right)
1074 except ZeroDivisionError: 1080 except ZeroDivisionError:
1075 raise error.Abort(_('division by zero is not defined')) 1081 raise error.Abort(_(b'division by zero is not defined'))
1076 1082
1077 1083
1078 def joinitems(itemiter, sep): 1084 def joinitems(itemiter, sep):
1079 """Join items with the separator; Returns generator of bytes""" 1085 """Join items with the separator; Returns generator of bytes"""
1080 first = True 1086 first = True