| Index: tools/telemetry/third_party/rope/rope/refactor/move.py
|
| diff --git a/tools/telemetry/third_party/rope/rope/refactor/move.py b/tools/telemetry/third_party/rope/rope/refactor/move.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..60df493e27fe2aab2e062e15dec894bce3bd440e
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/rope/rope/refactor/move.py
|
| @@ -0,0 +1,718 @@
|
| +"""A module containing classes for move refactoring
|
| +
|
| +`create_move()` is a factory for creating move refactoring objects
|
| +based on inputs.
|
| +
|
| +"""
|
| +from rope.base import (pyobjects, codeanalyze, exceptions, pynames,
|
| + taskhandle, evaluate, worder, libutils)
|
| +from rope.base.change import ChangeSet, ChangeContents, MoveResource
|
| +from rope.refactor import importutils, rename, occurrences, sourceutils, \
|
| + functionutils
|
| +
|
| +
|
| +def create_move(project, resource, offset=None):
|
| + """A factory for creating Move objects
|
| +
|
| + Based on `resource` and `offset`, return one of `MoveModule`,
|
| + `MoveGlobal` or `MoveMethod` for performing move refactoring.
|
| +
|
| + """
|
| + if offset is None:
|
| + return MoveModule(project, resource)
|
| + this_pymodule = project.get_pymodule(resource)
|
| + pyname = evaluate.eval_location(this_pymodule, offset)
|
| + if pyname is None:
|
| + raise exceptions.RefactoringError(
|
| + 'Move only works on classes, functions, modules and methods.')
|
| + pyobject = pyname.get_object()
|
| + if isinstance(pyobject, pyobjects.PyModule) or \
|
| + isinstance(pyobject, pyobjects.PyPackage):
|
| + return MoveModule(project, pyobject.get_resource())
|
| + if isinstance(pyobject, pyobjects.PyFunction) and \
|
| + isinstance(pyobject.parent, pyobjects.PyClass):
|
| + return MoveMethod(project, resource, offset)
|
| + if isinstance(pyobject, pyobjects.PyDefinedObject) and \
|
| + isinstance(pyobject.parent, pyobjects.PyModule):
|
| + return MoveGlobal(project, resource, offset)
|
| + raise exceptions.RefactoringError(
|
| + 'Move only works on global classes/functions, modules and methods.')
|
| +
|
| +
|
| +class MoveMethod(object):
|
| + """For moving methods
|
| +
|
| + It makes a new method in the destination class and changes
|
| + the body of the old method to call the new method. You can
|
| + inline the old method to change all of its occurrences.
|
| +
|
| + """
|
| +
|
| + def __init__(self, project, resource, offset):
|
| + self.project = project
|
| + this_pymodule = self.project.get_pymodule(resource)
|
| + pyname = evaluate.eval_location(this_pymodule, offset)
|
| + self.method_name = worder.get_name_at(resource, offset)
|
| + self.pyfunction = pyname.get_object()
|
| + if self.pyfunction.get_kind() != 'method':
|
| + raise exceptions.RefactoringError('Only normal methods'
|
| + ' can be moved.')
|
| +
|
| + def get_changes(self, dest_attr, new_name=None, resources=None,
|
| + task_handle=taskhandle.NullTaskHandle()):
|
| + """Return the changes needed for this refactoring
|
| +
|
| + Parameters:
|
| +
|
| + - `dest_attr`: the name of the destination attribute
|
| + - `new_name`: the name of the new method; if `None` uses
|
| + the old name
|
| + - `resources` can be a list of `rope.base.resources.File`\s to
|
| + apply this refactoring on. If `None`, the restructuring
|
| + will be applied to all python files.
|
| +
|
| + """
|
| + changes = ChangeSet('Moving method <%s>' % self.method_name)
|
| + if resources is None:
|
| + resources = self.project.get_python_files()
|
| + if new_name is None:
|
| + new_name = self.get_method_name()
|
| + resource1, start1, end1, new_content1 = \
|
| + self._get_changes_made_by_old_class(dest_attr, new_name)
|
| + collector1 = codeanalyze.ChangeCollector(resource1.read())
|
| + collector1.add_change(start1, end1, new_content1)
|
| +
|
| + resource2, start2, end2, new_content2 = \
|
| + self._get_changes_made_by_new_class(dest_attr, new_name)
|
| + if resource1 == resource2:
|
| + collector1.add_change(start2, end2, new_content2)
|
| + else:
|
| + collector2 = codeanalyze.ChangeCollector(resource2.read())
|
| + collector2.add_change(start2, end2, new_content2)
|
| + result = collector2.get_changed()
|
| + import_tools = importutils.ImportTools(self.project)
|
| + new_imports = self._get_used_imports(import_tools)
|
| + if new_imports:
|
| + goal_pymodule = libutils.get_string_module(
|
| + self.project, result, resource2)
|
| + result = _add_imports_to_module(
|
| + import_tools, goal_pymodule, new_imports)
|
| + if resource2 in resources:
|
| + changes.add_change(ChangeContents(resource2, result))
|
| +
|
| + if resource1 in resources:
|
| + changes.add_change(ChangeContents(resource1,
|
| + collector1.get_changed()))
|
| + return changes
|
| +
|
| + def get_method_name(self):
|
| + return self.method_name
|
| +
|
| + def _get_used_imports(self, import_tools):
|
| + return importutils.get_imports(self.project, self.pyfunction)
|
| +
|
| + def _get_changes_made_by_old_class(self, dest_attr, new_name):
|
| + pymodule = self.pyfunction.get_module()
|
| + indents = self._get_scope_indents(self.pyfunction)
|
| + body = 'return self.%s.%s(%s)\n' % (
|
| + dest_attr, new_name, self._get_passed_arguments_string())
|
| + region = sourceutils.get_body_region(self.pyfunction)
|
| + return (pymodule.get_resource(), region[0], region[1],
|
| + sourceutils.fix_indentation(body, indents))
|
| +
|
| + def _get_scope_indents(self, pyobject):
|
| + pymodule = pyobject.get_module()
|
| + return sourceutils.get_indents(
|
| + pymodule.lines, pyobject.get_scope().get_start()) + \
|
| + sourceutils.get_indent(self.project)
|
| +
|
| + def _get_changes_made_by_new_class(self, dest_attr, new_name):
|
| + old_pyclass = self.pyfunction.parent
|
| + if dest_attr not in old_pyclass:
|
| + raise exceptions.RefactoringError(
|
| + 'Destination attribute <%s> not found' % dest_attr)
|
| + pyclass = old_pyclass[dest_attr].get_object().get_type()
|
| + if not isinstance(pyclass, pyobjects.PyClass):
|
| + raise exceptions.RefactoringError(
|
| + 'Unknown class type for attribute <%s>' % dest_attr)
|
| + pymodule = pyclass.get_module()
|
| + resource = pyclass.get_module().get_resource()
|
| + start, end = sourceutils.get_body_region(pyclass)
|
| + pre_blanks = '\n'
|
| + if pymodule.source_code[start:end].strip() != 'pass':
|
| + pre_blanks = '\n\n'
|
| + start = end
|
| + indents = self._get_scope_indents(pyclass)
|
| + body = pre_blanks + sourceutils.fix_indentation(
|
| + self.get_new_method(new_name), indents)
|
| + return resource, start, end, body
|
| +
|
| + def get_new_method(self, name):
|
| + return '%s\n%s' % (
|
| + self._get_new_header(name),
|
| + sourceutils.fix_indentation(self._get_body(),
|
| + sourceutils.get_indent(self.project)))
|
| +
|
| + def _get_unchanged_body(self):
|
| + return sourceutils.get_body(self.pyfunction)
|
| +
|
| + def _get_body(self, host='host'):
|
| + self_name = self._get_self_name()
|
| + body = self_name + ' = None\n' + self._get_unchanged_body()
|
| + pymodule = libutils.get_string_module(self.project, body)
|
| + finder = occurrences.create_finder(
|
| + self.project, self_name, pymodule[self_name])
|
| + result = rename.rename_in_module(finder, host, pymodule=pymodule)
|
| + if result is None:
|
| + result = body
|
| + return result[result.index('\n') + 1:]
|
| +
|
| + def _get_self_name(self):
|
| + return self.pyfunction.get_param_names()[0]
|
| +
|
| + def _get_new_header(self, name):
|
| + header = 'def %s(self' % name
|
| + if self._is_host_used():
|
| + header += ', host'
|
| + definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
|
| + others = definition_info.arguments_to_string(1)
|
| + if others:
|
| + header += ', ' + others
|
| + return header + '):'
|
| +
|
| + def _get_passed_arguments_string(self):
|
| + result = ''
|
| + if self._is_host_used():
|
| + result = 'self'
|
| + definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
|
| + others = definition_info.arguments_to_string(1)
|
| + if others:
|
| + if result:
|
| + result += ', '
|
| + result += others
|
| + return result
|
| +
|
| + def _is_host_used(self):
|
| + return self._get_body('__old_self') != self._get_unchanged_body()
|
| +
|
| +
|
| +class MoveGlobal(object):
|
| + """For moving global function and classes"""
|
| +
|
| + def __init__(self, project, resource, offset):
|
| + self.project = project
|
| + this_pymodule = self.project.get_pymodule(resource)
|
| + self.old_pyname = evaluate.eval_location(this_pymodule, offset)
|
| + self.old_name = self.old_pyname.get_object().get_name()
|
| + pymodule = self.old_pyname.get_object().get_module()
|
| + self.source = pymodule.get_resource()
|
| + self.tools = _MoveTools(self.project, self.source,
|
| + self.old_pyname, self.old_name)
|
| + self.import_tools = self.tools.import_tools
|
| + self._check_exceptional_conditions()
|
| +
|
| + def _check_exceptional_conditions(self):
|
| + if self.old_pyname is None or \
|
| + not isinstance(self.old_pyname.get_object(),
|
| + pyobjects.PyDefinedObject):
|
| + raise exceptions.RefactoringError(
|
| + 'Move refactoring should be performed on a class/function.')
|
| + moving_pyobject = self.old_pyname.get_object()
|
| + if not self._is_global(moving_pyobject):
|
| + raise exceptions.RefactoringError(
|
| + 'Move refactoring should be performed ' +
|
| + 'on a global class/function.')
|
| +
|
| + def _is_global(self, pyobject):
|
| + return pyobject.get_scope().parent == pyobject.get_module().get_scope()
|
| +
|
| + def get_changes(self, dest, resources=None,
|
| + task_handle=taskhandle.NullTaskHandle()):
|
| + if resources is None:
|
| + resources = self.project.get_python_files()
|
| + if dest is None or not dest.exists():
|
| + raise exceptions.RefactoringError(
|
| + 'Move destination does not exist.')
|
| + if dest.is_folder() and dest.has_child('__init__.py'):
|
| + dest = dest.get_child('__init__.py')
|
| + if dest.is_folder():
|
| + raise exceptions.RefactoringError(
|
| + 'Move destination for non-modules should not be folders.')
|
| + if self.source == dest:
|
| + raise exceptions.RefactoringError(
|
| + 'Moving global elements to the same module.')
|
| + return self._calculate_changes(dest, resources, task_handle)
|
| +
|
| + def _calculate_changes(self, dest, resources, task_handle):
|
| + changes = ChangeSet('Moving global <%s>' % self.old_name)
|
| + job_set = task_handle.create_jobset('Collecting Changes',
|
| + len(resources))
|
| + for file_ in resources:
|
| + job_set.started_job(file_.path)
|
| + if file_ == self.source:
|
| + changes.add_change(self._source_module_changes(dest))
|
| + elif file_ == dest:
|
| + changes.add_change(self._dest_module_changes(dest))
|
| + elif self.tools.occurs_in_module(resource=file_):
|
| + pymodule = self.project.get_pymodule(file_)
|
| + # Changing occurrences
|
| + placeholder = '__rope_renaming_%s_' % self.old_name
|
| + source = self.tools.rename_in_module(placeholder,
|
| + resource=file_)
|
| + should_import = source is not None
|
| + # Removing out of date imports
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| + source = self.tools.remove_old_imports(pymodule)
|
| + # Adding new import
|
| + if should_import:
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| + source, imported = importutils.add_import(
|
| + self.project, pymodule, self._new_modname(dest),
|
| + self.old_name)
|
| + source = source.replace(placeholder, imported)
|
| + source = self.tools.new_source(pymodule, source)
|
| + if source != file_.read():
|
| + changes.add_change(ChangeContents(file_, source))
|
| + job_set.finished_job()
|
| + return changes
|
| +
|
| + def _source_module_changes(self, dest):
|
| + placeholder = '__rope_moving_%s_' % self.old_name
|
| + handle = _ChangeMoveOccurrencesHandle(placeholder)
|
| + occurrence_finder = occurrences.create_finder(
|
| + self.project, self.old_name, self.old_pyname)
|
| + start, end = self._get_moving_region()
|
| + renamer = ModuleSkipRenamer(occurrence_finder, self.source,
|
| + handle, start, end)
|
| + source = renamer.get_changed_module()
|
| + if handle.occurred:
|
| + pymodule = libutils.get_string_module(
|
| + self.project, source, self.source)
|
| + # Adding new import
|
| + source, imported = importutils.add_import(
|
| + self.project, pymodule, self._new_modname(dest), self.old_name)
|
| + source = source.replace(placeholder, imported)
|
| + return ChangeContents(self.source, source)
|
| +
|
| + def _new_modname(self, dest):
|
| + return libutils.modname(dest)
|
| +
|
| + def _dest_module_changes(self, dest):
|
| + # Changing occurrences
|
| + pymodule = self.project.get_pymodule(dest)
|
| + source = self.tools.rename_in_module(self.old_name, pymodule)
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| +
|
| + moving, imports = self._get_moving_element_with_imports()
|
| + source = self.tools.remove_old_imports(pymodule)
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| + pymodule, has_changed = self._add_imports2(pymodule, imports)
|
| +
|
| + module_with_imports = self.import_tools.module_imports(pymodule)
|
| + source = pymodule.source_code
|
| + lineno = 0
|
| + if module_with_imports.imports:
|
| + lineno = module_with_imports.imports[-1].end_line - 1
|
| + else:
|
| + while lineno < pymodule.lines.length() and \
|
| + pymodule.lines.get_line(lineno + 1).\
|
| + lstrip().startswith('#'):
|
| + lineno += 1
|
| + if lineno > 0:
|
| + cut = pymodule.lines.get_line_end(lineno) + 1
|
| + result = source[:cut] + '\n\n' + moving + source[cut:]
|
| + else:
|
| + result = moving + source
|
| +
|
| + # Organizing imports
|
| + source = result
|
| + pymodule = libutils.get_string_module(self.project, source, dest)
|
| + source = self.import_tools.organize_imports(pymodule, sort=False,
|
| + unused=False)
|
| + return ChangeContents(dest, source)
|
| +
|
| + def _get_moving_element_with_imports(self):
|
| + return moving_code_with_imports(
|
| + self.project, self.source, self._get_moving_element())
|
| +
|
| + def _get_module_with_imports(self, source_code, resource):
|
| + pymodule = libutils.get_string_module(
|
| + self.project, source_code, resource)
|
| + return self.import_tools.module_imports(pymodule)
|
| +
|
| + def _get_moving_element(self):
|
| + start, end = self._get_moving_region()
|
| + moving = self.source.read()[start:end]
|
| + return moving.rstrip() + '\n'
|
| +
|
| + def _get_moving_region(self):
|
| + pymodule = self.project.get_pymodule(self.source)
|
| + lines = pymodule.lines
|
| + scope = self.old_pyname.get_object().get_scope()
|
| + start = lines.get_line_start(scope.get_start())
|
| + end_line = scope.get_end()
|
| + while end_line < lines.length() and \
|
| + lines.get_line(end_line + 1).strip() == '':
|
| + end_line += 1
|
| + end = min(lines.get_line_end(end_line) + 1, len(pymodule.source_code))
|
| + return start, end
|
| +
|
| + def _add_imports2(self, pymodule, new_imports):
|
| + source = self.tools.add_imports(pymodule, new_imports)
|
| + if source is None:
|
| + return pymodule, False
|
| + else:
|
| + resource = pymodule.get_resource()
|
| + pymodule = libutils.get_string_module(
|
| + self.project, source, resource)
|
| + return pymodule, True
|
| +
|
| +
|
| +class MoveModule(object):
|
| + """For moving modules and packages"""
|
| +
|
| + def __init__(self, project, resource):
|
| + self.project = project
|
| + if not resource.is_folder() and resource.name == '__init__.py':
|
| + resource = resource.parent
|
| + if resource.is_folder() and not resource.has_child('__init__.py'):
|
| + raise exceptions.RefactoringError(
|
| + 'Cannot move non-package folder.')
|
| + dummy_pymodule = libutils.get_string_module(self.project, '')
|
| + self.old_pyname = pynames.ImportedModule(dummy_pymodule,
|
| + resource=resource)
|
| + self.source = self.old_pyname.get_object().get_resource()
|
| + if self.source.is_folder():
|
| + self.old_name = self.source.name
|
| + else:
|
| + self.old_name = self.source.name[:-3]
|
| + self.tools = _MoveTools(self.project, self.source,
|
| + self.old_pyname, self.old_name)
|
| + self.import_tools = self.tools.import_tools
|
| +
|
| + def get_changes(self, dest, resources=None,
|
| + task_handle=taskhandle.NullTaskHandle()):
|
| + if resources is None:
|
| + resources = self.project.get_python_files()
|
| + if dest is None or not dest.is_folder():
|
| + raise exceptions.RefactoringError(
|
| + 'Move destination for modules should be packages.')
|
| + return self._calculate_changes(dest, resources, task_handle)
|
| +
|
| + def _calculate_changes(self, dest, resources, task_handle):
|
| + changes = ChangeSet('Moving module <%s>' % self.old_name)
|
| + job_set = task_handle.create_jobset('Collecting changes',
|
| + len(resources))
|
| + for module in resources:
|
| + job_set.started_job(module.path)
|
| + if module == self.source:
|
| + self._change_moving_module(changes, dest)
|
| + else:
|
| + source = self._change_occurrences_in_module(dest,
|
| + resource=module)
|
| + if source is not None:
|
| + changes.add_change(ChangeContents(module, source))
|
| + job_set.finished_job()
|
| + if self.project == self.source.project:
|
| + changes.add_change(MoveResource(self.source, dest.path))
|
| + return changes
|
| +
|
| + def _new_modname(self, dest):
|
| + destname = libutils.modname(dest)
|
| + if destname:
|
| + return destname + '.' + self.old_name
|
| + return self.old_name
|
| +
|
| + def _new_import(self, dest):
|
| + return importutils.NormalImport([(self._new_modname(dest), None)])
|
| +
|
| + def _change_moving_module(self, changes, dest):
|
| + if not self.source.is_folder():
|
| + pymodule = self.project.get_pymodule(self.source)
|
| + source = self.import_tools.relatives_to_absolutes(pymodule)
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| + source = self._change_occurrences_in_module(dest, pymodule)
|
| + source = self.tools.new_source(pymodule, source)
|
| + if source != self.source.read():
|
| + changes.add_change(ChangeContents(self.source, source))
|
| +
|
| + def _change_occurrences_in_module(self, dest, pymodule=None,
|
| + resource=None):
|
| + if not self.tools.occurs_in_module(pymodule=pymodule,
|
| + resource=resource):
|
| + return
|
| + if pymodule is None:
|
| + pymodule = self.project.get_pymodule(resource)
|
| + new_name = self._new_modname(dest)
|
| + module_imports = importutils.get_module_imports(self.project, pymodule)
|
| + changed = False
|
| +
|
| + source = None
|
| + if libutils.modname(dest):
|
| + changed = self._change_import_statements(dest, new_name,
|
| + module_imports)
|
| + if changed:
|
| + source = module_imports.get_changed_source()
|
| + source = self.tools.new_source(pymodule, source)
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| +
|
| + new_import = self._new_import(dest)
|
| + source = self.tools.rename_in_module(
|
| + new_name, imports=True, pymodule=pymodule,
|
| + resource=resource if not changed else None)
|
| + should_import = self.tools.occurs_in_module(
|
| + pymodule=pymodule, resource=resource, imports=False)
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| + source = self.tools.remove_old_imports(pymodule)
|
| + if should_import:
|
| + pymodule = self.tools.new_pymodule(pymodule, source)
|
| + source = self.tools.add_imports(pymodule, [new_import])
|
| + source = self.tools.new_source(pymodule, source)
|
| + if source is not None and source != pymodule.resource.read():
|
| + return source
|
| + return None
|
| +
|
| +
|
| + def _change_import_statements(self, dest, new_name, module_imports):
|
| + moving_module = self.source
|
| + parent_module = moving_module.parent
|
| +
|
| + changed = False
|
| + for import_stmt in module_imports.imports:
|
| + if not any(name_and_alias[0] == self.old_name
|
| + for name_and_alias in
|
| + import_stmt.import_info.names_and_aliases) and \
|
| + not any(name_and_alias[0] == libutils.modname(self.source)
|
| + for name_and_alias in
|
| + import_stmt.import_info.names_and_aliases):
|
| + continue
|
| +
|
| + # Case 1: Look for normal imports of the moving module.
|
| + if isinstance(import_stmt.import_info, importutils.NormalImport):
|
| + continue
|
| +
|
| + # Case 2: The moving module is from-imported.
|
| + changed = self._handle_moving_in_from_import_stmt(
|
| + dest, import_stmt, module_imports, parent_module) or changed
|
| +
|
| + # Case 3: Names are imported from the moving module.
|
| + context = importutils.importinfo.ImportContext(self.project, None)
|
| + if not import_stmt.import_info.is_empty() and \
|
| + import_stmt.import_info.get_imported_resource(context) == \
|
| + moving_module:
|
| + import_stmt.import_info = importutils.FromImport(
|
| + new_name, import_stmt.import_info.level,
|
| + import_stmt.import_info.names_and_aliases)
|
| + changed = True
|
| +
|
| + return changed
|
| +
|
| + def _handle_moving_in_from_import_stmt(self, dest, import_stmt,
|
| + module_imports, parent_module):
|
| + changed = False
|
| + context = importutils.importinfo.ImportContext(self.project, None)
|
| + if import_stmt.import_info.get_imported_resource(context) == \
|
| + parent_module:
|
| + imports = import_stmt.import_info.names_and_aliases
|
| + new_imports = []
|
| + for name, alias in imports:
|
| + # The moving module was imported.
|
| + if name == self.old_name:
|
| + changed = True
|
| + new_import = importutils.FromImport(
|
| + libutils.modname(dest), 0,
|
| + [(self.old_name, alias)])
|
| + module_imports.add_import(new_import)
|
| + else:
|
| + new_imports.append((name, alias))
|
| +
|
| + # Update the imports if the imported names were changed.
|
| + if new_imports != imports:
|
| + changed = True
|
| + if new_imports:
|
| + import_stmt.import_info = importutils.FromImport(
|
| + import_stmt.import_info.module_name,
|
| + import_stmt.import_info.level,
|
| + new_imports)
|
| + else:
|
| + import_stmt.empty_import()
|
| + return changed
|
| +
|
| +
|
| +class _ChangeMoveOccurrencesHandle(object):
|
| +
|
| + def __init__(self, new_name):
|
| + self.new_name = new_name
|
| + self.occurred = False
|
| +
|
| + def occurred_inside_skip(self, change_collector, occurrence):
|
| + pass
|
| +
|
| + def occurred_outside_skip(self, change_collector, occurrence):
|
| + start, end = occurrence.get_primary_range()
|
| + change_collector.add_change(start, end, self.new_name)
|
| + self.occurred = True
|
| +
|
| +
|
| +class _MoveTools(object):
|
| +
|
| + def __init__(self, project, source, pyname, old_name):
|
| + self.project = project
|
| + self.source = source
|
| + self.old_pyname = pyname
|
| + self.old_name = old_name
|
| + self.import_tools = importutils.ImportTools(self.project)
|
| +
|
| + def remove_old_imports(self, pymodule):
|
| + old_source = pymodule.source_code
|
| + module_with_imports = self.import_tools.module_imports(pymodule)
|
| +
|
| + class CanSelect(object):
|
| + changed = False
|
| + old_name = self.old_name
|
| + old_pyname = self.old_pyname
|
| +
|
| + def __call__(self, name):
|
| + try:
|
| + if name == self.old_name and \
|
| + pymodule[name].get_object() == \
|
| + self.old_pyname.get_object():
|
| + self.changed = True
|
| + return False
|
| + except exceptions.AttributeNotFoundError:
|
| + pass
|
| + return True
|
| + can_select = CanSelect()
|
| + module_with_imports.filter_names(can_select)
|
| + new_source = module_with_imports.get_changed_source()
|
| + if old_source != new_source:
|
| + return new_source
|
| +
|
| + def rename_in_module(self, new_name, pymodule=None,
|
| + imports=False, resource=None):
|
| + occurrence_finder = self._create_finder(imports)
|
| + source = rename.rename_in_module(
|
| + occurrence_finder, new_name, replace_primary=True,
|
| + pymodule=pymodule, resource=resource)
|
| + return source
|
| +
|
| + def occurs_in_module(self, pymodule=None, resource=None, imports=True):
|
| + finder = self._create_finder(imports)
|
| + for occurrence in finder.find_occurrences(pymodule=pymodule,
|
| + resource=resource):
|
| + return True
|
| + return False
|
| +
|
| + def _create_finder(self, imports):
|
| + return occurrences.create_finder(self.project, self.old_name,
|
| + self.old_pyname, imports=imports)
|
| +
|
| + def new_pymodule(self, pymodule, source):
|
| + if source is not None:
|
| + return libutils.get_string_module(
|
| + self.project, source, pymodule.get_resource())
|
| + return pymodule
|
| +
|
| + def new_source(self, pymodule, source):
|
| + if source is None:
|
| + return pymodule.source_code
|
| + return source
|
| +
|
| + def add_imports(self, pymodule, new_imports):
|
| + return _add_imports_to_module(self.import_tools, pymodule, new_imports)
|
| +
|
| +
|
| +def _add_imports_to_module(import_tools, pymodule, new_imports):
|
| + module_with_imports = import_tools.module_imports(pymodule)
|
| + for new_import in new_imports:
|
| + module_with_imports.add_import(new_import)
|
| + return module_with_imports.get_changed_source()
|
| +
|
| +
|
| +def moving_code_with_imports(project, resource, source):
|
| + import_tools = importutils.ImportTools(project)
|
| + pymodule = libutils.get_string_module(project, source, resource)
|
| + origin = project.get_pymodule(resource)
|
| +
|
| + imports = []
|
| + for stmt in import_tools.module_imports(origin).imports:
|
| + imports.append(stmt.import_info)
|
| +
|
| + back_names = []
|
| + for name in origin:
|
| + if name not in pymodule:
|
| + back_names.append(name)
|
| + imports.append(import_tools.get_from_import(resource, back_names))
|
| +
|
| + source = _add_imports_to_module(import_tools, pymodule, imports)
|
| + pymodule = libutils.get_string_module(project, source, resource)
|
| +
|
| + source = import_tools.relatives_to_absolutes(pymodule)
|
| + pymodule = libutils.get_string_module(project, source, resource)
|
| + source = import_tools.organize_imports(pymodule, selfs=False)
|
| + pymodule = libutils.get_string_module(project, source, resource)
|
| +
|
| + # extracting imports after changes
|
| + module_imports = import_tools.module_imports(pymodule)
|
| + imports = [import_stmt.import_info
|
| + for import_stmt in module_imports.imports]
|
| + start = 1
|
| + if module_imports.imports:
|
| + start = module_imports.imports[-1].end_line
|
| + lines = codeanalyze.SourceLinesAdapter(source)
|
| + while start < lines.length() and not lines.get_line(start).strip():
|
| + start += 1
|
| + moving = source[lines.get_line_start(start):]
|
| + return moving, imports
|
| +
|
| +
|
| +class ModuleSkipRenamerHandle(object):
|
| +
|
| + def occurred_outside_skip(self, change_collector, occurrence):
|
| + pass
|
| +
|
| + def occurred_inside_skip(self, change_collector, occurrence):
|
| + pass
|
| +
|
| +
|
| +class ModuleSkipRenamer(object):
|
| + """Rename occurrences in a module
|
| +
|
| + This class can be used when you want to treat a region in a file
|
| + separately from other parts when renaming.
|
| +
|
| + """
|
| +
|
| + def __init__(self, occurrence_finder, resource, handle=None,
|
| + skip_start=0, skip_end=0, replacement=''):
|
| + """Constructor
|
| +
|
| + if replacement is `None` the region is not changed. Otherwise
|
| + it is replaced with `replacement`.
|
| +
|
| + """
|
| + self.occurrence_finder = occurrence_finder
|
| + self.resource = resource
|
| + self.skip_start = skip_start
|
| + self.skip_end = skip_end
|
| + self.replacement = replacement
|
| + self.handle = handle
|
| + if self.handle is None:
|
| + self.handle = ModuleSkipRenamerHandle()
|
| +
|
| + def get_changed_module(self):
|
| + source = self.resource.read()
|
| + change_collector = codeanalyze.ChangeCollector(source)
|
| + if self.replacement is not None:
|
| + change_collector.add_change(self.skip_start, self.skip_end,
|
| + self.replacement)
|
| + for occurrence in self.occurrence_finder.find_occurrences(
|
| + self.resource):
|
| + start, end = occurrence.get_primary_range()
|
| + if self.skip_start <= start < self.skip_end:
|
| + self.handle.occurred_inside_skip(change_collector, occurrence)
|
| + else:
|
| + self.handle.occurred_outside_skip(change_collector, occurrence)
|
| + result = change_collector.get_changed()
|
| + if result is not None and result != source:
|
| + return result
|
|
|