- will now be 1.0
- drop python 2.4, 2.5 support
- various pep8ing
diff --git a/doc/build/changelog.rst b/doc/build/changelog.rst
index 279a0d5..f43b26d 100644
--- a/doc/build/changelog.rst
+++ b/doc/build/changelog.rst
@@ -2,14 +2,21 @@
 Changelog
 =========
 
-0.9
+1.0
 ===
 
 .. changelog::
-    :version: 0.9.2
+    :version: 1.0.0
     :released:
 
     .. change::
+        :tags: general
+
+      Compatibility changes; in order to modernize the codebase, Mako
+      is now dropping support for Python 2.4 and Python 2.5 altogether.
+      The source base is now targeted at Python 2.6 and forwards.
+
+    .. change::
         :tags: bug, py3k
 
       Fixed bug in ``decode.<encoding>`` filter where a non-string object
@@ -25,6 +32,15 @@
 
     .. change::
         :tags: feature
+        :pullreq: bitbucket:5
+
+      mako-render is now implemented as a setuptools entrypoint script;
+      a standalone mako.cmd.cmdline() callable is now available, and the
+      system also uses argparse now instead of optparse.  Pull request
+      courtesy Derek Harland.
+
+    .. change::
+        :tags: feature
         :pullreq: bitbucket:4
 
       The mako-render script will now catch exceptions and run them
@@ -51,6 +67,9 @@
       template lookup directories.  Standard input for templates also works
       now too.  Pull request courtesy Derek Harland.
 
+0.9
+===
+
 .. changelog::
     :version: 0.9.1
     :released: Thu Dec 26 2013
diff --git a/mako/__init__.py b/mako/__init__.py
index aa99505..52a1c05 100644
--- a/mako/__init__.py
+++ b/mako/__init__.py
@@ -5,5 +5,7 @@
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 
-__version__ = '0.9.2'
+__version__ = '1.0.0'
+
+
 
diff --git a/mako/_ast_util.py b/mako/_ast_util.py
index 788b86a..5c274be 100644
--- a/mako/_ast_util.py
+++ b/mako/_ast_util.py
@@ -34,42 +34,42 @@
 from mako.compat import arg_stringname
 
 BOOLOP_SYMBOLS = {
-    And:        'and',
-    Or:         'or'
+    And: 'and',
+    Or: 'or'
 }
 
 BINOP_SYMBOLS = {
-    Add:        '+',
-    Sub:        '-',
-    Mult:       '*',
-    Div:        '/',
-    FloorDiv:   '//',
-    Mod:        '%',
-    LShift:     '<<',
-    RShift:     '>>',
-    BitOr:      '|',
-    BitAnd:     '&',
-    BitXor:     '^'
+    Add: '+',
+    Sub: '-',
+    Mult: '*',
+    Div: '/',
+    FloorDiv: '//',
+    Mod: '%',
+    LShift: '<<',
+    RShift: '>>',
+    BitOr: '|',
+    BitAnd: '&',
+    BitXor: '^'
 }
 
 CMPOP_SYMBOLS = {
-    Eq:         '==',
-    Gt:         '>',
-    GtE:        '>=',
-    In:         'in',
-    Is:         'is',
-    IsNot:      'is not',
-    Lt:         '<',
-    LtE:        '<=',
-    NotEq:      '!=',
-    NotIn:      'not in'
+    Eq: '==',
+    Gt: '>',
+    GtE: '>=',
+    In: 'in',
+    Is: 'is',
+    IsNot: 'is not',
+    Lt: '<',
+    LtE: '<=',
+    NotEq: '!=',
+    NotIn: 'not in'
 }
 
 UNARYOP_SYMBOLS = {
-    Invert:     '~',
-    Not:        'not',
-    UAdd:       '+',
-    USub:       '-'
+    Invert: '~',
+    Not: 'not',
+    UAdd: '+',
+    USub: '-'
 }
 
 ALL_SYMBOLS = {}
@@ -215,8 +215,8 @@
     if not isinstance(node, mod):
         raise TypeError('expected mod node, got %r' % node.__class__.__name__)
     return {
-        Expression:     'eval',
-        Interactive:    'single'
+        Expression: 'eval',
+        Interactive: 'single'
     }.get(node.__class__, 'expr')
 
 
