Skip to content

Commit

Permalink
need_env is disabled (until documented). env is now static.
Browse files Browse the repository at this point in the history
  • Loading branch information
David Cramer committed Sep 14, 2009
1 parent e44bb8a commit 7dbd769
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 169 deletions.
263 changes: 131 additions & 132 deletions coffin/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,146 +4,145 @@
from django import dispatch
from jinja2 import Environment, loaders

__all__ = ('get_env', 'need_env')
__all__ = ('env', 'need_env')

env = None

_ENV = None
_LOADERS = [] # See :fun:`_infer_loaders`.
_TEMPLATE_LIBS = []
_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'])
def _get_loaders():
"""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.
"""
from coffin.template.loaders import jinja_loader_from_django_loader
global _LOADERS

if _LOADERS:
return _LOADERS
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)
'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:
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():
"""Return an iterable of template ``Library`` instances.
Since we cannot support the {% load %} tag in Jinja, we have to
register all libraries globally.
"""
global _TEMPLATE_LIBS

if _TEMPLATE_LIBS:
return _TEMPLATE_LIBS

from django.conf import settings
from django.template import get_library, InvalidTemplateLibrary

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
_TEMPLATE_LIBS.append(get_library(
"django.templatetags.%s" % os.path.splitext(f)[0]))
except InvalidTemplateLibrary:
pass
return _TEMPLATE_LIBS

def _get_all_extensions():
# TODO: should these be cached as well?
from django.conf import settings
from coffin.template import builtins
from django.core.urlresolvers import get_callable

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

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

if settings.USE_I18N:
extensions.append(_JINJA_I18N_EXTENSION_NAME)

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

user = getattr(settings, 'JINJA2_FILTERS', {})
if isinstance(user, dict):
for key, value in user.iteritems():
filters[user] = callable(value) and value or get_callable(value)
else:
for value in user:
value = callable(value) and value or get_callable(value)
filters[value.__name__] = value

user = getattr(settings, 'JINJA2_GLOBALS', {})
if isinstance(user, dict):
for key, value in user.iteritems():
globals[user] = callable(value) and value or get_callable(value)
else:
for value in user:
value = callable(value) and value or get_callable(value)
globals[value.__name__] = value

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

return extensions, filters, globals
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.
"""
global _ENV

if not _ENV:
loaders_ = _get_loaders()
extensions, filters, globals = _get_all_extensions()
arguments = {
'autoescape': True,
}

need_env.send(sender=Environment, arguments=arguments,
loaders=loaders_, extensions=extensions,
filters=filters, globals=globals)

if not _ENV:
if not 'loader' in arguments:
arguments['loader'] = loaders.ChoiceLoader(loaders_)
if not 'extensions' in arguments:
arguments['extensions'] = extensions

_ENV = Environment(**arguments)
_ENV.filters.update(filters)
_ENV.globals.update(globals)
from coffin.template import Template as CoffinTemplate
_ENV.template_class = CoffinTemplate
return _ENV
# need_env.send(sender=Environment, arguments=arguments,
# loaders=loaders_, extensions=extensions,
# filters=filters, tests=tests, globals=globals)
return CoffinEnvironment(autoescape=True)

env = get_env()
4 changes: 2 additions & 2 deletions coffin/template/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
add_to_builtins as django_add_to_builtins,
get_library)
from jinja2 import Template as _Jinja2Template
from coffin.common import get_env

# Merge with ``django.template``.
from django.template import __all__
Expand All @@ -29,8 +28,9 @@ def __new__(cls, template_string, origin=None, name=None):
# We accept the "origin" and "name" arguments, but discard them
# right away - Jinja's Template class (apparently) stores no
# equivalent information.
from coffin.common import env

return get_env().from_string(template_string, template_class=cls)
return env.from_string(template_string, template_class=cls)

def __iter__(self):
# TODO: Django allows iterating over the templates nodes. Should
Expand Down
11 changes: 1 addition & 10 deletions coffin/template/defaultfilters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@

from coffin.template import Library
from jinja2.runtime import Undefined

# from jinja2 import Markup

register = Library()


@register.filter(jinja2_only=True)
def url(view_name, *args, **kwargs):
from coffin.template.defaulttags import url
return url._reverse(view_name, args, kwargs)


@register.filter(jinja2_only=True)
def timesince(value, arg=None):
if value is None or isinstance(value, Undefined):
Expand All @@ -25,15 +23,13 @@ def timesince(value, arg=None):
return timesince(value, arg)
return timesince(value)


@register.filter(jinja2_only=True)
def timeuntil(value, arg=None):
if value is None or isinstance(value, Undefined):
return u''
from django.utils.timesince import timeuntil
return timeuntil(date, arg)


@register.filter(jinja2_only=True)
def date(value, arg=None):
if value is None or isinstance(value, Undefined):
Expand All @@ -44,7 +40,6 @@ def date(value, arg=None):
arg = settings.DATE_FORMAT
return format(value, arg)


@register.filter(jinja2_only=True)
def time(value, arg=None):
if value is None or isinstance(value, Undefined):
Expand All @@ -55,21 +50,18 @@ def time(value, arg=None):
arg = settings.TIME_FORMAT
return time_format(value, arg)


@register.filter(jinja2_only=True)
def truncatewords(value, length):
# Jinja2 has it's own ``truncate`` filter that supports word
# boundaries and more stuff, but cannot deal with HTML.
from django.utils.text import truncate_words
return truncate_words(value, int(length))


@register.filter(jinja2_only=True)
def truncatewords_html(value, length):
from django.utils.text import truncate_html_words
return truncate_html_words(value, int(length))


@register.filter(jinja2_only=True)
def pluralize(value, s1='s', s2=None):
"""Like Django's pluralize-filter, but instead of using an optional
Expand All @@ -93,7 +85,6 @@ def pluralize(value, s1='s', s2=None):
return plural_suffix
return singular_suffix


@register.filter(jinja2_only=True)
def floatformat(value, arg=-1):
"""Builds on top of Django's own version, but adds strict error
Expand Down

0 comments on commit 7dbd769

Please sign in to comment.