def CompileTemplate(
    template_str, builder=None, meta='{}', format_char='|',
    more_formatters=lambda x: None, more_predicates=lambda x: None,
    default_formatter='str'):
  builder = builder or _ProgramBuilder(more_formatters, more_predicates)
  meta_left, meta_right = SplitMeta(meta)

  # : is meant to look like Python 3000 formatting {foo:.3f}.  According to
  # PEP 3101, that's also what .NET uses.
  # | is more readable, but, more importantly, reminiscent of pipes, which is
  # useful for multiple formatters, e.g. {name|js-string|html}
  if format_char not in (':', '|'):
    raise ConfigurationError(
        'Only format characters : and | are accepted (got %r)' % format_char)

  # If we go to -1, then we got too many {end}.  If end at 1, then we're missing
  # an {end}.
  balance_counter = 0

  for token_type, token in _Tokenize(template_str, meta_left, meta_right):

    if token_type == LITERAL_TOKEN:
      if token:
        builder.Append(token)
      continue

    if token_type in (SECTION_TOKEN, REPEATED_SECTION_TOKEN):
      builder.NewSection(token_type, token)
      balance_counter += 1
      continue

    if token_type == PREDICATE_TOKEN:
      # Everything of the form {.predicate?} starts a new predicate section
      block_made = builder.NewPredicateSection(token)
      balance_counter += 1
      continue

    if token_type == OR_TOKEN:
      builder.NewOrClause(token)
      continue

    if token_type == ALTERNATES_TOKEN:
      builder.AlternatesWith()
      continue

    if token_type == END_TOKEN:
      balance_counter -= 1
      if balance_counter < 0:
        # TODO: Show some context for errors
        raise TemplateSyntaxError(
            'Got too many %send%s statements.  You may have mistyped an '
            "earlier 'section' or 'repeated section' directive."
            % (meta_left, meta_right))
      builder.EndSection()
      continue

    if token_type == SUBSTITUTION_TOKEN:
      parts = token.split(format_char)
      if len(parts) == 1:
        if default_formatter is None:
          raise MissingFormatter('This template requires explicit formatters.')
        # If no formatter is specified, the default is the 'str' formatter,
        # which the user can define however they desire.
        name = token
        formatters = [default_formatter]
      else:
        name = parts[0]
        formatters = parts[1:]

      builder.AppendSubstitution(name, formatters)

  if balance_counter != 0:
    raise TemplateSyntaxError('Got too few %send%s statements' %
        (meta_left, meta_right))

  return builder.Root()
Get right.
dataset/ETHPy150Open cloudbuilders/radioedit/jsontemplate.py/CompileTemplate--crossover with--dataset/ETHPy150Open facelessuser/EasyDiff/easy_diff_basic.py/EasyDiffCompareBothClipboardCommand.get_right