diff options
Diffstat (limited to 'release/scripts/modules/bl_console_utils/autocomplete/complete_import.py')
-rw-r--r-- | release/scripts/modules/bl_console_utils/autocomplete/complete_import.py | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py b/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py new file mode 100644 index 00000000000..2339e79c8f1 --- /dev/null +++ b/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py @@ -0,0 +1,181 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright (c) 2009 Fernando Perez, www.stani.be + +# Original copyright (see docstring): +# **************************************************************************** +# Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu> +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +# **************************************************************************** + +# <pep8 compliant> + +"""Completer for import statements + +Original code was from IPython/Extensions/ipy_completers.py. The following +changes have been made: +- ported to python3 +- pep8 polishing +- limit list of modules to prefix in case of "from w" +- sorted modules +- added sphinx documentation +- complete() returns a blank list of the module isn't found +""" + + +import os +import sys + +TIMEOUT_STORAGE = 3 # Time in secs after which the root-modules will be stored +TIMEOUT_GIVEUP = 20 # Time in secs after which we give up + +ROOT_MODULES = None + + +def get_root_modules(): + """ + Returns a list containing the names of all the modules available in the + folders of the python-path. + + :returns: modules + :rtype: list + """ + global ROOT_MODULES + modules = [] + if not(ROOT_MODULES is None): + return ROOT_MODULES + from time import time + t = time() + store = False + for path in sys.path: + modules += module_list(path) + if time() - t >= TIMEOUT_STORAGE and not store: + # Caching the list of root modules, please wait! + store = True + if time() - t > TIMEOUT_GIVEUP: + # This is taking too long, we give up. + ROOT_MODULES = [] + return [] + + modules += sys.builtin_module_names + + # needed for modules defined in C + modules += sys.modules.keys() + + modules = list(set(modules)) + if '__init__' in modules: + modules.remove('__init__') + modules = sorted(modules) + if store: + ROOT_MODULES = modules + return modules + + +def module_list(path): + """ + Return the list containing the names of the modules available in + the given folder. + + :param path: folder path + :type path: str + :returns: modules + :rtype: list + """ + + if os.path.isdir(path): + folder_list = os.listdir(path) + elif path.endswith('.egg'): + from zipimport import zipimporter + try: + folder_list = [f for f in zipimporter(path)._files] + except: + folder_list = [] + else: + folder_list = [] + #folder_list = glob.glob(os.path.join(path,'*')) + folder_list = [ + p for p in folder_list + if (os.path.exists(os.path.join(path, p, '__init__.py')) or + p[-3:] in {'.py', '.so'} or + p[-4:] in {'.pyc', '.pyo', '.pyd'})] + + folder_list = [os.path.basename(p).split('.')[0] for p in folder_list] + return folder_list + + +def complete(line): + """ + Returns a list containing the completion possibilities for an import line. + + :param line: + + incomplete line which contains an import statement:: + + import xml.d + from xml.dom import + + :type line: str + :returns: list of completion possibilities + :rtype: list + + >>> complete('import weak') + ['weakref'] + >>> complete('from weakref import C') + ['CallableProxyType'] + """ + import inspect + + def try_import(mod, *, only_modules=False): + + def is_importable(module, attr): + if only_modules: + return inspect.ismodule(getattr(module, attr)) + else: + return not(attr[:2] == '__' and attr[-2:] == '__') + + try: + m = __import__(mod) + except: + return [] + mods = mod.split('.') + for module in mods[1:]: + m = getattr(m, module) + if (not hasattr(m, '__file__')) or (not only_modules) or\ + (hasattr(m, '__file__') and '__init__' in m.__file__): + completion_list = [attr for attr in dir(m) + if is_importable(m, attr)] + else: + completion_list = [] + completion_list.extend(getattr(m, '__all__', [])) + if hasattr(m, '__file__') and '__init__' in m.__file__: + completion_list.extend(module_list(os.path.dirname(m.__file__))) + completion_list = list(set(completion_list)) + if '__init__' in completion_list: + completion_list.remove('__init__') + return completion_list + + def filter_prefix(names, prefix): + return [name for name in names if name.startswith(prefix)] + + words = line.split(' ') + if len(words) == 3 and words[0] == 'from': + return ['import '] + if len(words) < 3 and (words[0] in {'import', 'from'}): + if len(words) == 1: + return get_root_modules() + mod = words[1].split('.') + if len(mod) < 2: + return filter_prefix(get_root_modules(), words[-1]) + completion_list = try_import('.'.join(mod[:-1]), only_modules=True) + completion_list = ['.'.join(mod[:-1] + [el]) for el in completion_list] + return filter_prefix(completion_list, words[-1]) + if len(words) >= 3 and words[0] == 'from': + mod = words[1] + return filter_prefix(try_import(mod), words[-1]) + + # get here if the import is not found + # import invalidmodule + # ^, in this case return nothing + return [] |