# 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,
                    )
                    six.reraise(*sys.exc_info())
        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


# Traceback (AttributeError)
test: [ERROR   ] An un-handled exception was caught by salt's global exception handler:
test: AttributeError: 'unicode' object has no attribute 'name'
test: Traceback (most recent call last):
test:   File "/bin/spm", line 12, in <module>
test:     salt_spm()
test:   File "/usr/lib/python2.7/site-packages/salt/scripts.py", line 527, in salt_spm
test:     spm.run()
test:   File "/usr/lib/python2.7/site-packages/salt/cli/spm.py", line 41, in run
test:     client.run(self.args)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 125, in run
test:     self._install(args)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 379, in _install
test:     self._install_indv_pkg(package, out_file)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 532, in _install_indv_pkg
test:     self.files_conn)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 161, in _pkgfiles_fun
test:     return self.pkgfiles['{0}.{1}'.format(self.files_prov, func)](*args, **kwargs)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/pkgfiles/local.py", line 147, in install_file
test:     member.name = new_name.name.replace('{0}/'.format(package), '')
test: AttributeError: 'unicode' object has no attribute 'name'
test: Traceback (most recent call last):
test:   File "/bin/spm", line 12, in <module>
test:     salt_spm()
test:   File "/usr/lib/python2.7/site-packages/salt/scripts.py", line 527, in salt_spm
test:     spm.run()
test:   File "/usr/lib/python2.7/site-packages/salt/cli/spm.py", line 41, in run
test:     client.run(self.args)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 125, in run
test:     self._install(args)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 379, in _install
test:     self._install_indv_pkg(package, out_file)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 532, in _install_indv_pkg
test:     self.files_conn)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/__init__.py", line 161, in _pkgfiles_fun
test:     return self.pkgfiles['{0}.{1}'.format(self.files_prov, func)](*args, **kwargs)
test:   File "/usr/lib/python2.7/site-packages/salt/spm/pkgfiles/local.py", line 147, in install_file
test:     member.name = new_name.name.replace('{0}/'.format(package), '')
test: AttributeError: 'unicode' object has no attribute 'name'

# 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("/", "."),
                    "tplroot": tpldir.split("/")[0],
                }
                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,
                    )
                    six.reraise(*sys.exc_info())
        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