docs: 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')