- guess you need compat.py huh
- dont need 2to3
- clean up some list() calls we dont need
diff --git a/mako/_ast_util.py b/mako/_ast_util.py
index af29506..a1bd54c 100644
--- a/mako/_ast_util.py
+++ b/mako/_ast_util.py
@@ -693,7 +693,7 @@
 
     def visit_Dict(self, node):
         self.write('{')
-        for idx, (key, value) in enumerate(list(zip(node.keys, node.values))):
+        for idx, (key, value) in enumerate(zip(node.keys, node.values)):
             if idx:
                 self.write(', ')
             self.visit(key)
diff --git a/mako/cache.py b/mako/cache.py
index c60f0e8..66fb75e 100644
--- a/mako/cache.py
+++ b/mako/cache.py
@@ -4,7 +4,7 @@
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-from mako import exceptions, util
+from mako import compat, util
 
 _cache_plugins = util.PluginLoader("mako.cache")
 
@@ -64,7 +64,7 @@
     def __init__(self, template, *args):
         # check for a stale template calling the
         # constructor
-        if isinstance(template, str) and args:
+        if isinstance(template, compat.string_types) and args:
             return
         self.template = template
         self.id = template.module.__name__
diff --git a/mako/codegen.py b/mako/codegen.py
index f876db8..f730127 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -232,7 +232,7 @@
         self.compiler.identifiers = module_identifiers
         self.printer.writeline("_exports = %r" %
                             [n.name for n in
-                            list(main_identifiers.topleveldefs.values())]
+                            main_identifiers.topleveldefs.values()]
                         )
         self.printer.write("\n\n")
 
@@ -329,7 +329,7 @@
         self.printer.writeline("def _mako_generate_namespaces(context):")
 
 
-        for node in list(namespaces.values()):
+        for node in namespaces.values():
             if 'import' in node.attributes:
                 self.compiler.has_ns_imports = True
             self.write_source_comment(node)
@@ -438,7 +438,7 @@
         # write closure functions for closures that we define
         # right here
         to_write = to_write.union(
-                        [c.funcname for c in list(identifiers.closuredefs.values())])
+                        [c.funcname for c in identifiers.closuredefs.values()])
 
         # remove identifiers that are declared in the argument
         # signature of the callable
@@ -700,22 +700,22 @@
                 "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 list(cache_args.items())]),
+                            ''.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,
                                             False)
-            self.printer.writelines("return " + s,None)
+            self.printer.writelines("return " + s, None)
         else:
             self.printer.writelines(
                     "__M_writer(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 list(cache_args.items())]),
+                    ''.join(["%s=%s, " % (k, v)
+                        for k, v in cache_args.items()]),
                     name,
                     ),
                     "return ''",
@@ -968,7 +968,7 @@
                 # 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 list(parent.closuredefs.values())]).\
+                         union([c.name for c in parent.closuredefs.values()]).\
                          union(parent.locally_declared).\
                          union(parent.argument_declared)
 
@@ -1039,8 +1039,8 @@
                     list(self.declared),
                     list(self.locally_declared),
                     list(self.undeclared),
-                    [c.name for c in list(self.topleveldefs.values())],
-                    [c.name for c in list(self.closuredefs.values())],
+                    [c.name for c in self.topleveldefs.values()],
+                    [c.name for c in self.closuredefs.values()],
                     self.argument_declared)
 
     def check_declared(self, node):
