# Buggy code
def wrap_tmpl_func(render_str):
    def render_tmpl(
        tmplsrc, from_str=False, to_str=False, context=None, tmplpath=None, **kws
    ):
        if context is None:
            context = {}

        # Alias cmd.run to cmd.shell to make python_shell=True the default for
        # templated calls
        if "salt" in kws:
            kws["salt"] = AliasedLoader(kws["salt"])

        # We want explicit context to overwrite the **kws
        kws.update(context)
        context = kws
        assert "opts" in context
        assert "saltenv" in context

        if "sls" in context:
            slspath = context["sls"].replace(".", "/")
            if tmplpath is not None:
                context["tplpath"] = tmplpath
                if not tmplpath.lower().replace("\\", "/").endswith("/init.sls"):
                    slspath = os.path.dirname(slspath)
                template = tmplpath.replace("\\", "/")
                i = template.rfind(slspath.replace(".", "/"))
                if i != -1:
                    template = template[i:]
                tpldir = os.path.dirname(template).replace("\\", "/")
                tpldata = {
                    "tplfile": template,
                    "tpldir": "." if tpldir == "" else tpldir,
                    "tpldot": tpldir.replace("/", "."),
                }
                context.update(tpldata)
            context["slsdotpath"] = slspath.replace("/", ".")
            context["slscolonpath"] = slspath.replace("/", ":")
            context["sls_path"] = slspath.replace("/", "_")
            context["slspath"] = slspath

        if isinstance(tmplsrc, six.string_types):
            if from_str:
                tmplstr = tmplsrc
            else:
                try:
                    if tmplpath is not None:
                        tmplsrc = os.path.join(tmplpath, tmplsrc)
                    with codecs.open(tmplsrc, "r", SLS_ENCODING) as _tmplsrc:
                        tmplstr = _tmplsrc.read()
                except (UnicodeDecodeError, ValueError, OSError, IOError) as exc:
                    if salt.utils.files.is_binary(tmplsrc):
                        # Template is a bin file, return the raw file
                        return dict(result=True, data=tmplsrc)
                    log.error(
                        "Exception occurred while reading file %s: %s",
                        tmplsrc,
                        exc,
                        exc_info_on_loglevel=logging.DEBUG,
                    )
                    raise exc
        else:  # assume tmplsrc is file-like.
            tmplstr = tmplsrc.read()
            tmplsrc.close()
        try:
            output = render_str(tmplstr, context, tmplpath)
            if six.PY2:
                output = output.encode(SLS_ENCODING)
            if salt.utils.platform.is_windows():
                newline = False
                if salt.utils.stringutils.to_unicode(output).endswith(
                    ("\n", os.linesep)
                ):
                    newline = True
                # Write out with Windows newlines
                output = os.linesep.join(output.splitlines())
                if newline:
                    output += os.linesep

        except SaltRenderError as exc:
            log.exception("Rendering exception occurred")
            # return dict(result=False, data=six.text_type(exc))
            raise
        except Exception:
            return dict(result=False, data=traceback.format_exc())
        else:
            if to_str:  # then render as string
                return dict(result=True, data=output)
            with tempfile.NamedTemporaryFile(
                "wb", delete=False, prefix=salt.utils.files.TEMPFILE_PREFIX
            ) as outf:
                if six.PY3:
                    output = output.encode(SLS_ENCODING)
                outf.write(output)
                # Note: If nothing is replaced or added by the rendering
                #       function, then the contents of the output file will
                #       be exactly the same as the input.
            return dict(result=True, data=outf.name)

    render_tmpl.render_str = render_str
    return render_tmpl


