52
52
from inspect import getargspec
53
54
from django.conf import settings
54
55
from django.template.context import Context, RequestContext, ContextPopException
56
from django.utils.importlib import import_module
55
57
from django.utils.itercompat import is_iterable
56
58
from django.utils.functional import curry, Promise
57
from django.utils.text import smart_split
58
from django.utils.encoding import smart_unicode, force_unicode
59
from django.utils.text import smart_split, unescape_string_literal
60
from django.utils.encoding import smart_unicode, force_unicode, smart_str
59
61
from django.utils.translation import ugettext as _
60
62
from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping
61
63
from django.utils.html import escape
448
# This only matches constant *strings* (things in quotes or marked for
449
# translation). Numbers are treated as variables for implementation reasons
450
# (so that they retain their type when passed to filters).
451
constant_string = r"""
452
(?:%(i18n_open)s%(strdq)s%(i18n_close)s|
453
%(i18n_open)s%(strsq)s%(i18n_close)s|
457
'strdq': r'"[^"\\]*(?:\\.[^"\\]*)*"', # double-quoted string
458
'strsq': r"'[^'\\]*(?:\\.[^'\\]*)*'", # single-quoted string
459
'i18n_open' : re.escape("_("),
460
'i18n_close' : re.escape(")"),
462
constant_string = constant_string.replace("\n", "")
446
464
filter_raw_string = r"""
447
^%(i18n_open)s"(?P<i18n_constant>%(str)s)"%(i18n_close)s|
448
^"(?P<constant>%(str)s)"|
449
^(?P<var>[%(var_chars)s]+)|
465
^(?P<constant>%(constant)s)|
466
^(?P<var>[%(var_chars)s]+|%(num)s)|
450
467
(?:%(filter_sep)s
451
468
(?P<filter_name>\w+)
454
%(i18n_open)s"(?P<i18n_arg>%(str)s)"%(i18n_close)s|
455
"(?P<constant_arg>%(str)s)"|
456
(?P<var_arg>[%(var_chars)s]+)
471
(?P<constant_arg>%(constant)s)|
472
(?P<var_arg>[%(var_chars)s]+|%(num)s)
460
'str': r"""[^"\\]*(?:\\.[^"\\]*)*""",
476
'constant': constant_string,
477
'num': r'[-+\.]?\d[\d\.e]*',
461
478
'var_chars': "\w\." ,
462
479
'filter_sep': re.escape(FILTER_SEPARATOR),
463
480
'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR),
464
'i18n_open' : re.escape("_("),
465
'i18n_close' : re.escape(")"),
468
filter_raw_string = filter_raw_string.replace("\n", "").replace(" ", "")
469
filter_re = re.compile(filter_raw_string, re.UNICODE)
483
filter_re = re.compile(filter_raw_string, re.UNICODE|re.VERBOSE)
471
485
class FilterExpression(object):
473
487
Parses a variable token and its optional filters (all as a single string),
474
488
and return a list of tuples of the filter name and arguments.
487
501
def __init__(self, token, parser):
488
502
self.token = token
489
503
matches = filter_re.finditer(token)
493
507
for match in matches:
494
508
start = match.start()
495
509
if upto != start:
496
510
raise TemplateSyntaxError("Could not parse some characters: %s|%s|%s" % \
497
(token[:upto], token[upto:start], token[start:]))
499
var, constant, i18n_constant = match.group("var", "constant", "i18n_constant")
500
if i18n_constant is not None:
501
# Don't pass the empty string to gettext, because the empty
502
# string translates to meta information.
503
if i18n_constant == "":
506
var = '"%s"' % _(i18n_constant.replace(r'\"', '"'))
507
elif constant is not None:
508
var = '"%s"' % constant.replace(r'\"', '"')
511
raise TemplateSyntaxError("Could not find variable at start of %s" % token)
511
(token[:upto], token[upto:start], token[start:]))
513
var, constant = match.group("var", "constant")
516
var_obj = Variable(constant).resolve({})
517
except VariableDoesNotExist:
520
raise TemplateSyntaxError("Could not find variable at start of %s." % token)
512
521
elif var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or var[0] == '_':
513
522
raise TemplateSyntaxError("Variables and attributes may not begin with underscores: '%s'" % var)
524
var_obj = Variable(var)
515
526
filter_name = match.group("filter_name")
517
constant_arg, i18n_arg, var_arg = match.group("constant_arg", "i18n_arg", "var_arg")
519
args.append((False, _(i18n_arg.replace(r'\"', '"'))))
520
elif constant_arg is not None:
521
args.append((False, constant_arg.replace(r'\"', '"')))
528
constant_arg, var_arg = match.group("constant_arg", "var_arg")
530
args.append((False, Variable(constant_arg).resolve({})))
523
532
args.append((True, Variable(var_arg)))
524
533
filter_func = parser.find_filter(filter_name)
525
534
self.args_check(filter_name,filter_func, args)
526
535
filters.append( (filter_func,args))
528
537
if upto != len(token):
529
538
raise TemplateSyntaxError("Could not parse the remainder: '%s' from '%s'" % (token[upto:], token))
530
540
self.filters = filters
531
self.var = Variable(var)
533
543
def resolve(self, context, ignore_failures=False):
535
obj = self.var.resolve(context)
536
except VariableDoesNotExist:
540
if settings.TEMPLATE_STRING_IF_INVALID:
541
global invalid_var_format_string
542
if invalid_var_format_string is None:
543
invalid_var_format_string = '%s' in settings.TEMPLATE_STRING_IF_INVALID
544
if invalid_var_format_string:
545
return settings.TEMPLATE_STRING_IF_INVALID % self.var
546
return settings.TEMPLATE_STRING_IF_INVALID
544
if isinstance(self.var, Variable):
546
obj = self.var.resolve(context)
547
except VariableDoesNotExist:
548
obj = settings.TEMPLATE_STRING_IF_INVALID
551
if settings.TEMPLATE_STRING_IF_INVALID:
552
global invalid_var_format_string
553
if invalid_var_format_string is None:
554
invalid_var_format_string = '%s' in settings.TEMPLATE_STRING_IF_INVALID
555
if invalid_var_format_string:
556
return settings.TEMPLATE_STRING_IF_INVALID % self.var
557
return settings.TEMPLATE_STRING_IF_INVALID
559
obj = settings.TEMPLATE_STRING_IF_INVALID
549
562
for func, args in self.filters:
551
564
for lookup, arg in args:
787
798
def __repr__(self):
788
return "<Text Node: '%s'>" % self.s[:25]
799
return "<Text Node: '%s'>" % smart_str(self.s[:25], 'ascii',
790
802
def render(self, context):
805
def _render_value_in_context(value, context):
807
Converts any value to a string to become part of a rendered template. This
808
means escaping, if required, and conversion to a unicode object. If value
809
is a string, it is expected to have already been translated.
811
value = force_unicode(value)
812
if (context.autoescape and not isinstance(value, SafeData)) or isinstance(value, EscapeData):
793
817
class VariableNode(Node):
794
818
def __init__(self, filter_expression):
800
824
def render(self, context):
802
output = force_unicode(self.filter_expression.resolve(context))
826
output = self.filter_expression.resolve(context)
803
827
except UnicodeDecodeError:
804
828
# Unicode conversion can fail sometimes for reasons out of our
805
829
# control (e.g. exception rendering). In that case, we fail quietly.
807
if (context.autoescape and not isinstance(output, SafeData)) or isinstance(output, EscapeData):
808
return force_unicode(escape(output))
810
return force_unicode(output)
831
return _render_value_in_context(output, context)
812
833
def generic_tag_compiler(params, defaults, name, node_class, parser, token):
813
834
"Returns a template.Node subclass."