diff --git a/mako/compat.py b/mako/compat.py
new file mode 100644
index 0000000..c53091d
--- /dev/null
+++ b/mako/compat.py
@@ -0,0 +1,168 @@
+import sys
+import time
+
+py3k = sys.version_info >= (3, 0)
+py3kwarning = getattr(sys, 'py3kwarning', False) or py3k
+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')
+
+if py3k:
+    from io import StringIO
+    import builtins as compat_builtins
+    from urllib.parse import quote_plus, unquote_plus
+    from html.entities import codepoint2name, name2codepoint
+    string_types = str,
+    binary_type = bytes
+    text_type = str
+
+    def u(s):
+        return s
+
+    def octal(lit):
+        return eval("0o" + lit)
+
+else:
+    import __builtin__ as compat_builtins
+    try:
+        from cStringIO import StringIO
+    except:
+        from StringIO import StringIO
+    from urllib import quote_plus, unquote_plus
+    from htmlentitydefs import codepoint2name, name2codepoint
+    string_types = basestring,
+    binary_type = str
+    text_type = unicode
+
+    def u(s):
+        return unicode(s, "utf-8")
+
+    def octal(lit):
+        return eval("0" + lit)
+
+def exception_as():
+    return sys.exc_info()[1]
+
+try:
+    import threading
+    if py3k:
+        import _thread as thread
+    else:
+        import thread
+except ImportError:
+    import dummy_threading as threading
+    if py3k:
+        import _dummy_thread as thread
+    else:
+        import dummy_thread as thread
+
+if win32 or jython:
+    time_func = time.clock
+else:
+    time_func = time.time
+
+try:
+    from functools import partial
+except:
+    def partial(func, *args, **keywords):
+        def newfunc(*fargs, **fkeywords):
+            newkeywords = keywords.copy()
+            newkeywords.update(fkeywords)
+            return func(*(args + fargs), **newkeywords)
+        return newfunc
+
+if not py25:
+    def all(iterable):
+        for i in iterable:
+            if not i:
+                return False
+        return True
+
+    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__
+
+try:
+    from inspect import CO_VARKEYWORDS, CO_VARARGS
+    def inspect_func_args(fn):
+        if py3k:
+            co = fn.__code__
+        else:
+            co = fn.func_code
+
+        nargs = co.co_argcount
+        names = co.co_varnames
+        args = list(names[:nargs])
+
+        varargs = None
+        if co.co_flags & CO_VARARGS:
+            varargs = co.co_varnames[nargs]
+            nargs = nargs + 1
+        varkw = None
+        if co.co_flags & CO_VARKEYWORDS:
+            varkw = co.co_varnames[nargs]
+
+        if py3k:
+            return args, varargs, varkw, fn.__defaults__
+        else:
+            return args, varargs, varkw, fn.func_defaults
+except ImportError:
+    import inspect
+    def inspect_func_args(fn):
+        return inspect.getargspec(fn)
+
+if py3kwarning:
+    def callable(fn):
+        return hasattr(fn, '__call__')
+else:
+    callable = callable
+
+################################################
+# cross-compatible exec_()
+# Copyright (c) 2010-2012 Benjamin Peterson
+if py3k:
+    import builtins
+    exec_ = getattr(builtins, "exec")
+
+
+    def reraise(tp, value, tb=None):
+        if value.__traceback__ is not tb:
+            raise value.with_traceback(tb)
+        raise value
+
+
+    print_ = getattr(builtins, "print")
+    del builtins
+
+else:
+    def exec_(code, globs=None, locs=None):
+        """Execute code in a namespace."""
+        if globs is None:
+            frame = sys._getframe(1)
+            globs = frame.f_globals
+            if locs is None:
+                locs = frame.f_locals
+            del frame
+        elif locs is None:
+            locs = globs
+        exec("""exec code in globs, locs""")
+################################################
+
+################################################
+# cross-compatible metaclass implementation
+# Copyright (c) 2010-2012 Benjamin Peterson
+def with_metaclass(meta, base=object):
+    """Create a base class with a metaclass."""
+    return meta("%sBase" % meta.__name__, (base,), {})
+################################################
+
+
diff --git a/mako/parsetree.py b/mako/parsetree.py
index 3db8c6b..1d9d1a7 100644
--- a/mako/parsetree.py
+++ b/mako/parsetree.py
@@ -394,7 +394,7 @@
     def undeclared_identifiers(self):
         return self.filter_args.\
                             undeclared_identifiers.\
-                            difference(list(filters.DEFAULT_ESCAPES.keys())).union(
+                            difference(filters.DEFAULT_ESCAPES.keys()).union(
                         self.expression_undeclared_identifiers
                     )
 
@@ -447,7 +447,7 @@
         return set(res).union(
             self.filter_args.\
                             undeclared_identifiers.\
-                            difference(list(filters.DEFAULT_ESCAPES.keys()))
+                            difference(filters.DEFAULT_ESCAPES.keys())
         ).union(
             self.expression_undeclared_identifiers
         ).difference(
@@ -507,7 +507,7 @@
     def undeclared_identifiers(self):
         return (self.filter_args.\
                             undeclared_identifiers.\
-                            difference(list(filters.DEFAULT_ESCAPES.keys()))
+                            difference(filters.DEFAULT_ESCAPES.keys())
                 ).union(self.expression_undeclared_identifiers)
 
 
diff --git a/setup.py b/setup.py
index 07b350e..a6b9198 100644
--- a/setup.py
+++ b/setup.py
@@ -3,12 +3,6 @@
 import re
 import sys
 
-extra = {}
-if sys.version_info >= (3, 0):
-    extra.update(
-        use_2to3=True,
-    )
-
 v = open(os.path.join(os.path.dirname(__file__), 'mako', '__init__.py'))
 VERSION = re.compile(r".*__version__ = '(.*?)'", re.S).match(v.read()).group(1)
 v.close()
@@ -47,7 +41,7 @@
       entry_points="""
       [python.templating.engines]
       mako = mako.ext.turbogears:TGPlugin
- 
+
       [pygments.lexers]
       mako = mako.ext.pygmentplugin:MakoLexer
       html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
@@ -57,6 +51,5 @@
 
       [babel.extractors]
       mako = mako.ext.babelplugin:extract
-      """,
-      **extra
+      """
 )