# Buggy code
def get_source(self, environment, template):
    """
    Salt-specific loader to find imported jinja files.

    Jinja imports will be interpreted as originating from the top
    of each of the directories in the searchpath when the template
    name does not begin with './' or '../'.  When a template name
    begins with './' or '../' then the import will be relative to
    the importing file.

    """
    # FIXME: somewhere do seprataor replacement: '\\' => '/'
    _template = template
    if template.split("/", 1)[0] in ("..", "."):
        is_relative = True
    else:
        is_relative = False
    # checks for relative '..' paths that step-out of file_roots
    if is_relative:
        # Starts with a relative path indicator

        if not environment or "tpldir" not in environment.globals:
            log.warning(
                'Relative path "%s" cannot be resolved without an environment', template
            )
            raise TemplateNotFound
        base_path = environment.globals["tpldir"]
        _template = os.path.normpath("/".join((base_path, _template)))
        if _template.split("/", 1)[0] == "..":
            log.warning(
                'Discarded template path "%s": attempts to ascend outside of salt://',
                template,
            )
            raise TemplateNotFound(template)

    self.check_cache(_template)

    if environment and template:
        tpldir = os.path.dirname(_template).replace("\\", "/")
        tplfile = _template
        if is_relative:
            tpldir = environment.globals.get("tpldir", tpldir)
            tplfile = template
        tpldata = {
            "tplfile": tplfile,
            "tpldir": "." if tpldir == "" else tpldir,
            "tpldot": tpldir.replace("/", "."),
        }
        environment.globals.update(tpldata)

    # pylint: disable=cell-var-from-loop
    for spath in self.searchpath:
        filepath = os.path.join(spath, _template)
        try:
            with salt.utils.files.fopen(filepath, "rb") as ifile:
                contents = ifile.read().decode(self.encoding)
                mtime = os.path.getmtime(filepath)

                def uptodate():
                    try:
                        return os.path.getmtime(filepath) == mtime
                    except OSError:
                        return False

                return contents, filepath, uptodate
        except IOError:
            # there is no file under current path
            continue
    # pylint: enable=cell-var-from-loop

    # there is no template file within searchpaths
    raise TemplateNotFound(template)


# 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 get_source(self, environment, template):
    """
    Salt-specific loader to find imported jinja files.

    Jinja imports will be interpreted as originating from the top
    of each of the directories in the searchpath when the template
    name does not begin with './' or '../'.  When a template name
    begins with './' or '../' then the import will be relative to
    the importing file.

    """
    # FIXME: somewhere do seprataor replacement: '\\' => '/'
    _template = template
    if template.split("/", 1)[0] in ("..", "."):
        is_relative = True
    else:
        is_relative = False
    # checks for relative '..' paths that step-out of file_roots
    if is_relative:
        # Starts with a relative path indicator

        if not environment or "tpldir" not in environment.globals:
            log.warning(
                'Relative path "%s" cannot be resolved without an environment', template
            )
            raise TemplateNotFound
        base_path = environment.globals["tpldir"]
        _template = os.path.normpath("/".join((base_path, _template)))
        if _template.split("/", 1)[0] == "..":
            log.warning(
                'Discarded template path "%s": attempts to ascend outside of salt://',
                template,
            )
            raise TemplateNotFound(template)

    self.check_cache(_template)

    if environment and template:
        tpldir = os.path.dirname(_template).replace("\\", "/")
        tplfile = _template
        if is_relative:
            tpldir = environment.globals.get("tpldir", tpldir)
            tplfile = template
        tpldata = {
            "tplfile": tplfile,
            "tpldir": "." if tpldir == "" else tpldir,
            "tpldot": tpldir.replace("/", "."),
            "tplroot": tpldir.split("/")[0],
        }
        environment.globals.update(tpldata)

    # pylint: disable=cell-var-from-loop
    for spath in self.searchpath:
        filepath = os.path.join(spath, _template)
        try:
            with salt.utils.files.fopen(filepath, "rb") as ifile:
                contents = ifile.read().decode(self.encoding)
                mtime = os.path.getmtime(filepath)

                def uptodate():
                    try:
                        return os.path.getmtime(filepath) == mtime
                    except OSError:
                        return False

                return contents, filepath, uptodate
        except IOError:
            # there is no file under current path
            continue
    # pylint: enable=cell-var-from-loop

    # there is no template file within searchpaths
    raise TemplateNotFound(template)