mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Added consistent support for double- and single-quote delimiters in templates.
Some template filters and tags understood single-quoted arguments, others didn't. This makes everything consistent. Based on a patch from akaihola. Fixed #7295. git-svn-id: http://code.djangoproject.com/svn/django/trunk@10118 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -50,12 +50,13 @@ u'<html></html>' | ||||
| """ | ||||
| import re | ||||
| from inspect import getargspec | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.template.context import Context, RequestContext, ContextPopException | ||||
| from django.utils.importlib import import_module | ||||
| from django.utils.itercompat import is_iterable | ||||
| from django.utils.functional import curry, Promise | ||||
| from django.utils.text import smart_split | ||||
| from django.utils.text import smart_split, unescape_string_literal | ||||
| from django.utils.encoding import smart_unicode, force_unicode, smart_str | ||||
| from django.utils.translation import ugettext as _ | ||||
| from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping | ||||
| @@ -444,33 +445,44 @@ class TokenParser(object): | ||||
|             self.pointer = i | ||||
|             return s | ||||
|  | ||||
| constant_string = r""" | ||||
| (?:%(i18n_open)s%(strdq)s%(i18n_close)s| | ||||
| %(i18n_open)s%(strsq)s%(i18n_close)s| | ||||
| %(strdq)s| | ||||
| %(strsq)s)| | ||||
| %(num)s | ||||
| """ % { | ||||
|     'strdq': r'"[^"\\]*(?:\\.[^"\\]*)*"', # double-quoted string | ||||
|     'strsq': r"'[^'\\]*(?:\\.[^'\\]*)*'", # single-quoted string | ||||
|     'num': r'[-+\.]?\d[\d\.e]*', # numeric constant | ||||
|     'i18n_open' : re.escape("_("), | ||||
|     'i18n_close' : re.escape(")"), | ||||
|     } | ||||
| constant_string = constant_string.replace("\n", "") | ||||
|  | ||||
| filter_raw_string = r""" | ||||
| ^%(i18n_open)s"(?P<i18n_constant>%(str)s)"%(i18n_close)s| | ||||
| ^"(?P<constant>%(str)s)"| | ||||
| ^(?P<constant>%(constant)s)| | ||||
| ^(?P<var>[%(var_chars)s]+)| | ||||
|  (?:%(filter_sep)s | ||||
|      (?P<filter_name>\w+) | ||||
|          (?:%(arg_sep)s | ||||
|              (?: | ||||
|               %(i18n_open)s"(?P<i18n_arg>%(str)s)"%(i18n_close)s| | ||||
|               "(?P<constant_arg>%(str)s)"| | ||||
|               (?P<constant_arg>%(constant)s)| | ||||
|               (?P<var_arg>[%(var_chars)s]+) | ||||
|              ) | ||||
|          )? | ||||
|  )""" % { | ||||
|     'str': r"""[^"\\]*(?:\\.[^"\\]*)*""", | ||||
|     'constant': constant_string, | ||||
|     'var_chars': "\w\." , | ||||
|     'filter_sep': re.escape(FILTER_SEPARATOR), | ||||
|     'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR), | ||||
|     'i18n_open' : re.escape("_("), | ||||
|     'i18n_close' : re.escape(")"), | ||||
|   } | ||||
|  | ||||
| filter_raw_string = filter_raw_string.replace("\n", "").replace(" ", "") | ||||
| filter_re = re.compile(filter_raw_string, re.UNICODE) | ||||
|  | ||||
| class FilterExpression(object): | ||||
|     """ | ||||
|     r""" | ||||
|     Parses a variable token and its optional filters (all as a single string), | ||||
|     and return a list of tuples of the filter name and arguments. | ||||
|     Sample: | ||||
| @@ -488,65 +500,64 @@ class FilterExpression(object): | ||||
|     def __init__(self, token, parser): | ||||
|         self.token = token | ||||
|         matches = filter_re.finditer(token) | ||||
|         var = None | ||||
|         var_obj = None | ||||
|         filters = [] | ||||
|         upto = 0 | ||||
|         for match in matches: | ||||
|             start = match.start() | ||||
|             if upto != start: | ||||
|                 raise TemplateSyntaxError("Could not parse some characters: %s|%s|%s"  % \ | ||||
|                                            (token[:upto], token[upto:start], token[start:])) | ||||
|             if var == None: | ||||
|                 var, constant, i18n_constant = match.group("var", "constant", "i18n_constant") | ||||
|                 if i18n_constant is not None: | ||||
|                     # Don't pass the empty string to gettext, because the empty | ||||
|                     # string translates to meta information. | ||||
|                     if i18n_constant == "": | ||||
|                         var = '""' | ||||
|                     else: | ||||
|                         var = '"%s"' %  _(i18n_constant.replace(r'\"', '"')) | ||||
|                 elif constant is not None: | ||||
|                     var = '"%s"' % constant.replace(r'\"', '"') | ||||
|                 upto = match.end() | ||||
|                 if var == None: | ||||
|                     raise TemplateSyntaxError("Could not find variable at start of %s" % token) | ||||
|                         (token[:upto], token[upto:start], token[start:])) | ||||
|             if var_obj is None: | ||||
|                 var, constant = match.group("var", "constant") | ||||
|                 if constant: | ||||
|                     try: | ||||
|                         var_obj = Variable(constant).resolve({}) | ||||
|                     except VariableDoesNotExist: | ||||
|                         var_obj = None | ||||
|                 elif var is None: | ||||
|                     raise TemplateSyntaxError("Could not find variable at start of %s." % token) | ||||
|                 elif var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or var[0] == '_': | ||||
|                     raise TemplateSyntaxError("Variables and attributes may not begin with underscores: '%s'" % var) | ||||
|                 else: | ||||
|                     var_obj = Variable(var) | ||||
|             else: | ||||
|                 filter_name = match.group("filter_name") | ||||
|                 args = [] | ||||
|                 constant_arg, i18n_arg, var_arg = match.group("constant_arg", "i18n_arg", "var_arg") | ||||
|                 if i18n_arg: | ||||
|                     args.append((False, _(i18n_arg.replace(r'\"', '"')))) | ||||
|                 elif constant_arg is not None: | ||||
|                     args.append((False, constant_arg.replace(r'\"', '"'))) | ||||
|                 constant_arg, var_arg = match.group("constant_arg", "var_arg") | ||||
|                 if constant_arg: | ||||
|                     args.append((False, Variable(constant_arg).resolve({}))) | ||||
|                 elif var_arg: | ||||
|                     args.append((True, Variable(var_arg))) | ||||
|                 filter_func = parser.find_filter(filter_name) | ||||
|                 self.args_check(filter_name,filter_func, args) | ||||
|                 filters.append( (filter_func,args)) | ||||
|                 upto = match.end() | ||||
|             upto = match.end() | ||||
|         if upto != len(token): | ||||
|             raise TemplateSyntaxError("Could not parse the remainder: '%s' from '%s'" % (token[upto:], token)) | ||||
|  | ||||
|         self.filters = filters | ||||
|         self.var = Variable(var) | ||||
|         self.var = var_obj | ||||
|  | ||||
|     def resolve(self, context, ignore_failures=False): | ||||
|         try: | ||||
|             obj = self.var.resolve(context) | ||||
|         except VariableDoesNotExist: | ||||
|             if ignore_failures: | ||||
|                 obj = None | ||||
|             else: | ||||
|                 if settings.TEMPLATE_STRING_IF_INVALID: | ||||
|                     global invalid_var_format_string | ||||
|                     if invalid_var_format_string is None: | ||||
|                         invalid_var_format_string = '%s' in settings.TEMPLATE_STRING_IF_INVALID | ||||
|                     if invalid_var_format_string: | ||||
|                         return settings.TEMPLATE_STRING_IF_INVALID % self.var | ||||
|                     return settings.TEMPLATE_STRING_IF_INVALID | ||||
|         if isinstance(self.var, Variable): | ||||
|             try: | ||||
|                 obj = self.var.resolve(context) | ||||
|             except VariableDoesNotExist: | ||||
|                 if ignore_failures: | ||||
|                     obj = None | ||||
|                 else: | ||||
|                     obj = settings.TEMPLATE_STRING_IF_INVALID | ||||
|                     if settings.TEMPLATE_STRING_IF_INVALID: | ||||
|                         global invalid_var_format_string | ||||
|                         if invalid_var_format_string is None: | ||||
|                             invalid_var_format_string = '%s' in settings.TEMPLATE_STRING_IF_INVALID | ||||
|                         if invalid_var_format_string: | ||||
|                             return settings.TEMPLATE_STRING_IF_INVALID % self.var | ||||
|                         return settings.TEMPLATE_STRING_IF_INVALID | ||||
|                     else: | ||||
|                         obj = settings.TEMPLATE_STRING_IF_INVALID | ||||
|         else: | ||||
|             obj = self.var | ||||
|         for func, args in self.filters: | ||||
|             arg_vals = [] | ||||
|             for lookup, arg in args: | ||||
| @@ -611,7 +622,7 @@ def resolve_variable(path, context): | ||||
|     return Variable(path).resolve(context) | ||||
|  | ||||
| class Variable(object): | ||||
|     """ | ||||
|     r""" | ||||
|     A template variable, resolvable against a given context. The variable may be | ||||
|     a hard-coded string (if it begins and ends with single or double quote | ||||
|     marks):: | ||||
| @@ -625,8 +636,6 @@ class Variable(object): | ||||
|         >>> c = AClass() | ||||
|         >>> c.article = AClass() | ||||
|         >>> c.article.section = u'News' | ||||
|         >>> Variable('article.section').resolve(c) | ||||
|         u'News' | ||||
|  | ||||
|     (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') | ||||
|     """ | ||||
| @@ -663,9 +672,9 @@ class Variable(object): | ||||
|                 var = var[2:-1] | ||||
|             # If it's wrapped with quotes (single or double), then | ||||
|             # we're also dealing with a literal. | ||||
|             if var[0] in "\"'" and var[0] == var[-1]: | ||||
|                 self.literal = mark_safe(var[1:-1]) | ||||
|             else: | ||||
|             try: | ||||
|                 self.literal = mark_safe(unescape_string_literal(var)) | ||||
|             except ValueError: | ||||
|                 # Otherwise we'll set self.lookups so that resolve() knows we're | ||||
|                 # dealing with a bonafide variable | ||||
|                 self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user