# Buggy code
def render_jinja_tmpl(tmplstr, context, tmplpath=None):
    opts = context["opts"]
    env = context["env"]
    loader = None
    newline = False

    if tmplstr.endswith("\n"):
        newline = True

    if not env:
        if tmplpath:
            # ie, the template is from a file outside the state tree
            loader = jinja2.FileSystemLoader(context, os.path.dirname(tmplpath))
    else:
        loader = JinjaSaltCacheLoader(opts, context["env"])
    env_args = {"extensions": [], "loader": loader}

    if hasattr(jinja2.ext, "with_"):
        env_args["extensions"].append("jinja2.ext.with_")
    if hasattr(jinja2.ext, "do"):
        env_args["extensions"].append("jinja2.ext.do")
    if hasattr(jinja2.ext, "loopcontrols"):
        env_args["extensions"].append("jinja2.ext.loopcontrols")
    env_args["extensions"].append(JinjaSerializerExtension)

    if opts.get("allow_undefined", False):
        jinja_env = jinja2.Environment(**env_args)
    else:
        jinja_env = jinja2.Environment(undefined=jinja2.StrictUndefined, **env_args)
    jinja_env.filters["strftime"] = salt.utils.date_format

    unicode_context = {}
    for key, value in context.iteritems():
        if not isinstance(value, basestring):
            unicode_context[key] = value
            continue

        # Let's try UTF-8 and fail if this still fails, that's why this is not
        # wrapped in a try/except
        unicode_context[key] = unicode(value, "utf-8")

    try:
        output = jinja_env.from_string(tmplstr).render(**unicode_context)
        if isinstance(output, unicode):
            # Let's encode the output back to utf-8 since that's what's assumed
            # in salt
            output = output.encode("utf-8")
    except jinja2.exceptions.TemplateSyntaxError as exc:
        line = traceback.extract_tb(sys.exc_info()[2])[-1][1]
        marker = "    <======================"
        context = get_template_context(tmplstr, line, marker=marker)
        error = "{0}; line {1} in template:\n\n{2}".format(exc, line, context)
        raise SaltTemplateRenderError(error)
    except jinja2.exceptions.UndefinedError:
        line = traceback.extract_tb(sys.exc_info()[2])[-1][1]
        marker = "    <======================"
        context = get_template_context(tmplstr, line, marker=marker)
        error = "Undefined jinja variable; line {0} in template\n\n{1}".format(
            line, context
        )
        raise SaltTemplateRenderError(error)

    # Workaround a bug in Jinja that removes the final newline
    # (https://github.com/mitsuhiko/jinja2/issues/75)
    if newline:
        output += "\n"

    return output


# Traceback (AttributeError)
[ERROR   ] Error in function _master_opts:
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/salt/master.py", line 1444, in run_func
ret = getattr(self, func)(load)
File "/usr/lib/pymodules/python2.7/salt/master.py", line 891, in _master_opts
envs = self._file_envs()
File "/usr/lib/pymodules/python2.7/salt/fileserver/__init__.py", line 153, in envs
ret.update(self.servers[fstr]())
File "/usr/lib/pymodules/python2.7/salt/fileserver/hgfs.py", line 176, in envs
tags = repo.get_tags()
AttributeError: 'hgclient' object has no attribute 'get_tags'

# Fixed code
def render_jinja_tmpl(tmplstr, context, tmplpath=None):
    opts = context["opts"]
    env = context["env"]
    loader = None
    newline = False

    if tmplstr and not isinstance(tmplstr, unicode):
        # http://jinja.pocoo.org/docs/api/#unicode
        tmplstr = tmplstr.decode(SLS_ENCODING)

    if tmplstr.endswith("\n"):
        newline = True

    if not env:
        if tmplpath:
            # ie, the template is from a file outside the state tree
            #
            # XXX: FileSystemLoader is not being properly instantiated here is
            # it? At least it ain't according to:
            #
            #   http://jinja.pocoo.org/docs/api/#jinja2.FileSystemLoader
            loader = jinja2.FileSystemLoader(context, os.path.dirname(tmplpath))
    else:
        loader = JinjaSaltCacheLoader(opts, context["env"])

    env_args = {"extensions": [], "loader": loader}

    if hasattr(jinja2.ext, "with_"):
        env_args["extensions"].append("jinja2.ext.with_")
    if hasattr(jinja2.ext, "do"):
        env_args["extensions"].append("jinja2.ext.do")
    if hasattr(jinja2.ext, "loopcontrols"):
        env_args["extensions"].append("jinja2.ext.loopcontrols")
    env_args["extensions"].append(JinjaSerializerExtension)

    if opts.get("allow_undefined", False):
        jinja_env = jinja2.Environment(**env_args)
    else:
        jinja_env = jinja2.Environment(undefined=jinja2.StrictUndefined, **env_args)

    jinja_env.filters["strftime"] = salt.utils.date_format

    unicode_context = {}
    for key, value in context.iteritems():
        if not isinstance(value, basestring):
            unicode_context[key] = value
            continue

        # Let's try UTF-8 and fail if this still fails, that's why this is not
        # wrapped in a try/except
        unicode_context[key] = unicode(value, "utf-8")

    try:
        output = jinja_env.from_string(tmplstr).render(**unicode_context)
    except jinja2.exceptions.TemplateSyntaxError as exc:
        line = traceback.extract_tb(sys.exc_info()[2])[-1][1]
        marker = "    <======================"
        context = get_template_context(tmplstr, line, marker=marker)
        error = "{0}; line {1} in template:\n\n{2}".format(exc, line, context)
        raise SaltTemplateRenderError(error)
    except jinja2.exceptions.UndefinedError:
        line = traceback.extract_tb(sys.exc_info()[2])[-1][1]
        marker = "    <======================"
        context = get_template_context(tmplstr, line, marker=marker)
        error = "Undefined jinja variable; line {0} in template\n\n{1}".format(
            line, context
        )
        raise SaltTemplateRenderError(error)

    # Workaround a bug in Jinja that removes the final newline
    # (https://github.com/mitsuhiko/jinja2/issues/75)
    if newline:
        output += "\n"

    return output