From 5a613e02854f73d1aab6c918b3395368dff59fb3 2017-09-11 22:57:26 From: Matthias Bussonnier Date: 2017-09-11 22:57:26 Subject: [PATCH] Do not shadow explicit magic completion. If a binding has the same name than a magic, the magic should be shadowed; unless the use is explicitly requesting a magic with a leading percent sign. Closes #10754 --- diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 18905b1..12890a2 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -1221,7 +1221,9 @@ class IPCompleter(Completer): cell_magics = lsm['cell'] pre = self.magic_escape pre2 = pre+pre - + + explicit_magic = text.startswith(pre) + # Completion logic: # - user gives %%: only do cell magics # - user gives %: do both line and cell magics @@ -1229,11 +1231,23 @@ class IPCompleter(Completer): # In other words, line magics are skipped if the user gives %% explicitly # # We also exclude magics that match any currently visible names: - # https://github.com/ipython/ipython/issues/4877 + # https://github.com/ipython/ipython/issues/4877, unless the user has + # typed a %: + # https://github.com/ipython/ipython/issues/10754 bare_text = text.lstrip(pre) global_matches = self.global_matches(bare_text) - matches = lambda magic: magic.startswith(bare_text) \ - and magic not in global_matches + if not explicit_magic: + def matches(magic): + """ + Filter magics, in particular remove magics that match + a name present in global namespace. + """ + return ( magic.startswith(bare_text) and + magic not in global_matches ) + else: + def matches(magic): + return magic.startswith(bare_text) + comp = [ pre2+m for m in cell_magics if matches(m)] if not text.startswith(pre2): comp += [ pre+m for m in line_magics if matches(m)] diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 80026fa..61f1466 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -589,6 +589,24 @@ def test_magic_completion_shadowing(): text, matches = c.complete("mat") nt.assert_equal(matches, ["%matplotlib"]) +def test_magic_completion_shadowing_explicit(): + """ + If the user try to complete a shadowed magic, and explicit % start should + still return the completions. + """ + ip = get_ipython() + c = ip.Completer + + # Before importing matplotlib, %matplotlib magic should be the only option. + text, matches = c.complete("%mat") + nt.assert_equal(matches, ["%matplotlib"]) + + ip.run_cell("matplotlib = 1") + + # After removing matplotlib from namespace, the magic should still be + # the only option. + text, matches = c.complete("%mat") + nt.assert_equal(matches, ["%matplotlib"]) def test_magic_config(): ip = get_ipython()