From: Ben Darnell Date: Sun, 8 Feb 2015 18:26:56 +0000 (-0500) Subject: Allow unicode strings in import_object in python 2. X-Git-Tag: v4.2.0b1~129 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=03c7ce3c9ba1725a7f0ec70115c8ca2661a0d805;p=thirdparty%2Ftornado.git Allow unicode strings in import_object in python 2. Fixes #1316. --- diff --git a/tornado/test/util_test.py b/tornado/test/util_test.py index 1cd78fe46..a0fbae43c 100644 --- a/tornado/test/util_test.py +++ b/tornado/test/util_test.py @@ -3,8 +3,9 @@ from __future__ import absolute_import, division, print_function, with_statement import sys import datetime +import tornado.escape from tornado.escape import utf8 -from tornado.util import raise_exc_info, Configurable, u, exec_in, ArgReplacer, timedelta_to_seconds +from tornado.util import raise_exc_info, Configurable, u, exec_in, ArgReplacer, timedelta_to_seconds, import_object from tornado.test.util import unittest try: @@ -177,3 +178,20 @@ class TimedeltaToSecondsTest(unittest.TestCase): def test_timedelta_to_seconds(self): time_delta = datetime.timedelta(hours=1) self.assertEqual(timedelta_to_seconds(time_delta), 3600.0) + + +class ImportObjectTest(unittest.TestCase): + def test_import_member(self): + self.assertIs(import_object('tornado.escape.utf8'), utf8) + + def test_import_member_unicode(self): + self.assertIs(import_object(u('tornado.escape.utf8')), utf8) + + def test_import_module(self): + self.assertIs(import_object('tornado.escape'), tornado.escape) + + def test_import_module_unicode(self): + # The internal implementation of __import__ differs depending on + # whether the thing being imported is a module or not. + # This variant requires a byte string in python 2. + self.assertIs(import_object(u('tornado.escape')), tornado.escape) diff --git a/tornado/util.py b/tornado/util.py index 34c4b072c..cac4e3aae 100644 --- a/tornado/util.py +++ b/tornado/util.py @@ -78,6 +78,23 @@ class GzipDecompressor(object): return self.decompressobj.flush() +# Fake unicode literal support: Python 3.2 doesn't have the u'' marker for +# literal strings, and alternative solutions like "from __future__ import +# unicode_literals" have other problems (see PEP 414). u() can be applied +# to ascii strings that include \u escapes (but they must not contain +# literal non-ascii characters). +if type('') is not type(b''): + def u(s): + return s + unicode_type = str + basestring_type = str +else: + def u(s): + return s.decode('unicode_escape') + unicode_type = unicode + basestring_type = basestring + + def import_object(name): """Imports an object by name. @@ -96,6 +113,9 @@ def import_object(name): ... ImportError: No module named missing_module """ + if isinstance(name, unicode_type) and str is not unicode_type: + # On python 2 a byte string is required. + name = name.encode('utf-8') if name.count('.') == 0: return __import__(name, None, None) @@ -107,22 +127,6 @@ def import_object(name): raise ImportError("No module named %s" % parts[-1]) -# Fake unicode literal support: Python 3.2 doesn't have the u'' marker for -# literal strings, and alternative solutions like "from __future__ import -# unicode_literals" have other problems (see PEP 414). u() can be applied -# to ascii strings that include \u escapes (but they must not contain -# literal non-ascii characters). -if type('') is not type(b''): - def u(s): - return s - unicode_type = str - basestring_type = str -else: - def u(s): - return s.decode('unicode_escape') - unicode_type = unicode - basestring_type = basestring - # Deprecated alias that was used before we dropped py25 support. # Left here in case anyone outside Tornado is using it. bytes_type = bytes