Approaching python3 compatibility

--HG--
branch : trunk
diff --git a/jinja2/environment.py b/jinja2/environment.py
index cda6171..965b058 100644
--- a/jinja2/environment.py
+++ b/jinja2/environment.py
@@ -808,15 +808,15 @@
         self.__dict__.update(context.get_exported())
         self.__name__ = template.name
 
-    def __unicode__(self):
-        return concat(self._body_stream)
-
     def __html__(self):
         return Markup(concat(self._body_stream))
 
     def __str__(self):
         return unicode(self).encode('utf-8')
 
+    def __unicode__(self):
+        return concat(self._body_stream)
+
     def __repr__(self):
         if self.__name__ is None:
             name = 'memory:%x' % id(self)
diff --git a/jinja2/exceptions.py b/jinja2/exceptions.py
index 37071ed..4df8324 100644
--- a/jinja2/exceptions.py
+++ b/jinja2/exceptions.py
@@ -41,12 +41,12 @@
         self.name = name
         self.templates = [name]
 
-    def __unicode__(self):
-        return self.message
-
     def __str__(self):
         return self.message.encode('utf-8')
 
+    def __unicode__(self):
+        return self.message
+
 
 class TemplatesNotFound(TemplateNotFound):
     """Like :class:`TemplateNotFound` but raised if multiple templates
@@ -78,6 +78,9 @@
         # function translated the syntax error into a new traceback
         self.translated = False
 
+    def __str__(self):
+        return unicode(self).encode('utf-8')
+
     def __unicode__(self):
         # for translated errors we only return the message
         if self.translated:
@@ -101,9 +104,6 @@
 
         return u'\n'.join(lines)
 
-    def __str__(self):
-        return unicode(self).encode('utf-8')
-
 
 class TemplateAssertionError(TemplateSyntaxError):
     """Like a template syntax error, but covers cases where something in the
diff --git a/jinja2/sandbox.py b/jinja2/sandbox.py
index 9887310..7497195 100644
--- a/jinja2/sandbox.py
+++ b/jinja2/sandbox.py
@@ -37,13 +37,21 @@
 warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
                         module='jinja2.sandbox')
 
-
 from collections import deque
-from UserDict import UserDict, DictMixin
-from UserList import UserList
+
 _mutable_set_types = (set,)
-_mutable_mapping_types = (UserDict, DictMixin, dict)
-_mutable_sequence_types = (UserList, list)
+_mutable_mapping_types = (dict,)
+_mutable_sequence_types = (list,)
+
+
+# on python 2.x we can register the user collection types
+try:
+    from UserDict import UserDict, DictMixin
+    from UserList import UserList
+    _mutable_mapping_types += (UserDict, DictMixin)
+    _mutable_set_types += (UserList,)
+except ImportError:
+    pass
 
 # if sets is still available, register the mutable set from there as well
 try:
diff --git a/jinja2/testsuite/__init__.py b/jinja2/testsuite/__init__.py
index a222777..7099355 100644
--- a/jinja2/testsuite/__init__.py
+++ b/jinja2/testsuite/__init__.py
@@ -11,8 +11,8 @@
     :license: BSD, see LICENSE for more details.
 """
 import os
-import sys
 import re
+import sys
 import unittest
 from traceback import format_exception
 from jinja2 import loaders
@@ -74,5 +74,10 @@
     suite.addTest(regression.suite())
     suite.addTest(debug.suite())
     suite.addTest(utils.suite())
-    suite.addTest(doctests.suite())
+
+    # doctests will not run on python 3 currently.  Too many issues
+    # with that, do not test that on that platform.
+    if sys.version_info < (3, 0):
+        suite.addTest(doctests.suite())
+
     return suite
diff --git a/jinja2/utils.py b/jinja2/utils.py
index f43743c..57fd3c5 100644
--- a/jinja2/utils.py
+++ b/jinja2/utils.py
@@ -203,7 +203,7 @@
     otherwise `None`.
     """
     try:
-        return file(filename, mode)
+        return open(filename, mode)
     except IOError, e:
         if e.errno not in (errno.ENOENT, errno.EISDIR):
             raise
@@ -506,8 +506,8 @@
         self.obj = obj
 
     __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x])
-    __unicode__ = lambda s: unicode(escape(s.obj))
     __str__ = lambda s: str(escape(s.obj))
+    __unicode__ = lambda s: unicode(escape(s.obj))
     __repr__ = lambda s: str(escape(repr(s.obj)))
     __int__ = lambda s: int(s.obj)
     __float__ = lambda s: float(s.obj)