def render(template='', data={}, partials_path='.', partials_ext='mustache',
           partials_dict={}, padding='', def_ldel='{{', def_rdel='}}',
           scopes=None):
    """Render a mustache template.

    Renders a mustache template with a data scope and partial capability.
    Given the file structure...
    ╷
    ├─╼ main.py
    ├─╼ main.ms
    └─┮ partials
      └── part.ms

    then main.py would make the following call:

    render(open('main.ms', 'r'), {...}, 'partials', 'ms')


    Arguments:

    template      -- A file-like object or a string containing the template

    data          -- A python dictionary with your data scope

    partials_path -- The path to where your partials are stored
                     (defaults to '.')

    partials_ext  -- The extension that you want the parser to look for
                     (defaults to 'mustache')

    partials_dict -- A python dictionary which will be search for partials
                     before the filesystem is. {'include': 'foo'} is the same
                     as a file called include.mustache
                     (defaults to {})

    padding       -- This is for padding partials, and shouldn't be used
                     (but can be if you really want to)

    def_ldel      -- The default left delimiter
                     ("{{" by default, as in spec compliant mustache)

    def_rdel      -- The default right delimiter
                     ("}}" by default, as in spec compliant mustache)

    scopes        -- The list of scopes that get_key will look through


    Returns:

    A string containing the rendered template.
    """

    # If the template is a seqeuence but not derived from a string
    if isinstance(template, Sequence) and \
            not isinstance(template, string_type):
        # Then we don't need to tokenize it
        # But it does need to be a generator
        tokens = (token for token in template)
    else:
        if template in g_token_cache:
            tokens = (token for token in g_token_cache[template])
        else:
            # Otherwise make a generator
            tokens = tokenize(template, def_ldel, def_rdel)

    output = unicode('', 'utf-8')

    if scopes is None:
        scopes = [data]

    # Run through the tokens
    for tag, key in tokens:
        # Set the current scope
        current_scope = scopes[0]

        # If we're an end tag
        if tag == 'end':
            # Pop out of the latest scope
            del scopes[0]

        # If the current scope is falsy and not the only scope
        elif not current_scope and len(scopes) != 1:
            if tag in ['section', 'inverted section']:
                # Set the most recent scope to a falsy value
                # (I heard False is a good one)
                scopes.insert(0, False)

        # If we're a literal tag
        elif tag == 'literal':
            # Add padding to the key and add it to the output
            if not isinstance(key, unicode_type):  # python 2
                key = unicode(key, 'utf-8')
            output += key.replace('\n', '\n' + padding)

        # If we're a variable tag
        elif tag == 'variable':
            # Add the html escaped key to the output
            thing = _get_key(key, scopes)
            if thing is True and key == '.':
                # if we've coerced into a boolean by accident
                # (inverted tags do this)
                # then get the un-coerced object (next in the stack)
                thing = scopes[1]
            if not isinstance(thing, unicode_type):
                thing = unicode(str(thing), 'utf-8')
            output += _html_escape(thing)

        # If we're a no html escape tag
        elif tag == 'no escape':
            # Just lookup the key and add it
            thing = _get_key(key, scopes)
            if not isinstance(thing, unicode_type):
                thing = unicode(str(thing), 'utf-8')
            output += thing

        # If we're a section tag
        elif tag == 'section':
            # Get the sections scope
            scope = _get_key(key, scopes)

            # If the scope is a callable (as described in
            # https://mustache.github.io/mustache.5.html)
            if isinstance(scope, Callable):

                # Generate template text from tags
                text = unicode('', 'utf-8')
                tags = []
                for tag in tokens:
                    if tag == ('end', key):
                        break

                    tags.append(tag)
                    tag_type, tag_key = tag
                    if tag_type == 'literal':
                        text += tag_key
                    elif tag_type == 'no escape':
                        text += "%s& %s %s" % (def_ldel, tag_key, def_rdel)
                    else:
                        text += "%s%s %s%s" % (def_ldel, {
                                'commment': '!',
                                'section': '#',
                                'inverted section': '^',
                                'end': '/',
                                'partial': '>',
                                'set delimiter': '=',
                                'no escape': '&',
                                'variable': ''
                            }[tag_type], tag_key, def_rdel)

                g_token_cache[text] = tags

                rend = scope(text, lambda template, data=None: render(template,
                             data={},
                             partials_path=partials_path,
                             partials_ext=partials_ext,
                             partials_dict=partials_dict,
                             padding=padding,
                             def_ldel=def_ldel, def_rdel=def_rdel,
                             scopes=data and [data]+scopes or scopes))

                if python3:
                    output += rend
                else:  # python 2
                    output += rend.decode('utf-8')

            # If the scope is a sequence, an iterator or generator but not
            # derived from a string
            elif isinstance(scope, (Sequence, Iterator)) and \
                    not isinstance(scope, string_type):
                # Then we need to do some looping

                # Gather up all the tags inside the section
                # (And don't be tricked by nested end tags with the same key)
                # TODO: This feels like it still has edge cases, no?
                tags = []
                tags_with_same_key = 0
                for tag in tokens:
                    if tag == ('section', key):
                        tags_with_same_key += 1
                    if tag == ('end', key):
                        tags_with_same_key -= 1
                        if tags_with_same_key < 0:
                            break
                    tags.append(tag)

                # For every item in the scope
                for thing in scope:
                    # Append it as the most recent scope and render
                    new_scope = [thing] + scopes
                    rend = render(template=tags, scopes=new_scope,
                                  partials_path=partials_path,
                                  partials_ext=partials_ext,
                                  partials_dict=partials_dict,
                                  def_ldel=def_ldel, def_rdel=def_rdel)

                    if python3:
                        output += rend
                    else:  # python 2
                        output += rend.decode('utf-8')

            else:
                # Otherwise we're just a scope section
                scopes.insert(0, scope)

        # If we're an inverted section
        elif tag == 'inverted section':
            # Add the flipped scope to the scopes
            scope = _get_key(key, scopes)
            scopes.insert(0, not scope)

        # If we're a partial
        elif tag == 'partial':
            # Load the partial
            partial = _get_partial(key, partials_dict,
                                   partials_path, partials_ext)

            # Find what to pad the partial with
            left = output.split('\n')[-1]
            part_padding = padding
            if left.isspace():
                part_padding += left

            # Render the partial
            part_out = render(template=partial, partials_path=partials_path,
                              partials_ext=partials_ext,
                              partials_dict=partials_dict,
                              def_ldel=def_ldel, def_rdel=def_rdel,
                              padding=part_padding, scopes=scopes)

            # If the partial was indented
            if left.isspace():
                # then remove the spaces from the end
                part_out = part_out.rstrip(' \t')

            # Add the partials output to the ouput
            if python3:
                output += part_out
            else:  # python 2
                output += part_out.decode('utf-8')

    if python3:
        return output
    else:  # python 2
        return output.encode('utf-8')
