summaryrefslogtreecommitdiffstats
path: root/coffin/common.py
blob: 2e381ff382c664934bcbf18f1970321fb591a76f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import os
import warnings

from django import dispatch
from jinja2 import Environment, loaders

__all__ = ('env', 'need_env')

env = None

_JINJA_I18N_EXTENSION_NAME = 'jinja2.ext.i18n'

# TODO: This should be documented (as even I'm not sure where it's use-case is)
need_env = dispatch.Signal(providing_args=['arguments', 'loaders',
                                           'filters', 'extensions',
                                           'globals', 'tests'])

class CoffinEnvironment(Environment):
    def __init__(self, filters={}, globals={}, tests={}, loader=None, extensions=[], **kwargs):
        if not loader:
            loader = loaders.ChoiceLoader(self._get_loaders())
        all_ext = self._get_all_extensions()
        
        extensions.extend(all_ext['extensions'])
        super(CoffinEnvironment, self).__init__(extensions=extensions, loader=loader, **kwargs)
        self.filters.update(filters)
        self.filters.update(all_ext['filters'])
        self.globals.update(globals)
        self.globals.update(all_ext['globals'])
        self.tests.update(tests)
        self.tests.update(all_ext['tests'])

        from coffin.template import Template as CoffinTemplate
        self.template_class = CoffinTemplate
        
    def _get_loaders(self):
        """Tries to translate each template loader given in the Django settings
        (:mod:`django.settings`) to a similarly-behaving Jinja loader.
        Warns if a similar loader cannot be found.
        Allows for Jinja2 loader instances to be placed in the template loader
        settings.
        """
        loaders = []
        
        from coffin.template.loaders import jinja_loader_from_django_loader

        from django.conf import settings
        for loader in settings.TEMPLATE_LOADERS:
            if isinstance(loader, basestring):
                loader_obj = jinja_loader_from_django_loader(loader)
                if loader_obj:
                    loaders.append(loader_obj)
                else:
                    warnings.warn('Cannot translate loader: %s' % loader)
            else: # It's assumed to be a Jinja2 loader instance.
                loaders.append(loader)
        return loaders


    def _get_templatelibs(self):
        """Return an iterable of template ``Library`` instances.

        Since we cannot support the {% load %} tag in Jinja, we have to
        register all libraries globally.
        """
        from django.conf import settings
        from django.template import get_library, InvalidTemplateLibrary

        libs = []
        for a in settings.INSTALLED_APPS:
            try:
                path = __import__(a + '.templatetags', {}, {}, ['__file__']).__file__
                path = os.path.dirname(path)  # we now have the templatetags/ directory
            except ImportError:
                pass
            else:
                for f in os.listdir(path):
                    if f == '__init__.py':
                        continue
                    if f.endswith('.py'):
                        try:
                            # TODO: will need updating when #6587 lands
                            libs.append(get_library(
                                "django.templatetags.%s" % os.path.splitext(f)[0]))
                        except InvalidTemplateLibrary:
                            pass
        return libs

    def _get_all_extensions(self):
        from django.conf import settings
        from coffin.template import builtins
        from django.core.urlresolvers import get_callable

        extensions, filters, globals, tests = [], {}, {}, {}

        # start with our builtins
        for lib in builtins:
            extensions.extend(getattr(lib, 'jinja2_extensions', []))
            filters.update(getattr(lib, 'jinja2_filters', {}))
            globals.update(getattr(lib, 'jinja2_globals', {}))
            tests.update(getattr(lib, 'jinja2_tests', {}))

        if settings.USE_I18N:
            extensions.append(_JINJA_I18N_EXTENSION_NAME)

        # add the globally defined extension list
        extensions.extend(list(getattr(settings, 'JINJA2_EXTENSIONS', [])))

        def from_setting(setting):
            retval = {}
            setting = getattr(settings, setting, {})
            if isinstance(setting, dict):
                for key, value in setting.iteritems():
                    retval[user] = callable(value) and value or get_callable(value)
            else:
                for value in setting:
                    value = callable(value) and value or get_callable(value)
                    retval[value.__name__] = value
            return retval

        filters.update(from_setting('JINJA2_FILTERS'))
        globals.update(from_setting('JINJA2_GLOBALS'))
        tests.update(from_setting('JINJA2_TESTS'))

        # add extensions defined in application's templatetag libraries
        for lib in self._get_templatelibs():
            extensions.extend(getattr(lib, 'jinja2_extensions', []))
            filters.update(getattr(lib, 'jinja2_filters', {}))
            globals.update(getattr(lib, 'jinja2_globals', {}))
            tests.update(getattr(lib, 'jinja2_tests', {}))

        return dict(
            extensions=extensions,
            filters=filters,
            globals=globals,
            tests=tests,
        )

def get_env():
    """
    :return: A Jinja2 environment singleton.
    """
    # need_env.send(sender=Environment, arguments=arguments,
    #                       loaders=loaders_, extensions=extensions,
    #                       filters=filters, tests=tests, globals=globals)
    return CoffinEnvironment(autoescape=True)

env = get_env()