Commit 80d6b6b8 authored by Preston Timmons's avatar Preston Timmons Committed by Tim Graham
Browse files

Fixed #24409 -- Combined the app_directories and filesystem loader implementation.

Besides the directories they look in, these two loaders are functionally
the same. This removes unnecessary code duplication between the two.
parent 4b8979e4
Loading
Loading
Loading
Loading
+4 −31
Original line number Diff line number Diff line
@@ -3,39 +3,12 @@ Wrapper for loading templates from "templates" directories in INSTALLED_APPS
packages.
"""

import io

from django.core.exceptions import SuspiciousFileOperation
from django.template.base import TemplateDoesNotExist
from django.template.utils import get_app_template_dirs
from django.utils._os import safe_join

from .base import Loader as BaseLoader

from .filesystem import Loader as FilesystemLoader

class Loader(BaseLoader):

    def get_template_sources(self, template_name, template_dirs=None):
        """
        Returns the absolute paths to "template_name", when appended to each
        directory in "template_dirs". Any paths that don't lie inside one of the
        template dirs are excluded from the result set, for security reasons.
        """
        if not template_dirs:
            template_dirs = get_app_template_dirs('templates')
        for template_dir in template_dirs:
            try:
                yield safe_join(template_dir, template_name)
            except SuspiciousFileOperation:
                # The joined path was located outside of this template_dir
                # (it might be inside another one, so this isn't fatal).
                pass
class Loader(FilesystemLoader):

    def load_template_source(self, template_name, template_dirs=None):
        for filepath in self.get_template_sources(template_name, template_dirs):
            try:
                with io.open(filepath, encoding=self.engine.file_charset) as fp:
                    return fp.read(), filepath
            except IOError:
                pass
        raise TemplateDoesNotExist(template_name)
    def get_dirs(self):
        return get_app_template_dirs('templates')
+6 −9
Original line number Diff line number Diff line
@@ -13,6 +13,9 @@ from .base import Loader as BaseLoader

class Loader(BaseLoader):

    def get_dirs(self):
        return self.engine.dirs

    def get_template_sources(self, template_name, template_dirs=None):
        """
        Returns the absolute paths to "template_name", when appended to each
@@ -20,7 +23,7 @@ class Loader(BaseLoader):
        template dirs are excluded from the result set, for security reasons.
        """
        if not template_dirs:
            template_dirs = self.engine.dirs
            template_dirs = self.get_dirs()
        for template_dir in template_dirs:
            try:
                yield safe_join(template_dir, template_name)
@@ -30,16 +33,10 @@ class Loader(BaseLoader):
                pass

    def load_template_source(self, template_name, template_dirs=None):
        tried = []
        for filepath in self.get_template_sources(template_name, template_dirs):
            try:
                with io.open(filepath, encoding=self.engine.file_charset) as fp:
                    return fp.read(), filepath
            except IOError:
                tried.append(filepath)
        if tried:
            error_msg = "Tried %s" % tried
        else:
            error_msg = ("Your template directories configuration is empty. "
                         "Change it to point to at least one template directory.")
        raise TemplateDoesNotExist(error_msg)
                pass
        raise TemplateDoesNotExist(template_name)
+17 −3
Original line number Diff line number Diff line
@@ -185,11 +185,16 @@ class FileSystemLoaderTests(SimpleTestCase):
        def check_sources(path, expected_sources):
            expected_sources = [os.path.abspath(s) for s in expected_sources]
            self.assertEqual(
                list(loader.get_template_sources(path, dirs)),
                list(loader.get_template_sources(path)),
                expected_sources,
            )

        original_dirs = self.engine.dirs
        self.engine.dirs = dirs
        try:
            yield check_sources
        finally:
            self.engine.dirs = original_dirs

    def test_directory_security(self):
        with self.source_checker(['/dir1', '/dir2']) as check_sources:
@@ -234,9 +239,18 @@ class FileSystemLoaderTests(SimpleTestCase):
            check_sources('/DIR1/index.HTML', ['/DIR1/index.HTML'])


class AppDirectoriesLoaderTest(FileSystemLoaderTests):
class AppDirectoriesLoaderTest(SimpleTestCase):

    def setUp(self):
        self.engine = Engine(
            loaders=['django.template.loaders.app_directories.Loader'],
        )

    @override_settings(INSTALLED_APPS=['template_tests'])
    def test_load_template(self):
        self.engine.get_template('index.html')

    @override_settings(INSTALLED_APPS=[])
    def test_not_installed(self):
        with self.assertRaises(TemplateDoesNotExist):
            self.engine.get_template('index.html')