Jinja: FileSystemLoader ne fonctionne pas avec les chemins Windows (barres obliques inverses)

Créé le 7 sept. 2017  ·  9Commentaires  ·  Source: pallets/jinja

Comportement prévisible

Sous Windows, FileSystemLoader devrait autoriser les chemins de style Windows (avec \ ) et de style UNIX (avec / ).

Comportement réel

Sous Windows, lors de l'utilisation FileSystemLoader , ce qui suit échoue :
jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata')
avec
jinja2.exceptions.TemplateNotFound: .\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata

alors que ce jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata'.replace('\\', '/')) fonctionne parfaitement bien.

Retraçage complet

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

Votre environnement

  • Version Python : 2.7.12
  • Version Jinja : 2.9.6

Commentaire le plus utile

Je pense que cette information devrait être explicitement indiquée dans la documentation en caractères gras si vous n'avez pas l'intention de la corriger. Ce n'est pas que j'ai délibérément utilisé des barres obliques inverses - lors de la génération du nom de fichier à l'aide d'un autre code python (par exemple en recherchant dans les dossiers les extensions appropriées), la chaîne contient les barres obliques natives du système (donc les barres obliques inverses sous Windows). Dans ce cas, vous devez remplacer explicitement les barres obliques...

BTW - Je n'utilise pas Windows, mais j'écris un script qui devrait fonctionner sur toutes les plateformes.

Tous les 9 commentaires

Les noms de modèles Jinja ne sont pas des chemins de système de fichiers (même s'ils correspondent à des chemins de système de fichiers lors de l'utilisation d'un seul FileSystemLoader). Ils utilisent toujours des barres obliques afin que cela fonctionne comme prévu.

Je pense que cette information devrait être explicitement indiquée dans la documentation en caractères gras si vous n'avez pas l'intention de la corriger. Ce n'est pas que j'ai délibérément utilisé des barres obliques inverses - lors de la génération du nom de fichier à l'aide d'un autre code python (par exemple en recherchant dans les dossiers les extensions appropriées), la chaîne contient les barres obliques natives du système (donc les barres obliques inverses sous Windows). Dans ce cas, vous devez remplacer explicitement les barres obliques...

BTW - Je n'utilise pas Windows, mais j'écris un script qui devrait fonctionner sur toutes les plateformes.

@FreddieChopin
Celui-ci est-il fixe ? semble encore m'affecter en 2019.

Ce que je dois faire est de remplacer manuellement tous les \\ par / .

Celui-ci est-il fixe ?

"Ce n'est pas un bug - c'est une fonctionnalité !" (;

C'est vraiment bizarre ! Cela pourrait-il être modifié ou mentionné (en grosses lettres) dans la documentation, s'il vous plaît ?

PR bienvenu (pour les docs)

J'ai commencé sur un, mais ensuite j'ai trouvé ceci : 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)

Les docs disent explicitement que os.path.join devrait/pourrait être utilisé. Peut-être qu'un problème est plus approprié?

Le vrai problème est que le module de chemin python renvoie le chemin avec '\' sous Windows par défaut. Je sais que c'est un bon comportement d'une manière ou d'une autre, mais une fonction intégrée comme "open" accepte à la fois la barre oblique et la barre oblique inverse, donc "parfois ça marche, parfois ça ne marche pas" ce genre de choses se produit. Nous avons probablement besoin d'un moyen de traiter les chemins indépendants des plates-formes ... une sorte de "convention python pour traiter un chemin en interne" genre de choses ... Je pense que ce n'est pas un problème de jinja2 (C'est un problème de convention historique entre Unix et Windows et cela semble durer éternellement), mais certains "avertissements" dans un document de démarrage sont les bienvenus.

Le problème fondamental est qu'un "chemin" de modèle n'est pas vraiment un chemin d'accès au système d'exploitation, mais est censé contenir uniquement des séparateurs "/". Mais dans loaders.get_source() , self.searchpath pense également que le séparateur de chemin est toujours "/".

Les chemins de modèle ne doivent pas être modifiés pour être des chemins de système d'exploitation réels, car il existe apparemment d'autres endroits où cette hypothèse canonique est utilisée.

La solution consiste à modifier à la fois le modèle et le chemin de recherche pour contenir les véritables séparateurs de chemin du système d'exploitation, au point où les chemins du système d'exploitation sont nécessaires :

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

J'ai brièvement testé ce code dans Windows 10/Python 2.7, et il a corrigé mon erreur "Modèle introuvable".

Cette page vous a été utile?
0 / 5 - 0 notes