| Index: tools/telemetry/third_party/rope/rope/contrib/autoimport.py
|
| diff --git a/tools/telemetry/third_party/rope/rope/contrib/autoimport.py b/tools/telemetry/third_party/rope/rope/contrib/autoimport.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9670080cf7f3c223f7e84156089c6c45e2a5db5b
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/rope/rope/contrib/autoimport.py
|
| @@ -0,0 +1,222 @@
|
| +import re
|
| +
|
| +from rope.base import builtins
|
| +from rope.base import exceptions
|
| +from rope.base import libutils
|
| +from rope.base import pynames
|
| +from rope.base import pyobjects
|
| +from rope.base import resources
|
| +from rope.base import resourceobserver
|
| +from rope.base import taskhandle
|
| +from rope.refactor import importutils
|
| +
|
| +
|
| +class AutoImport(object):
|
| + """A class for finding the module that provides a name
|
| +
|
| + This class maintains a cache of global names in python modules.
|
| + Note that this cache is not accurate and might be out of date.
|
| +
|
| + """
|
| +
|
| + def __init__(self, project, observe=True, underlined=False):
|
| + """Construct an AutoImport object
|
| +
|
| + If `observe` is `True`, listen for project changes and update
|
| + the cache.
|
| +
|
| + If `underlined` is `True`, underlined names are cached, too.
|
| + """
|
| + self.project = project
|
| + self.underlined = underlined
|
| + self.names = project.data_files.read_data('globalnames')
|
| + if self.names is None:
|
| + self.names = {}
|
| + project.data_files.add_write_hook(self._write)
|
| + # XXX: using a filtered observer
|
| + observer = resourceobserver.ResourceObserver(
|
| + changed=self._changed, moved=self._moved, removed=self._removed)
|
| + if observe:
|
| + project.add_observer(observer)
|
| +
|
| + def import_assist(self, starting):
|
| + """Return a list of ``(name, module)`` tuples
|
| +
|
| + This function tries to find modules that have a global name
|
| + that starts with `starting`.
|
| + """
|
| + # XXX: breaking if gave up! use generators
|
| + result = []
|
| + for module in self.names:
|
| + for global_name in self.names[module]:
|
| + if global_name.startswith(starting):
|
| + result.append((global_name, module))
|
| + return result
|
| +
|
| + def get_modules(self, name):
|
| + """Return the list of modules that have global `name`"""
|
| + result = []
|
| + for module in self.names:
|
| + if name in self.names[module]:
|
| + result.append(module)
|
| + return result
|
| +
|
| + def get_all_names(self):
|
| + """Return the list of all cached global names"""
|
| + result = set()
|
| + for module in self.names:
|
| + result.update(set(self.names[module]))
|
| + return result
|
| +
|
| + def get_name_locations(self, name):
|
| + """Return a list of ``(resource, lineno)`` tuples"""
|
| + result = []
|
| + for module in self.names:
|
| + if name in self.names[module]:
|
| + try:
|
| + pymodule = self.project.get_module(module)
|
| + if name in pymodule:
|
| + pyname = pymodule[name]
|
| + module, lineno = pyname.get_definition_location()
|
| + if module is not None:
|
| + resource = module.get_module().get_resource()
|
| + if resource is not None and lineno is not None:
|
| + result.append((resource, lineno))
|
| + except exceptions.ModuleNotFoundError:
|
| + pass
|
| + return result
|
| +
|
| + def generate_cache(self, resources=None, underlined=None,
|
| + task_handle=taskhandle.NullTaskHandle()):
|
| + """Generate global name cache for project files
|
| +
|
| + If `resources` is a list of `rope.base.resource.File`\s, only
|
| + those files are searched; otherwise all python modules in the
|
| + project are cached.
|
| +
|
| + """
|
| + if resources is None:
|
| + resources = self.project.get_python_files()
|
| + job_set = task_handle.create_jobset(
|
| + 'Generatig autoimport cache', len(resources))
|
| + for file in resources:
|
| + job_set.started_job('Working on <%s>' % file.path)
|
| + self.update_resource(file, underlined)
|
| + job_set.finished_job()
|
| +
|
| + def generate_modules_cache(self, modules, underlined=None,
|
| + task_handle=taskhandle.NullTaskHandle()):
|
| + """Generate global name cache for modules listed in `modules`"""
|
| + job_set = task_handle.create_jobset(
|
| + 'Generatig autoimport cache for modules', len(modules))
|
| + for modname in modules:
|
| + job_set.started_job('Working on <%s>' % modname)
|
| + if modname.endswith('.*'):
|
| + mod = self.project.find_module(modname[:-2])
|
| + if mod:
|
| + for sub in submodules(mod):
|
| + self.update_resource(sub, underlined)
|
| + else:
|
| + self.update_module(modname, underlined)
|
| + job_set.finished_job()
|
| +
|
| + def clear_cache(self):
|
| + """Clear all entries in global-name cache
|
| +
|
| + It might be a good idea to use this function before
|
| + regenerating global names.
|
| +
|
| + """
|
| + self.names.clear()
|
| +
|
| + def find_insertion_line(self, code):
|
| + """Guess at what line the new import should be inserted"""
|
| + match = re.search(r'^(def|class)\s+', code)
|
| + if match is not None:
|
| + code = code[:match.start()]
|
| + try:
|
| + pymodule = libutils.get_string_module(self.project, code)
|
| + except exceptions.ModuleSyntaxError:
|
| + return 1
|
| + testmodname = '__rope_testmodule_rope'
|
| + importinfo = importutils.NormalImport(((testmodname, None),))
|
| + module_imports = importutils.get_module_imports(self.project,
|
| + pymodule)
|
| + module_imports.add_import(importinfo)
|
| + code = module_imports.get_changed_source()
|
| + offset = code.index(testmodname)
|
| + lineno = code.count('\n', 0, offset) + 1
|
| + return lineno
|
| +
|
| + def update_resource(self, resource, underlined=None):
|
| + """Update the cache for global names in `resource`"""
|
| + try:
|
| + pymodule = self.project.get_pymodule(resource)
|
| + modname = self._module_name(resource)
|
| + self._add_names(pymodule, modname, underlined)
|
| + except exceptions.ModuleSyntaxError:
|
| + pass
|
| +
|
| + def update_module(self, modname, underlined=None):
|
| + """Update the cache for global names in `modname` module
|
| +
|
| + `modname` is the name of a module.
|
| + """
|
| + try:
|
| + pymodule = self.project.get_module(modname)
|
| + self._add_names(pymodule, modname, underlined)
|
| + except exceptions.ModuleNotFoundError:
|
| + pass
|
| +
|
| + def _module_name(self, resource):
|
| + return libutils.modname(resource)
|
| +
|
| + def _add_names(self, pymodule, modname, underlined):
|
| + if underlined is None:
|
| + underlined = self.underlined
|
| + globals = []
|
| + if isinstance(pymodule, pyobjects.PyDefinedObject):
|
| + attributes = pymodule._get_structural_attributes()
|
| + else:
|
| + attributes = pymodule.get_attributes()
|
| + for name, pyname in attributes.items():
|
| + if not underlined and name.startswith('_'):
|
| + continue
|
| + if isinstance(pyname, (pynames.AssignedName, pynames.DefinedName)):
|
| + globals.append(name)
|
| + if isinstance(pymodule, builtins.BuiltinModule):
|
| + globals.append(name)
|
| + self.names[modname] = globals
|
| +
|
| + def _write(self):
|
| + self.project.data_files.write_data('globalnames', self.names)
|
| +
|
| + def _changed(self, resource):
|
| + if not resource.is_folder():
|
| + self.update_resource(resource)
|
| +
|
| + def _moved(self, resource, newresource):
|
| + if not resource.is_folder():
|
| + modname = self._module_name(resource)
|
| + if modname in self.names:
|
| + del self.names[modname]
|
| + self.update_resource(newresource)
|
| +
|
| + def _removed(self, resource):
|
| + if not resource.is_folder():
|
| + modname = self._module_name(resource)
|
| + if modname in self.names:
|
| + del self.names[modname]
|
| +
|
| +
|
| +def submodules(mod):
|
| + if isinstance(mod, resources.File):
|
| + if mod.name.endswith('.py') and mod.name != '__init__.py':
|
| + return set([mod])
|
| + return set()
|
| + if not mod.has_child('__init__.py'):
|
| + return set()
|
| + result = set([mod])
|
| + for child in mod.get_children():
|
| + result |= submodules(child)
|
| + return result
|
|
|