From 8de6d199a7165e4c9cee90c409fe7b623b06a5fb 2007-05-30 14:14:34 From: dan.milstein Date: 2007-05-30 14:14:34 Subject: [PATCH] Changing input filtering to require whitespace separation between the initial command (alias, magic, autocall) and rest of line. This fixes some subtle but nasty bugs with lines that start with, e.g. r'a_string'. They had been getting parsed as the magic %r followed by the string literal 'a_string' -- now that's been fixed. --- diff --git a/IPython/prefilter.py b/IPython/prefilter.py index d317884..ad84deb 100644 --- a/IPython/prefilter.py +++ b/IPython/prefilter.py @@ -105,7 +105,7 @@ def splitUserInput(line, pattern=None): #print 'line:<%s>' % line # dbg #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg - return pre,iFun.strip(),theRest + return pre,iFun.strip(),theRest.lstrip() # RegExp for splitting line contents into pre-char//first word-method//rest. @@ -122,10 +122,10 @@ def splitUserInput(line, pattern=None): # The three parts of the regex are: # 1) pre: pre_char *or* initial whitespace # 2) iFun: first word/method (mix of \w and '.') -# 3) theRest: rest of line +# 3) theRest: rest of line (separated from iFun by space if non-empty) line_split = re.compile(r'^([,;/%?]|!!?|\s*)' - r'\s*([\w\.]+)\s*' - r'(.*)$') + r'\s*([\w\.]+)' + r'(\s+.*$|$)') shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)') diff --git a/test/test_handlers.py b/test/test_handlers.py index 9f15656..495239b 100644 --- a/test/test_handlers.py +++ b/test/test_handlers.py @@ -17,7 +17,8 @@ def run(tests): ip.runlines(pre) ip.runlines('_i') # Not sure why I need this... actual = ip.user_ns['_i'] - if actual != None: actual = actual.rstrip('\n') + if actual != None: + actual = actual.rstrip('\n') if actual != post: failures.append('Expected %r to become %r, found %r' % ( pre, post, actual)) @@ -53,8 +54,8 @@ try: # write anything to stdout. # Turn off actual execution of aliases, because it's noisy - old_system_cmd = ip.IP.system - ip.IP.system = lambda cmd: None + old_system_cmd = ip.system + ip.system = lambda cmd: None ip.IP.alias_table['an_alias'] = (0, 'true') @@ -66,7 +67,7 @@ try: # chars, *not* initial chars which happen to be aliases: ("top", '_ip.system("d:/cygwin/top ")'), ]) - ip.IP.system = old_system_cmd + ip.system = old_system_cmd call_idx = CallableIndexable() diff --git a/test/test_prefilter.py b/test/test_prefilter.py index f240303..4d7aa62 100644 --- a/test/test_prefilter.py +++ b/test/test_prefilter.py @@ -154,12 +154,24 @@ esc_handler_tests = [ # XXX Possibly, add test for /,; once those are unhooked from %autocall ( 'emacs_mode # PYTHON-MODE', handle_emacs ), ( ' ', handle_normal), + # Trailing qmark combos. Odd special cases abound - ( '!thing?', handle_shell_escape), # trailing '?' loses to shell esc - ( '!thing ?', handle_shell_escape), - ( '!!thing?', handle_shell_escape), + + # The key is: we don't want the trailing ? to trigger help if it's a + # part of a shell glob (like, e.g. '!ls file.?'). Instead, we want the + # shell handler to be called. Due to subtleties of the input string + # parsing, however, we only call the shell handler if the trailing ? is + # part of something whitespace-separated from the !cmd. See examples. + ( '!thing?', handle_help), + ( '!thing arg?', handle_shell_escape), + ( '!!thing?', handle_help), + ( '!!thing arg?', handle_shell_escape), + + # For all other leading esc chars, we always trigger help ( '%cmd?', handle_help), + ( '%cmd ?', handle_help), ( '/cmd?', handle_help), + ( '/cmd ?', handle_help), ( ';cmd?', handle_help), ( ',cmd?', handle_help), ] @@ -216,6 +228,9 @@ run_handler_tests([ ( '%does_not_exist', handle_magic), ( 'cd /', handle_magic), ( 'cd = 2', handle_normal), + ( 'r', handle_magic), + ( 'r thing', handle_magic), + ( 'r"str"', handle_normal), ]) # If next elt starts with anything that could be an assignment, func call,