diff --git a/mako/ast.py b/mako/ast.py
index 8f711b4..44355bc 100644
--- a/mako/ast.py
+++ b/mako/ast.py
@@ -8,7 +8,6 @@
 code, as well as generating Python from AST nodes"""
 
 from mako import exceptions, pyparser, compat
-from mako.compat import arg_stringname
 import re
 
 class PythonCode(object):
@@ -107,8 +106,8 @@
         f.visit(expr)
         if not hasattr(self, 'funcname'):
             raise exceptions.CompileException(
-                              "Code '%s' is not a function declaration" % code,
-                              **exception_kwargs)
+                            "Code '%s' is not a function declaration" % code,
+                            **exception_kwargs)
         if not allow_kwargs and self.kwargs:
             raise exceptions.CompileException(
                                 "'**%s' keyword argument not allowed here" %
diff --git a/mako/codegen.py b/mako/codegen.py
index 045d03c..2240ba2 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -187,7 +187,7 @@
 
         # module-level names, python code
         if self.compiler.generate_magic_comment and \
-            self.compiler.source_encoding:
+                self.compiler.source_encoding:
             self.printer.writeline("# -*- coding:%s -*-" %
                                     self.compiler.source_encoding)
 
@@ -255,7 +255,7 @@
             decorator = node.decorator
             if decorator:
                 self.printer.writeline(
-                                 "@runtime._decorate_toplevel(%s)" % decorator)
+                                "@runtime._decorate_toplevel(%s)" % decorator)
 
         self.printer.writelines(
             "def %s(%s):" % (name, ','.join(args)),
@@ -267,7 +267,7 @@
             self.printer.writeline("context._push_buffer()")
 
         self.identifier_stack.append(
-                                   self.compiler.identifiers.branch(self.node))
+                                self.compiler.identifiers.branch(self.node))
         if (not self.in_def or self.node.is_block) and '**pageargs' in args:
             self.identifier_stack[-1].argument_declared.add('pageargs')
 
@@ -309,9 +309,9 @@
             "def _mako_inherit(template, context):",
                 "_mako_generate_namespaces(context)",
                 "return runtime._inherit_from(context, %s, _template_uri)" %
-                 (node.parsed_attributes['file']),
+                (node.parsed_attributes['file']),
                 None
-            )
+        )
 
     def write_namespaces(self, namespaces):
         """write the module-level namespace-generating callable."""
@@ -323,7 +323,7 @@
                     "_mako_generate_namespaces(context)",
                 "return context.namespaces[(__name__, name)]",
             None, None
-            )
+        )
         self.printer.writeline("def _mako_generate_namespaces(context):")
 
 
@@ -369,9 +369,9 @@
                                 " templateuri=%s, callables=%s, "
                                 " calling_uri=_template_uri)" %
                                 (
-                                   node.name,
-                                   node.parsed_attributes.get('file', 'None'),
-                                   callable_name,
+                                    node.name,
+                                    node.parsed_attributes.get('file', 'None'),
+                                    callable_name,
                                 )
                             )
             elif 'module' in node.parsed_attributes:
@@ -381,9 +381,10 @@
                                 " callables=%s, calling_uri=_template_uri,"
                                 " module=%s)" %
                                 (
-                                   node.name,
-                                   callable_name,
-                                   node.parsed_attributes.get('module', 'None')
+                                    node.name,
+                                    callable_name,
+                                    node.parsed_attributes.get(
+                                                'module', 'None')
                                 )
                             )
             else:
@@ -400,7 +401,7 @@
                 self.printer.writeline("context['self'].%s = ns" % (node.name))
 
             self.printer.writeline(
-                   "context.namespaces[(__name__, %s)] = ns" % repr(node.name))
+                "context.namespaces[(__name__, %s)] = ns" % repr(node.name))
             self.printer.write("\n")
         if not len(namespaces):
             self.printer.writeline("pass")
@@ -466,7 +467,7 @@
             for ident, ns in self.compiler.namespaces.items():
                 if 'import' in ns.attributes:
                     self.printer.writeline(
-                            "_mako_get_namespace(context, %r)."\
+                            "_mako_get_namespace(context, %r)."
                                     "_populate(_import_ns, %r)" %
                             (
                                 ident,
@@ -553,7 +554,7 @@
             nameargs.insert(0, 'context')
         self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls)))
         self.printer.writeline(
-                       "return render_%s(%s)" % (funcname, ",".join(nameargs)))
+                    "return render_%s(%s)" % (funcname, ",".join(nameargs)))
         self.printer.writeline(None)
 
     def write_inline_def(self, node, identifiers, nested):
@@ -564,9 +565,9 @@
         decorator = node.decorator
         if decorator:
             self.printer.writeline(
-                          "@runtime._decorate_inline(context, %s)" % decorator)
+                        "@runtime._decorate_inline(context, %s)" % decorator)
         self.printer.writeline(
-                          "def %s(%s):" % (node.funcname, ",".join(namedecls)))
+                        "def %s(%s):" % (node.funcname, ",".join(namedecls)))
         filtered = len(node.filter_args.args) > 0
         buffered = eval(node.attributes.get('buffered', 'False'))
         cached = eval(node.attributes.get('cached', 'False'))
@@ -574,11 +575,11 @@
             # push new frame, assign current frame to __M_caller
             "__M_caller = context.caller_stack._push_frame()",
             "try:"
-            )
+        )
         if buffered or filtered or cached:
             self.printer.writelines(
                 "context._push_buffer()",
-                )
+            )
 
         identifiers = identifiers.branch(node, nested=nested)
 
@@ -627,8 +628,8 @@
                 )
             else:
                 self.printer.writelines(
-                   "finally:",
-                       "__M_buf, __M_writer = context._pop_buffer_and_writer()"
+                    "finally:",
+                    "__M_buf, __M_writer = context._pop_buffer_and_writer()"
                 )
 
             if callstack:
@@ -684,7 +685,7 @@
 
         # form "arg1, arg2, arg3=arg3, arg4=arg4", etc.
         pass_args = [
-                        '=' in a and "%s=%s" % ((a.split('=')[0],)*2) or a
+                        "%s=%s" % ((a.split('=')[0],) * 2) if '=' in a else a
                         for a in args
                     ]
 
@@ -696,11 +697,11 @@
         if buffered:
             s = "context.get('local')."\
                 "cache._ctx_get_or_create("\
-                "%s, lambda:__M_%s(%s),  context, %s__M_defname=%r)" % \
-                            (cachekey, name, ','.join(pass_args),
-                            ''.join(["%s=%s, " % (k, v)
-                            for k, v in cache_args.items()]),
-                            name
+                "%s, lambda:__M_%s(%s),  context, %s__M_defname=%r)" % (
+                                cachekey, name, ','.join(pass_args),
+                                ''.join(["%s=%s, " % (k, v)
+                                for k, v in cache_args.items()]),
+                                name
                             )
             # apply buffer_filters
             s = self.create_filter_callable(self.compiler.buffer_filters, s,
@@ -709,12 +710,13 @@
         else:
             self.printer.writelines(
                     "__M_writer(context.get('local')."
-                    "cache._ctx_get_or_create("\
+                    "cache._ctx_get_or_create("
                     "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" %
-                    (cachekey, name, ','.join(pass_args),
-                    ''.join(["%s=%s, " % (k, v)
+                    (
+                        cachekey, name, ','.join(pass_args),
+                        ''.join(["%s=%s, " % (k, v)
                         for k, v in cache_args.items()]),
-                    name,
+                        name,
                     ),
                     "return ''",
                 None
@@ -745,11 +747,10 @@
                 continue
             m = re.match(r'(.+?)(\(.*\))', e)
             if m:
-                (ident, fargs) = m.group(1,2)
+                ident, fargs = m.group(1, 2)
                 f = locate_encode(ident)
                 e = f + fargs
             else:
-                x = e
                 e = locate_encode(e)
                 assert e is not None
             target = "%s(%s)" % (e, target)
@@ -822,7 +823,7 @@
                                 "__M_buf.getvalue()",
                                 False),
                 None
-                )
+            )
 
     def visitCode(self, node):
         if not node.ismodule:
@@ -835,20 +836,20 @@
                 # which is used for def calls within the same template,
                 # to simulate "enclosing scope"
                 self.printer.writeline(
-                      '__M_locals_builtin_stored = __M_locals_builtin()')
+                    '__M_locals_builtin_stored = __M_locals_builtin()')
                 self.printer.writeline(
-                      '__M_locals.update(__M_dict_builtin([(__M_key,'
-                      ' __M_locals_builtin_stored[__M_key]) for __M_key in'
-                      ' [%s] if __M_key in __M_locals_builtin_stored]))' %
-                      ','.join([repr(x) for x in node.declared_identifiers()]))
+                    '__M_locals.update(__M_dict_builtin([(__M_key,'
+                    ' __M_locals_builtin_stored[__M_key]) for __M_key in'
+                    ' [%s] if __M_key in __M_locals_builtin_stored]))' %
+                    ','.join([repr(x) for x in node.declared_identifiers()]))
 
     def visitIncludeTag(self, node):
         self.write_source_comment(node)
         args = node.attributes.get('args')
         if args:
             self.printer.writeline(
-                      "runtime._include_file(context, %s, _template_uri, %s)" %
-                      (node.parsed_attributes['file'], args))
+                    "runtime._include_file(context, %s, _template_uri, %s)" %
+                    (node.parsed_attributes['file'], args))
         else:
             self.printer.writeline(
                         "runtime._include_file(context, %s, _template_uri)" %
@@ -941,7 +942,7 @@
             # push on caller for nested call
             "context.caller_stack.nextcaller = "
                 "runtime.Namespace('caller', context, "
-                                  "callables=ccall(__M_caller))",
+                                "callables=ccall(__M_caller))",
             "try:")
         self.write_source_comment(node)
         self.printer.writelines(
@@ -966,9 +967,9 @@
                 # things that have already been declared
                 # in an enclosing namespace (i.e. names we can just use)
                 self.declared = set(parent.declared).\
-                         union([c.name for c in parent.closuredefs.values()]).\
-                         union(parent.locally_declared).\
-                         union(parent.argument_declared)
+                        union([c.name for c in parent.closuredefs.values()]).\
+                        union(parent.locally_declared).\
+                        union(parent.argument_declared)
 
                 # if these identifiers correspond to a "nested"
                 # scope, it means whatever the parent identifiers
@@ -1012,7 +1013,7 @@
             node.accept_visitor(self)
 
         illegal_names = self.compiler.reserved_names.intersection(
-                                                         self.locally_declared)
+                                                        self.locally_declared)
         if illegal_names:
             raise exceptions.NameConflictError(
                 "Reserved words declared in template: %s" %
@@ -1047,7 +1048,7 @@
 
         for ident in node.undeclared_identifiers():
             if ident != 'context' and\
-                       ident not in self.declared.union(self.locally_declared):
+                    ident not in self.declared.union(self.locally_declared):
                 self.undeclared.add(ident)
         for ident in node.declared_identifiers():
             self.locally_declared.add(ident)
@@ -1067,7 +1068,7 @@
         if not node.ismodule:
             self.check_declared(node)
             self.locally_assigned = self.locally_assigned.union(
-                                                   node.declared_identifiers())
+                                                node.declared_identifiers())
 
     def visitNamespaceTag(self, node):
         # only traverse into the sub-elements of a
@@ -1095,8 +1096,8 @@
             self._check_name_exists(self.closuredefs, node)
 
         for ident in node.undeclared_identifiers():
-            if ident != 'context' and\
-                       ident not in self.declared.union(self.locally_declared):
+            if ident != 'context' and \
+                    ident not in self.declared.union(self.locally_declared):
                 self.undeclared.add(ident)
 
         # visit defs only one level deep
@@ -1108,8 +1109,7 @@
                 n.accept_visitor(self)
 
     def visitBlockTag(self, node):
-        if node is not self.node and \
-            not node.is_anonymous:
+        if node is not self.node and not node.is_anonymous:
 
             if isinstance(self.node, parsetree.DefTag):
                 raise exceptions.CompileException(
@@ -1123,7 +1123,7 @@
 
         for ident in node.undeclared_identifiers():
             if ident != 'context' and \
-                       ident not in self.declared.union(self.locally_declared):
+                    ident not in self.declared.union(self.locally_declared):
                 self.undeclared.add(ident)
 
         if not node.is_anonymous:
@@ -1139,7 +1139,7 @@
     def visitTextTag(self, node):
         for ident in node.undeclared_identifiers():
             if ident != 'context' and \
-                ident not in self.declared.union(self.locally_declared):
+                    ident not in self.declared.union(self.locally_declared):
                 self.undeclared.add(ident)
 
     def visitIncludeTag(self, node):
@@ -1156,8 +1156,9 @@
     def visitCallTag(self, node):
         if node is self.node:
             for ident in node.undeclared_identifiers():
-                if ident != 'context' and\
-                       ident not in self.declared.union(self.locally_declared):
+                if ident != 'context' and \
+                        ident not in self.declared.union(
+                                                self.locally_declared):
                     self.undeclared.add(ident)
             for ident in node.declared_identifiers():
                 self.argument_declared.add(ident)
@@ -1165,15 +1166,16 @@
                 n.accept_visitor(self)
         else:
             for ident in node.undeclared_identifiers():
-                if ident != 'context' and\
-                       ident not in self.declared.union(self.locally_declared):
+                if ident != 'context' and \
+                        ident not in self.declared.union(
+                                                self.locally_declared):
                     self.undeclared.add(ident)
 
 
 _FOR_LOOP = re.compile(
         r'^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*'
         r'(?:\s*,\s*(?:[A-Za-z_][A-Za-z0-9_]*),??)*\s*(?:\)?))\s+in\s+(.*):'
-    )
+)
 
 def mangle_mako_loop(node, printer):
     """converts a for loop into a context manager wrapped around a for loop
@@ -1189,7 +1191,7 @@
                     'loop = __M_loop._enter(%s)' % match.group(2),
                     'try:'
                     #'with __M_loop(%s) as loop:' % match.group(2)
-                )
+            )
             text = 'for %s in loop:' % match.group(1)
         else:
             raise SyntaxError("Couldn't apply loop context: %s" % node.text)
diff --git a/mako/compat.py b/mako/compat.py
index 82b6c05..f782aa9 100644
--- a/mako/compat.py
+++ b/mako/compat.py
@@ -5,7 +5,6 @@
 py33 = sys.version_info >= (3, 3)
 py2k = sys.version_info < (3,)
 py26 = sys.version_info >= (2, 6)
-py25 = sys.version_info >= (2, 5)
 jython = sys.platform.startswith('java')
 win32 = sys.platform.startswith('win')
 pypy = hasattr(sys, 'pypy_version_info')
@@ -100,23 +99,10 @@
             return func(*(args + fargs), **newkeywords)
         return newfunc
 
-if not py25:
-    def all(iterable):
-        for i in iterable:
-            if not i:
-                return False
-        return True
+all = all
 
-    def exception_name(exc):
-        try:
-            return exc.__class__.__name__
-        except AttributeError:
-            return exc.__name__
-else:
-    all = all
-
-    def exception_name(exc):
-        return exc.__class__.__name__
+def exception_name(exc):
+    return exc.__class__.__name__
 
 try:
     from inspect import CO_VARKEYWORDS, CO_VARARGS
diff --git a/mako/exceptions.py b/mako/exceptions.py
index b8f97ee..a7bab8c 100644
--- a/mako/exceptions.py
+++ b/mako/exceptions.py
@@ -28,7 +28,7 @@
     def __init__(self, message, source, lineno, pos, filename):
         MakoException.__init__(self,
                               message + _format_filepos(lineno, pos, filename))
-        self.lineno =lineno
+        self.lineno = lineno
         self.pos = pos
         self.filename = filename
         self.source = source
@@ -37,7 +37,7 @@
     def __init__(self, message, source, lineno, pos, filename):
         MakoException.__init__(self,
                               message + _format_filepos(lineno, pos, filename))
-        self.lineno =lineno
+        self.lineno = lineno
         self.pos = pos
         self.filename = filename
         self.source = source
@@ -260,10 +260,11 @@
     filenames, line numbers and code for that of the originating source
     template, as applicable.
 
