diff --git a/IPython/prefilter.py b/IPython/prefilter.py index 070167e..6da7db7 100644 --- a/IPython/prefilter.py +++ b/IPython/prefilter.py @@ -138,8 +138,9 @@ def prefilter(line_info, ip): checkIPyAutocall, checkMultiLineShell, checkEscChars, - checkPythonChars, + checkAssignment, checkAutomagic, + checkPythonOps, checkAlias, checkAutocall, ]: @@ -202,24 +203,27 @@ def checkEscChars(l_info,ip): return ip.esc_handlers[l_info.preChar] else: return None + + +def checkAssignment(l_info,ip): + """Check to see if user is assigning to a var for the first time, in + which case we want to avoid any sort of automagic / autocall games. -def checkPythonChars(l_info,ip): - """If the 'rest' of the line begins with an (in)equality, assginment, - function call or tuple comma, we should simply execute the line - (regardless of whether or not there's a possible alias, automagic or - autocall expansion). This both avoids spurious geattr() accesses on - objects upon assignment, and also allows users to assign to either alias - or magic names true python variables (the magic/alias systems always - take second seat to true python code). E.g. ls='hi', or ls,that=1,2""" - if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|': + This allows users to assign to either alias or magic names true python + variables (the magic/alias systems always take second seat to true + python code). E.g. ls='hi', or ls,that=1,2""" + if l_info.theRest and l_info.theRest[0] in '=,': return ip.handle_normal else: return None + def checkAutomagic(l_info,ip): """If the iFun is magic, and automagic is on, run it. Note: normal, non-auto magic would already have been triggered via '%' in - check_esc_chars. This just checks for automagic.""" + check_esc_chars. This just checks for automagic. Also, before + triggering the magic handler, make sure that there is nothing in the + user namespace which could shadow it.""" if not ip.rc.automagic or not hasattr(ip,'magic_'+l_info.iFun): return None @@ -233,7 +237,18 @@ def checkAutomagic(l_info,ip): return ip.handle_magic - + +def checkPythonOps(l_info,ip): + """If the 'rest' of the line begins with a function call or pretty much + any python operator, we should simply execute the line (regardless of + whether or not there's a possible alias or autocall expansion). This + avoids spurious (and very confusing) geattr() accesses.""" + if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|': + return ip.handle_normal + else: + return None + + def checkAlias(l_info,ip): "Check if the initital identifier on the line is an alias." # Note: aliases can not contain '.' diff --git a/test/test_prefilter.py b/test/test_prefilter.py index 76d2f21..499a5bc 100644 --- a/test/test_prefilter.py +++ b/test/test_prefilter.py @@ -206,22 +206,25 @@ run_handler_tests([ # Without automagic, only shows up with explicit escape ( 'cpaste', handle_normal), ( '%cpaste', handle_magic), - ( '%does_not_exist', handle_magic) + ( '%does_not_exist', handle_magic), ]) ip.options.automagic = 1 run_handler_tests([ ( 'cpaste', handle_magic), ( '%cpaste', handle_magic), ( 'does_not_exist', handle_normal), - ( '%does_not_exist', handle_magic)]) + ( '%does_not_exist', handle_magic), + ( 'cd /', handle_magic), + ( 'cd = 2', handle_normal), + ]) # If next elt starts with anything that could be an assignment, func call, # etc, we don't call the magic func, unless explicitly escaped to do so. -magic_killing_tests = [] -for c in list('!=()<>,'): - magic_killing_tests.append(('cpaste %s killed_automagic' % c, handle_normal)) - magic_killing_tests.append(('%%cpaste %s escaped_magic' % c, handle_magic)) -run_handler_tests(magic_killing_tests) +#magic_killing_tests = [] +#for c in list('!=()<>,'): +# magic_killing_tests.append(('cpaste %s killed_automagic' % c, handle_normal)) +# magic_killing_tests.append(('%%cpaste %s escaped_magic' % c, handle_magic)) +#run_handler_tests(magic_killing_tests) # magic on indented continuation lines -- on iff multi_line_specials == 1 ip.options.multi_line_specials = 0