Index: tools/telemetry/third_party/rope/rope/refactor/introduce_factory.py |
diff --git a/tools/telemetry/third_party/rope/rope/refactor/introduce_factory.py b/tools/telemetry/third_party/rope/rope/refactor/introduce_factory.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7532e361a808543b65c0bb9768964901ff90e15b |
--- /dev/null |
+++ b/tools/telemetry/third_party/rope/rope/refactor/introduce_factory.py |
@@ -0,0 +1,135 @@ |
+import rope.base.exceptions |
+import rope.base.pyobjects |
+from rope.base import libutils |
+from rope.base import taskhandle, evaluate |
+from rope.base.change import (ChangeSet, ChangeContents) |
+from rope.refactor import rename, occurrences, sourceutils, importutils |
+ |
+ |
+class IntroduceFactory(object): |
+ |
+ def __init__(self, project, resource, offset): |
+ self.project = project |
+ self.offset = offset |
+ |
+ this_pymodule = self.project.get_pymodule(resource) |
+ self.old_pyname = evaluate.eval_location(this_pymodule, offset) |
+ if self.old_pyname is None or \ |
+ not isinstance(self.old_pyname.get_object(), |
+ rope.base.pyobjects.PyClass): |
+ raise rope.base.exceptions.RefactoringError( |
+ 'Introduce factory should be performed on a class.') |
+ self.old_name = self.old_pyname.get_object().get_name() |
+ self.pymodule = self.old_pyname.get_object().get_module() |
+ self.resource = self.pymodule.get_resource() |
+ |
+ def get_changes(self, factory_name, global_factory=False, resources=None, |
+ task_handle=taskhandle.NullTaskHandle()): |
+ """Get the changes this refactoring makes |
+ |
+ `factory_name` indicates the name of the factory function to |
+ be added. If `global_factory` is `True` the factory will be |
+ global otherwise a static method is added to the class. |
+ |
+ `resources` can be a list of `rope.base.resource.File`\s that |
+ this refactoring should be applied on; if `None` all python |
+ files in the project are searched. |
+ |
+ """ |
+ if resources is None: |
+ resources = self.project.get_python_files() |
+ changes = ChangeSet('Introduce factory method <%s>' % factory_name) |
+ job_set = task_handle.create_jobset('Collecting Changes', |
+ len(resources)) |
+ self._change_module(resources, changes, factory_name, |
+ global_factory, job_set) |
+ return changes |
+ |
+ def get_name(self): |
+ """Return the name of the class""" |
+ return self.old_name |
+ |
+ def _change_module(self, resources, changes, |
+ factory_name, global_, job_set): |
+ if global_: |
+ replacement = '__rope_factory_%s_' % factory_name |
+ else: |
+ replacement = self._new_function_name(factory_name, global_) |
+ |
+ for file_ in resources: |
+ job_set.started_job(file_.path) |
+ if file_ == self.resource: |
+ self._change_resource(changes, factory_name, global_) |
+ job_set.finished_job() |
+ continue |
+ changed_code = self._rename_occurrences(file_, replacement, |
+ global_) |
+ if changed_code is not None: |
+ if global_: |
+ new_pymodule = libutils.get_string_module( |
+ self.project, changed_code, self.resource) |
+ modname = libutils.modname(self.resource) |
+ changed_code, imported = importutils.add_import( |
+ self.project, new_pymodule, modname, factory_name) |
+ changed_code = changed_code.replace(replacement, imported) |
+ changes.add_change(ChangeContents(file_, changed_code)) |
+ job_set.finished_job() |
+ |
+ def _change_resource(self, changes, factory_name, global_): |
+ class_scope = self.old_pyname.get_object().get_scope() |
+ source_code = self._rename_occurrences( |
+ self.resource, self._new_function_name(factory_name, |
+ global_), global_) |
+ if source_code is None: |
+ source_code = self.pymodule.source_code |
+ else: |
+ self.pymodule = libutils.get_string_module( |
+ self.project, source_code, resource=self.resource) |
+ lines = self.pymodule.lines |
+ start = self._get_insertion_offset(class_scope, lines) |
+ result = source_code[:start] |
+ result += self._get_factory_method(lines, class_scope, |
+ factory_name, global_) |
+ result += source_code[start:] |
+ changes.add_change(ChangeContents(self.resource, result)) |
+ |
+ def _get_insertion_offset(self, class_scope, lines): |
+ start_line = class_scope.get_end() |
+ if class_scope.get_scopes(): |
+ start_line = class_scope.get_scopes()[-1].get_end() |
+ start = lines.get_line_end(start_line) + 1 |
+ return start |
+ |
+ def _get_factory_method(self, lines, class_scope, |
+ factory_name, global_): |
+ unit_indents = ' ' * sourceutils.get_indent(self.project) |
+ if global_: |
+ if self._get_scope_indents(lines, class_scope) > 0: |
+ raise rope.base.exceptions.RefactoringError( |
+ 'Cannot make global factory method for nested classes.') |
+ return ('\ndef %s(*args, **kwds):\n%sreturn %s(*args, **kwds)\n' % |
+ (factory_name, unit_indents, self.old_name)) |
+ unindented_factory = \ |
+ ('@staticmethod\ndef %s(*args, **kwds):\n' % factory_name + |
+ '%sreturn %s(*args, **kwds)\n' % (unit_indents, self.old_name)) |
+ indents = self._get_scope_indents(lines, class_scope) + \ |
+ sourceutils.get_indent(self.project) |
+ return '\n' + sourceutils.indent_lines(unindented_factory, indents) |
+ |
+ def _get_scope_indents(self, lines, scope): |
+ return sourceutils.get_indents(lines, scope.get_start()) |
+ |
+ def _new_function_name(self, factory_name, global_): |
+ if global_: |
+ return factory_name |
+ else: |
+ return self.old_name + '.' + factory_name |
+ |
+ def _rename_occurrences(self, file_, changed_name, global_factory): |
+ finder = occurrences.create_finder(self.project, self.old_name, |
+ self.old_pyname, only_calls=True) |
+ result = rename.rename_in_module(finder, changed_name, resource=file_, |
+ replace_primary=global_factory) |
+ return result |
+ |
+IntroduceFactoryRefactoring = IntroduceFactory |