diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 4280410..f473f07 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -1158,10 +1158,17 @@ class IPCompleter(Completer): # - user gives %: do both line and cell magics # - no prefix: do both # 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 bare_text = text.lstrip(pre) - comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)] + global_matches = self.global_matches(bare_text) + matches = lambda magic: magic.startswith(bare_text) \ + and magic not in global_matches + 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 m.startswith(bare_text)] + comp += [ pre+m for m in line_magics if matches(m)] + return [cast_unicode_py2(c) for c in comp] def _jedi_matches(self, cursor_column:int, cursor_line:int, text:str): diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 533ba42..bccbbd5 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -519,31 +519,33 @@ def test_line_cell_magics(): def test_magic_completion_order(): - ip = get_ipython() c = ip.Completer - # Test ordering of magics and non-magics with the same name - # We want the non-magic first - - # Before importing matplotlib, there should only be one option: - - text, matches = c.complete('mat') - nt.assert_equal(matches, ["%matplotlib"]) + # Test ordering of line and cell magics. + text, matches = c.complete("timeit") + nt.assert_equal(matches, ["%timeit", "%%timeit"]) - ip.run_cell("matplotlib = 1") # introduce name into namespace +def test_magic_completion_shadowing(): + ip = get_ipython() + c = ip.Completer - # After the import, there should be two options, ordered like this: - text, matches = c.complete('mat') - nt.assert_equal(matches, ["matplotlib", "%matplotlib"]) + # Before importing matplotlib, %matplotlib magic should be the only option. + text, matches = c.complete("mat") + nt.assert_equal(matches, ["%matplotlib"]) + # The newly introduced name should shadow the magic. + ip.run_cell("matplotlib = 1") + text, matches = c.complete("mat") + nt.assert_equal(matches, ["matplotlib"]) - ip.run_cell("timeit = 1") # define a user variable called 'timeit' + # After removing matplotlib from namespace, the magic should again be + # the only option. + del ip.user_ns["matplotlib"] + text, matches = c.complete("mat") + nt.assert_equal(matches, ["%matplotlib"]) - # Order of user variable and line and cell magics with same name: - text, matches = c.complete('timeit') - nt.assert_equal(matches, ["timeit", "%timeit", "%%timeit"]) def test_match_dict_keys(): """ diff --git a/docs/source/whatsnew/pr/variables-shadow-magics-in-autocompletion.rst b/docs/source/whatsnew/pr/variables-shadow-magics-in-autocompletion.rst new file mode 100644 index 0000000..e85e23a --- /dev/null +++ b/docs/source/whatsnew/pr/variables-shadow-magics-in-autocompletion.rst @@ -0,0 +1 @@ +Variables now shadow magics in autocompletion. See :ghissue:`4877` and :ghpull:`10542`.