diff --git a/flask/app.py b/flask/app.py index b76e69e6..41eea79d 100644 --- a/flask/app.py +++ b/flask/app.py @@ -206,8 +206,9 @@ class Flask(_PackageBoundObject): test_client_class = None def __init__(self, import_name, static_path=None, static_url_path=None, - static_folder='static'): - _PackageBoundObject.__init__(self, import_name) + static_folder='static', template_folder='templates'): + _PackageBoundObject.__init__(self, import_name, + template_folder=template_folder) if static_path is not None: from warnings import warn warn(DeprecationWarning('static_path is now called ' @@ -456,7 +457,7 @@ class Flask(_PackageBoundObject): rv.filters['tojson'] = _tojson_filter return rv - def create_jinja_loader(self): + def create_global_jinja_loader(self): """Creates the loader for the Jinja2 environment. Can be used to override just the loader and keeping the rest unchanged. diff --git a/flask/blueprints.py b/flask/blueprints.py index 41d5ef95..7afcc8a8 100644 --- a/flask/blueprints.py +++ b/flask/blueprints.py @@ -56,9 +56,9 @@ class Blueprint(_PackageBoundObject): _got_registered_once = False def __init__(self, name, import_name, static_folder=None, - static_url_path=None, url_prefix=None, - subdomain=None): - _PackageBoundObject.__init__(self, import_name) + static_url_path=None, template_folder=None, + url_prefix=None, subdomain=None): + _PackageBoundObject.__init__(self, import_name, template_folder) self.name = name self.url_prefix = url_prefix self.subdomain = subdomain diff --git a/flask/helpers.py b/flask/helpers.py index eff32273..09e8620e 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -485,13 +485,15 @@ class locked_cached_property(object): class _PackageBoundObject(object): - template_folder = 'templates' - - def __init__(self, import_name): + def __init__(self, import_name, template_folder=None): #: The name of the package or module. Do not change this once #: it was set by the constructor. self.import_name = import_name + #: location of the templates. `None` if templates should not be + #: exposed. + self.template_folder = template_folder + #: Where is the app root located? self.root_path = _get_package_path(self.import_name) @@ -544,8 +546,7 @@ class _PackageBoundObject(object): """ if not self.has_static_folder: raise RuntimeError('No static folder for this object') - return send_from_directory(os.path.join(self.root_path, 'static'), - filename) + return send_from_directory(self.static_folder, filename) def open_resource(self, resource): """Opens a resource from the application's resource folder. To see diff --git a/flask/module.py b/flask/module.py index 2e9b9db4..61b3cbc4 100644 --- a/flask/module.py +++ b/flask/module.py @@ -11,7 +11,6 @@ import os -from .helpers import _PackageBoundObject, _endpoint_from_view_func from .blueprints import Blueprint @@ -37,7 +36,7 @@ class Module(Blueprint): 'does not point to a submodule' name = import_name.rsplit('.', 1)[1] Blueprint.__init__(self, name, import_name, url_prefix=url_prefix, - subdomain=subdomain) + subdomain=subdomain, template_folder='templates') if os.path.isdir(os.path.join(self.root_path, 'static')): self._static_folder = 'static' diff --git a/flask/templating.py b/flask/templating.py index 5800bf83..d50691b3 100644 --- a/flask/templating.py +++ b/flask/templating.py @@ -38,69 +38,64 @@ class Environment(BaseEnvironment): def __init__(self, app, **options): if 'loader' not in options: - options['loader'] = app.create_jinja_loader() + options['loader'] = app.create_global_jinja_loader() BaseEnvironment.__init__(self, **options) self.app = app - def join_path(self, template, parent): - if template and template[0] == ':': - template = parent.split(':', 1)[0] + template - return template - class DispatchingJinjaLoader(BaseLoader): """A loader that looks for templates in the application and all - the module folders. + the blueprint folders. """ def __init__(self, app): self.app = app def get_source(self, environment, template): - # newstyle template support. blueprints are explicit and no further - # magic is involved. If the template cannot be loaded by the - # blueprint loader it just gives up, no further steps involved. - if ':' in template: - blueprint_name, local_template = template.split(':', 1) - local_template = posixpath.normpath(local_template) - blueprint = self.app.blueprints.get(blueprint_name) - if blueprint is None: - raise TemplateNotFound(template) - loader = blueprint.jinja_loader - if loader is not None: - return loader.get_source(environment, local_template) + for loader, local_name in self._iter_loaders(template): + try: + return loader.get_source(environment, local_name) + except TemplateNotFound: + pass + + raise TemplateNotFound(template) - # if modules are enabled we call into the old style template lookup - # and try that before we go with the real deal. - loader = None + def _iter_loaders(self, template): + loader = self.app.jinja_loader + if loader is not None: + yield loader, template + + # old style module based loaders in case we are dealing with a + # blueprint that is an old style module try: - module, name = posixpath.normpath(template).split('/', 1) + module, local_name = posixpath.normpath(template).split('/', 1) blueprint = self.app.blueprints[module] if blueprint_is_module(blueprint): loader = blueprint.jinja_loader - except (ValueError, KeyError, TemplateNotFound): - pass - try: - if loader is not None: - return loader.get_source(environment, name) - except TemplateNotFound: + if loader is not None: + yield loader, local_name + except (ValueError, KeyError): pass - # at the very last, load templates from the environment - return self.app.jinja_loader.get_source(environment, template) + for blueprint in self.app.blueprints.itervalues(): + loader = blueprint.jinja_loader + if loader is not None: + yield loader, template def list_templates(self): - result = set(self.app.jinja_loader.list_templates()) - - for name, module in self.app.modules.iteritems(): - if module.jinja_loader is not None: - for template in module.jinja_loader.list_templates(): - result.add('%s/%s' % (name, template)) + result = set() + loader = self.app.jinja_loader + if loader is not None: + result.update(loader.list_templates()) for name, blueprint in self.app.blueprints.iteritems(): - if blueprint.jinja_loader is not None: - for template in blueprint.jinja_loader.list_templates(): - result.add('%s:%s' % (name, template)) + loader = blueprint.jinja_loader + if loader is not None: + for template in loader.list_templates(): + prefix = '' + if not blueprint_is_module(blueprint): + prefix = name + '/' + result.add(prefix + template) return list(result) diff --git a/tests/flask_tests.py b/tests/flask_tests.py index 7c430417..75da40d5 100644 --- a/tests/flask_tests.py +++ b/tests/flask_tests.py @@ -992,7 +992,7 @@ class TemplatingTestCase(unittest.TestCase): def test_custom_template_loader(self): class MyFlask(flask.Flask): - def create_jinja_loader(self): + def create_global_jinja_loader(self): from jinja2 import DictLoader return DictLoader({'index.html': 'Hello Custom World!'}) app = MyFlask(__name__)