# HG changeset patch # User Alexander Solovyov # Date 1249326986 -10800 # Node ID 2967868b59b8ddc2a0838bcbfbfe5c174a1a3ef5 # Parent 2e291c2aa8072edaa2fd9dc4dfc95543b13e6418 revamp of template loading diff --git a/samples/simple/test/manage.py b/samples/simple/test/manage.py old mode 100644 new mode 100755 diff --git a/samples/simple/test/settings.py b/samples/simple/test/settings.py --- a/samples/simple/test/settings.py +++ b/samples/simple/test/settings.py @@ -1,3 +1,6 @@ +from os import path as op +ROOT = op.normpath(op.dirname(__file__)) + # Aliases mapping ALIASES = { } @@ -11,7 +14,7 @@ import urls URLCONF = urls.url_map # Jinja2 template path -TEMPLATE_PATH = 'templates' +TEMPLATE_PATHS = [op.join(ROOT, 'templates')] # SQL Alchemy settings SQLA_URL = 'sqlite:///data.db' diff --git a/svarga/core/settings/default_settings.py b/svarga/core/settings/default_settings.py --- a/svarga/core/settings/default_settings.py +++ b/svarga/core/settings/default_settings.py @@ -5,28 +5,33 @@ SETTINGS_PROVIDER = 'svarga.core.provide # List of global-configuration initializers. # By default, Svarga will create virtual mappings for registered applications -GLOBAL_INIT = ( +GLOBAL_INIT = [ 'svarga.alias.init', 'svarga.apps.init', - ) + ] # List of local-configuration initializers # Their responsibility is to map settings to the request-level configuration. -LOCAL_INIT = ( +LOCAL_INIT = [ 'svarga.template.LocalSettingsProvider', 'svarga.apps.LocalSettingsProvider', - ) + ] # Application initializers -APPS_INIT = ( +APPS_INIT = [ 'svarga.models.apps.contribute', - ) + ] + +TEMPLATE_LOADERS = [ + 'svarga.template.loaders.PathLoader', + 'svarga.template.loaders.AppLoader' + ] # Virtual application mapping. First value is application identification string. # Second parameter is module to use. # Mappings are generated only once, when Svarga global configuration is # initialized. -# You can import applications using virtual path starting with 'svarga.apps'. +# You can import applications using virtual path starting with 'svarga.alias'. # Sample: # ALIASES = { # 'contrib.auth': 'svarga.contrib.auth', @@ -34,7 +39,7 @@ APPS_INIT = ( # } # In above example, you can access 'contrib.auth' application using # 'import svarga.alias.contrib.auth'. You're not limited with app module only -# import. If you reference any submodules undef given application. +# import, you can reference any submodules under given application. # So, from svarga.alias.contrib.auth.models import User will also work, if you # have 'models' module with 'User' in it. ALIASES = {} diff --git a/svarga/template/__init__.py b/svarga/template/__init__.py --- a/svarga/template/__init__.py +++ b/svarga/template/__init__.py @@ -1,18 +1,15 @@ -from jinja2 import Environment, FileSystemLoader +from jinja2 import Environment, ChoiceLoader -from svarga.core.exceptions import ImproperlyConfigured +from svarga.utils.imports import import_attribute class LocalSettingsProvider(object): """Create jinja2 environment using configuration settings.""" def __init__(self, env_class): - template_path = getattr(env_class.settings, 'TEMPLATE_PATH', None) - - if template_path is None: - raise ImproperlyConfigured('Failed to initialize Jinja2 context - missing TEMPLATE_PATH in local settings') - # Get any user supplied extensions (if any) extensions = getattr(env_class.settings, 'JINJA_EXTENSIONS', []) extensions.extend(['svarga.template.tags.UrlReverseExtension']) + loaders = map(lambda x: import_attribute(x)(env_class), + env_class.settings.TEMPLATE_LOADERS) - env_class.jinja = Environment(loader=FileSystemLoader(template_path), - extensions=extensions) + env_class.jinja = Environment(loader=ChoiceLoader(loaders), + extensions=extensions) diff --git a/svarga/template/loaders.py b/svarga/template/loaders.py new file mode 100644 --- /dev/null +++ b/svarga/template/loaders.py @@ -0,0 +1,30 @@ +from jinja2 import FileSystemLoader, PackageLoader +from jinja2.exceptions import TemplateNotFound + +from svarga.core.exceptions import ImproperlyConfigured + +class PathLoader(FileSystemLoader): + def __init__(self, env_class): + self.encoding = 'utf-8' + self.searchpath = getattr(env_class.settings, 'TEMPLATE_PATHS', None) + if not self.searchpath: + raise ImproperlyConfigured('Failed to inialize PathLoader - settings has no or empty TEMPLATE_PATHS') + +class AppLoader(PackageLoader): + def __init__(self, env_class): + from pkg_resources import ResourceManager + self.encoding = 'utf-8' + self.package_path = 'templates' + self.env_class = env_class + self.manager = ResourceManager() + + def get_source(self, environment, template): + from pkg_resources import get_provider, DefaultProvider + for app in self.env_class.apps: + self.provider = get_provider(app) + self.filesystem_bound = isinstance(self.provider, DefaultProvider) + try: + return super(AppLoader, self).get_source(environment, template) + except TemplateNotFound: + pass + raise TemplateNotFound(template)