web/lib/django/template/__init__.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
    46 u'<html><h1>Hello</h1></html>'
    46 u'<html><h1>Hello</h1></html>'
    47 >>> c = template.Context({'test':False, 'varvalue': 'Hello'})
    47 >>> c = template.Context({'test':False, 'varvalue': 'Hello'})
    48 >>> t.render(c)
    48 >>> t.render(c)
    49 u'<html></html>'
    49 u'<html></html>'
    50 """
    50 """
       
    51 import imp
    51 import re
    52 import re
    52 from inspect import getargspec
    53 from inspect import getargspec
    53 
    54 
    54 from django.conf import settings
    55 from django.conf import settings
    55 from django.template.context import Context, RequestContext, ContextPopException
    56 from django.template.context import Context, RequestContext, ContextPopException
    56 from django.utils.importlib import import_module
    57 from django.utils.importlib import import_module
    57 from django.utils.itercompat import is_iterable
    58 from django.utils.itercompat import is_iterable
    58 from django.utils.functional import curry, Promise
    59 from django.utils.functional import curry, Promise
    59 from django.utils.text import smart_split, unescape_string_literal
    60 from django.utils.text import smart_split, unescape_string_literal, get_text_list
    60 from django.utils.encoding import smart_unicode, force_unicode, smart_str
    61 from django.utils.encoding import smart_unicode, force_unicode, smart_str
    61 from django.utils.translation import ugettext as _
    62 from django.utils.translation import ugettext as _
    62 from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping
    63 from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping
       
    64 from django.utils.formats import localize
    63 from django.utils.html import escape
    65 from django.utils.html import escape
       
    66 from django.utils.module_loading import module_has_submodule
    64 
    67 
    65 __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
    68 __all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
    66 
    69 
    67 TOKEN_TEXT = 0
    70 TOKEN_TEXT = 0
    68 TOKEN_VAR = 1
    71 TOKEN_VAR = 1
    84 
    87 
    85 ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'
    88 ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'
    86 
    89 
    87 # what to report as the origin for templates that come from non-loader sources
    90 # what to report as the origin for templates that come from non-loader sources
    88 # (e.g. strings)
    91 # (e.g. strings)
    89 UNKNOWN_SOURCE="&lt;unknown source&gt;"
    92 UNKNOWN_SOURCE = '<unknown source>'
    90 
    93 
    91 # match a variable or block tag and capture the entire tag, including start/end delimiters
    94 # match a variable or block tag and capture the entire tag, including start/end delimiters
    92 tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
    95 tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
    93                                           re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
    96                                           re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
    94                                           re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
    97                                           re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
   101 # True if TEMPLATE_STRING_IF_INVALID contains a format string (%s). None means
   104 # True if TEMPLATE_STRING_IF_INVALID contains a format string (%s). None means
   102 # uninitialised.
   105 # uninitialised.
   103 invalid_var_format_string = None
   106 invalid_var_format_string = None
   104 
   107 
   105 class TemplateSyntaxError(Exception):
   108 class TemplateSyntaxError(Exception):
   106     def __str__(self):
   109     pass
   107         try:
       
   108             import cStringIO as StringIO
       
   109         except ImportError:
       
   110             import StringIO
       
   111         output = StringIO.StringIO()
       
   112         output.write(Exception.__str__(self))
       
   113         # Check if we wrapped an exception and print that too.
       
   114         if hasattr(self, 'exc_info'):
       
   115             import traceback
       
   116             output.write('\n\nOriginal ')
       
   117             e = self.exc_info
       
   118             traceback.print_exception(e[0], e[1], e[2], 500, output)
       
   119         return output.getvalue()
       
   120 
   110 
   121 class TemplateDoesNotExist(Exception):
   111 class TemplateDoesNotExist(Exception):
   122     pass
   112     pass
   123 
   113 
   124 class TemplateEncodingError(Exception):
   114 class TemplateEncodingError(Exception):
   171     def __iter__(self):
   161     def __iter__(self):
   172         for node in self.nodelist:
   162         for node in self.nodelist:
   173             for subnode in node:
   163             for subnode in node:
   174                 yield subnode
   164                 yield subnode
   175 
   165 
       
   166     def _render(self, context):
       
   167         return self.nodelist.render(context)
       
   168 
   176     def render(self, context):
   169     def render(self, context):
   177         "Display stage -- can be called many times"
   170         "Display stage -- can be called many times"
   178         return self.nodelist.render(context)
   171         context.render_context.push()
       
   172         try:
       
   173             return self._render(context)
       
   174         finally:
       
   175             context.render_context.pop()
   179 
   176 
   180 def compile_string(template_string, origin):
   177 def compile_string(template_string, origin):
   181     "Compiles template_string into NodeList ready for rendering"
   178     "Compiles template_string into NodeList ready for rendering"
   182     if settings.TEMPLATE_DEBUG:
   179     if settings.TEMPLATE_DEBUG:
   183         from debug import DebugLexer, DebugParser
   180         from debug import DebugLexer, DebugParser
   278                 # execute callback function for this tag and append resulting node
   275                 # execute callback function for this tag and append resulting node
   279                 self.enter_command(command, token)
   276                 self.enter_command(command, token)
   280                 try:
   277                 try:
   281                     compile_func = self.tags[command]
   278                     compile_func = self.tags[command]
   282                 except KeyError:
   279                 except KeyError:
   283                     self.invalid_block_tag(token, command)
   280                     self.invalid_block_tag(token, command, parse_until)
   284                 try:
   281                 try:
   285                     compiled_result = compile_func(self, token)
   282                     compiled_result = compile_func(self, token)
   286                 except TemplateSyntaxError, e:
   283                 except TemplateSyntaxError, e:
   287                     if not self.compile_function_error(token, e):
   284                     if not self.compile_function_error(token, e):
   288                         raise
   285                         raise
   329         raise self.error(token, "Empty variable tag")
   326         raise self.error(token, "Empty variable tag")
   330 
   327 
   331     def empty_block_tag(self, token):
   328     def empty_block_tag(self, token):
   332         raise self.error(token, "Empty block tag")
   329         raise self.error(token, "Empty block tag")
   333 
   330 
   334     def invalid_block_tag(self, token, command):
   331     def invalid_block_tag(self, token, command, parse_until=None):
       
   332         if parse_until:
       
   333             raise self.error(token, "Invalid block tag: '%s', expected %s" % (command, get_text_list(["'%s'" % p for p in parse_until])))
   335         raise self.error(token, "Invalid block tag: '%s'" % command)
   334         raise self.error(token, "Invalid block tag: '%s'" % command)
   336 
   335 
   337     def unclosed_block_tag(self, parse_until):
   336     def unclosed_block_tag(self, parse_until):
   338         raise self.error(None, "Unclosed tags: %s " %  ', '.join(parse_until))
   337         raise self.error(None, "Unclosed tags: %s " %  ', '.join(parse_until))
   339 
   338 
   409 
   408 
   410     def value(self):
   409     def value(self):
   411         "A microparser that parses for a value: some string constant or variable name."
   410         "A microparser that parses for a value: some string constant or variable name."
   412         subject = self.subject
   411         subject = self.subject
   413         i = self.pointer
   412         i = self.pointer
       
   413 
       
   414         def next_space_index(subject, i):
       
   415             "Increment pointer until a real space (i.e. a space not within quotes) is encountered"
       
   416             while i < len(subject) and subject[i] not in (' ', '\t'):
       
   417                 if subject[i] in ('"', "'"):
       
   418                     c = subject[i]
       
   419                     i += 1
       
   420                     while i < len(subject) and subject[i] != c:
       
   421                         i += 1
       
   422                     if i >= len(subject):
       
   423                         raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
       
   424                 i += 1
       
   425             return i
       
   426 
   414         if i >= len(subject):
   427         if i >= len(subject):
   415             raise TemplateSyntaxError("Searching for value. Expected another value but found end of string: %s" % subject)
   428             raise TemplateSyntaxError("Searching for value. Expected another value but found end of string: %s" % subject)
   416         if subject[i] in ('"', "'"):
   429         if subject[i] in ('"', "'"):
   417             p = i
   430             p = i
   418             i += 1
   431             i += 1
   419             while i < len(subject) and subject[i] != subject[p]:
   432             while i < len(subject) and subject[i] != subject[p]:
   420                 i += 1
   433                 i += 1
   421             if i >= len(subject):
   434             if i >= len(subject):
   422                 raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
   435                 raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
   423             i += 1
   436             i += 1
       
   437 
       
   438             # Continue parsing until next "real" space, so that filters are also included
       
   439             i = next_space_index(subject, i)
       
   440 
   424             res = subject[p:i]
   441             res = subject[p:i]
   425             while i < len(subject) and subject[i] in (' ', '\t'):
   442             while i < len(subject) and subject[i] in (' ', '\t'):
   426                 i += 1
   443                 i += 1
   427             self.backout.append(self.pointer)
   444             self.backout.append(self.pointer)
   428             self.pointer = i
   445             self.pointer = i
   429             return res
   446             return res
   430         else:
   447         else:
   431             p = i
   448             p = i
   432             while i < len(subject) and subject[i] not in (' ', '\t'):
   449             i = next_space_index(subject, i)
   433                 if subject[i] in ('"', "'"):
       
   434                     c = subject[i]
       
   435                     i += 1
       
   436                     while i < len(subject) and subject[i] != c:
       
   437                         i += 1
       
   438                     if i >= len(subject):
       
   439                         raise TemplateSyntaxError("Searching for value. Unexpected end of string in column %d: %s" % (i, subject))
       
   440                 i += 1
       
   441             s = subject[p:i]
   450             s = subject[p:i]
   442             while i < len(subject) and subject[i] in (' ', '\t'):
   451             while i < len(subject) and subject[i] in (' ', '\t'):
   443                 i += 1
   452                 i += 1
   444             self.backout.append(self.pointer)
   453             self.backout.append(self.pointer)
   445             self.pointer = i
   454             self.pointer = i
   516                         var_obj = Variable(constant).resolve({})
   525                         var_obj = Variable(constant).resolve({})
   517                     except VariableDoesNotExist:
   526                     except VariableDoesNotExist:
   518                         var_obj = None
   527                         var_obj = None
   519                 elif var is None:
   528                 elif var is None:
   520                     raise TemplateSyntaxError("Could not find variable at start of %s." % token)
   529                     raise TemplateSyntaxError("Could not find variable at start of %s." % token)
   521                 elif var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or var[0] == '_':
       
   522                     raise TemplateSyntaxError("Variables and attributes may not begin with underscores: '%s'" % var)
       
   523                 else:
   530                 else:
   524                     var_obj = Variable(var)
   531                     var_obj = Variable(var)
   525             else:
   532             else:
   526                 filter_name = match.group("filter_name")
   533                 filter_name = match.group("filter_name")
   527                 args = []
   534                 args = []
   529                 if constant_arg:
   536                 if constant_arg:
   530                     args.append((False, Variable(constant_arg).resolve({})))
   537                     args.append((False, Variable(constant_arg).resolve({})))
   531                 elif var_arg:
   538                 elif var_arg:
   532                     args.append((True, Variable(var_arg)))
   539                     args.append((True, Variable(var_arg)))
   533                 filter_func = parser.find_filter(filter_name)
   540                 filter_func = parser.find_filter(filter_name)
   534                 self.args_check(filter_name,filter_func, args)
   541                 self.args_check(filter_name, filter_func, args)
   535                 filters.append( (filter_func,args))
   542                 filters.append((filter_func, args))
   536             upto = match.end()
   543             upto = match.end()
   537         if upto != len(token):
   544         if upto != len(token):
   538             raise TemplateSyntaxError("Could not parse the remainder: '%s' from '%s'" % (token[upto:], token))
   545             raise TemplateSyntaxError("Could not parse the remainder: '%s' from '%s'" % (token[upto:], token))
   539 
   546 
   540         self.filters = filters
   547         self.filters = filters
   676             try:
   683             try:
   677                 self.literal = mark_safe(unescape_string_literal(var))
   684                 self.literal = mark_safe(unescape_string_literal(var))
   678             except ValueError:
   685             except ValueError:
   679                 # Otherwise we'll set self.lookups so that resolve() knows we're
   686                 # Otherwise we'll set self.lookups so that resolve() knows we're
   680                 # dealing with a bonafide variable
   687                 # dealing with a bonafide variable
       
   688                 if var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or var[0] == '_':
       
   689                     raise TemplateSyntaxError("Variables and attributes may not begin with underscores: '%s'" % var)
   681                 self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR))
   690                 self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR))
   682 
   691 
   683     def resolve(self, context):
   692     def resolve(self, context):
   684         """Resolve this variable against a given context."""
   693         """Resolve this variable against a given context."""
   685         if self.lookups is not None:
   694         if self.lookups is not None:
   741                 except Exception, e:
   750                 except Exception, e:
   742                     if getattr(e, 'silent_variable_failure', False):
   751                     if getattr(e, 'silent_variable_failure', False):
   743                         current = settings.TEMPLATE_STRING_IF_INVALID
   752                         current = settings.TEMPLATE_STRING_IF_INVALID
   744                     else:
   753                     else:
   745                         raise
   754                         raise
       
   755             except Exception, e:
       
   756                 if getattr(e, 'silent_variable_failure', False):
       
   757                     current = settings.TEMPLATE_STRING_IF_INVALID
       
   758                 else:
       
   759                     raise
   746 
   760 
   747         return current
   761         return current
   748 
   762 
   749 class Node(object):
   763 class Node(object):
   750     # Set this to True for nodes that must be first in the template (although
   764     # Set this to True for nodes that must be first in the template (although
   751     # they can be preceded by text nodes.
   765     # they can be preceded by text nodes.
   752     must_be_first = False
   766     must_be_first = False
       
   767     child_nodelists = ('nodelist',)
   753 
   768 
   754     def render(self, context):
   769     def render(self, context):
   755         "Return the node rendered as a string"
   770         "Return the node rendered as a string"
   756         pass
   771         pass
   757 
   772 
   761     def get_nodes_by_type(self, nodetype):
   776     def get_nodes_by_type(self, nodetype):
   762         "Return a list of all nodes (within this node and its nodelist) of the given type"
   777         "Return a list of all nodes (within this node and its nodelist) of the given type"
   763         nodes = []
   778         nodes = []
   764         if isinstance(self, nodetype):
   779         if isinstance(self, nodetype):
   765             nodes.append(self)
   780             nodes.append(self)
   766         if hasattr(self, 'nodelist'):
   781         for attr in self.child_nodelists:
   767             nodes.extend(self.nodelist.get_nodes_by_type(nodetype))
   782             nodelist = getattr(self, attr, None)
       
   783             if nodelist:
       
   784                 nodes.extend(nodelist.get_nodes_by_type(nodetype))
   768         return nodes
   785         return nodes
   769 
   786 
   770 class NodeList(list):
   787 class NodeList(list):
   771     # Set to True the first time a non-TextNode is inserted by
   788     # Set to True the first time a non-TextNode is inserted by
   772     # extend_nodelist().
   789     # extend_nodelist().
   799         return "<Text Node: '%s'>" % smart_str(self.s[:25], 'ascii',
   816         return "<Text Node: '%s'>" % smart_str(self.s[:25], 'ascii',
   800                 errors='replace')
   817                 errors='replace')
   801 
   818 
   802     def render(self, context):
   819     def render(self, context):
   803         return self.s
   820         return self.s
   804     
   821 
   805 def _render_value_in_context(value, context):
   822 def _render_value_in_context(value, context):
   806     """
   823     """
   807     Converts any value to a string to become part of a rendered template. This
   824     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
   825     means escaping, if required, and conversion to a unicode object. If value
   809     is a string, it is expected to have already been translated.
   826     is a string, it is expected to have already been translated.
   810     """
   827     """
       
   828     value = localize(value)
   811     value = force_unicode(value)
   829     value = force_unicode(value)
   812     if (context.autoescape and not isinstance(value, SafeData)) or isinstance(value, EscapeData):
   830     if (context.autoescape and not isinstance(value, SafeData)) or isinstance(value, EscapeData):
   813         return escape(value)
   831         return escape(value)
   814     else:
   832     else:
   815         return value
   833         return value
   940                         if not isinstance(file_name, basestring) and is_iterable(file_name):
   958                         if not isinstance(file_name, basestring) and is_iterable(file_name):
   941                             t = select_template(file_name)
   959                             t = select_template(file_name)
   942                         else:
   960                         else:
   943                             t = get_template(file_name)
   961                             t = get_template(file_name)
   944                         self.nodelist = t.nodelist
   962                         self.nodelist = t.nodelist
   945                     return self.nodelist.render(context_class(dict,
   963                     new_context = context_class(dict, autoescape=context.autoescape)
   946                             autoescape=context.autoescape))
   964                     # Copy across the CSRF token, if present, because inclusion
       
   965                     # tags are often used for forms, and we need instructions
       
   966                     # for using CSRF protection to be as simple as possible.
       
   967                     csrf_token = context.get('csrf_token', None)
       
   968                     if csrf_token is not None:
       
   969                         new_context['csrf_token'] = csrf_token
       
   970                     return self.nodelist.render(new_context)
   947 
   971 
   948             compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, InclusionNode)
   972             compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, InclusionNode)
   949             compile_func.__doc__ = func.__doc__
   973             compile_func.__doc__ = func.__doc__
   950             self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
   974             self.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
   951             return func
   975             return func
   952         return dec
   976         return dec
   953 
   977 
   954 def get_library(module_name):
   978 def import_library(taglib_module):
   955     lib = libraries.get(module_name, None)
   979     """Load a template tag library module.
       
   980 
       
   981     Verifies that the library contains a 'register' attribute, and
       
   982     returns that attribute as the representation of the library
       
   983     """
       
   984     app_path, taglib = taglib_module.rsplit('.',1)
       
   985     app_module = import_module(app_path)
       
   986     try:
       
   987         mod = import_module(taglib_module)
       
   988     except ImportError, e:
       
   989         # If the ImportError is because the taglib submodule does not exist, that's not
       
   990         # an error that should be raised. If the submodule exists and raised an ImportError
       
   991         # on the attempt to load it, that we want to raise.
       
   992         if not module_has_submodule(app_module, taglib):
       
   993             return None
       
   994         else:
       
   995             raise InvalidTemplateLibrary("ImportError raised loading %s: %s" % (taglib_module, e))
       
   996     try:
       
   997         return mod.register
       
   998     except AttributeError:
       
   999         raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % taglib_module)
       
  1000 
       
  1001 templatetags_modules = []
       
  1002 
       
  1003 def get_templatetags_modules():
       
  1004     """Return the list of all available template tag modules.
       
  1005 
       
  1006     Caches the result for faster access.
       
  1007     """
       
  1008     global templatetags_modules
       
  1009     if not templatetags_modules:
       
  1010         _templatetags_modules = []
       
  1011         # Populate list once per thread.
       
  1012         for app_module in ['django'] + list(settings.INSTALLED_APPS):
       
  1013             try:
       
  1014                 templatetag_module = '%s.templatetags' % app_module
       
  1015                 import_module(templatetag_module)
       
  1016                 _templatetags_modules.append(templatetag_module)
       
  1017             except ImportError:
       
  1018                 continue
       
  1019         templatetags_modules = _templatetags_modules
       
  1020     return templatetags_modules
       
  1021 
       
  1022 def get_library(library_name):
       
  1023     """
       
  1024     Load the template library module with the given name.
       
  1025 
       
  1026     If library is not already loaded loop over all templatetags modules to locate it.
       
  1027 
       
  1028     {% load somelib %} and {% load someotherlib %} loops twice.
       
  1029 
       
  1030     Subsequent loads eg. {% load somelib %} in the same process will grab the cached
       
  1031     module from libraries.
       
  1032     """
       
  1033     lib = libraries.get(library_name, None)
   956     if not lib:
  1034     if not lib:
   957         try:
  1035         templatetags_modules = get_templatetags_modules()
   958             mod = import_module(module_name)
  1036         tried_modules = []
   959         except ImportError, e:
  1037         for module in templatetags_modules:
   960             raise InvalidTemplateLibrary("Could not load template library from %s, %s" % (module_name, e))
  1038             taglib_module = '%s.%s' % (module, library_name)
   961         try:
  1039             tried_modules.append(taglib_module)
   962             lib = mod.register
  1040             lib = import_library(taglib_module)
   963             libraries[module_name] = lib
  1041             if lib:
   964         except AttributeError:
  1042                 libraries[library_name] = lib
   965             raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % module_name)
  1043                 break
       
  1044         if not lib:
       
  1045             raise InvalidTemplateLibrary("Template library %s not found, tried %s" % (library_name, ','.join(tried_modules)))
   966     return lib
  1046     return lib
   967 
  1047 
   968 def add_to_builtins(module_name):
  1048 def add_to_builtins(module):
   969     builtins.append(get_library(module_name))
  1049     builtins.append(import_library(module))
   970 
  1050 
   971 add_to_builtins('django.template.defaulttags')
  1051 add_to_builtins('django.template.defaulttags')
   972 add_to_builtins('django.template.defaultfilters')
  1052 add_to_builtins('django.template.defaultfilters')