diff --git a/qt/python/mantidqt/widgets/codeeditor/completion.py b/qt/python/mantidqt/widgets/codeeditor/completion.py index f9db633a3eb5275e340f47b2913e17bf8c317d19..a3cd41f4d7c03ac51266ddb33aff583c911ace91 100644 --- a/qt/python/mantidqt/widgets/codeeditor/completion.py +++ b/qt/python/mantidqt/widgets/codeeditor/completion.py @@ -27,6 +27,7 @@ revisiting when we move to Python 3. from __future__ import (absolute_import, unicode_literals) +import ast import inspect import re import sys @@ -148,8 +149,8 @@ def generate_call_tips(definitions, prepend_module_name=None): :param dict definitions: Dictionary with names of python objects as keys and the objects themselves as values - :param str prepend_module_name: Prepend the name of the module to the call tips - default is None + :param prepend_module_name: bool, None, or str. Prepend the name of the module to the call tips + default is None, if string given that string will act as the module name :returns list: A list of call tips """ if not isinstance(definitions, dict): @@ -158,6 +159,8 @@ def generate_call_tips(definitions, prepend_module_name=None): for name, py_object in definitions.items(): if name.startswith('_'): continue + if prepend_module_name is True: + prepend_module_name = py_object.__module__ if inspect.isfunction(py_object) or inspect.isbuiltin(py_object): if not prepend_module_name: call_tips.append(name + get_function_spec(py_object)) @@ -184,6 +187,17 @@ def generate_call_tips(definitions, prepend_module_name=None): return call_tips +def get_line_number_from_index(string, index): + return string[:index].count('\n') + + +def get_module_import_alias(import_name, text): + for node in ast.walk(ast.parse(text)): + if isinstance(node, ast.alias) and node.name == import_name: + return node.asname + return import_name + + class CodeCompleter(object): """ This class generates autocompletions for Workbench's script editor. @@ -198,12 +212,12 @@ class CodeCompleter(object): self._completions_dict = dict() if "from mantid.simpleapi import *" in self.editor.text(): self._add_to_completions(self._get_module_call_tips('mantid.simpleapi')) - if re.search("import .*numpy( |,|$)", self.editor.text()): + if re.search("^#{0}import .*numpy( |,|$)", self.editor.text(), re.MULTILINE): self._add_to_completions(self._get_module_call_tips('numpy')) - if re.search("import .*pyplot( |,|$)", self.editor.text()): + if re.search("^#{0}import .*pyplot( |,|$)", self.editor.text(), re.MULTILINE): self._add_to_completions(self._get_module_call_tips('matplotlib.pyplot')) - self.editor.enableAutoCompletion(CodeEditor.AcsAll) + self.editor.enableAutoCompletion(CodeEditor.AcsAPIs) self.editor.updateCompletionAPI(self.completions) @property @@ -211,7 +225,7 @@ class CodeCompleter(object): return list(self._completions_dict.keys()) def _get_completions_from_globals(self): - return generate_call_tips(self.env_globals) + return generate_call_tips(self.env_globals, prepend_module_name=True) def _add_to_completions(self, completions): for completion in completions: @@ -232,4 +246,5 @@ class CodeCompleter(object): module = sys.modules[module] except KeyError: return [] - return generate_call_tips(module.__dict__, module.__name__) + module_name = get_module_import_alias(module.__name__, self.editor.text()) + return generate_call_tips(module.__dict__, module_name) diff --git a/qt/python/mantidqt/widgets/codeeditor/test/test_completion.py b/qt/python/mantidqt/widgets/codeeditor/test/test_completion.py index 976e975f57c9cf795591cf6fbfb74d3f3f1ceef0..0d02677ee05f8b9b711f4de2b366ac05ca0cde61 100644 --- a/qt/python/mantidqt/widgets/codeeditor/test/test_completion.py +++ b/qt/python/mantidqt/widgets/codeeditor/test/test_completion.py @@ -16,7 +16,7 @@ import numpy as np # noqa from mantid.simpleapi import Rebin # noqa # needed so sys.modules can pick up Rebin from mantid.py3compat.mock import Mock from mantidqt.widgets.codeeditor.completion import (CodeCompleter, get_function_spec, - get_builtin_argspec) + get_builtin_argspec, get_module_import_alias) from testhelpers import assertRaisesNothing @@ -46,11 +46,11 @@ class CodeCompletionTest(unittest.TestCase): def test_numpy_call_tips_generated_if_numpy_imported_in_script(self): self._run_check_call_tip_generated("import numpy as np\n# My code", - "numpy\.asarray\(a, \[dtype\], .*\)") + "np\.asarray\(a, \[dtype\], .*\)") def test_pyplot_call_tips_generated_if_imported_in_script(self): self._run_check_call_tip_generated("import matplotlib.pyplot as plt\n# My code", - "matplotlib.pyplot\.figure\(\[num\], .*\)") + "plt\.figure\(\[num\], .*\)") def test_simple_api_call_tips_not_generated_on_construction_if_api_import_not_in_script(self): self._run_check_call_tip_not_generated("import numpy as np\n# My code", "Rebin") @@ -82,6 +82,25 @@ class CodeCompletionTest(unittest.TestCase): self.assertIn("shape, dtype, order", ', '.join(argspec.args)) self.assertIn("float, 'C'", ', '.join(argspec.defaults)) + def test_get_module_import_alias_finds_import_aliases(self): + script = ("import numpy as np\n" + "from keyword import kwlist as key_word_list\n" + "import matplotlib.pyplot as plt\n" + "import mymodule.some_func as func, something as _smthing\n" + "# import commented.module as not_imported\n" + "import thing as _thing # import kwlist2 as kew_word_list2") + aliases = { + 'numpy': 'np', + 'kwlist': 'key_word_list', + 'matplotlib.pyplot': 'plt', + 'mymodule.some_func': 'func', + 'something': '_smthing', + 'commented.module': 'commented.module', + 'kwlist2': 'kwlist2' # alias is commented out so expect alias to not be assigned + } + for import_name, alias in aliases.items(): + self.assertEqual(alias, get_module_import_alias(import_name, script)) + if __name__ == '__main__': unittest.main()