-    The template's default ``encoding_errors`` value is ``'htmlentityreplace'``. The
-    template has two options. With the ``full`` option disabled, only a section of
-    an HTML document is returned. With the ``css`` option disabled, the default
-    stylesheet won't be included.
+    The template's default ``encoding_errors`` value is
+    ``'htmlentityreplace'``. The template has two options. With the
+    ``full`` option disabled, only a section of an HTML document is
+    returned. With the ``css`` option disabled, the default stylesheet
+    won't be included.
 
     """
     import mako.template
diff --git a/mako/lexer.py b/mako/lexer.py
index dca88e1..dd46b10 100644
--- a/mako/lexer.py
+++ b/mako/lexer.py
@@ -44,10 +44,10 @@
 
     @property
     def exception_kwargs(self):
-        return {'source':self.text,
-                'lineno':self.matched_lineno,
-                'pos':self.matched_charpos,
-                'filename':self.filename}
+        return {'source': self.text,
+                'lineno': self.matched_lineno,
+                'pos': self.matched_charpos,
+                'filename': self.filename}
 
     def match(self, regexp, flags=None):
         """compile the given regexp, cache the reg, and call match_reg()."""
@@ -83,8 +83,8 @@
             self.matched_lineno = self.lineno
             lines = re.findall(r"\n", self.text[mp:self.match_position])
             cp = mp - 1
-            while (cp >= 0 and cp<self.textlength and self.text[cp] != '\n'):
-                cp -=1
+            while (cp >= 0 and cp < self.textlength and self.text[cp] != '\n'):
+                cp -= 1
             self.matched_charpos = mp - cp
             self.lineno += len(lines)
             #print "MATCHED:", match.group(0), "LINE START:",
@@ -111,8 +111,8 @@
                     brace_level -= 1
                     continue
                 return \
-                    self.text[startpos:\
-                              self.match_position-len(match.group(1))],\
+                    self.text[startpos:
+                              self.match_position - len(match.group(1))],\
                     match.group(1)
             match = self.match(r"(.*?)(?=\"|\'|#|%s)" % text_re, re.S)
             if match:
@@ -162,9 +162,9 @@
             elif self.control_line and \
                     not self.control_line[-1].is_ternary(node.keyword):
                 raise exceptions.SyntaxException(
-                          "Keyword '%s' not a legal ternary for keyword '%s'" %
-                          (node.keyword, self.control_line[-1].keyword),
-                          **self.exception_kwargs)
+                        "Keyword '%s' not a legal ternary for keyword '%s'" %
+                        (node.keyword, self.control_line[-1].keyword),
+                        **self.exception_kwargs)
 
     _coding_re = re.compile(r'#.*coding[:=]\s*([-\w.]+).*\r?\n')
 
@@ -201,10 +201,10 @@
                 text = text.decode(parsed_encoding)
             except UnicodeDecodeError:
                 raise exceptions.CompileException(
-                           "Unicode decode operation of encoding '%s' failed" %
-                           parsed_encoding,
-                           text.decode('utf-8', 'ignore'),
-                           0, 0, filename)
+                        "Unicode decode operation of encoding '%s' failed" %
+                        parsed_encoding,
+                        text.decode('utf-8', 'ignore'),
+                        0, 0, filename)
 
         return parsed_encoding, text
 
@@ -254,11 +254,11 @@
                                                 **self.exception_kwargs)
         if len(self.control_line):
             raise exceptions.SyntaxException(
-                                      "Unterminated control keyword: '%s'" %
-                                      self.control_line[-1].keyword,
-                                      self.text,
-                                      self.control_line[-1].lineno,
-                                      self.control_line[-1].pos, self.filename)
+                                    "Unterminated control keyword: '%s'" %
+                                    self.control_line[-1].keyword,
+                                    self.text,
+                                    self.control_line[-1].lineno,
+                                    self.control_line[-1].pos, self.filename)
         return self.template
 
     def match_tag_start(self):
@@ -311,14 +311,14 @@
         if match:
             if not len(self.tag):
                 raise exceptions.SyntaxException(
-                                   "Closing tag without opening tag: </%%%s>" %
-                                    match.group(1),
-                                    **self.exception_kwargs)
+                                "Closing tag without opening tag: </%%%s>" %
+                                match.group(1),
+                                **self.exception_kwargs)
             elif self.tag[-1].keyword != match.group(1):
                 raise exceptions.SyntaxException(
-                             "Closing tag </%%%s> does not match tag: <%%%s>" %
-                             (match.group(1), self.tag[-1].keyword),
-                             **self.exception_kwargs)
+                            "Closing tag </%%%s> does not match tag: <%%%s>" %
+                            (match.group(1), self.tag[-1].keyword),
+                            **self.exception_kwargs)
             self.tag.pop()
             return True
         else:
@@ -370,9 +370,9 @@
             # compiler.parse() not complain about indentation
             text = adjust_whitespace(text) + "\n"
             self.append_node(
-                            parsetree.Code,
-                            text,
-                            match.group(1)=='!', lineno=line, pos=pos)
+                        parsetree.Code,
+                        text,
+                        match.group(1) == '!', lineno=line, pos=pos)
             return True
         else:
             return False
@@ -397,8 +397,8 @@
 
     def match_control_line(self):
         match = self.match(
-                      r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)"
-                      r"(?:\r?\n|\Z)", re.M)
+                    r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)"
+                    r"(?:\r?\n|\Z)", re.M)
         if match:
             operator = match.group(1)
             text = match.group(2)
diff --git a/mako/pygen.py b/mako/pygen.py
index cba9464..52e32be 100644
--- a/mako/pygen.py
+++ b/mako/pygen.py
@@ -80,7 +80,7 @@
             ):
 
             if self.indent > 0:
-                self.indent -=1
+                self.indent -= 1
                 # if the indent_detail stack is empty, the user
                 # probably put extra closures - the resulting
                 # module wont compile.
@@ -108,7 +108,7 @@
             if match:
                 # its a "compound" keyword, so we will check for "unindentors"
                 indentor = match.group(1)
-                self.indent +=1
+                self.indent += 1
                 self.indent_detail.append(indentor)
             else:
                 indentor = None
@@ -265,7 +265,7 @@
 
         return start_state
 
-    def _indent_line(line, stripspace = ''):
+    def _indent_line(line, stripspace=''):
         return re.sub(r"^%s" % stripspace, '', line)
 
     lines = []
diff --git a/mako/pyparser.py b/mako/pyparser.py
index db5c295..e1edc5b 100644
--- a/mako/pyparser.py
+++ b/mako/pyparser.py
@@ -11,7 +11,7 @@
 """
 
 from mako import exceptions, util, compat
-from mako.compat import StringIO, arg_stringname
+from mako.compat import arg_stringname
 import operator
 
 if compat.py3k:
@@ -29,29 +29,16 @@
     # the "id" attribute on a function node
     arg_id = operator.attrgetter('id')
 
-
-try:
-    import _ast
-    util.restore__ast(_ast)
-    from mako import _ast_util
-except ImportError:
-    _ast = None
-    from compiler import parse as compiler_parse
-    from compiler import visitor
-
+import _ast
+util.restore__ast(_ast)
+from mako import _ast_util
 
 
 def parse(code, mode='exec', **exception_kwargs):
     """Parse an expression into AST"""
 
-
     try:
-        if _ast:
-            return _ast_util.parse(code, '<unknown>', mode)
-        else:
-            if isinstance(code, compat.text_type):
-                code = code.encode('ascii', 'backslashreplace')
-            return compiler_parse(code, mode)
+        return _ast_util.parse(code, '<unknown>', mode)
     except Exception:
         raise exceptions.SyntaxException(
                     "(%s) %s (%r)" % (
@@ -61,529 +48,185 @@
                     ), **exception_kwargs)
 
 
-if _ast:
-    class FindIdentifiers(_ast_util.NodeVisitor):
+class FindIdentifiers(_ast_util.NodeVisitor):
 
-        def __init__(self, listener, **exception_kwargs):
-            self.in_function = False
-            self.in_assign_targets = False
-            self.local_ident_stack = set()
-            self.listener = listener
-            self.exception_kwargs = exception_kwargs
+    def __init__(self, listener, **exception_kwargs):
+        self.in_function = False
+        self.in_assign_targets = False
+        self.local_ident_stack = set()
+        self.listener = listener
+        self.exception_kwargs = exception_kwargs
 
-        def _add_declared(self, name):
-            if not self.in_function:
-                self.listener.declared_identifiers.add(name)
-            else:
-                self.local_ident_stack.add(name)
+    def _add_declared(self, name):
+        if not self.in_function:
+            self.listener.declared_identifiers.add(name)
+        else:
+            self.local_ident_stack.add(name)
 
-        def visit_ClassDef(self, node):
-            self._add_declared(node.name)
+    def visit_ClassDef(self, node):
+        self._add_declared(node.name)
 
-        def visit_Assign(self, node):
+    def visit_Assign(self, node):
 
-            # flip around the visiting of Assign so the expression gets
-            # evaluated first, in the case of a clause like "x=x+5" (x
-            # is undeclared)
+        # flip around the visiting of Assign so the expression gets
+        # evaluated first, in the case of a clause like "x=x+5" (x
+        # is undeclared)
 
-            self.visit(node.value)
-            in_a = self.in_assign_targets
-            self.in_assign_targets = True
-            for n in node.targets:
-                self.visit(n)
-            self.in_assign_targets = in_a
+        self.visit(node.value)
+        in_a = self.in_assign_targets
+        self.in_assign_targets = True
+        for n in node.targets:
+            self.visit(n)
+        self.in_assign_targets = in_a
 
-        if compat.py3k:
+    if compat.py3k:
 
-            # ExceptHandler is in Python 2, but this block only works in
-            # Python 3 (and is required there)
+        # ExceptHandler is in Python 2, but this block only works in
+        # Python 3 (and is required there)
 
-            def visit_ExceptHandler(self, node):
-                if node.name is not None:
-                    self._add_declared(node.name)
-                if node.type is not None:
-                    self.visit(node.type)
-                for statement in node.body:
-                    self.visit(statement)
-
-        def visit_Lambda(self, node, *args):
-            self._visit_function(node, True)
-
-        def visit_FunctionDef(self, node):
-            self._add_declared(node.name)
-            self._visit_function(node, False)
-
-        def _expand_tuples(self, args):
-            for arg in args:
-                if isinstance(arg, _ast.Tuple):
-                    for n in arg.elts:
-                        yield n
-                else:
-                    yield arg
-
-        def _visit_function(self, node, islambda):
-
-            # push function state onto stack.  dont log any more
-            # identifiers as "declared" until outside of the function,
-            # but keep logging identifiers as "undeclared". track
-            # argument names in each function header so they arent
-            # counted as "undeclared"
-
-            inf = self.in_function
-            self.in_function = True
-
-            local_ident_stack = self.local_ident_stack
-            self.local_ident_stack = local_ident_stack.union([
-                arg_id(arg) for arg in self._expand_tuples(node.args.args)
-            ])
-            if islambda:
-                self.visit(node.body)
-            else:
-                for n in node.body:
-                    self.visit(n)
-            self.in_function = inf
-            self.local_ident_stack = local_ident_stack
-
-        def visit_For(self, node):
-
-            # flip around visit
-
-            self.visit(node.iter)
-            self.visit(node.target)
+        def visit_ExceptHandler(self, node):
+            if node.name is not None:
+                self._add_declared(node.name)
+            if node.type is not None:
+                self.visit(node.type)
             for statement in node.body:
                 self.visit(statement)
-            for statement in node.orelse:
-                self.visit(statement)
 
-        def visit_Name(self, node):
-            if isinstance(node.ctx, _ast.Store):
-                # this is eqiuvalent to visit_AssName in
-                # compiler
-                self._add_declared(node.id)
-            elif node.id not in reserved and node.id \
-                not in self.listener.declared_identifiers and node.id \
+    def visit_Lambda(self, node, *args):
+        self._visit_function(node, True)
+
+    def visit_FunctionDef(self, node):
+        self._add_declared(node.name)
+        self._visit_function(node, False)
+
+    def _expand_tuples(self, args):
+        for arg in args:
+            if isinstance(arg, _ast.Tuple):
+                for n in arg.elts:
+                    yield n
+            else:
+                yield arg
+
+    def _visit_function(self, node, islambda):
+
+        # push function state onto stack.  dont log any more
+        # identifiers as "declared" until outside of the function,
+        # but keep logging identifiers as "undeclared". track
+        # argument names in each function header so they arent
+        # counted as "undeclared"
+
+        inf = self.in_function
+        self.in_function = True
+
+        local_ident_stack = self.local_ident_stack
+        self.local_ident_stack = local_ident_stack.union([
+            arg_id(arg) for arg in self._expand_tuples(node.args.args)
+        ])
+        if islambda:
+            self.visit(node.body)
+        else:
+            for n in node.body:
+                self.visit(n)
+        self.in_function = inf
+        self.local_ident_stack = local_ident_stack
+
+    def visit_For(self, node):
+
+        # flip around visit
+
+        self.visit(node.iter)
+        self.visit(node.target)
+        for statement in node.body:
+            self.visit(statement)
+        for statement in node.orelse:
+            self.visit(statement)
+
+    def visit_Name(self, node):
+        if isinstance(node.ctx, _ast.Store):
+            # this is eqiuvalent to visit_AssName in
+            # compiler
+            self._add_declared(node.id)
+        elif node.id not in reserved and node.id \
+            not in self.listener.declared_identifiers and node.id \
                 not in self.local_ident_stack:
-                self.listener.undeclared_identifiers.add(node.id)
+            self.listener.undeclared_identifiers.add(node.id)
 
-        def visit_Import(self, node):
-            for name in node.names:
-                if name.asname is not None:
-                    self._add_declared(name.asname)
-                else:
-                    self._add_declared(name.name.split('.')[0])
-
-        def visit_ImportFrom(self, node):
-            for name in node.names:
-                if name.asname is not None:
-                    self._add_declared(name.asname)
-                else:
-                    if name.name == '*':
-                        raise exceptions.CompileException(
-                          "'import *' is not supported, since all identifier "
-                          "names must be explicitly declared.  Please use the "
-                          "form 'from <modulename> import <name1>, <name2>, "
-                          "...' instead.", **self.exception_kwargs)
-                    self._add_declared(name.name)
-
-
-    class FindTuple(_ast_util.NodeVisitor):
-
-        def __init__(self, listener, code_factory, **exception_kwargs):
-            self.listener = listener
-            self.exception_kwargs = exception_kwargs
-            self.code_factory = code_factory
-
-        def visit_Tuple(self, node):
-            for n in node.elts:
-                p = self.code_factory(n, **self.exception_kwargs)
-                self.listener.codeargs.append(p)
-                self.listener.args.append(ExpressionGenerator(n).value())
-                self.listener.declared_identifiers = \
-                    self.listener.declared_identifiers.union(
-                                                    p.declared_identifiers)
-                self.listener.undeclared_identifiers = \
-                    self.listener.undeclared_identifiers.union(
-                                                    p.undeclared_identifiers)
-
-
-    class ParseFunc(_ast_util.NodeVisitor):
-
-        def __init__(self, listener, **exception_kwargs):
-            self.listener = listener
-            self.exception_kwargs = exception_kwargs
-
-        def visit_FunctionDef(self, node):
-            self.listener.funcname = node.name
-
-            argnames = [arg_id(arg) for arg in node.args.args]
-            if node.args.vararg:
-                argnames.append(arg_stringname(node.args.vararg))
-
-            if compat.py2k:
-                # kw-only args don't exist in Python 2
-                kwargnames = []
+    def visit_Import(self, node):
+        for name in node.names:
+            if name.asname is not None:
+                self._add_declared(name.asname)
             else:
-                kwargnames = [arg_id(arg) for arg in node.args.kwonlyargs]
-            if node.args.kwarg:
-                kwargnames.append(arg_stringname(node.args.kwarg))
-            self.listener.argnames = argnames
-            self.listener.defaults = node.args.defaults  # ast
-            self.listener.kwargnames = kwargnames
-            if compat.py2k:
-                self.listener.kwdefaults = []
+                self._add_declared(name.name.split('.')[0])
+
+    def visit_ImportFrom(self, node):
+        for name in node.names:
+            if name.asname is not None:
+                self._add_declared(name.asname)
             else:
