From 48b0ab3fc9f3eab5a39928b4ca5d13d92e236907 2011-07-03 21:51:14 From: MinRK Date: 2011-07-03 21:51:14 Subject: [PATCH] fix handling of unicode in KV loader CaselessStrEnum had to be updated to typecheck basestring instead of str tests included --- diff --git a/IPython/config/loader.py b/IPython/config/loader.py index 4999925..d1f72ed 100644 --- a/IPython/config/loader.py +++ b/IPython/config/loader.py @@ -379,7 +379,20 @@ class KeyValueConfigLoader(CommandLineConfigLoader): super(KeyValueConfigLoader, self).clear() self.extra_args = [] - + + def _decode_argv(self, argv, enc=None): + """decode argv if bytes, using stin.encoding, falling back on default enc""" + uargv = [] + if enc is None: + enc = sys.stdin.encoding or sys.getdefaultencoding() + for arg in argv: + if not isinstance(arg, unicode): + # only decode if not already decoded + arg = arg.decode(enc) + uargv.append(arg) + return uargv + + def load_config(self, argv=None, aliases=None, flags=None): """Parse the configuration and generate the Config object. @@ -413,7 +426,7 @@ class KeyValueConfigLoader(CommandLineConfigLoader): if flags is None: flags = self.flags - for item in argv: + for item in self._decode_argv(argv): if kv_pattern.match(item): lhs,rhs = item.split('=',1) # Substitute longnames for aliases. @@ -427,9 +440,10 @@ class KeyValueConfigLoader(CommandLineConfigLoader): exec exec_str in locals(), globals() except (NameError, SyntaxError): # This case happens if the rhs is a string but without - # the quote marks. We add the quote marks and see if + # the quote marks. Use repr, to get quote marks, and + # 'u' prefix and see if # it succeeds. If it still fails, we let it raise. - exec_str = 'self.config.' + lhs + '="' + rhs + '"' + exec_str = u'self.config.' + lhs + '=' + repr(rhs) exec exec_str in locals(), globals() elif flag_pattern.match(item): # trim leading '--' diff --git a/IPython/config/tests/test_loader.py b/IPython/config/tests/test_loader.py index bafaa6b..e1b3509 100755 --- a/IPython/config/tests/test_loader.py +++ b/IPython/config/tests/test_loader.py @@ -21,9 +21,12 @@ Authors: #----------------------------------------------------------------------------- import os +import sys from tempfile import mkstemp from unittest import TestCase +from nose import SkipTest + from IPython.utils.traitlets import Int, Unicode from IPython.config.configurable import Configurable from IPython.config.loader import ( @@ -130,6 +133,23 @@ class TestKeyValueCL(TestCase): self.assertEquals(cl.extra_args, ['b', 'd']) self.assertEquals(config.a, 5) self.assertEquals(config.c, 10) + + def test_unicode_args(self): + cl = KeyValueConfigLoader() + argv = [u'a=épsîlön'] + config = cl.load_config(argv) + self.assertEquals(config.a, u'épsîlön') + + def test_unicode_bytes_args(self): + uarg = u'a=é' + try: + barg = uarg.encode(sys.stdin.encoding) + except (TypeError, UnicodeEncodeError): + raise SkipTest("sys.stdin.encoding can't handle 'é'") + + cl = KeyValueConfigLoader() + config = cl.load_config([barg]) + self.assertEquals(config.a, u'é') class TestConfig(TestCase): diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py index e95e7d0..a0ad5ca 100644 --- a/IPython/utils/traitlets.py +++ b/IPython/utils/traitlets.py @@ -1099,7 +1099,7 @@ class CaselessStrEnum(Enum): if self._allow_none: return value - if not isinstance(value, str): + if not isinstance(value, basestring): self.error(obj, value) for v in self.values: