Jinja: FileSystemLoader funktioniert nicht mit Windows Pfaden (Backslashes)

Erstellt am 7. Sept. 2017  ·  9Kommentare  ·  Quelle: pallets/jinja

Erwartetes Verhalten

Unter Windows sollte FileSystemLoader sowohl Pfade im Windows-Stil (mit \ ) als auch im UNIX-Stil (mit / ) zulassen.

Tatsächliches Verhalten

Unter Windows schlägt bei Verwendung FileSystemLoader Folgendes fehl:
jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata')
mit
jinja2.exceptions.TemplateNotFound: .\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata

während dieses jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata'.replace('\\', '/')) einwandfrei funktioniert.

Vollständige Rückverfolgung

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

Ihre Umgebung

  • Python-Version: 2.7.12
  • Jinja-Version: 2.9.6

Hilfreichster Kommentar

Ich denke, diese Informationen sollten in der Dokumentation ausdrücklich in Fettschrift angegeben werden, wenn Sie nicht beabsichtigen, sie zu beheben. Es ist nicht so, dass ich absichtlich Backslashes verwendet habe - beim Generieren des Dateinamens mit einem anderen Python-Code (z. B. durch Durchsuchen der Ordner nach geeigneten Erweiterungen) hat die Zeichenfolge systemeigene Schrägstriche (also Backslashes unter Windows). In diesem Fall müssen Sie die Schrägstriche explizit ersetzen ...

Übrigens - ich benutze kein Windows, aber ich schreibe ein Skript, das auf allen Plattformen funktionieren sollte.

Alle 9 Kommentare

Jinja-Vorlagennamen sind keine Dateisystempfade (obwohl sie Dateisystempfaden zugeordnet sind, wenn nur ein FileSystemLoader verwendet wird). Sie verwenden immer Schrägstriche, damit dies wie beabsichtigt funktioniert.

Ich denke, diese Informationen sollten in der Dokumentation ausdrücklich in Fettschrift angegeben werden, wenn Sie nicht beabsichtigen, sie zu beheben. Es ist nicht so, dass ich absichtlich Backslashes verwendet habe - beim Generieren des Dateinamens mit einem anderen Python-Code (z. B. durch Durchsuchen der Ordner nach geeigneten Erweiterungen) hat die Zeichenfolge systemeigene Schrägstriche (also Backslashes unter Windows). In diesem Fall müssen Sie die Schrägstriche explizit ersetzen ...

Übrigens - ich benutze kein Windows, aber ich schreibe ein Skript, das auf allen Plattformen funktionieren sollte.

@FreddieChopin
Ist dieser fest? scheint mich 2019 noch zu beeinflussen.

Was ich tun muss, ist, alle \\ manuell durch $#$ / $#$ zu ersetzen.

Ist dieser fest?

„Das ist kein Bug – das ist ein Feature!“ (;

Das ist wirklich seltsam! Könnte dies bitte geändert oder (in großen Buchstaben) in den Dokumenten erwähnt werden?

PR willkommen (für die Dokumente)

Ich habe mit einem angefangen, aber dann habe ich das hier gefunden: 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)

Die Dokumentation sagt ausdrücklich, dass os.path.join verwendet werden sollte/könnte. Vielleicht ist ein Thema besser geeignet?

Das eigentliche Problem ist, dass das Python-Pfadmodul den Pfad standardmäßig mit „\“ unter Windows zurückgibt. Ich weiß, dass es irgendwie das richtige Verhalten ist, aber eingebaute Funktionen wie "open" akzeptieren sowohl Schrägstriche als auch umgekehrte Schrägstriche, sodass "manchmal funktioniert es, manchmal nicht" so etwas passiert. Wahrscheinlich brauchen wir eine Möglichkeit, Pfade unabhängig von Plattformen zu behandeln ... eine Art "Python-Konvention, um Pfade intern zu behandeln" ... Ich denke, das ist kein Problem von jinja2 (Dies ist ein Problem der historischen Konvention zwischen Unix und Windows und es scheint ewig zu dauern), aber einige "Hinweise" in einem Startdokument sind willkommen.

Das grundlegende Problem besteht darin, dass ein Vorlagen-"Pfad" nicht wirklich ein Betriebssystempfad ist, sondern nur "/"-Trennzeichen enthalten soll. Aber in loaders.get_source() denkt self.searchpath auch, dass das Pfadtrennzeichen immer "/" ist.

Die Vorlagenpfade sollten nicht in tatsächliche Betriebssystempfade geändert werden, da es anscheinend andere Stellen gibt, an denen diese kanonische Annahme verwendet wird.

Die Lösung besteht darin, sowohl die Vorlage als auch den Suchpfad so zu ändern, dass sie an der Stelle, an der Betriebssystempfade benötigt werden, tatsächliche Pfadtrennzeichen des Betriebssystems enthalten:

    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 ...

Ich habe diesen Code kurz in Windows 10/Python 2.7 getestet und meinen Fehler „Vorlage nicht gefunden“ behoben.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen