Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileSystemLoader doesn't work with Windows paths (backslashes) #767

Closed
FreddieChopin opened this issue Sep 7, 2017 · 9 comments
Closed

Comments

@FreddieChopin
Copy link

Expected Behavior

On Windows FileSystemLoader should allow both Windows-style (with \) and UNIX-style (with /) paths.

Actual Behavior

On Windows, when using FileSystemLoader the following fails:
jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata')
with
jinja2.exceptions.TemplateNotFound: .\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata

while this jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata'.replace('\\', '/')) works perfectly fine.

Full Traceback

Traceback (most recent call last):
  File "./scripts/generateBoard.py", line 186, in <module>
    metadata = jinjaEnvironment.get_template(metadataFile).render(dictionary = d
ictionary)
  File "C:\Python27\lib\site-packages\jinja2\environment.py", line 830, in get_t
emplate
    return self._load_template(name, self.make_globals(globals))
  File "C:\Python27\lib\site-packages\jinja2\environment.py", line 804, in _load
_template
    template = self.loader.load(self, name, globals)
  File "C:\Python27\lib\site-packages\jinja2\loaders.py", line 113, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "C:\Python27\lib\site-packages\jinja2\loaders.py", line 168, in get_sourc
e
    pieces = split_template_path(template)
  File "C:\Python27\lib\site-packages\jinja2\loaders.py", line 31, in split_temp
late_path
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: .\source\architecture\ARM\ARMv6-M-ARMv7-M\bo
ardTemplates\ARMv6-M-ARMv7-M.metadata

Your Environment

  • Python version: 2.7.12
  • Jinja version: 2.9.6
@ThiefMaster
Copy link
Member

Jinja template names are not fileystem paths (even though they map to filesystem paths when using just a FileSystemLoader). They always use forward slashes so this is working as intended.

@FreddieChopin
Copy link
Author

FreddieChopin commented Sep 7, 2017

I think this information should be explicitly stated in the documentation with bold font if you don't intend to fix it. It's not that I have purposefully used backslashes - when generating the filename using some other python code (for example by searching the folders for appropriate extensions), the string has system's native slashes (so backslashes on Windows). In that case you have to explicitly replace the slashes...

BTW - I'm not using Windows, but I'm writing a script which should work on all platforms.

FreddieChopin pushed a commit to DISTORTEC/distortos that referenced this issue Sep 7, 2017
The fixes are related to the fact that both jinja (
pallets/jinja#767 ) and templates expect
forward slashes only.
1. Use posixpath instead of os.path
2. Replace all backslashes with slashes in current folder returned by
os.walk()
caseycesari added a commit to CoastalResilienceNetwork/GeositeFramework that referenced this issue Oct 15, 2018
caseycesari added a commit to CoastalResilienceNetwork/GeositeFramework that referenced this issue Oct 16, 2018
caseycesari added a commit to CoastalResilienceNetwork/GeositeFramework that referenced this issue Oct 22, 2018
@gotexis
Copy link

gotexis commented Mar 29, 2019

@FreddieChopin
Is this one fixed? seems still affecting me in 2019.

What I have to do is to manually replace all \\ to /.

@FreddieChopin
Copy link
Author

Is this one fixed?

"It is not a bug - it's a feature!" (;

@MichaelClerx
Copy link

This is a really weird one! Could this be changed or mentioned (in big letters) in the docs please?

@ThiefMaster
Copy link
Member

PR welcome (for the docs)

@MichaelClerx
Copy link

MichaelClerx commented Aug 14, 2019

I started on one, but then I found this: https://github.com/pallets/jinja/blob/master/jinja2/loaders.py#L43-L61

A very basic example for a loader that looks up templates on the file
system could look like this::
    from jinja2 import BaseLoader, TemplateNotFound
    from os.path import join, exists, getmtime
    class MyLoader(BaseLoader):
        def __init__(self, path):
            self.path = path
        def get_source(self, environment, template):
            path = join(self.path, template)
            if not exists(path):
                raise TemplateNotFound(template)
            mtime = getmtime(path)
            with file(path) as f:
                source = f.read().decode('utf-8')
            return source, path, lambda: mtime == getmtime(path)

The docs explicitly say that os.path.join should/could be used. Perhaps an issue is more appropriate?

@fuwaraido
Copy link

The real problem is python path module returns path with '\' on windows by default. I know it's right behaviour somehow but built-in function like "open" accepts both slash and backslash so "sometimes it works, sometimes it doesn't" kind of things happens. Probably we need some way to treat paths independent from platforms...some sort of "python convention to treat a paths internally" sort of things...I think this is not a problem of jinja2 (This is a problem of historical convention between Unix and Windows and it seems last forever) but some "heads up" in a starter documents are welcomed.

@tbpassin
Copy link

tbpassin commented Dec 19, 2019

The fundamental problem is that a template "path" is not really an OS path, but is expected to contain only "/" separators. But in the loaders.get_source(), self.searchpath also thinks that the path separator is always "/".

The template paths should not be changed to be actual OS paths, because there are apparently other places where this canonical assumption is used.

The solution is to change both the template and the searchpath to contain actual OS path separators, at the point where OS paths are needed:

    def get_source(self, environment, template):
        _searchpaths = self.searchpath
        if path.sep != '/':
            template = template.replace('/', path.sep)
            _searchpaths = [p.replace('/', path.sep) for p in self.searchpath]
        pieces = os.path.split(template)
        for searchpath in _searchpaths:
            # Existing code continues here ...

I have tested this code briefly in Windows 10/Python 2.7, and it corrected my "Template not found" error.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants