diff -urN --exclude-from=django.exclue django_src_current/django/contrib/markup/templatetags/markup.py django_autoescape/django/contrib/markup/templatetags/markup.py
--- django_src_current/django/contrib/markup/templatetags/markup.py	2006-07-01 10:34:46.000000000 +1000
+++ django_autoescape/django/contrib/markup/templatetags/markup.py	2006-07-16 20:07:48.000000000 +1000
@@ -16,6 +16,7 @@
 
 from django import template
 from django.conf import settings
+from django.utils.safestring import mark_safe
 
 register = template.Library()
 
@@ -25,9 +26,10 @@
     except ImportError:
         if settings.DEBUG:
             raise template.TemplateSyntaxError, "Error in {% textile %} filter: The Python textile library isn't installed."
-        return value
+        return mark_safe(value)
     else:
-        return textile.textile(value, encoding=settings.DEFAULT_CHARSET, output=settings.DEFAULT_CHARSET)
+        return mark_safe(textile.textile(value, encoding=settings.DEFAULT_CHARSET, output=settings.DEFAULT_CHARSET))
+textile.is_safe = True
 
 def markdown(value):
     try:
@@ -35,9 +37,10 @@
     except ImportError:
         if settings.DEBUG:
             raise template.TemplateSyntaxError, "Error in {% markdown %} filter: The Python markdown library isn't installed."
-        return value
+        return mark_safe(value)
     else:
-        return markdown.markdown(value)
+        return mark_safe(markdown.markdown(value))
+markdown.is_safe = True
 
 def restructuredtext(value):
     try:
@@ -45,11 +48,12 @@
     except ImportError:
         if settings.DEBUG:
             raise template.TemplateSyntaxError, "Error in {% restructuredtext %} filter: The Python docutils library isn't installed."
-        return value
+        return mark_safe(value)
     else:
         docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
         parts = publish_parts(source=value, writer_name="html4css1", settings_overrides=docutils_settings)
-        return parts["fragment"]
+        return mark_safe(parts["fragment"])
+restructuredtext.is_safe = True
 
 register.filter(textile)
 register.filter(markdown)
diff -urN --exclude-from=django.exclue django_src_current/django/template/context.py django_autoescape/django/template/context.py
--- django_src_current/django/template/context.py	2006-07-04 13:58:51.000000000 +1000
+++ django_autoescape/django/template/context.py	2006-07-15 16:53:21.000000000 +1000
@@ -9,6 +9,9 @@
 
 class Context(object):
     "A stack container for variable context"
+
+    autoescape = False
+
     def __init__(self, dict_=None):
         dict_ = dict_ or {}
         self.dicts = [dict_]
@@ -95,3 +98,10 @@
             processors = tuple(processors)
         for processor in get_standard_processors() + processors:
             self.update(processor(request))
+
+class SafeContext(Context):
+    "A Context derivative that autoescapes by default."
+    autoescape = True
+
+class SafeRequestContext(RequestContext):
+    autoescape = True
diff -urN --exclude-from=django.exclue django_src_current/django/template/defaultfilters.py django_autoescape/django/template/defaultfilters.py
--- django_src_current/django/template/defaultfilters.py	2006-07-15 21:45:43.000000000 +1000
+++ django_autoescape/django/template/defaultfilters.py	2006-07-16 19:33:37.000000000 +1000
@@ -3,6 +3,7 @@
 from django.template import resolve_variable, Library
 from django.conf import settings
 from django.utils.translation import gettext
+from django.utils.safestring import mark_safe, SafeData
 import re
 import random as random_module
 
@@ -16,16 +17,19 @@
 def addslashes(value):
     "Adds slashes - useful for passing strings to JavaScript, for example."
     return value.replace('"', '\\"').replace("'", "\\'")
+addslashes.is_safe = True
 
 def capfirst(value):
     "Capitalizes the first character of the value"
     value = str(value)
     return value and value[0].upper() + value[1:]
+capfirst.is_safe = True
 
 def fix_ampersands(value):
     "Replaces ampersands with ``&amp;`` entities"
     from django.utils.html import fix_ampersands
     return fix_ampersands(value)
+fix_ampersands.is_safe = True
 
 def floatformat(text):
     """
@@ -40,21 +44,29 @@
     if m:
         return '%.1f' % f
     else:
-        return '%d' % int(f)
+        return mark_safe('%d' % int(f))
+floatformat.is_safe = True
 
-def linenumbers(value):
+def linenumbers(value, autoescape = None):
     "Displays text with line numbers"
     from django.utils.html import escape
     lines = value.split('\n')
     # Find the maximum width of the line count, for use with zero padding string format command
     width = str(len(str(len(lines))))
-    for i, line in enumerate(lines):
-        lines[i] = ("%0" + width  + "d. %s") % (i + 1, escape(line))
-    return '\n'.join(lines)
+    if not autoescape or isinstance(value, SafeData):
+        for i, line in enumerate(lines):
+            lines[i] = ("%0" + width  + "d. %s") % (i + 1, line)
+    else:
+        for i, line in enumerate(lines):
+            lines[i] = ("%0" + width  + "d. %s") % (i + 1, escape(line))
+    return mark_safe('\n'.join(lines))
+linenumbers.is_safe = True
+linenumbers.needs_autoescape = True
 
 def lower(value):
     "Converts a string into all lowercase"
     return value.lower()
+lower.is_safe = True
 
 def make_list(value):
     """
@@ -62,11 +74,13 @@
     digits. For a string, it's a list of characters.
     """
     return list(str(value))
+make_list.is_safe = False
 
 def slugify(value):
     "Converts to lowercase, removes non-alpha chars and converts spaces to hyphens"
     value = re.sub('[^\w\s-]', '', value).strip().lower()
-    return re.sub('[-\s]+', '-', value)
+    return mark_safe(re.sub('[-\s]+', '-', value))
+slugify.is_safe = True
 
 def stringformat(value, arg):
     """
@@ -81,10 +95,12 @@
         return ("%" + arg) % value
     except (ValueError, TypeError):
         return ""
+stringformat.is_safe = True
 
 def title(value):
     "Converts a string into titlecase"
     return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title())
+title.is_safe = False
 
 def truncatewords(value, arg):
     """
@@ -100,20 +116,24 @@
     if not isinstance(value, basestring):
         value = str(value)
     return truncate_words(value, length)
+truncatewords.is_safe = True
 
 def upper(value):
     "Converts a string into all uppercase"
     return value.upper()
+upper.is_safe = False
 
 def urlencode(value):
     "Escapes a value for use in a URL"
     import urllib
     return urllib.quote(value)
+urlencode.is_safe = False
 
 def urlize(value):
     "Converts URLs in plain text into clickable links"
     from django.utils.html import urlize
-    return urlize(value, nofollow=True)
+    return mark_safe(urlize(value, nofollow=True))
+urlize.is_safe = True
 
 def urlizetrunc(value, limit):
     """
@@ -123,11 +143,13 @@
     Argument: Length to truncate URLs to.
     """
     from django.utils.html import urlize
-    return urlize(value, trim_url_limit=int(limit), nofollow=True)
+    return mark_safe(urlize(value, trim_url_limit=int(limit), nofollow=True))
+urlize.is_safe = True
 
 def wordcount(value):
     "Returns the number of words"
     return len(value.split())
+wordcount.is_safe = False
 
 def wordwrap(value, arg):
     """
@@ -137,6 +159,7 @@
     """
     from django.utils.text import wrap
     return wrap(str(value), int(arg))
+wordwrap.is_safe = True
 
 def ljust(value, arg):
     """
@@ -145,6 +168,7 @@
     Argument: field size
     """
     return str(value).ljust(int(arg))
+ljust.is_safe = True
 
 def rjust(value, arg):
     """
@@ -153,14 +177,17 @@
     Argument: field size
     """
     return str(value).rjust(int(arg))
+rjust.is_safe = True
 
 def center(value, arg):
     "Centers the value in a field of a given width"
     return str(value).center(int(arg))
+center.is_safe = True
 
 def cut(value, arg):
     "Removes all values of arg from the given string"
     return value.replace(arg, '')
+cut.is_safe = False
 
 ###################
 # HTML STRINGS    #
@@ -168,17 +195,37 @@
 
 def escape(value):
     "Escapes a string's HTML"
-    from django.utils.html import escape
-    return escape(value)
+    if not isinstance(value, SafeData):
+        from django.utils.html import escape
+        return mark_safe(escape(value))
+    else:
+        return value
+escape.is_safe = True
 
-def linebreaks(value):
+def linebreaks(value, autoescape = None):
     "Converts newlines into <p> and <br />s"
     from django.utils.html import linebreaks
-    return linebreaks(value)
+    autoescape = autoescape and not isinstance(value, SafeData)
+    return mark_safe(linebreaks(value, autoescape))
+linebreaks.is_safe = True
+linebreaks.needs_autoescape = True
 
-def linebreaksbr(value):
+def linebreaksbr(value, autoescape = None):
     "Converts newlines into <br />s"
-    return value.replace('\n', '<br />')
+    if autoescape and not isinstance(value, SafeData):
+        from django.utils.html import escape
+        data = escape(value)
+    else:
+        data = value
+    return mark_safe(data.replace('\n', '<br />'))
+linebreaksbr.is_safe = True
+linebreaksbr.needs_autoescape = True
+
+def noescape(value):
+    "Marks the value as a string that should not be auto-escaped."
+    from django.utils.safestring import mark_safe
+    return mark_safe(value)
+noescape.is_safe = True
 
 def removetags(value, tags):
     "Removes a space separated list of [X]HTML tags from the output"
@@ -189,6 +236,7 @@
     value = starttag_re.sub('', value)
     value = endtag_re.sub('', value)
     return value
+removetags.is_safe = True
 
 def striptags(value):
     "Strips all [X]HTML tags"
@@ -196,6 +244,7 @@
     if not isinstance(value, basestring):
         value = str(value)
     return strip_tags(value)
+striptags.is_safe = True
 
 ###################
 # LISTS           #
@@ -209,6 +258,7 @@
     decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
     decorated.sort()
     return [item[1] for item in decorated]
+dictsort.is_safe = False
 
 def dictsortreversed(value, arg):
     """
@@ -219,6 +269,7 @@
     decorated.sort()
     decorated.reverse()
     return [item[1] for item in decorated]
+dictsortreversed.is_safe = False
 
 def first(value):
     "Returns the first item in a list"
@@ -226,25 +277,35 @@
         return value[0]
     except IndexError:
         return ''
+first.is_safe = True
 
 def join(value, arg):
     "Joins a list with a string, like Python's ``str.join(list)``"
     try:
-        return arg.join(map(str, value))
+        data = arg.join(map(str, value))
     except AttributeError: # fail silently but nicely
         return value
+    safe_args = reduce(lambda lhs, rhs: lhs and isinstance(rhs, SafeData), value, True)
+    if safe_args:
+        return mark_safe(data)
+    else:
+        return data
+join.is_safe = True
 
 def length(value):
     "Returns the length of the value - useful for lists"
     return len(value)
+length.is_safe = False
 
 def length_is(value, arg):
     "Returns a boolean of whether the value's length is the argument"
     return len(value) == int(arg)
+length.is_safe = False
 
 def random(value):
     "Returns a random item from the list"
     return random_module.choice(value)
+length.is_safe = True
 
 def slice_(value, arg):
     """
@@ -265,8 +326,9 @@
 
     except (ValueError, TypeError):
         return value # Fail silently.
+slice_.is_safe = True
 
-def unordered_list(value):
+def unordered_list(value, autoescape = None):
     """
     Recursively takes a self-nested list and returns an HTML unordered list --
     WITHOUT opening and closing <ul> tags.
@@ -287,14 +349,22 @@
         </ul>
         </li>
     """
+    if autoescape:
+        from django.utils.html import conditional_escape
+        escaper = conditional_escape
+    else:
+        escaper = lambda x: x
+
     def _helper(value, tabs):
         indent = '\t' * tabs
         if value[1]:
-            return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent,
+            return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, escaper(value[0]), indent,
                 '\n'.join([_helper(v, tabs+1) for v in value[1]]), indent, indent)
         else:
-            return '%s<li>%s</li>' % (indent, value[0])
-    return _helper(value, 1)
+            return '%s<li>%s</li>' % (indent, escaper(value[0]))
+    return mark_safe(_helper(value, 1))
+unordered_list.is_safe = True
+unordered_list.needs_autoescape = True
 
 ###################
 # INTEGERS        #
@@ -303,6 +373,7 @@
 def add(value, arg):
     "Adds the arg to the value"
     return int(value) + int(arg)
+add.is_safe = False
 
 def get_digit(value, arg):
     """
@@ -322,6 +393,7 @@
         return int(str(value)[-arg])
     except IndexError:
         return 0
+get_digit.is_safe = False
 
 ###################
 # DATES           #
@@ -335,6 +407,7 @@
     if arg is None:
         arg = settings.DATE_FORMAT
     return format(value, arg)
+date.is_safe = False
 
 def time(value, arg=None):
     "Formats a time according to the given format"
@@ -344,6 +417,7 @@
     if arg is None:
         arg = settings.TIME_FORMAT
     return time_format(value, arg)
+time.is_safe = False
 
 def timesince(value, arg=None):
     'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
@@ -353,6 +427,7 @@
     if arg:
         return timesince(arg, value)
     return timesince(value)
+timesince.is_safe = False
 
 def timeuntil(value, arg=None):
     'Formats a date as the time until that date (i.e. "4 days, 6 hours")'
@@ -363,6 +438,7 @@
     if arg:
         return timesince(arg, value)
     return timesince(datetime.now(), value)
+timeuntil.is_safe = False
 
 ###################
 # LOGIC           #
@@ -371,16 +447,19 @@
 def default(value, arg):
     "If value is unavailable, use given default"
     return value or arg
+default.is_safe = False
 
 def default_if_none(value, arg):
     "If value is None, use given default"
     if value is None:
         return arg
     return value
+default_if_none.is_safe = False
 
 def divisibleby(value, arg):
     "Returns true if the value is devisible by the argument"
     return int(value) % int(arg) == 0
+divisibleby.is_safe = False
 
 def yesno(value, arg=None):
     """
@@ -411,6 +490,7 @@
     if value:
         return yes
     return no
+yesno.is_safe = False
 
 ###################
 # MISC            #
@@ -429,6 +509,7 @@
     if bytes < 1024 * 1024 * 1024:
         return "%.1f MB" % (bytes / (1024 * 1024))
     return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
+filesizeformat.is_safe = True
 
 def pluralize(value, arg='s'):
     """
@@ -456,11 +537,13 @@
         except TypeError: # len() of unsized object
             pass
     return singular_suffix
+pluralize.is_safe = False
 
 def phone2numeric(value):
     "Takes a phone number and converts it in to its numerical equivalent"
     from django.utils.text import phone2numeric
     return phone2numeric(value)
+phone2numeric.is_safe = True
 
 def pprint(value):
     "A wrapper around pprint.pprint -- for debugging, really"
@@ -469,6 +552,7 @@
         return pformat(value)
     except Exception, e:
         return "Error in formatting:%s" % e
+pprint.is_safe = True
 
 # Syntax: register.filter(name of filter, callback)
 register.filter(add)
@@ -497,6 +581,7 @@
 register.filter(ljust)
 register.filter(lower)
 register.filter(make_list)
+register.filter(noescape)
 register.filter(phone2numeric)
 register.filter(pluralize)
 register.filter(pprint)
diff -urN --exclude-from=django.exclue django_src_current/django/template/defaulttags.py django_autoescape/django/template/defaulttags.py
--- django_src_current/django/template/defaulttags.py	2006-07-04 13:58:51.000000000 +1000
+++ django_autoescape/django/template/defaulttags.py	2006-07-16 18:00:41.000000000 +1000
@@ -4,10 +4,25 @@
 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END
 from django.template import get_library, Library, InvalidTemplateLibrary
 from django.conf import settings
+from django.utils.safestring import mark_safe
 import sys
 
 register = Library()
 
+class AutoEscapeNode(Node):
+    def __init__(self, setting, nodelist):
+        self.setting, self.nodelist = setting, nodelist
+
+    def render(self, context):
+        old_setting = context.autoescape
+        context.autoescape = self.setting
+        output = self.nodelist.render(context)
+        context.autoescape = old_setting
+        if self.setting:
+            return mark_safe(output)
+        else:
+            return output
+
 class CommentNode(Node):
     def render(self, context):
         return ''
@@ -318,6 +333,20 @@
         return str(int(round(ratio)))
 
 #@register.tag
+def autoescape(parser, token):
+    """
+    Set autoescape behaviour for this block. Possible values are "on" and "off".
+    """
+    unused, rest = token.contents.split(None, 1)
+    if rest not in ('on', 'off'):
+        raise TemplateSyntaxError("autoescape argument must be 'on' or 'off'")
+    setting = (rest == 'on')
+    nodelist = parser.parse(('endautoescape',))
+    parser.delete_first_token()
+    return AutoEscapeNode(setting, nodelist)
+autoescape = register.tag(autoescape)
+
+#@register.tag
 def comment(parser, token):
     """
     Ignore everything between ``{% comment %}`` and ``{% endcomment %}``
@@ -417,6 +446,9 @@
     """
     _, rest = token.contents.split(None, 1)
     filter_expr = parser.compile_filter("var|%s" % (rest))
+    for func, unused in filter_expr.filters:
+        if func.__name__ == 'noescape':
+            raise TemplateSyntaxError('"filter noescape" is not permitted.  Use the "autoescape" tag instead.')
     nodelist = parser.parse(('endfilter',))
     parser.delete_first_token()
     return FilterNode(filter_expr, nodelist)
diff -urN --exclude-from=django.exclue django_src_current/django/template/__init__.py django_autoescape/django/template/__init__.py
--- django_src_current/django/template/__init__.py	2006-07-10 19:53:37.000000000 +1000
+++ django_autoescape/django/template/__init__.py	2006-07-16 17:46:46.000000000 +1000
@@ -57,11 +57,13 @@
 import re
 from inspect import getargspec
 from django.conf import settings
-from django.template.context import Context, RequestContext, ContextPopException
+from django.template.context import Context, SafeContext, RequestContext, ContextPopException
 from django.utils.functional import curry
 from django.utils.text import smart_split
+from django.utils.safestring import SafeData, mark_safe
+from django.utils.html import escape
 
-__all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
+__all__ = ('Template', 'Context', 'SafeContext', 'RequestContext', 'compile_string')
 
 TOKEN_TEXT = 0
 TOKEN_VAR = 1
@@ -558,7 +560,15 @@
                     arg_vals.append(arg)
                 else:
                     arg_vals.append(resolve_variable(arg, context))
-            obj = func(obj, *arg_vals)
+            if getattr(func, 'needs_autoescape', False):
+                new_obj = func(obj, autoescape = context.autoescape, *arg_vals)
+            else:
+                new_obj = func(obj, *arg_vals)
+            if getattr(func, 'is_safe', False) and isinstance(obj, SafeData):
+                obj = mark_safe(new_obj)
+            else:
+                obj = new_obj
+                
         return obj
 
     def args_check(name, func, provided):
@@ -744,7 +754,11 @@
 
     def render(self, context):
         output = self.filter_expression.resolve(context)
-        return self.encode_output(output)
+        encoded_output = self.encode_output(output)
+        if context.autoescape and not isinstance(encoded_output, SafeData):
+            return escape(encoded_output)
+        else:
+            return encoded_output
 
 class DebugVariableNode(VariableNode):
     def render(self, context):
@@ -754,7 +768,11 @@
             if not hasattr(e, 'source'):
                 e.source = self.source
             raise
-        return self.encode_output(output)
+        encoded_output = self.encode_output(output)
+        if context.autoescape and not isinstance(encoded_output, SafeData):
+            return escape(encoded_output)
+        else:
+            return encoded_output
 
 def generic_tag_compiler(params, defaults, name, node_class, parser, token):
     "Returns a template.Node subclass."
diff -urN --exclude-from=django.exclue django_src_current/django/utils/html.py django_autoescape/django/utils/html.py
--- django_src_current/django/utils/html.py	2006-05-03 00:33:38.000000000 +1000
+++ django_autoescape/django/utils/html.py	2006-07-16 00:33:57.000000000 +1000
@@ -1,6 +1,7 @@
 "HTML utilities suitable for global use."
 
 import re, string
+from django.utils.safestring import SafeData
 
 # Configuration for urlize() function
 LEADING_PUNCTUATION  = ['(', '<', '&lt;']
@@ -27,11 +28,21 @@
         html = str(html)
     return html.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;')
 
-def linebreaks(value):
+def conditional_escape(html):
+    "Similar to escape(), except that it does not operate on pre-escaped strings"
+    if isinstance(html, SafeData):
+        return html
+    else:
+        return escape(html)
+
+def linebreaks(value, autoescape = False):
     "Converts newlines into <p> and <br />s"
     value = re.sub(r'\r\n|\r|\n', '\n', value) # normalize newlines
     paras = re.split('\n{2,}', value)
-    paras = ['<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras]
+    if autoescape:
+        paras = ['<p>%s</p>' % escape(p.strip()).replace('\n', '<br />') for p in paras]
+    else:
+        paras = ['<p>%s</p>' % p.strip().replace('\n', '<br />') for p in paras]
     return '\n\n'.join(paras)
 
 def strip_tags(value):
diff -urN --exclude-from=django.exclue django_src_current/django/utils/safestring.py django_autoescape/django/utils/safestring.py
--- django_src_current/django/utils/safestring.py	1970-01-01 10:00:00.000000000 +1000
+++ django_autoescape/django/utils/safestring.py	2006-07-15 19:10:50.000000000 +1000
@@ -0,0 +1,73 @@
+"""
+Functions for working with "safe strings": strings that can be display safely
+without further modification in HTML.
+"""
+from django.utils.functional import curry
+
+class SafeData(object):
+    pass
+
+class SafeString(str, SafeData):
+    """
+    A string subclass that has been specifically marked as "safe" for output
+    purposes.
+    """
+    def __add__(self, rhs):
+        """
+        Concatenating a safe string with another safe string or safe unicode
+        object is safe. Otherwise, the result is no longer safe.
+        """
+        if isinstance(rhs, SafeUnicode):
+            return SafeUnicode(self + rhs)
+        elif isinstance(rhs, SafeString):
+            return SafeString(self, rhs)
+        else:
+            return super(SafeString, self).__add__(rhs)
+
+class SafeUnicode(unicode, SafeData):
+    """
+    A unicode subclass that has been specifically marked as "safe" for output
+    purposes.
+    """
+    def __add__(self, rhs):
+        """
+        Concatenating a safe unicode object with another safe string or safe
+        unicode object is safe. Otherwise, the result is no longer safe.
+        """
+        if isinstance(rhs, SafeData):
+            return SafeUnicode(self + rhs)
+        else:
+            return super(SafeUnicode, self).__add__(rhs)
+
+    def _proxy_method(self, *args, **kwargs):
+        """
+        Wrap a call to a normal unicode method up so that we return safe
+        results. The method that is being wrapped is passed in the 'method'
+        argument.
+        """
+        method = kwargs.pop('method')
+        data = method(self, *args, **kwargs)
+        if isinstance(data, str):
+            return SafeString(data)
+        else:
+            return SafeUnicode(data)
+
+    encode = curry(_proxy_method, method = unicode.encode)
+    decode = curry(_proxy_method, method = unicode.decode)
+
+
+def mark_safe(s):
+    """
+    Explicitly mark a string as safe for output purposes. The returned object
+    can be used everywhere a string or unicode object is appropriate.
+
+    Can safely be called multiple times on a single string.
+    """
+    if isinstance(s, SafeData):
+        return s
+    if isinstance(s, str):
+        return SafeString(s)
+    if isinstance(s, unicode):
+        return SafeUnicode(s)
+    raise TypeError, "Input must be str or unicode (got %s)" % type(s)
+
diff -urN --exclude-from=django.exclue django_src_current/django/views/debug.py django_autoescape/django/views/debug.py
--- django_src_current/django/views/debug.py	2006-06-14 21:42:37.000000000 +1000
+++ django_autoescape/django/views/debug.py	2006-07-16 18:37:42.000000000 +1000
@@ -1,5 +1,5 @@
 from django.conf import settings
-from django.template import Template, Context, TemplateDoesNotExist
+from django.template import Template, Context, SafeContext, TemplateDoesNotExist
 from django.utils.html import escape
 from django.http import HttpResponseServerError, HttpResponseNotFound
 import os, re
@@ -118,7 +118,7 @@
             'lineno': '?',
         }]
     t = Template(TECHNICAL_500_TEMPLATE)
-    c = Context({
+    c = SafeContext({
         'exception_type': exc_type.__name__,
         'exception_value': exc_value,
         'frames': frames,
@@ -157,7 +157,7 @@
 def empty_urlconf(request):
     "Create an empty URLconf 404 error response."
     t = Template(EMPTY_URLCONF_TEMPLATE)
-    c = Context({
+    c = SafeContext({
         'project_name': settings.SETTINGS_MODULE.split('.')[0]
     })
     return HttpResponseNotFound(t.render(c), mimetype='text/html')
@@ -295,7 +295,7 @@
 
 <div id="summary">
   <h1>{{ exception_type }} at {{ request.path }}</h1>
-  <h2>{{ exception_value|escape }}</h2>
+  <h2>{{ exception_value }}</h2>
   <table class="meta">
     <tr>
       <th>Request Method:</th>
@@ -340,7 +340,7 @@
 <div id="template">
    <h2>Template error</h2>
    <p>In template <code>{{ template_info.name }}</code>, error at line <strong>{{ template_info.line }}</strong></p>
-   <h3>{{ template_info.message|escape }}</h3>
+   <h3>{{ template_info.message }}</h3>
    <table class="source{% if template_info.top %} cut-top{% endif %}{% ifnotequal template_info.bottom template_info.total %} cut-bottom{% endifnotequal %}">
    {% for source_line in template_info.source_lines %}
    {% ifequal source_line.0 template_info.line %}
@@ -367,11 +367,11 @@
           {% if frame.context_line %}
             <div class="context" id="c{{ frame.id }}">
               {% if frame.pre_context %}
-                <ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
+                <ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">{% for line in frame.pre_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol>
               {% endif %}
-              <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line|escape }} <span>...</span></li></ol>
+              <ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line }} <span>...</span></li></ol>
               {% if frame.post_context %}
-                <ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line|escape }}</li>{% endfor %}</ol>
+                <ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ line }}</li>{% endfor %}</ol>
               {% endif %}
             </div>
           {% endif %}
@@ -391,7 +391,7 @@
                 {% for var in frame.vars|dictsort:"0" %}
                   <tr>
                     <td>{{ var.0 }}</td>
-                    <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
+                    <td class="code"><div>{{ var.1|pprint }}</div></td>
                   </tr>
                 {% endfor %}
               </tbody>
@@ -411,11 +411,11 @@
 {% for frame in frames %}
   File "{{ frame.filename }}" in {{ frame.function }}<br/>
   {% if frame.context_line %}
-    &nbsp;&nbsp;{{ frame.lineno }}. {{ frame.context_line|escape }}<br/>
+    &nbsp;&nbsp;{{ frame.lineno }}. {{ frame.context_line }}<br/>
   {% endif %}
 {% endfor %}<br/>
 &nbsp;&nbsp;{{ exception_type }} at {{ request.path }}<br/>
-&nbsp;&nbsp;{{ exception_value|escape }}</code>
+&nbsp;&nbsp;{{ exception_value }}</code>
           </td>
         </tr>
       </tbody>
@@ -439,7 +439,7 @@
         {% for var in request.GET.items %}
           <tr>
             <td>{{ var.0 }}</td>
-            <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
+            <td class="code"><div>{{ var.1|pprint }}</div></td>
           </tr>
         {% endfor %}
       </tbody>
@@ -461,7 +461,7 @@
         {% for var in request.POST.items %}
           <tr>
             <td>{{ var.0 }}</td>
-            <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
+            <td class="code"><div>{{ var.1|pprint }}</div></td>
           </tr>
         {% endfor %}
       </tbody>
@@ -483,7 +483,7 @@
         {% for var in request.COOKIES.items %}
           <tr>
             <td>{{ var.0 }}</td>
-            <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
+            <td class="code"><div>{{ var.1|pprint }}</div></td>
           </tr>
         {% endfor %}
       </tbody>
@@ -504,7 +504,7 @@
       {% for var in request.META.items|dictsort:"0" %}
         <tr>
           <td>{{ var.0 }}</td>
-          <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
+          <td class="code"><div>{{ var.1|pprint }}</div></td>
         </tr>
       {% endfor %}
     </tbody>
@@ -523,7 +523,7 @@
       {% for var in settings.items|dictsort:"0" %}
         <tr>
           <td>{{ var.0 }}</td>
-          <td class="code"><div>{{ var.1|pprint|escape }}</div></td>
+          <td class="code"><div>{{ var.1|pprint }}</div></td>
         </tr>
       {% endfor %}
     </tbody>
@@ -590,12 +590,12 @@
       </p>
       <ol>
         {% for pattern in urlpatterns %}
-          <li>{{ pattern|escape }}</li>
+          <li>{{ pattern }}</li>
         {% endfor %}
       </ol>
       <p>The current URL, <code>{{ request.path }}</code>, didn't match any of these.</p>
     {% else %}
-      <p>{{ reason|escape }}</p>
+      <p>{{ reason }}</p>
     {% endif %}
   </div>
 
diff -urN --exclude-from=django.exclue django_src_current/tests/othertests/autoescape.py django_autoescape/tests/othertests/autoescape.py
--- django_src_current/tests/othertests/autoescape.py	1970-01-01 10:00:00.000000000 +1000
+++ django_autoescape/tests/othertests/autoescape.py	2006-07-16 19:37:41.000000000 +1000
@@ -0,0 +1,232 @@
+from django.conf import settings
+
+if __name__ == '__main__':
+    # When running this file in isolation, we need to set up the configuration
+    # before importing 'template'.
+    settings.configure()
+
+import templates
+from django import template
+from django.template import loader
+from django.utils.translation import activate, deactivate, install
+from django.utils.tzinfo import LocalTimezone
+from django.utils.safestring import mark_safe
+from datetime import datetime, timedelta
+import traceback
+
+# We want to check all the normal template tests against SafeContext by
+# default. We just update results that would change with autoescaping and add
+# in new tests.
+TEMPLATE_TESTS = templates.TEMPLATE_TESTS.copy()
+
+# SYNTAX --
+# 'template_name': ('template contents', 'context dict', 'expected string output' or Exception class)
+TEMPLATE_TESTS.update({
+
+    ### BASIC SYNTAX ##########################################################
+
+    # Escaped string as argument (this replaces the non-escaped version)
+    'basic-syntax30': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote&quot; hah'),
+
+    # Autoescaping is applied by default
+    'autoescape-basic01': ("{{ first }}", {"first": "<b>first</b>"}, "&lt;b&gt;first&lt;/b&gt;"),
+
+    # Strings (ASCII or unicode) already marked as "safe" are not auto-escaped
+    'autoescape-basic02': ("{{ first }}", {"first": mark_safe("<b>first</b>")}, "<b>first</b>"),
+    'autoescape-basic03': ("{{ first }}", {"first": mark_safe(u"<b>Apple</b>")}, u"<b>Apple</b>"),
+
+
+    ### AUTOESCAPE TAG ########################################################
+    'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),
+    'autoescape-tag02': ("{% autoescape off %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "<b>hello</b>"),
+    'autoescape-tag03': ("{% autoescape on %}{{ first }}{% endautoescape %}", {"first": "<b>hello</b>"}, "&lt;b&gt;hello&lt;/b&gt;"),
+
+    ### FILTER TAG ############################################################
+
+    # The "noescape" filter cannot work due to internal implementation details
+    # (fortunately, it is equivalent to using the autoescape tag in these
+    # cases).
+    'autoescape-filtertag01': ("{{ first }}{% filter noescape %}{{ first }} x<y{% endfilter %}", {"first": "<a>"}, template.TemplateSyntaxError),
+
+    ### FILTER TESTS ##########################################################
+
+    'ae-filter-addslash01': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"&lt;a&gt;\&#39; <a>\'"),
+
+    'ae-filter-capfirst01': ("{{ a|capfirst }} {{ b|capfirst }}", {"a": "fred>", "b": mark_safe("fred&gt;")}, "Fred&gt; Fred&gt;"),
+
+    # Note that applying fix_ampsersands in autoescape mode leads to double
+    # escaping.
+    'ae-filter-fix_ampersands01': ("{{ a|fix_ampersands }} {{ b|fix_ampersands }}", {"a": "a&b", "b": mark_safe("a&b")}, "a&amp;amp;b a&amp;b"),
+
+    'ae-filter-floatformat01': ("{{ a|floatformat }} {{ b|floatformat }}", {"a": "1.42", "b": mark_safe("1.42")}, "1.4 1.4"),
+
+    # The contents of "linenumbers" is escaped according to the current
+    # autoescape setting.
+    'ae-filter-linenumbers01': ("{{ a|linenumbers }} {{ b|linenumbers }}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. &lt;two&gt;\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
+    'ae-filter-linenumbers02': ("{% autoescape off %}{{ a|linenumbers }} {{ b|linenumbers }}{% endautoescape %}", {"a": "one\n<two>\nthree", "b": mark_safe("one\n&lt;two&gt;\nthree")}, "1. one\n2. <two>\n3. three 1. one\n2. &lt;two&gt;\n3. three"),
+
+    'ae-filter-lower01': ("{{ a|lower }} {{ b|lower }}", {"a": "Apple & banana", "b": mark_safe("Apple &amp; banana")}, "apple &amp; banana apple &amp; banana"),
+
+    # The make_list filter can destroy # existing encoding, so the results are
+    # escaped.
+    'ae-filter-make_list01': ("{{ a|make_list }}", {"a": mark_safe("&")}, "[&#39;&amp;&#39;]"),
+    'ae-filter-make_list02': ('{{ a|make_list|stringformat:"s"|noescape }}', {"a": mark_safe("&")}, "['&']"),
+
+    # Running slugify on a pre-escaped string leads to odd behaviour, but the
+    # result is still safe.
+    'ae-filter-slugify01': ("{{ a|slugify }} {{ b|slugify }}", {"a": "a & b", "b": mark_safe("a &amp; b")}, "a-b a-amp-b"),
+    
+    # Notice that escaping is applied *after* any filters, so the string
+    # formatting here only needs to deal with pre-escaped characters.
+    'ae-filter-stringformat01': ('.{{ a|stringformat:"5s" }}. .{{ b|stringformat:"5s" }}.', {"a": "a<b", "b": mark_safe("a<b")}, ".  a&lt;b. .  a<b."),
+
+    # XXX No test for "title" filter; needs an actual object.
+    
+    'ae-filter-truncatewords01': ('{{ a|truncatewords:"2" }} {{ b|truncatewords:"2"}}', {"a": "alpha & bravo", "b": mark_safe("alpha &amp; bravo")}, "alpha &amp; ... alpha &amp; ..."),
+
+    # The "upper" filter messes up entities (which are case-sensitive), so it's
+    # not safe for non-escaping purposes.
+    'ae-filter-upper01': ('{{ a|upper }} {{ b|upper }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "A &amp; B A &amp;AMP; B"),
+
+    'ae-filter-urlize01': ('{{ a|urlize }} {{ b|urlize }}', {"a": "http://example.com/x=&y=", "b": mark_safe("http://example.com?x=&y=")}, '<a href="http://example.com/x=&y=" rel="nofollow">http://example.com/x=&y=</a> <a href="http://example.com?x=&y=" rel="nofollow">http://example.com?x=&y=</a>'),
+    'ae-filter-urlize02': ('{{ a|urlize }}', {"a": mark_safe("a &amp; b")}, 'a &amp; b'),
+
+    'ae-filter-urlizetrunc01': ('{{ a|urlizetrunc:"5" }} {{ b|urlizetrunc:"5" }}', {"a": "http://example.com/x=&y=", "b": mark_safe("http://example.com?x=&y=")}, '<a href="http://example.com/x=&y=" rel="nofollow">http:...</a> <a href="http://example.com?x=&y=" rel="nofollow">http:...</a>'),
+
+    'ae-filter-wordcount01': ('{{ a|wordcount }} {{ b|wordcount }}', {"a": "a & b", "b": mark_safe("a &amp; b")}, "3 3"),
+
+    'ae-filter-wordwrap01': ('{{ a|wordwrap:"3" }} {{ b|wordwrap:"3" }}', {"a": "a & b", "b": mark_safe("a & b")}, "a &amp;\nb a &\nb"),
+
+    'ae-filter-ljust01': ('.{{ a|ljust:"5" }}. .{{ b|ljust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ".a&amp;b  . .a&b  ."),
+
+    'ae-filter-rjust01': ('.{{ a|rjust:"5" }}. .{{ b|rjust:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ".  a&amp;b. .  a&b."),
+
+    'ae-filter-center01': ('.{{ a|center:"5" }}. .{{ b|center:"5" }}.', {"a": "a&b", "b": mark_safe("a&b")}, ". a&amp;b . . a&b ."),
+
+    # Because "cut" might remove a leading ampersand, so the results are not
+    # safe.
+    'ae-filter-cut01': ('{{ a|cut:"x" }} {{ b|cut:"x" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "&amp;y &amp;amp;y"),
+    'ae-filter-cut02': ('{{ a|cut:"&" }} {{ b|cut:"&" }}', {"a": "x&y", "b": mark_safe("x&amp;y")}, "xy xamp;y"),
+
+    # The "escape" filter works the same whether autoescape is on or off, but
+    # it has no effect on strings already marked as safe.
+    'ae-filter-escape01': ('{{ a|escape }} {{ b|escape }}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),
+    'ae-filter-escape02': ('{% autoescape off %}{{ a|escape }} {{ b|escape }}{% endautoescape %}', {"a": "x&y", "b": mark_safe("x&y")}, "x&amp;y x&y"),
+    'ae-filter-escape03': ('{{ a|escape|escape }}', {"a": "x&y"}, "x&amp;y"),
+
+    # The contents in "linebreaks" and "linebreaksbr" are escaped according to
+    # the current autoescape setting.
+    'ae-filter-linebreaks01': ('{{ a|linebreaks }} {{ b|linebreaks }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&amp;<br />y</p> <p>x&<br />y</p>"),
+    'ae-filter-linebreaks02': ('{% autoescape off %}{{ a|linebreaks }} {{ b|linebreaks }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "<p>x&<br />y</p> <p>x&<br />y</p>"),
+
+    'ae-filter-linebreaksbr01': ('{{ a|linebreaksbr }} {{ b|linebreaksbr }}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&amp;<br />y x&<br />y"),
+    'ae-filter-linebreaksbr02': ('{% autoescape off %}{{ a|linebreaksbr }} {{ b|linebreaksbr }}{% endautoescape %}', {"a": "x&\ny", "b": mark_safe("x&\ny")}, "x&<br />y x&<br />y"),
+
+    'ae-filter-noescape01': ("{{ a }} -- {{ a|noescape }}", {"a": "<b>hello</b>"}, "&lt;b&gt;hello&lt;/b&gt; -- <b>hello</b>"),
+    'ae-filter-noescape02': ("{% autoescape off %}{{ a }} -- {{ a|noescape }}{% endautoescape %}", {"a": "<b>hello</b>"}, "<b>hello</b> -- <b>hello</b>"),
+
+    'ae-filter-removetags01': ('{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x &lt;p&gt;y&lt;/p&gt; x <p>y</p>"),
+
+    'ae-filter-striptags01': ('{{ a|striptags }} {{ b|striptags }}', {"a": "<a>x</a> <p><b>y</b></p>", "b": mark_safe("<a>x</a> <p><b>y</b></p>")}, "x y x y"),
+
+    'ae-filter-first01': ('{{ a|first }} {{ b|first }}', {"a": ["a&b", "x"], "b": [mark_safe("a&b"), "x"]}, "a&amp;b a&b"),
+
+    'ae-filter-random01': ('{{ a|random }} {{ b|random }}', {"a": ["a&b", "a&b"], "b": [mark_safe("a&b"), mark_safe("a&b")]}, "a&amp;b a&b"),
+
+    'ae-filter-slice01': ('{{ a|slice:"1:3" }} {{ b|slice:"1:3" }}', {"a": "a&b", "b": mark_safe("a&b")}, "&amp;b &b"),
+
+    'ae-filter-unordered_list01': ('{{ a|unordered_list }}', {"a": ["x>", [["<y", []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li>&lt;y</li>\n\t</ul>\n\t</li>"),
+    'ae-filter-unordered_list02': ('{{ a|unordered_list }}', {"a": ["x>", [[mark_safe("<y"), []]]]}, "\t<li>x&gt;\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
+    'ae-filter-unordered_list03': ('{% autoescape off %}{{ a|unordered_list }}{% endautoescape %}', {"a": ["x>", [["<y", []]]]}, "\t<li>x>\n\t<ul>\n\t\t<li><y</li>\n\t</ul>\n\t</li>"),
+
+    # If the input to "default" filter is marked as safe, then so is the
+    # output. However, if the default arg is used, auto-escaping kicks in (if
+    # enabled), because we cannot mark the default as safe.
+    # Note: we have to use {"a": ""} here, otherwise the invalid template
+    # variable string interferes with the test result.
+    'ae-filter-default01': ('{{ a|default:"x<" }}', {"a": ""}, "x&lt;"),
+    'ae-filter-default02': ('{{ a|default:"x<" }}', {"a": mark_safe("x>")}, "x>"),
+
+    'ae-filter-default_if_none01': ('{{ a|default:"x<" }}', {"a": None}, "x&lt;"),
+
+    'ae-filter-phone2numeric01': ('{{ a|phone2numeric }} {{ b|phone2numeric }}', {"a": "<1-800-call-me>", "b": mark_safe("<1-800-call-me>") }, "&lt;1-800-2255-63&gt; <1-800-2255-63>"),
+
+    # Chaining a bunch of safeness-preserving filters should not alter the safe
+    # status either way.
+    'ae-chaining01': ('{{ a|capfirst|center:"7" }}.{{ b|capfirst|center:"7" }}', {"a": "a < b", "b": mark_safe("a < b")}, " A &lt; b . A < b "),
+
+    # Using a filter that forces a string back to unsafe:
+    'ae-chaining02': ('{{ a|cut:"b"|capfirst }}.{{ b|cut:"b"|capfirst }}', {"a": "a < b", "b": mark_safe("a < b")}, "A &lt; .A &lt; "),
+
+    # Using a filter that forces safeness does not lead to double-escaping
+    'ae-chaining03': ('{{ a|escape|capfirst }}', {"a": "a < b"}, "A &lt; b"),
+
+    # Force to safe, then back (also showing why using escape too early in a
+    # chain can lead to unexpected results).
+    'ae-chaining04': ('{{ a|escape|cut:"b" }}', {"a": "a < b"}, "a &amp;lt; "),
+    'ae-chaining05': ('{{ a|cut:"b"|escape }}', {"a": "a < b"}, "a &lt; "),
+    'ae-chaining06': ('{{ a|cut:"b"|noescape }}', {"a": "a < b"}, "a < "),
+    'ae-chaining07': ('{{ a|noescape|escape }}', {"a": "a < b"}, "a < b"),
+})
+
+def test_template_loader(template_name, template_dirs=None):
+    "A custom template loader that loads the unit-test templates."
+    try:
+        return (TEMPLATE_TESTS[template_name][0] , "test:%s" % template_name)
+    except KeyError:
+        raise template.TemplateDoesNotExist, template_name
+
+def run_tests(verbosity=0, standalone=False):
+    # Register our custom template loader.
+    old_template_loaders = loader.template_source_loaders
+    loader.template_source_loaders = [test_template_loader]
+
+    failed_tests = []
+    tests = TEMPLATE_TESTS.items()
+    tests.sort()
+
+    # Turn TEMPLATE_DEBUG off, because tests assume that.
+    old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False
+    # Set TEMPLATE_STRING_IF_INVALID to a known string 
+    old_invalid, settings.TEMPLATE_STRING_IF_INVALID = settings.TEMPLATE_STRING_IF_INVALID, 'INVALID'
+    
+    for name, vals in tests:
+        install()
+        if 'LANGUAGE_CODE' in vals[1]:
+            activate(vals[1]['LANGUAGE_CODE'])
+        else:
+            activate('en-us')
+        try:
+            output = loader.get_template(name).render(template.SafeContext(vals[1]))
+        except Exception, e:
+            if e.__class__ == vals[2]:
+                if verbosity:
+                    print "Template test: %s -- Passed" % name
+            else:
+                if verbosity:
+                    traceback.print_exc()
+                    print "Template test: %s -- FAILED. Got %s, exception: %s" % (name, e.__class__, e)
+                failed_tests.append(name)
+            continue
+        if 'LANGUAGE_CODE' in vals[1]:
+            deactivate()
+        if output == vals[2]:
+            if verbosity:
+                print "Template test: %s -- Passed" % name
+        else:
+            if verbosity:
+                print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
+            failed_tests.append(name)
+    loader.template_source_loaders = old_template_loaders
+    deactivate()
+    settings.TEMPLATE_DEBUG = old_td
+    settings.TEMPLATE_STRING_IF_INVALID = old_invalid
+
+    if failed_tests and not standalone:
+        msg = "Template tests %s failed." % failed_tests
+        if not verbosity:
+            msg += "  Re-run tests with -v1 to see actual failures"
+        raise Exception, msg
+
+if __name__ == "__main__":
+    run_tests(1, True)