def render ( template = '' , data = { } , partials_path = '.' , partials_ext = 'mustache' , partials_dict = { } , padding = '' , def_ldel = '{{' , def_rdel = '}}' , scopes = None ) : if isinstance ( template , Sequence ) and not isinstance ( template , string_type ) : tokens = ( token for token in template ) else : if template in g_token_cache : tokens = ( token for token in g_token_cache [ template ] ) else : tokens = tokenize ( template , def_ldel , def_rdel ) output = unicode ( '' , 'utf-8' ) if scopes is None : scopes = [ data ] for tag , key in tokens : current_scope = scopes [ 0 ] if tag == 'end' : del scopes [ 0 ] elif not current_scope and len ( scopes ) != 1 : if tag in [ 'section' , 'inverted section' ] : scopes . insert ( 0 , False ) elif tag == 'literal' : if not isinstance ( key , unicode_type ) : key = unicode ( key , 'utf-8' ) output += key . replace ( '\n' , '\n' + padding ) elif tag == 'variable' : thing = _get_key ( key , scopes ) if thing is True and key == '.' : thing = scopes [ 1 ] if not isinstance ( thing , unicode_type ) : thing = unicode ( str ( thing ) , 'utf-8' ) output += _html_escape ( thing ) elif tag == 'no escape' : thing = _get_key ( key , scopes ) if not isinstance ( thing , unicode_type ) : thing = unicode ( str ( thing ) , 'utf-8' ) output += thing elif tag == 'section' : scope = _get_key ( key , scopes ) if isinstance ( scope , Callable ) : text = unicode ( '' , 'utf-8' ) tags = [ ] for tag in tokens : if tag == ( 'end' , key ) : break tags . append ( tag ) tag_type , tag_key = tag if tag_type == 'literal' : text += tag_key elif tag_type == 'no escape' : text += "%s& %s %s" % ( def_ldel , tag_key , def_rdel ) else : text += "%s%s %s%s" % ( def_ldel , { 'commment' : '!' , 'section' : '#' , 'inverted section' : '^' , 'end' : '/' , 'partial' : '>' , 'set delimiter' : '=' , 'no escape' : '&' , 'variable' : '' } [ tag_type ] , tag_key , def_rdel ) g_token_cache [ text ] = tags rend = scope ( text , lambda template , data = None : render ( template , data = { } , partials_path = partials_path , partials_ext = partials_ext , partials_dict = partials_dict , padding = padding , def_ldel = def_ldel , def_rdel = def_rdel , scopes = data and [ data ] + scopes or scopes ) ) if python3 : output += rend else : output += rend . decode ( 'utf-8' ) elif isinstance ( scope , ( Sequence , Iterator ) ) and not isinstance ( scope , string_type ) : tags = [ ] tags_with_same_key = 0 for tag in tokens : if tag == ( 'section' , key ) : tags_with_same_key += 1 if tag == ( 'end' , key ) : tags_with_same_key -= 1 if tags_with_same_key < 0 : break tags . append ( tag ) for thing in scope : new_scope = [ thing ] + scopes rend = render ( template = tags , scopes = new_scope , partials_path = partials_path , partials_ext = partials_ext , partials_dict = partials_dict , def_ldel = def_ldel , def_rdel = def_rdel ) if python3 : output += rend else : output += rend . decode ( 'utf-8' ) else : scopes . insert ( 0 , scope ) elif tag == 'inverted section' : scope = _get_key ( key , scopes ) scopes . insert ( 0 , not scope ) elif tag == 'partial' : partial = _get_partial ( key , partials_dict , partials_path , partials_ext ) left = output . split ( '\n' ) [ - 1 ] part_padding = padding if left . isspace ( ) : part_padding += left part_out = render ( template = partial , partials_path = partials_path , partials_ext = partials_ext , partials_dict = partials_dict , def_ldel = def_ldel , def_rdel = def_rdel , padding = part_padding , scopes = scopes ) if left . isspace ( ) : part_out = part_out . rstrip ( ' \t' ) if python3 : output += part_out else : output += part_out . decode ( 'utf-8' ) if python3 : return output else : return output . encode ( 'utf-8' )
Render a mustache template.

    Renders a mustache template with a data scope and partial capability.
    Given the file structure...
    ╷
    ├─╼ main.py
    ├─╼ main.ms
    └─┮ partials
      └── part.ms

    then main.py would make the following call:

    render(open('main.ms', 'r'), {...}, 'partials', 'ms')


    Arguments:

    template      -- A file-like object or a string containing the template

    data          -- A python dictionary with your data scope

    partials_path -- The path to where your partials are stored
                     (defaults to '.')

    partials_ext  -- The extension that you want the parser to look for
                     (defaults to 'mustache')

    partials_dict -- A python dictionary which will be search for partials
                     before the filesystem is. {'include': 'foo'} is the same
                     as a file called include.mustache
                     (defaults to {})

    padding       -- This is for padding partials, and shouldn't be used
                     (but can be if you really want to)

    def_ldel      -- The default left delimiter
                     ("{{" by default, as in spec compliant mustache)

    def_rdel      -- The default right delimiter
                     ("}}" by default, as in spec compliant mustache)

    scopes        -- The list of scopes that get_key will look through


    Returns:

    A string containing the rendered template.