=== modified file 'django/contrib/admin/templatetags/admin_modify.py'
--- django/contrib/admin/templatetags/admin_modify.py	2007-07-11 16:02:41 +0000
+++ django/contrib/admin/templatetags/admin_modify.py	2007-07-12 09:21:51 +0000
@@ -72,7 +72,7 @@
     default = None
 
     def __init__(self, bound_field_var):
-        self.bound_field_var = bound_field_var
+        self.bound_field_var = template.Variable(bound_field_var)
 
     def get_nodelist(cls, klass):
         if klass not in cls.nodelists:
@@ -96,7 +96,7 @@
     get_nodelist = classmethod(get_nodelist)
 
     def render(self, context):
-        bound_field = template.resolve_variable(self.bound_field_var, context)
+        bound_field = self.bound_field_var.resolve(context)
 
         context.push()
         context['bound_field'] = bound_field
@@ -156,10 +156,10 @@
 
 class EditInlineNode(template.Node):
     def __init__(self, rel_var):
-        self.rel_var = rel_var
+        self.rel_var = template.Variable(rel_var)
 
     def render(self, context):
-        relation = template.resolve_variable(self.rel_var, context)
+        relation = self.rel_var.resolve(context)
         context.push()
         if relation.field.rel.edit_inline == models.TABULAR:
             bound_related_object_class = TabularBoundRelatedObject

=== modified file 'django/contrib/comments/templatetags/comments.py'
--- django/contrib/comments/templatetags/comments.py	2007-06-22 09:27:01 +0000
+++ django/contrib/comments/templatetags/comments.py	2007-07-12 09:21:51 +0000
@@ -18,6 +18,8 @@
         ratings_optional=False, ratings_required=False, rating_options='',
         is_public=True):
         self.content_type = content_type
+        if obj_id_lookup is not None:
+            obj_id_lookup = template.Variable
         self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free
         self.photos_optional, self.photos_required = photos_optional, photos_required
         self.ratings_optional, self.ratings_required = ratings_optional, ratings_required
@@ -31,7 +33,7 @@
         context.push()
         if self.obj_id_lookup_var is not None:
             try:
-                self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context)
+                self.obj_id = self.obj_id_lookup_var.resolve(context)
             except template.VariableDoesNotExist:
                 return ''
             # Validate that this object ID is valid for this content-type.
@@ -74,6 +76,8 @@
 class CommentCountNode(template.Node):
     def __init__(self, package, module, context_var_name, obj_id, var_name, free):
         self.package, self.module = package, module
+        if context_var_name is not None:
+            context_var_name = template.Variable(context_var_name)
         self.context_var_name, self.obj_id = context_var_name, obj_id
         self.var_name, self.free = var_name, free
 
@@ -81,7 +85,7 @@
         from django.conf import settings
         manager = self.free and FreeComment.objects or Comment.objects
         if self.context_var_name is not None:
-            self.obj_id = template.resolve_variable(self.context_var_name, context)
+            self.obj_id = self.context_var_name.resolve(context)
         comment_count = manager.filter(object_id__exact=self.obj_id,
             content_type__app_label__exact=self.package,
             content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count()
@@ -91,6 +95,8 @@
 class CommentListNode(template.Node):
     def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None):
         self.package, self.module = package, module
+        if context_var_name is not None:
+            context_var_name = template.Variable(context_var_name)
         self.context_var_name, self.obj_id = context_var_name, obj_id
         self.var_name, self.free = var_name, free
         self.ordering = ordering
@@ -101,7 +107,7 @@
         get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma
         if self.context_var_name is not None:
             try:
-                self.obj_id = template.resolve_variable(self.context_var_name, context)
+                self.obj_id = self.context_var_name.resolve(context)
             except template.VariableDoesNotExist:
                 return ''
         kwargs = {

=== modified file 'django/template/__init__.py'
--- django/template/__init__.py	2007-07-11 16:02:39 +0000
+++ django/template/__init__.py	2007-07-12 09:29:09 +0000
@@ -93,8 +93,6 @@
 tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
                                           re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
                                           re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
-# matches if the string is valid number
-number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')
 
 # global dictionary of libraries that have been loaded using get_library
 libraries = {}
@@ -568,18 +566,19 @@
                 elif constant_arg is not None:
                     args.append((False, constant_arg.replace(r'\"', '"')))
                 elif var_arg:
-                    args.append((True, 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()
         if upto != len(token):
             raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token)
-        self.var, self.filters = var, filters
+        self.filters = filters
+        self.var = Variable(var)
 
     def resolve(self, context, ignore_failures=False):
         try:
-            obj = resolve_variable(self.var, context)
+            obj = self.var.resolve(context)
         except VariableDoesNotExist:
             if ignore_failures:
                 obj = None
@@ -599,7 +598,7 @@
                 if not lookup:
                     arg_vals.append(arg)
                 else:
-                    arg_vals.append(resolve_variable(arg, context))
+                    arg_vals.append(arg.resolve(context))
             obj = func(obj, *arg_vals)
         return obj
 
@@ -658,20 +657,49 @@
 
     (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
     """
-    if number_re.match(path):
-        number_type = '.' in path and float or int
-        current = number_type(path)
-    elif path[0] in ('"', "'") and path[0] == path[-1]:
-        current = path[1:-1]
-    else:
+    return Variable(path).resolve(context)
+
+class LiteralVariable(object):
+
+    def __init__(self, val):
+        self.val = val
+
+    def resolve(self, context):
+        return self.val
+
+    def __str__(self):
+        return self.val
+
+def Variable(val):
+    try:
+        # note we're not catching OverflowError here; point of debate on how best to handle that...
+        current = float(val)
+        if '.' not in val:
+            # downside to this approach is that 1e07 becomes an int; float may be preferable still.
+            current = int(current)
+        elif val[-1] == '.':
+            # 2. is invalid
+            raise ValueError
+        return LiteralVariable(current)
+    except ValueError:
+        pass
+    if val[0] in "\"'" and val[0] == val[-1]:
+        return LiteralVariable(val[1:-1])
+    return ChainedLookupVariable(val)
+    
+class ChainedLookupVariable(object):
+
+    def __init__(self, val):
+        self.lookups = tuple(val.split(VARIABLE_ATTRIBUTE_SEPARATOR))
+    
+    def resolve(self, context):
         current = context
-        bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR)
-        while bits:
+        for bit in self.lookups:
             try: # dictionary lookup
-                current = current[bits[0]]
+                current = current[bit]
             except (TypeError, AttributeError, KeyError):
                 try: # attribute lookup
-                    current = getattr(current, bits[0])
+                    current = getattr(current, bit)
                     if callable(current):
                         if getattr(current, 'alters_data', False):
                             current = settings.TEMPLATE_STRING_IF_INVALID
@@ -689,27 +717,30 @@
                                     raise
                 except (TypeError, AttributeError):
                     try: # list-index lookup
-                        current = current[int(bits[0])]
+                        current = current[int(bit)]
                     except (IndexError, # list index out of range
                             ValueError, # invalid literal for int()
-                            KeyError,   # current is a dict without `int(bits[0])` key
+                            KeyError,   # current is a dict without `int(bit)` key
                             TypeError,  # unsubscriptable object
                             ):
-                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bits[0], current)) # missing attribute
+                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
                 except Exception, e:
                     if getattr(e, 'silent_variable_failure', False):
                         current = settings.TEMPLATE_STRING_IF_INVALID
                     else:
                         raise
-            del bits[0]
-    if isinstance(current, (basestring, Promise)):
-        try:
-            current = force_unicode(current)
-        except UnicodeDecodeError:
-            # Failing to convert to unicode can happen sometimes (e.g. debug
-            # tracebacks). So we allow it in this particular instance.
-            pass
-    return current
+    
+        if isinstance(current, (basestring, Promise)):
+            try:
+                current = force_unicode(current)
+            except UnicodeDecodeError:
+                # Failing to convert to unicode can happen sometimes (e.g. debug
+                # tracebacks). So we allow it in this particular instance.
+                pass
+        return current
+
+    def __str__(self):
+        return VARIABLE_ATTRIBUTE_SEPARATOR.join(self.lookups)
 
 class Node(object):
     def render(self, context):
@@ -865,11 +896,10 @@
 
         class SimpleNode(Node):
             def __init__(self, vars_to_resolve):
-                self.vars_to_resolve = vars_to_resolve
+                self.vars_to_resolve = map(Variable, vars_to_resolve)
 
             def render(self, context):
-                resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
-                return func(*resolved_vars)
+                return func(*[var.resolve(context) for var in self.vars_to_resolve])
 
         compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
         compile_func.__doc__ = func.__doc__
@@ -887,10 +917,10 @@
 
             class InclusionNode(Node):
                 def __init__(self, vars_to_resolve):
-                    self.vars_to_resolve = vars_to_resolve
+                    self.vars_to_resolve = map(Variable, vars_to_resolve)
 
                 def render(self, context):
-                    resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
+                    resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
                     if takes_context:
                         args = [context] + resolved_vars
                     else:

=== modified file 'django/template/defaultfilters.py'
--- django/template/defaultfilters.py	2007-07-11 16:02:41 +0000
+++ django/template/defaultfilters.py	2007-07-12 09:47:26 +0000
@@ -1,6 +1,6 @@
 "Default variable filters"
 
-from django.template import resolve_variable, Library
+from django.template import Variable, Library
 from django.conf import settings
 from django.utils.translation import ugettext, ungettext
 from django.utils.encoding import force_unicode, smart_str, iri_to_uri
@@ -290,7 +290,8 @@
     Takes a list of dicts, returns that list sorted by the property given in
     the argument.
     """
-    decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value]
+    var_resolve = Variable(arg).resolve
+    decorated = [(var_resolve(item), item) for item in value]
     decorated.sort()
     return [item[1] for item in decorated]
 
@@ -299,7 +300,8 @@
     Takes a list of dicts, returns that list sorted in reverse order by the
     property given in the argument.
     """
-    decorated = [(resolve_variable(u'var.' + arg, {u'var' : item}), item) for item in value]
+    var_resolve = Variable(arg).resolve
+    decorated = [(var_resolve(item), item) for item in value]
     decorated.sort()
     decorated.reverse()
     return [item[1] for item in decorated]

=== modified file 'django/template/defaulttags.py'
--- django/template/defaulttags.py	2007-07-11 16:02:40 +0000
+++ django/template/defaulttags.py	2007-07-12 09:21:51 +0000
@@ -1,6 +1,6 @@
 "Default tags used by the template system, available to all templates."
 
-from django.template import Node, NodeList, Template, Context, resolve_variable
+from django.template import Node, NodeList, Template, Context, Variable
 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
 from django.template import get_library, Library, InvalidTemplateLibrary
 from django.conf import settings
@@ -56,12 +56,12 @@
 
 class FirstOfNode(Node):
     def __init__(self, vars):
-        self.vars = vars
+        self.vars = map(Variable, vars)
 
     def render(self, context):
         for var in self.vars:
             try:
-                value = resolve_variable(var, context)
+                value = var.resolve(context)
             except VariableDoesNotExist:
                 continue
             if value:
@@ -146,7 +146,7 @@
     def __init__(self, nodelist, *varlist):
         self.nodelist = nodelist
         self._last_seen = None
-        self._varlist = varlist
+        self._varlist = map(Variable, varlist)
 
     def render(self, context):
         if 'forloop' in context and context['forloop']['first']:
@@ -155,7 +155,7 @@
             if self._varlist:
                 # Consider multiple parameters.
                 # This automatically behaves like a OR evaluation of the multiple variables.
-                compare_to = [resolve_variable(var, context) for var in self._varlist]
+                compare_to = [var.resolve(context) for var in self._varlist]
             else:
                 compare_to = self.nodelist.render(context)
         except VariableDoesNotExist:
@@ -174,7 +174,7 @@
 
 class IfEqualNode(Node):
     def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
-        self.var1, self.var2 = var1, var2
+        self.var1, self.var2 = Variable(var1), Variable(var2)
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
         self.negate = negate
 
@@ -183,11 +183,11 @@
 
     def render(self, context):
         try:
-            val1 = resolve_variable(self.var1, context)
+            val1 = self.var1.resolve(context)
         except VariableDoesNotExist:
             val1 = None
         try:
-            val2 = resolve_variable(self.var2, context)
+            val2 = self.var2.resolve(context)
         except VariableDoesNotExist:
             val2 = None
         if (self.negate and val1 != val2) or (not self.negate and val1 == val2):

=== modified file 'django/template/loader_tags.py'
--- django/template/loader_tags.py	2007-06-22 09:27:01 +0000
+++ django/template/loader_tags.py	2007-07-12 09:21:51 +0000
@@ -1,4 +1,4 @@
-from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable
+from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
 from django.template import Library, Node
 from django.template.loader import get_template, get_template_from_string, find_template_source
 from django.conf import settings
@@ -99,11 +99,11 @@
 
 class IncludeNode(Node):
     def __init__(self, template_name):
-        self.template_name = template_name
+        self.template_name = Variable(template_name)
 
     def render(self, context):
         try:
-            template_name = resolve_variable(self.template_name, context)
+            template_name = self.template_name.resolve(context)
             t = get_template(template_name)
             return t.render(context)
         except TemplateSyntaxError, e:

=== modified file 'django/templatetags/i18n.py'
--- django/templatetags/i18n.py	2007-07-11 16:02:41 +0000
+++ django/templatetags/i18n.py	2007-07-12 09:21:51 +0000
@@ -1,4 +1,4 @@
-from django.template import Node, resolve_variable
+from django.template import Node, Variable
 from django.template import TemplateSyntaxError, TokenParser, Library
 from django.template import TOKEN_TEXT, TOKEN_VAR
 from django.utils import translation
@@ -32,11 +32,11 @@
 
 class TranslateNode(Node):
     def __init__(self, value, noop):
-        self.value = value
+        self.value = Variable(value)
         self.noop = noop
 
     def render(self, context):
-        value = resolve_variable(self.value, context)
+        value = self.value.resolve(context)
         if self.noop:
             return value
         else:

=== modified file 'docs/templates_python.txt'
--- docs/templates_python.txt	2007-07-04 04:41:27 +0000
+++ docs/templates_python.txt	2007-07-12 09:44:40 +0000
@@ -864,32 +864,36 @@
 
 You also have to change the renderer to retrieve the actual contents of the
 ``date_updated`` property of the ``blog_entry`` object.  This can be
-accomplished by using the ``resolve_variable()`` function in
-``django.template``. You pass ``resolve_variable()`` the variable name and the
-current context, available in the ``render`` method::
+accomplished by using the ``Variable`` class in ``django.template``. 
+You pass ``Variable`` the variable name, and invoke the ``resolve`` method with the
+current context::
 
     from django import template
-    from django.template import resolve_variable
+    from django.template import Variable
     import datetime
     class FormatTimeNode(template.Node):
         def __init__(self, date_to_be_formatted, format_string):
-            self.date_to_be_formatted = date_to_be_formatted
+            self.date_to_be_formatted = Variable(date_to_be_formatted)
             self.format_string = format_string
         
         def render(self, context):
             try:
-                actual_date = resolve_variable(self.date_to_be_formatted, context)
+                actual_date = self.date_to_be_formatted.resolve(context)
                 return actual_date.strftime(self.format_string)
             except template.VariableDoesNotExist:
                 return ''
 
-``resolve_variable`` will try to resolve ``blog_entry.date_updated`` and then
-format it accordingly.
+``render`` will try to resolve ``blog_entry.date_updated`` via ``Variable.resolve``,
+and then format it accordingly.
 
 .. note::
-    The ``resolve_variable()`` function will throw a ``VariableDoesNotExist``
+    The ``Variable.resolve`` method will throw a ``VariableDoesNotExist``
     exception if it cannot resolve the string passed to it in the current
     context of the page.
+    
+    Additionally, ``resolve_variable(arg, context)`` is a function invoking
+    ``Variable(arg).resolve(context)``.  The ``Variable`` should be used instead,
+    since ``resolve_variable`` is deprecated.
 
 Shortcut for simple tags
 ~~~~~~~~~~~~~~~~~~~~~~~~

