From 268ecbecedd2aee4337b60c7dbe2fefe816a9a15 2011-11-20 20:24:16 From: Fernando Perez Date: 2011-11-20 20:24:16 Subject: [PATCH] Merge pull request #1019 from takluyver/repr-quotestring Use repr() to make quoted strings. This simplifies our quoting code by letting us rely on built-in capabilities of the language. --- diff --git a/IPython/config/tests/test_configurable.py b/IPython/config/tests/test_configurable.py index 0caf2f4..bb88795 100644 --- a/IPython/config/tests/test_configurable.py +++ b/IPython/config/tests/test_configurable.py @@ -31,7 +31,7 @@ from IPython.utils.traitlets import ( ) from IPython.config.loader import Config - +from IPython.utils.py3compat import PY3 #----------------------------------------------------------------------------- # Test cases @@ -62,6 +62,11 @@ mc_help_inst=u"""MyConfigurable options Current: 4.0 The integer b.""" +# On Python 3, the Integer trait is a synonym for Int +if PY3: + mc_help = mc_help.replace(u"", u"") + mc_help_inst = mc_help_inst.replace(u"", u"") + class Foo(Configurable): a = Integer(0, config=True, help="The integer a.") b = Unicode('nope', config=True) diff --git a/IPython/core/inputsplitter.py b/IPython/core/inputsplitter.py index b1c18a9..d0a15fd 100644 --- a/IPython/core/inputsplitter.py +++ b/IPython/core/inputsplitter.py @@ -75,7 +75,6 @@ from StringIO import StringIO # IPython modules from IPython.core.splitinput import split_user_input, LineInfo -from IPython.utils.text import make_quoted_expr from IPython.utils.py3compat import cast_unicode #----------------------------------------------------------------------------- @@ -503,8 +502,7 @@ def transform_assign_system(line): if m is not None: cmd = m.group('cmd') lhs = m.group('lhs') - expr = make_quoted_expr(cmd) - new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr) + new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd) return new_line return line @@ -518,8 +516,7 @@ def transform_assign_magic(line): if m is not None: cmd = m.group('cmd') lhs = m.group('lhs') - expr = make_quoted_expr(cmd) - new_line = '%s = get_ipython().magic(%s)' % (lhs, expr) + new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd) return new_line return line @@ -560,13 +557,13 @@ def _make_help_call(target, esc, lspace, next_input=None): method = 'pinfo2' if esc == '??' \ else 'psearch' if '*' in target \ else 'pinfo' - arg = make_quoted_expr(" ".join([method, target])) + arg = " ".join([method, target]) if next_input: - tpl = '%sget_ipython().magic(%s, next_input=%s)' - return tpl % (lspace, arg, make_quoted_expr(next_input)) + tpl = '%sget_ipython().magic(%r, next_input=%r)' + return tpl % (lspace, arg, next_input) else: - return '%sget_ipython().magic(%s)' % (lspace, arg) + return '%sget_ipython().magic(%r)' % (lspace, arg) _initial_space_re = re.compile(r'\s*') _help_end_re = re.compile(r"""(%? @@ -610,15 +607,13 @@ class EscapedTransformer(object): def _tr_system(line_info): "Translate lines escaped with: !" cmd = line_info.line.lstrip().lstrip(ESC_SHELL) - return '%sget_ipython().system(%s)' % (line_info.pre, - make_quoted_expr(cmd)) + return '%sget_ipython().system(%r)' % (line_info.pre, cmd) @staticmethod def _tr_system2(line_info): "Translate lines escaped with: !!" cmd = line_info.line.lstrip()[2:] - return '%sget_ipython().getoutput(%s)' % (line_info.pre, - make_quoted_expr(cmd)) + return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd) @staticmethod def _tr_help(line_info): @@ -632,9 +627,8 @@ class EscapedTransformer(object): @staticmethod def _tr_magic(line_info): "Translate lines escaped with: %" - tpl = '%sget_ipython().magic(%s)' - cmd = make_quoted_expr(' '.join([line_info.ifun, - line_info.the_rest]).strip()) + tpl = '%sget_ipython().magic(%r)' + cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip() return tpl % (line_info.pre, cmd) @staticmethod diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 08a0ce2..49e6e09 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -36,7 +36,6 @@ from IPython.core.splitinput import split_user_input, LineInfo from IPython.core import page from IPython.utils.traitlets import List, Integer, Any, Unicode, CBool, Bool, Instance -from IPython.utils.text import make_quoted_expr from IPython.utils.autoattr import auto_attr #----------------------------------------------------------------------------- @@ -405,8 +404,8 @@ class AssignSystemTransformer(PrefilterTransformer): if m is not None: cmd = m.group('cmd') lhs = m.group('lhs') - expr = make_quoted_expr("sc =%s" % cmd) - new_line = '%s = get_ipython().magic(%s)' % (lhs, expr) + expr = "sc =%s" % cmd + new_line = '%s = get_ipython().magic(%r)' % (lhs, expr) return new_line return line @@ -424,8 +423,7 @@ class AssignMagicTransformer(PrefilterTransformer): if m is not None: cmd = m.group('cmd') lhs = m.group('lhs') - expr = make_quoted_expr(cmd) - new_line = '%s = get_ipython().magic(%s)' % (lhs, expr) + new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd) return new_line return line @@ -733,8 +731,7 @@ class AliasHandler(PrefilterHandler): transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest) # pre is needed, because it carries the leading whitespace. Otherwise # aliases won't work in indented sections. - line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, - make_quoted_expr(transformed)) + line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed) return line_out @@ -762,8 +759,7 @@ class ShellEscapeHandler(PrefilterHandler): return magic_handler.handle(line_info) else: cmd = line.lstrip().lstrip(ESC_SHELL) - line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, - make_quoted_expr(cmd)) + line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, cmd) return line_out @@ -786,8 +782,8 @@ class MagicHandler(PrefilterHandler): """Execute magic functions.""" ifun = line_info.ifun the_rest = line_info.the_rest - cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace, - make_quoted_expr(ifun + " " + the_rest)) + cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace, + (ifun + " " + the_rest)) return cmd diff --git a/IPython/core/tests/test_handlers.py b/IPython/core/tests/test_handlers.py index 016764a..7fa814e 100644 --- a/IPython/core/tests/test_handlers.py +++ b/IPython/core/tests/test_handlers.py @@ -61,10 +61,10 @@ def test_handlers(): ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top') ip.alias_manager.alias_table['d'] = (0, 'true') run([(i,py3compat.u_format(o)) for i,o in \ - [("an_alias", 'get_ipython().system({u}"true ")'), # alias + [("an_alias", "get_ipython().system({u}'true ')"), # alias # Below: recursive aliases should expand whitespace-surrounded # chars, *not* initial chars which happen to be aliases: - ("top", 'get_ipython().system({u}"d:/cygwin/top ")'), + ("top", "get_ipython().system({u}'d:/cygwin/top ')"), ]]) ip.system = old_system_cmd @@ -76,15 +76,15 @@ def test_handlers(): # line. run([(i,py3compat.u_format(o)) for i,o in \ [('"no change"', '"no change"'), # normal - ("!true", 'get_ipython().system({u}"true")'), # shell_escapes - ("!! true", 'get_ipython().magic({u}"sx true")'), # shell_escapes + magic - ("!!true", 'get_ipython().magic({u}"sx true")'), # shell_escapes + magic - ("%lsmagic", 'get_ipython().magic({u}"lsmagic ")'), # magic - ("lsmagic", 'get_ipython().magic({u}"lsmagic ")'), # magic + (u"!true", "get_ipython().system({u}'true')"), # shell_escapes + (u"!! true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic + (u"!!true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic + (u"%lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic + (u"lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache # post-esc-char whitespace goes inside - ("! true", 'get_ipython().system({u}" true")'), + (u"! true", "get_ipython().system({u}' true')"), # handle_help @@ -99,19 +99,19 @@ def test_handlers(): ip.prefilter_manager.multi_line_specials = False # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion run([ - ('if 1:\n !true', 'if 1:\n !true'), - ('if 1:\n lsmagic', 'if 1:\n lsmagic'), - ('if 1:\n an_alias', 'if 1:\n an_alias'), + (u'if 1:\n !true', u'if 1:\n !true'), + (u'if 1:\n lsmagic', u'if 1:\n lsmagic'), + (u'if 1:\n an_alias', u'if 1:\n an_alias'), ]) ip.prefilter_manager.multi_line_specials = True # initial indents must be preserved. run([(i,py3compat.u_format(o)) for i,o in \ - [('if 1:\n !true', 'if 1:\n get_ipython().system({u}"true")'), - ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic({u}"lsmagic ")'), - ('if 1:\n an_alias', 'if 1:\n get_ipython().system({u}"true ")'), + [(u'if 1:\n !true', "if 1:\n get_ipython().system({u}'true')"), + (u'if 2:\n lsmagic', "if 2:\n get_ipython().magic({u}'lsmagic ')"), + (u'if 1:\n an_alias', "if 1:\n get_ipython().system({u}'true ')"), # Weird one - ('if 1:\n !!true', 'if 1:\n get_ipython().magic({u}"sx true")'), + (u'if 1:\n !!true', "if 1:\n get_ipython().magic({u}'sx true')"), # Even with m_l_s on, autocall is off even with special chars ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'), diff --git a/IPython/core/tests/test_inputsplitter.py b/IPython/core/tests/test_inputsplitter.py index c1ba2b7..79ecb73 100644 --- a/IPython/core/tests/test_inputsplitter.py +++ b/IPython/core/tests/test_inputsplitter.py @@ -405,16 +405,16 @@ def transform_checker(tests, func): syntax = \ dict(assign_system = [(i,py3compat.u_format(o)) for i,o in \ - [('a =! ls', 'a = get_ipython().getoutput({u}"ls")'), - ('b = !ls', 'b = get_ipython().getoutput({u}"ls")'), + [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"), + (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"), ('x=1', 'x=1'), # normal input is unmodified (' ',' '), # blank lines are kept intact ]], assign_magic = [(i,py3compat.u_format(o)) for i,o in \ - [('a =% who', 'a = get_ipython().magic({u}"who")'), - ('b = %who', 'b = get_ipython().magic({u}"who")'), + [(u'a =% who', "a = get_ipython().magic({u}'who')"), + (u'b = %who', "b = get_ipython().magic({u}'who')"), ('x=1', 'x=1'), # normal input is unmodified (' ',' '), # blank lines are kept intact ]], @@ -442,43 +442,45 @@ syntax = \ # System calls escaped_shell = [(i,py3compat.u_format(o)) for i,o in \ - [ ('!ls', 'get_ipython().system({u}"ls")'), + [ (u'!ls', "get_ipython().system({u}'ls')"), # Double-escape shell, this means to capture the output of the # subprocess and return it - ('!!ls', 'get_ipython().getoutput({u}"ls")'), + (u'!!ls', "get_ipython().getoutput({u}'ls')"), ]], # Help/object info escaped_help = [(i,py3compat.u_format(o)) for i,o in \ - [ ('?', 'get_ipython().show_usage()'), - ('?x1', 'get_ipython().magic({u}"pinfo x1")'), - ('??x2', 'get_ipython().magic({u}"pinfo2 x2")'), - ('?a.*s', 'get_ipython().magic({u}"psearch a.*s")'), - ('?%hist', 'get_ipython().magic({u}"pinfo %hist")'), - ('?abc = qwe', 'get_ipython().magic({u}"pinfo abc")'), + [ (u'?', 'get_ipython().show_usage()'), + (u'?x1', "get_ipython().magic({u}'pinfo x1')"), + (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"), + (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"), + (u'?%hist', "get_ipython().magic({u}'pinfo %hist')"), + (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"), ]], end_help = [(i,py3compat.u_format(o)) for i,o in \ - [ ('x3?', 'get_ipython().magic({u}"pinfo x3")'), - ('x4??', 'get_ipython().magic({u}"pinfo2 x4")'), - ('%hist?', 'get_ipython().magic({u}"pinfo %hist")'), - ('f*?', 'get_ipython().magic({u}"psearch f*")'), - ('ax.*aspe*?', 'get_ipython().magic({u}"psearch ax.*aspe*")'), - ('a = abc?', 'get_ipython().magic({u}"pinfo abc", next_input={u}"a = abc")'), - ('a = abc.qe??', 'get_ipython().magic({u}"pinfo2 abc.qe", next_input={u}"a = abc.qe")'), - ('a = *.items?', 'get_ipython().magic({u}"psearch *.items", next_input={u}"a = *.items")'), - ('plot(a?', 'get_ipython().magic({u}"pinfo a", next_input={u}"plot(a")'), - ('a*2 #comment?', 'a*2 #comment?'), + [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"), + (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"), + (u'%hist?', "get_ipython().magic({u}'pinfo %hist')"), + (u'f*?', "get_ipython().magic({u}'psearch f*')"), + (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"), + (u'a = abc?', "get_ipython().magic({u}'pinfo abc', next_input={u}'a = abc')"), + (u'a = abc.qe??', "get_ipython().magic({u}'pinfo2 abc.qe', next_input={u}'a = abc.qe')"), + (u'a = *.items?', "get_ipython().magic({u}'psearch *.items', next_input={u}'a = *.items')"), + (u'plot(a?', "get_ipython().magic({u}'pinfo a', next_input={u}'plot(a')"), + (u'a*2 #comment?', 'a*2 #comment?'), ]], # Explicit magic calls escaped_magic = [(i,py3compat.u_format(o)) for i,o in \ - [ ('%cd', 'get_ipython().magic({u}"cd")'), - ('%cd /home', 'get_ipython().magic({u}"cd /home")'), - (' %magic', ' get_ipython().magic({u}"magic")'), + [ (u'%cd', "get_ipython().magic({u}'cd')"), + (u'%cd /home', "get_ipython().magic({u}'cd /home')"), + # Backslashes need to be escaped. + (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"), + (u' %magic', " get_ipython().magic({u}'magic')"), ]], # Quoting with separate arguments @@ -508,11 +510,11 @@ syntax = \ # Check that we transform prompts before other transforms mixed = [(i,py3compat.u_format(o)) for i,o in \ - [ ('In [1]: %lsmagic', 'get_ipython().magic({u}"lsmagic")'), - ('>>> %lsmagic', 'get_ipython().magic({u}"lsmagic")'), - ('In [2]: !ls', 'get_ipython().system({u}"ls")'), - ('In [3]: abs?', 'get_ipython().magic({u}"pinfo abs")'), - ('In [4]: b = %who', 'b = get_ipython().magic({u}"who")'), + [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"), + (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"), + (u'In [2]: !ls', "get_ipython().system({u}'ls')"), + (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"), + (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"), ]], ) diff --git a/IPython/utils/text.py b/IPython/utils/text.py index cfec757..4deb669 100644 --- a/IPython/utils/text.py +++ b/IPython/utils/text.py @@ -295,40 +295,6 @@ def esc_quotes(strng): return strng.replace('"','\\"').replace("'","\\'") -def make_quoted_expr(s): - """Return string s in appropriate quotes, using raw string if possible. - - XXX - example removed because it caused encoding errors in documentation - generation. We need a new example that doesn't contain invalid chars. - - Note the use of raw string and padding at the end to allow trailing - backslash. - """ - - tail = '' - tailpadding = '' - raw = '' - ucode = '' if py3compat.PY3 else 'u' - if "\\" in s: - raw = 'r' - if s.endswith('\\'): - tail = '[:-1]' - tailpadding = '_' - if '"' not in s: - quote = '"' - elif "'" not in s: - quote = "'" - elif '"""' not in s and not s.endswith('"'): - quote = '"""' - elif "'''" not in s and not s.endswith("'"): - quote = "'''" - else: - # give up, backslash-escaped string will do - return '"%s"' % esc_quotes(s) - res = ucode + raw + quote + s + tailpadding + quote + tail - return res - - def qw(words,flat=0,sep=None,maxsplit=-1): """Similar to Perl's qw() operator, but with some more options.