Jinja: FileSystemLoader não funciona com caminhos do Windows (barras invertidas)

Criado em 7 set. 2017  ·  9Comentários  ·  Fonte: pallets/jinja

Comportamento esperado

No Windows FileSystemLoader deve permitir caminhos no estilo Windows (com \ ) e no estilo UNIX (com / ).

Comportamento real

No Windows, ao usar FileSystemLoader o seguinte falha:
jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata')
com
jinja2.exceptions.TemplateNotFound: .\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata

enquanto isso jinjaEnvironment.get_template('.\source\architecture\ARM\ARMv6-M-ARMv7-M\bo ardTemplates\ARMv6-M-ARMv7-M.metadata'.replace('\\', '/')) funciona perfeitamente bem.

Traceback completo

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

Seu ambiente

  • Versão do Python: 2.7.12
  • Versão Jinja: 2.9.6

Comentários muito úteis

Eu acho que essa informação deve ser explicitamente declarada na documentação com fonte em negrito se você não pretende corrigi-la. Não é que eu tenha usado barras invertidas propositadamente - ao gerar o nome do arquivo usando algum outro código python (por exemplo, pesquisando as pastas por extensões apropriadas), a string tem barras nativas do sistema (portanto, barras invertidas no Windows). Nesse caso, você deve substituir explicitamente as barras ...

BTW - não estou usando Windows, mas estou escrevendo um script que deve funcionar em todas as plataformas.

Todos 9 comentários

Os nomes dos modelos Jinja não são caminhos de sistema de arquivos (mesmo que mapeiem para caminhos de sistema de arquivos ao usar apenas um FileSystemLoader). Eles sempre usam barras para que isso funcione conforme o esperado.

Eu acho que essa informação deve ser explicitamente declarada na documentação com fonte em negrito se você não pretende corrigi-la. Não é que eu tenha usado barras invertidas propositadamente - ao gerar o nome do arquivo usando algum outro código python (por exemplo, pesquisando as pastas por extensões apropriadas), a string tem barras nativas do sistema (portanto, barras invertidas no Windows). Nesse caso, você deve substituir explicitamente as barras ...

BTW - não estou usando Windows, mas estou escrevendo um script que deve funcionar em todas as plataformas.

@FreddieChopin
Este é fixo? parece ainda me afetar em 2019.

O que eu tenho que fazer é substituir manualmente todos os \\ para / .

Este é fixo?

"Não é um bug - é um recurso!" (;

Essa é realmente estranha! Isso poderia ser alterado ou mencionado (em letras grandes) nos documentos, por favor?

PR bem-vindo (para os documentos)

Comecei em um, mas encontrei isso: 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)

Os documentos dizem explicitamente que os.path.join deve/poderia ser usado. Talvez um problema seja mais apropriado?

O problema real é que o módulo de caminho python retorna o caminho com '\' no Windows por padrão. Eu sei que é o comportamento certo de alguma forma, mas a função interna como "abrir" aceita barra e barra invertida, então "às vezes funciona, às vezes não" acontece. Provavelmente precisamos de alguma maneira de tratar caminhos independentes de plataformas... algum tipo de "convenção python para tratar caminhos internamente" tipo de coisas... acho que isso não é um problema de jinja2 (este é um problema de convenção histórica entre Unix e Windows e parece durar para sempre), mas alguns "avisos" em documentos iniciais são bem-vindos.

O problema fundamental é que um "caminho" de modelo não é realmente um caminho de SO, mas espera-se que contenha apenas separadores "/". Mas no loaders.get_source() , self.searchpath também pensa que o separador de caminho é sempre "/".

Os caminhos do modelo não devem ser alterados para serem caminhos reais do SO, porque aparentemente existem outros lugares onde essa suposição canônica é usada.

A solução é alterar o modelo e o caminho de pesquisa para conter os separadores de caminho do sistema operacional reais, no ponto em que os caminhos do sistema operacional são necessários:

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

Eu testei este código brevemente no Windows 10/Python 2.7 e corrigiu meu erro "Modelo não encontrado".

Esta página foi útil?
0 / 5 - 0 avaliações