-                self.listener.kwdefaults = node.args.kw_defaults
-            self.listener.varargs = node.args.vararg
-            self.listener.kwargs = node.args.kwarg
-
-    class ExpressionGenerator(object):
-
-        def __init__(self, astnode):
-            self.generator = _ast_util.SourceGenerator(' ' * 4)
-            self.generator.visit(astnode)
-
-        def value(self):
-            return ''.join(self.generator.result)
-else:
-    class FindIdentifiers(object):
-
-        def __init__(self, listener, **exception_kwargs):
-            self.in_function = False
-            self.local_ident_stack = set()
-            self.listener = listener
-            self.exception_kwargs = exception_kwargs
-
-        def _add_declared(self, name):
-            if not self.in_function:
-                self.listener.declared_identifiers.add(name)
-            else:
-                self.local_ident_stack.add(name)
-
-        def visitClass(self, node, *args):
-            self._add_declared(node.name)
-
-        def visitAssName(self, node, *args):
-            self._add_declared(node.name)
-
-        def visitAssign(self, node, *args):
-
-            # flip around the visiting of Assign so the expression gets
-            # evaluated first, in the case of a clause like "x=x+5" (x
-            # is undeclared)
-            self.visit(node.expr, *args)
-            for n in node.nodes:
-                self.visit(n, *args)
-
-        def visitLambda(self, node, *args):
-            self._visit_function(node, args)
-
-        def visitFunction(self, node, *args):
-            self._add_declared(node.name)
-            self._visit_function(node, args)
-
-        def _expand_tuples(self, args):
-            for arg in args:
-                if isinstance(arg, tuple):
-                    for n in arg:
-                        yield n
-                else:
-                    yield arg
-
-        def _visit_function(self, node, args):
-
-            # push function state onto stack.  dont log any more
-            # identifiers as "declared" until outside of the function,
-            # but keep logging identifiers as "undeclared". track
-            # argument names in each function header so they arent
-            # counted as "undeclared"
-
-            inf = self.in_function
-            self.in_function = True
-
-            local_ident_stack = self.local_ident_stack
-            self.local_ident_stack = local_ident_stack.union([
-                arg for arg in self._expand_tuples(node.argnames)
-            ])
-
-            for n in node.getChildNodes():
-                self.visit(n, *args)
-            self.in_function = inf
-            self.local_ident_stack = local_ident_stack
-
-        def visitFor(self, node, *args):
-
-            # flip around visit
-
-            self.visit(node.list, *args)
-            self.visit(node.assign, *args)
-            self.visit(node.body, *args)
-
-        def visitName(self, node, *args):
-            if node.name not in reserved and node.name \
-                not in self.listener.declared_identifiers and node.name \
-                not in self.local_ident_stack:
-                self.listener.undeclared_identifiers.add(node.name)
-
-        def visitImport(self, node, *args):
-            for mod, alias in node.names:
-                if alias is not None:
-                    self._add_declared(alias)
-                else:
-                    self._add_declared(mod.split('.')[0])
-
-        def visitFrom(self, node, *args):
-            for mod, alias in node.names:
-                if alias is not None:
-                    self._add_declared(alias)
-                else:
-                    if mod == '*':
-                        raise exceptions.CompileException(
+                if name.name == '*':
+                    raise exceptions.CompileException(
                         "'import *' is not supported, since all identifier "
                         "names must be explicitly declared.  Please use the "
                         "form 'from <modulename> import <name1>, <name2>, "
                         "...' instead.", **self.exception_kwargs)
-                    self._add_declared(mod)
-
-        def visit(self, expr):
-            visitor.walk(expr, self)  # , walker=walker())
+                self._add_declared(name.name)
 
 
-    class FindTuple(object):
+class FindTuple(_ast_util.NodeVisitor):
 
-        def __init__(self, listener, code_factory, **exception_kwargs):
-            self.listener = listener
-            self.exception_kwargs = exception_kwargs
-            self.code_factory = code_factory
+    def __init__(self, listener, code_factory, **exception_kwargs):
+        self.listener = listener
+        self.exception_kwargs = exception_kwargs
+        self.code_factory = code_factory
 
-        def visitTuple(self, node, *args):
-            for n in node.nodes:
-                p = self.code_factory(n, **self.exception_kwargs)
-                self.listener.codeargs.append(p)
-                self.listener.args.append(ExpressionGenerator(n).value())
-                self.listener.declared_identifiers = \
-                    self.listener.declared_identifiers.union(
-                                                      p.declared_identifiers)
-                self.listener.undeclared_identifiers = \
-                    self.listener.undeclared_identifiers.union(
-                                                      p.undeclared_identifiers)
-
-        def visit(self, expr):
-            visitor.walk(expr, self)  # , walker=walker())
+    def visit_Tuple(self, node):
+        for n in node.elts:
+            p = self.code_factory(n, **self.exception_kwargs)
+            self.listener.codeargs.append(p)
+            self.listener.args.append(ExpressionGenerator(n).value())
+            self.listener.declared_identifiers = \
+                self.listener.declared_identifiers.union(
+                                                p.declared_identifiers)
+            self.listener.undeclared_identifiers = \
+                self.listener.undeclared_identifiers.union(
+                                                p.undeclared_identifiers)
 
 
-    class ParseFunc(object):
+class ParseFunc(_ast_util.NodeVisitor):
 
-        def __init__(self, listener, **exception_kwargs):
-            self.listener = listener
-            self.exception_kwargs = exception_kwargs
+    def __init__(self, listener, **exception_kwargs):
+        self.listener = listener
+        self.exception_kwargs = exception_kwargs
 
-        def visitFunction(self, node, *args):
-            self.listener.funcname = node.name
-            self.listener.argnames = list(node.argnames)
-            if node.kwargs:
-                self.listener.kwargnames = [self.listener.argnames.pop()]
-            else:
-                self.listener.kwargnames = []
-            self.listener.defaults = node.defaults
+    def visit_FunctionDef(self, node):
+        self.listener.funcname = node.name
+
+        argnames = [arg_id(arg) for arg in node.args.args]
+        if node.args.vararg:
+            argnames.append(arg_stringname(node.args.vararg))
+
+        if compat.py2k:
+            # kw-only args don't exist in Python 2
+            kwargnames = []
+        else:
+            kwargnames = [arg_id(arg) for arg in node.args.kwonlyargs]
+        if node.args.kwarg:
+            kwargnames.append(arg_stringname(node.args.kwarg))
+        self.listener.argnames = argnames
+        self.listener.defaults = node.args.defaults  # ast
+        self.listener.kwargnames = kwargnames
+        if compat.py2k:
             self.listener.kwdefaults = []
-            self.listener.varargs = node.varargs
-            self.listener.kwargs = node.kwargs
+        else:
+            self.listener.kwdefaults = node.args.kw_defaults
+        self.listener.varargs = node.args.vararg
+        self.listener.kwargs = node.args.kwarg
 
-        def visit(self, expr):
-            visitor.walk(expr, self)
+class ExpressionGenerator(object):
 
+    def __init__(self, astnode):
+        self.generator = _ast_util.SourceGenerator(' ' * 4)
+        self.generator.visit(astnode)
 
-    class ExpressionGenerator(object):
-
-        """given an AST node, generates an equivalent literal Python
-        expression."""
-
-        def __init__(self, astnode):
-            self.buf = StringIO()
-            visitor.walk(astnode, self)  # , walker=walker())
-
-        def value(self):
-            return self.buf.getvalue()
-
-        def operator(self, op, node, *args):
-            self.buf.write('(')
-            self.visit(node.left, *args)
-            self.buf.write(' %s ' % op)
-            self.visit(node.right, *args)
-            self.buf.write(')')
-
-        def booleanop(self, op, node, *args):
-            self.visit(node.nodes[0])
-            for n in node.nodes[1:]:
-                self.buf.write(' ' + op + ' ')
-                self.visit(n, *args)
-
-        def visitConst(self, node, *args):
-            self.buf.write(repr(node.value))
-
-        def visitAssName(self, node, *args):
-
-            # TODO: figure out OP_ASSIGN, other OP_s
-
-            self.buf.write(node.name)
-
-        def visitName(self, node, *args):
-            self.buf.write(node.name)
-
-        def visitMul(self, node, *args):
-            self.operator('*', node, *args)
-
-        def visitAnd(self, node, *args):
-            self.booleanop('and', node, *args)
-
-        def visitOr(self, node, *args):
-            self.booleanop('or', node, *args)
-
-        def visitBitand(self, node, *args):
-            self.booleanop('&', node, *args)
-
-        def visitBitor(self, node, *args):
-            self.booleanop('|', node, *args)
-
-        def visitBitxor(self, node, *args):
-            self.booleanop('^', node, *args)
-
-        def visitAdd(self, node, *args):
-            self.operator('+', node, *args)
-
-        def visitGetattr(self, node, *args):
-            self.visit(node.expr, *args)
-            self.buf.write('.%s' % node.attrname)
-
-        def visitSub(self, node, *args):
-            self.operator('-', node, *args)
-
-        def visitNot(self, node, *args):
-            self.buf.write('not ')
-            self.visit(node.expr)
-
-        def visitDiv(self, node, *args):
-            self.operator('/', node, *args)
-
-        def visitFloorDiv(self, node, *args):
-            self.operator('//', node, *args)
-
-        def visitSubscript(self, node, *args):
-            self.visit(node.expr)
-            self.buf.write('[')
-            [self.visit(x) for x in node.subs]
-            self.buf.write(']')
-
-        def visitUnarySub(self, node, *args):
-            self.buf.write('-')
-            self.visit(node.expr)
-
-        def visitUnaryAdd(self, node, *args):
-            self.buf.write('-')
-            self.visit(node.expr)
-
-        def visitSlice(self, node, *args):
-            self.visit(node.expr)
-            self.buf.write('[')
-            if node.lower is not None:
-                self.visit(node.lower)
-            self.buf.write(':')
-            if node.upper is not None:
-                self.visit(node.upper)
-            self.buf.write(']')
-
-        def visitDict(self, node):
-            self.buf.write('{')
-            c = node.getChildren()
-            for i in range(0, len(c), 2):
-                self.visit(c[i])
-                self.buf.write(': ')
-                self.visit(c[i + 1])
-                if i < len(c) - 2:
-                    self.buf.write(', ')
-            self.buf.write('}')
-
-        def visitTuple(self, node):
-            self.buf.write('(')
-            c = node.getChildren()
-            for i in range(0, len(c)):
-                self.visit(c[i])
-                if i < len(c) - 1:
-                    self.buf.write(', ')
-            self.buf.write(')')
-
-        def visitList(self, node):
-            self.buf.write('[')
-            c = node.getChildren()
-            for i in range(0, len(c)):
-                self.visit(c[i])
-                if i < len(c) - 1:
-                    self.buf.write(', ')
-            self.buf.write(']')
-
-        def visitListComp(self, node):
-            self.buf.write('[')
-            self.visit(node.expr)
-            self.buf.write(' ')
-            for n in node.quals:
-                self.visit(n)
-            self.buf.write(']')
-
-        def visitListCompFor(self, node):
-            self.buf.write(' for ')
-            self.visit(node.assign)
-            self.buf.write(' in ')
-            self.visit(node.list)
-            for n in node.ifs:
-                self.visit(n)
-
-        def visitListCompIf(self, node):
-            self.buf.write(' if ')
-            self.visit(node.test)
-
-        def visitCompare(self, node):
-            self.visit(node.expr)
-            for tup in node.ops:
-                self.buf.write(tup[0])
-                self.visit(tup[1])
-
-        def visitCallFunc(self, node, *args):
-            self.visit(node.node)
-            self.buf.write('(')
-            if len(node.args):
-                self.visit(node.args[0])
-                for a in node.args[1:]:
-                    self.buf.write(', ')
-                    self.visit(a)
-            self.buf.write(')')
-
-        def visitLambda(self, node, *args):
-            self.buf.write('lambda ')
-
-            argnames = list(node.argnames)
-
-            kw = arg = None
-            if node.kwargs > 0:
-                kw = argnames.pop(-1)
-            if node.varargs > 0:
-                arg = argnames.pop(-1)
-
-            if arg:
-                argnames.append("*%s" % arg)
-            if kw:
-                argnames.append("**%s" % kw)
-
-            self.buf.write(", ".join(argnames))
-
-            self.buf.write(': ')
-            self.visit(node.code)
-
-
-    class walker(visitor.ASTVisitor):
-
-        def dispatch(self, node, *args):
-            print('Node:', str(node))
-
-            # print "dir:", dir(node)
-
-            return visitor.ASTVisitor.dispatch(self, node, *args)
+    def value(self):
+        return ''.join(self.generator.result)
diff --git a/mako/runtime.py b/mako/runtime.py
index 5a3489b..d7b9681 100644
--- a/mako/runtime.py
+++ b/mako/runtime.py
@@ -9,9 +9,7 @@
 
 from mako import exceptions, util, compat
 from mako.compat import compat_builtins
-import inspect
 import sys
-import collections
 
 
 class Context(object):
@@ -132,9 +130,7 @@
     def get(self, key, default=None):
         """Return a value from this :class:`.Context`."""
 
-        return self._data.get(key,
-                compat_builtins.__dict__.get(key, default)
-                )
+        return self._data.get(key, compat_builtins.__dict__.get(key, default))
 
     def write(self, string):
         """Write a string to this :class:`.Context` object's
@@ -474,8 +470,8 @@
     def get_template(self, uri):
         """Return a :class:`.Template` from the given ``uri``.
 
-        The ``uri`` resolution is relative to the ``uri`` of this :class:`.Namespace`
-        object's :class:`.Template`.
+        The ``uri`` resolution is relative to the ``uri`` of this
+        :class:`.Namespace` object's :class:`.Template`.
 
         """
         return _lookup_template(self.context, uri, self._templateuri)
@@ -673,7 +669,7 @@
 
     """
 
-    def wrap_stackframe(context,  *args, **kwargs):
+    def wrap_stackframe(context, *args, **kwargs):
         context.caller_stack._push_frame()
         try:
             return func(context, *args, **kwargs)
@@ -691,8 +687,8 @@
 
     if not compat.callable(callable_):
         raise exceptions.RuntimeException(
-                           "capture() function expects a callable as "
-                           "its argument (i.e. capture(func, *args, **kwargs))"
+                        "capture() function expects a callable as "
+                        "its argument (i.e. capture(func, *args, **kwargs))"
                         )
     context._push_buffer()
     try:
@@ -853,7 +849,6 @@
     template = context._with_template
     if template is not None and \
             (template.format_exceptions or template.error_handler):
-        error = None
         try:
             callable_(context, *args, **kwargs)
         except Exception:
@@ -872,7 +867,8 @@
     else:
         error_template = exceptions.html_error_template()
         if context._outputting_as_unicode:
-            context._buffer_stack[:] = [util.FastEncodingBuffer(as_unicode=True)]
+            context._buffer_stack[:] = [
+                                    util.FastEncodingBuffer(as_unicode=True)]
         else:
             context._buffer_stack[:] = [util.FastEncodingBuffer(
                                             error_template.output_encoding,
diff --git a/setup.py b/setup.py
index 91b5769..bbab08e 100644
--- a/setup.py
+++ b/setup.py
@@ -9,6 +9,9 @@
 
 readme = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read()
 
+if sys.version_info < (2, 6):
+    raise Exception("Mako requires Python 2.6 or higher.")
+
 markupsafe_installs = (
             sys.version_info >= (2, 6) and sys.version_info < (3, 0)
         ) or sys.version_info >= (3, 3)
@@ -48,7 +51,7 @@
       test_suite="nose.collector",
       zip_safe=False,
       install_requires=install_requires,
-      extras_require={'beaker': ['Beaker>=1.1']},
+      extras_require={},
       entry_points="""
       [python.templating.engines]
       mako = mako.ext.turbogears:TGPlugin
diff --git a/test/__init__.py b/test/__init__.py
index 91ff54e..cf5f36a 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -1,7 +1,7 @@
 from mako.template import Template
 import unittest
 import os
-from mako.compat import py3k, py26, py25
+from mako.compat import py3k, py26
 from mako import compat
 from mako.util import update_wrapper
 import re
@@ -111,9 +111,6 @@
 def requires_python_26_or_greater(fn):
     return skip_if(lambda: not py26, "Requires Python 2.6 or greater")(fn)
 
-def requires_python_25_or_greater(fn):
-    return skip_if(lambda: not py25, "Requires Python 2.5 or greater")(fn)
-
 def requires_pygments_14(fn):
     try:
         import pygments
diff --git a/test/test_exceptions.py b/test/test_exceptions.py
index 5160f8e..3330a1f 100644
--- a/test/test_exceptions.py
+++ b/test/test_exceptions.py
@@ -7,8 +7,7 @@
 from mako.compat import u
 from test.util import result_lines
 from test import TemplateTest
-from test import requires_pygments_14, requires_no_pygments_exceptions, \
-    requires_python_25_or_greater
+from test import requires_pygments_14, requires_no_pygments_exceptions
 
 class ExceptionsTest(TemplateTest):
     def test_html_error_template(self):
@@ -156,7 +155,6 @@
             html_error = exceptions.html_error_template().render()
             assert "RuntimeError: test" in str(html_error)
 
-    @requires_python_25_or_greater
     def test_py_utf8_html_error_template(self):
         try:
             foo = u('日本')
@@ -264,7 +262,6 @@
                 result_lines(l.get_template("foo.html").render().decode('utf-8'))
 
 
-    @requires_python_25_or_greater
     def test_custom_tback(self):
         try:
             raise RuntimeError("error 1")