# Traceback (UnicodeEncodeError)
The minion function caused an exception: Traceback (most recent call last):
File "c:\salt\bin\lib\site-packages\salt\minion.py", line 1624, in _thread_return
return_data = minion_instance.executors[fname](opts, data, func, args, kwargs)
File "c:\salt\bin\lib\site-packages\salt\executors\direct_call.py", line 12, in execute
return func(*args, **kwargs)
File "c:\salt\bin\lib\site-packages\salt\modules\win_pkg.py", line 1142, in install
old = list_pkgs(saltenv=saltenv, refresh=refresh, versions_as_list=True)
File "c:\salt\bin\lib\site-packages\salt\modules\win_pkg.py", line 400, in list_pkgs
name_map = _get_name_map(saltenv)
File "c:\salt\bin\lib\site-packages\salt\modules\win_pkg.py", line 1846, in _get_name_map
u_name_map[k.decode('utf-8')] = name_map[k]
File "c:\salt\bin\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 5-11: ordinal not in range(128)

# Fixed code
def wrap_tmpl_func(render_str):
    def render_tmpl(
        tmplsrc, from_str=False, to_str=False, context=None, tmplpath=None, **kws
    ):
        if context is None:
            context = {}

        # Alias cmd.run to cmd.shell to make python_shell=True the default for
        # templated calls
        if "salt" in kws:
            kws["salt"] = AliasedLoader(kws["salt"])

        # We want explicit context to overwrite the **kws
        kws.update(context)
        context = kws
        assert "opts" in context
        assert "saltenv" in context

        if "sls" in context:
            slspath = context["sls"].replace(".", "/")
            if tmplpath is not None:
                context["tplpath"] = tmplpath
                if not tmplpath.lower().replace("\\", "/").endswith("/init.sls"):
                    slspath = os.path.dirname(slspath)
                template = tmplpath.replace("\\", "/")
                i = template.rfind(slspath.replace(".", "/"))
                if i != -1:
                    template = template[i:]
                tpldir = os.path.dirname(template).replace("\\", "/")
                tpldata = {
                    "tplfile": template,
                    "tpldir": "." if tpldir == "" else tpldir,
                    "tpldot": tpldir.replace("/", "."),
                }
                context.update(tpldata)
            context["slsdotpath"] = slspath.replace("/", ".")
            context["slscolonpath"] = slspath.replace("/", ":")
            context["sls_path"] = slspath.replace("/", "_")
            context["slspath"] = slspath

        if isinstance(tmplsrc, six.string_types):
            if from_str:
                tmplstr = tmplsrc
            else:
                try:
                    if tmplpath is not None:
                        tmplsrc = os.path.join(tmplpath, tmplsrc)
                    with codecs.open(tmplsrc, "r", SLS_ENCODING) as _tmplsrc:
                        tmplstr = _tmplsrc.read()
                except (UnicodeDecodeError, ValueError, OSError, IOError) as exc:
                    if salt.utils.files.is_binary(tmplsrc):
                        # Template is a bin file, return the raw file
                        return dict(result=True, data=tmplsrc)
                    log.error(
                        "Exception occurred while reading file %s: %s",
                        tmplsrc,
                        exc,
                        exc_info_on_loglevel=logging.DEBUG,
                    )
                    raise exc
        else:  # assume tmplsrc is file-like.
            tmplstr = tmplsrc.read()
            tmplsrc.close()
        try:
            output = render_str(tmplstr, context, tmplpath)
            if salt.utils.platform.is_windows():
                newline = False
                if salt.utils.stringutils.to_unicode(
                    output, encoding=SLS_ENCODING
                ).endswith(("\n", os.linesep)):
                    newline = True
                # Write out with Windows newlines
                output = os.linesep.join(output.splitlines())
                if newline:
                    output += os.linesep

        except SaltRenderError as exc:
            log.exception("Rendering exception occurred")
            # return dict(result=False, data=six.text_type(exc))
            raise
        except Exception:
            return dict(result=False, data=traceback.format_exc())
        else:
            if to_str:  # then render as string
                return dict(result=True, data=output)
            with tempfile.NamedTemporaryFile(
                "wb", delete=False, prefix=salt.utils.files.TEMPFILE_PREFIX
            ) as outf:
                outf.write(
                    salt.utils.stringutils.to_bytes(output, encoding=SLS_ENCODING)
                )
                # Note: If nothing is replaced or added by the rendering
                #       function, then the contents of the output file will
                #       be exactly the same as the input.
            return dict(result=True, data=outf.name)

    render_tmpl.render_str = render_str
    return render_tmpl