From b2433d6146424da7e8fb26e0fe5e9fb352fe998e 2021-07-31 13:09:45 From: Daniel Shimon Date: 2021-07-31 13:09:45 Subject: [PATCH] Only complete exported submodules in import statements When completing `import m.` statements, only complete exported (`__all__`) objects if they are modules. E.g. `import os.pa` should complete `os.path` but not `os.pathconf`. --- diff --git a/IPython/core/completerlib.py b/IPython/core/completerlib.py index 7860cb6..0ca97e7 100644 --- a/IPython/core/completerlib.py +++ b/IPython/core/completerlib.py @@ -154,6 +154,17 @@ def is_importable(module, attr, only_modules): else: return not(attr[:2] == '__' and attr[-2:] == '__') +def is_possible_submodule(module, attr): + try: + obj = getattr(module, attr) + except AttributeError: + # Is possilby an unimported submodule + return True + except TypeError: + # https://github.com/ipython/ipython/issues/9678 + return False + return inspect.ismodule(obj) + def try_import(mod: str, only_modules=False) -> List[str]: """ @@ -172,7 +183,12 @@ def try_import(mod: str, only_modules=False) -> List[str]: completions.extend( [attr for attr in dir(m) if is_importable(m, attr, only_modules)]) - completions.extend(getattr(m, '__all__', [])) + m_all = getattr(m, "__all__", []) + if only_modules: + completions.extend(attr for attr in m_all if is_possible_submodule(m, attr)) + else: + completions.extend(m_all) + if m_is_init: completions.extend(module_list(os.path.dirname(m.__file__))) completions_set = {c for c in completions if isinstance(c, str)}