From aaf13a231cf6b902b7e854e3210ed098afd31480 Mon Sep 17 00:00:00 2001 From: David Lord Date: Sun, 13 Oct 2019 06:40:54 -0700 Subject: [PATCH] skip template with same name as directory When using multiple paths with FileSystemLoader, a template with the same name as a directory will not prevent loading a template in the directory. --- CHANGES.rst | 6 ++++-- jinja2/utils.py | 13 ++++++------- tests/res/templates2/foo | 2 ++ tests/test_loader.py | 11 +++++++++++ 4 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 tests/res/templates2/foo diff --git a/CHANGES.rst b/CHANGES.rst index 89844b23..305eb963 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,7 @@ .. currentmodule:: jinja2 -Version 2.11 ------------- +Version 2.11.0 +-------------- Unreleased @@ -37,6 +37,8 @@ Unreleased - The environment's ``finalize`` function is only applied to the output of expressions (constant or not), not static template data. :issue:`63` +- When providing multiple paths to ``FileSystemLoader``, a template + can have the same name as a directory. :issue:`821` Version 2.10.3 diff --git a/jinja2/utils.py b/jinja2/utils.py index 9fb2b353..a6f4dca0 100644 --- a/jinja2/utils.py +++ b/jinja2/utils.py @@ -8,9 +8,9 @@ :copyright: (c) 2017 by the Jinja Team. :license: BSD, see LICENSE for more details. """ +import os import re import json -import errno import warnings from collections import deque from threading import Lock @@ -147,13 +147,12 @@ def import_string(import_name, silent=False): def open_if_exists(filename, mode='rb'): """Returns a file descriptor for the filename if that file exists, - otherwise `None`. + otherwise ``None``. """ - try: - return open(filename, mode) - except IOError as e: - if e.errno not in (errno.ENOENT, errno.EISDIR, errno.EINVAL): - raise + if not os.path.isfile(filename): + return None + + return open(filename, mode) def object_type_repr(obj): diff --git a/tests/res/templates2/foo b/tests/res/templates2/foo new file mode 100644 index 00000000..1c4ad3e4 --- /dev/null +++ b/tests/res/templates2/foo @@ -0,0 +1,2 @@ +Looks like the start of templates/foo/test.html +Tested by test_filesystem_loader_overlapping_names diff --git a/tests/test_loader.py b/tests/test_loader.py index 7e12628b..cb30ebe5 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -44,6 +44,17 @@ class TestLoaders(object): assert tmpl.render().strip() == 'FOO' pytest.raises(TemplateNotFound, env.get_template, 'missing.html') + def test_filesystem_loader_overlapping_names(self, filesystem_loader): + res = os.path.dirname(filesystem_loader.searchpath[0]) + t2_dir = os.path.join(res, "templates2") + # Make "foo" show up before "foo/test.html". + filesystem_loader.searchpath.insert(0, t2_dir) + e = Environment(loader=filesystem_loader) + e.get_template("foo") + # This would raise NotADirectoryError if "t2/foo" wasn't skipped. + e.get_template("foo/test.html") + + def test_choice_loader(self, choice_loader): env = Environment(loader=choice_loader) tmpl = env.get_template('justdict.html') -- 2.47.2