Index: tools/telemetry/third_party/rope/rope/contrib/generate.py |
diff --git a/tools/telemetry/third_party/rope/rope/contrib/generate.py b/tools/telemetry/third_party/rope/rope/contrib/generate.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..825f26d6ddad24bb4fc2b5068884631ebb89580a |
--- /dev/null |
+++ b/tools/telemetry/third_party/rope/rope/contrib/generate.py |
@@ -0,0 +1,362 @@ |
+import rope.base.evaluate |
+from rope.base import libutils |
+from rope.base import (change, pyobjects, exceptions, pynames, worder, |
+ codeanalyze) |
+from rope.refactor import sourceutils, importutils, functionutils, suites |
+ |
+ |
+def create_generate(kind, project, resource, offset): |
+ """A factory for creating `Generate` objects |
+ |
+ `kind` can be 'variable', 'function', 'class', 'module' or |
+ 'package'. |
+ |
+ """ |
+ generate = eval('Generate' + kind.title()) |
+ return generate(project, resource, offset) |
+ |
+ |
+def create_module(project, name, sourcefolder=None): |
+ """Creates a module and returns a `rope.base.resources.File`""" |
+ if sourcefolder is None: |
+ sourcefolder = project.root |
+ packages = name.split('.') |
+ parent = sourcefolder |
+ for package in packages[:-1]: |
+ parent = parent.get_child(package) |
+ return parent.create_file(packages[-1] + '.py') |
+ |
+ |
+def create_package(project, name, sourcefolder=None): |
+ """Creates a package and returns a `rope.base.resources.Folder`""" |
+ if sourcefolder is None: |
+ sourcefolder = project.root |
+ packages = name.split('.') |
+ parent = sourcefolder |
+ for package in packages[:-1]: |
+ parent = parent.get_child(package) |
+ made_packages = parent.create_folder(packages[-1]) |
+ made_packages.create_file('__init__.py') |
+ return made_packages |
+ |
+ |
+class _Generate(object): |
+ |
+ def __init__(self, project, resource, offset): |
+ self.project = project |
+ self.resource = resource |
+ self.info = self._generate_info(project, resource, offset) |
+ self.name = self.info.get_name() |
+ self._check_exceptional_conditions() |
+ |
+ def _generate_info(self, project, resource, offset): |
+ return _GenerationInfo(project.pycore, resource, offset) |
+ |
+ def _check_exceptional_conditions(self): |
+ if self.info.element_already_exists(): |
+ raise exceptions.RefactoringError( |
+ 'Element <%s> already exists.' % self.name) |
+ if not self.info.primary_is_found(): |
+ raise exceptions.RefactoringError( |
+ 'Cannot determine the scope <%s> should be defined in.' % |
+ self.name) |
+ |
+ def get_changes(self): |
+ changes = change.ChangeSet('Generate %s <%s>' % |
+ (self._get_element_kind(), self.name)) |
+ indents = self.info.get_scope_indents() |
+ blanks = self.info.get_blank_lines() |
+ base_definition = sourceutils.fix_indentation(self._get_element(), |
+ indents) |
+ definition = '\n' * blanks[0] + base_definition + '\n' * blanks[1] |
+ |
+ resource = self.info.get_insertion_resource() |
+ start, end = self.info.get_insertion_offsets() |
+ |
+ collector = codeanalyze.ChangeCollector(resource.read()) |
+ collector.add_change(start, end, definition) |
+ changes.add_change(change.ChangeContents( |
+ resource, collector.get_changed())) |
+ return changes |
+ |
+ def get_location(self): |
+ return (self.info.get_insertion_resource(), |
+ self.info.get_insertion_lineno()) |
+ |
+ def _get_element_kind(self): |
+ raise NotImplementedError() |
+ |
+ def _get_element(self): |
+ raise NotImplementedError() |
+ |
+ |
+class GenerateFunction(_Generate): |
+ |
+ def _generate_info(self, project, resource, offset): |
+ return _FunctionGenerationInfo(project.pycore, resource, offset) |
+ |
+ def _get_element(self): |
+ decorator = '' |
+ args = [] |
+ if self.info.is_static_method(): |
+ decorator = '@staticmethod\n' |
+ if self.info.is_method() or self.info.is_constructor() or \ |
+ self.info.is_instance(): |
+ args.append('self') |
+ args.extend(self.info.get_passed_args()) |
+ definition = '%sdef %s(%s):\n pass\n' % (decorator, self.name, |
+ ', '.join(args)) |
+ return definition |
+ |
+ def _get_element_kind(self): |
+ return 'Function' |
+ |
+ |
+class GenerateVariable(_Generate): |
+ |
+ def _get_element(self): |
+ return '%s = None\n' % self.name |
+ |
+ def _get_element_kind(self): |
+ return 'Variable' |
+ |
+ |
+class GenerateClass(_Generate): |
+ |
+ def _get_element(self): |
+ return 'class %s(object):\n pass\n' % self.name |
+ |
+ def _get_element_kind(self): |
+ return 'Class' |
+ |
+ |
+class GenerateModule(_Generate): |
+ |
+ def get_changes(self): |
+ package = self.info.get_package() |
+ changes = change.ChangeSet('Generate Module <%s>' % self.name) |
+ new_resource = self.project.get_file('%s/%s.py' % |
+ (package.path, self.name)) |
+ if new_resource.exists(): |
+ raise exceptions.RefactoringError( |
+ 'Module <%s> already exists' % new_resource.path) |
+ changes.add_change(change.CreateResource(new_resource)) |
+ changes.add_change(_add_import_to_module( |
+ self.project, self.resource, new_resource)) |
+ return changes |
+ |
+ def get_location(self): |
+ package = self.info.get_package() |
+ return (package.get_child('%s.py' % self.name), 1) |
+ |
+ |
+class GeneratePackage(_Generate): |
+ |
+ def get_changes(self): |
+ package = self.info.get_package() |
+ changes = change.ChangeSet('Generate Package <%s>' % self.name) |
+ new_resource = self.project.get_folder('%s/%s' % |
+ (package.path, self.name)) |
+ if new_resource.exists(): |
+ raise exceptions.RefactoringError( |
+ 'Package <%s> already exists' % new_resource.path) |
+ changes.add_change(change.CreateResource(new_resource)) |
+ changes.add_change(_add_import_to_module( |
+ self.project, self.resource, new_resource)) |
+ child = self.project.get_folder(package.path + '/' + self.name) |
+ changes.add_change(change.CreateFile(child, '__init__.py')) |
+ return changes |
+ |
+ def get_location(self): |
+ package = self.info.get_package() |
+ child = package.get_child(self.name) |
+ return (child.get_child('__init__.py'), 1) |
+ |
+ |
+def _add_import_to_module(project, resource, imported): |
+ pymodule = project.get_pymodule(resource) |
+ import_tools = importutils.ImportTools(project) |
+ module_imports = import_tools.module_imports(pymodule) |
+ module_name = libutils.modname(imported) |
+ new_import = importutils.NormalImport(((module_name, None), )) |
+ module_imports.add_import(new_import) |
+ return change.ChangeContents(resource, module_imports.get_changed_source()) |
+ |
+ |
+class _GenerationInfo(object): |
+ |
+ def __init__(self, pycore, resource, offset): |
+ self.pycore = pycore |
+ self.resource = resource |
+ self.offset = offset |
+ self.source_pymodule = self.pycore.project.get_pymodule(resource) |
+ finder = rope.base.evaluate.ScopeNameFinder(self.source_pymodule) |
+ self.primary, self.pyname = finder.get_primary_and_pyname_at(offset) |
+ self._init_fields() |
+ |
+ def _init_fields(self): |
+ self.source_scope = self._get_source_scope() |
+ self.goal_scope = self._get_goal_scope() |
+ self.goal_pymodule = self._get_goal_module(self.goal_scope) |
+ |
+ def _get_goal_scope(self): |
+ if self.primary is None: |
+ return self._get_source_scope() |
+ pyobject = self.primary.get_object() |
+ if isinstance(pyobject, pyobjects.PyDefinedObject): |
+ return pyobject.get_scope() |
+ elif isinstance(pyobject.get_type(), pyobjects.PyClass): |
+ return pyobject.get_type().get_scope() |
+ |
+ def _get_goal_module(self, scope): |
+ if scope is None: |
+ return |
+ while scope.parent is not None: |
+ scope = scope.parent |
+ return scope.pyobject |
+ |
+ def _get_source_scope(self): |
+ module_scope = self.source_pymodule.get_scope() |
+ lineno = self.source_pymodule.lines.get_line_number(self.offset) |
+ return module_scope.get_inner_scope_for_line(lineno) |
+ |
+ def get_insertion_lineno(self): |
+ lines = self.goal_pymodule.lines |
+ if self.goal_scope == self.source_scope: |
+ line_finder = self.goal_pymodule.logical_lines |
+ lineno = lines.get_line_number(self.offset) |
+ lineno = line_finder.logical_line_in(lineno)[0] |
+ root = suites.ast_suite_tree(self.goal_scope.pyobject.get_ast()) |
+ suite = root.find_suite(lineno) |
+ indents = sourceutils.get_indents(lines, lineno) |
+ while self.get_scope_indents() < indents: |
+ lineno = suite.get_start() |
+ indents = sourceutils.get_indents(lines, lineno) |
+ suite = suite.parent |
+ return lineno |
+ else: |
+ return min(self.goal_scope.get_end() + 1, lines.length()) |
+ |
+ def get_insertion_resource(self): |
+ return self.goal_pymodule.get_resource() |
+ |
+ def get_insertion_offsets(self): |
+ if self.goal_scope.get_kind() == 'Class': |
+ start, end = sourceutils.get_body_region(self.goal_scope.pyobject) |
+ if self.goal_pymodule.source_code[start:end].strip() == 'pass': |
+ return start, end |
+ lines = self.goal_pymodule.lines |
+ start = lines.get_line_start(self.get_insertion_lineno()) |
+ return (start, start) |
+ |
+ def get_scope_indents(self): |
+ if self.goal_scope.get_kind() == 'Module': |
+ return 0 |
+ return sourceutils.get_indents(self.goal_pymodule.lines, |
+ self.goal_scope.get_start()) + 4 |
+ |
+ def get_blank_lines(self): |
+ if self.goal_scope.get_kind() == 'Module': |
+ base_blanks = 2 |
+ if self.goal_pymodule.source_code.strip() == '': |
+ base_blanks = 0 |
+ if self.goal_scope.get_kind() == 'Class': |
+ base_blanks = 1 |
+ if self.goal_scope.get_kind() == 'Function': |
+ base_blanks = 0 |
+ if self.goal_scope == self.source_scope: |
+ return (0, base_blanks) |
+ return (base_blanks, 0) |
+ |
+ def get_package(self): |
+ primary = self.primary |
+ if self.primary is None: |
+ return self.pycore.project.get_source_folders()[0] |
+ if isinstance(primary.get_object(), pyobjects.PyPackage): |
+ return primary.get_object().get_resource() |
+ raise exceptions.RefactoringError( |
+ 'A module/package can be only created in a package.') |
+ |
+ def primary_is_found(self): |
+ return self.goal_scope is not None |
+ |
+ def element_already_exists(self): |
+ if self.pyname is None or isinstance(self.pyname, pynames.UnboundName): |
+ return False |
+ return self.get_name() in self.goal_scope.get_defined_names() |
+ |
+ def get_name(self): |
+ return worder.get_name_at(self.resource, self.offset) |
+ |
+ |
+class _FunctionGenerationInfo(_GenerationInfo): |
+ |
+ def _get_goal_scope(self): |
+ if self.is_constructor(): |
+ return self.pyname.get_object().get_scope() |
+ if self.is_instance(): |
+ return self.pyname.get_object().get_type().get_scope() |
+ if self.primary is None: |
+ return self._get_source_scope() |
+ pyobject = self.primary.get_object() |
+ if isinstance(pyobject, pyobjects.PyDefinedObject): |
+ return pyobject.get_scope() |
+ elif isinstance(pyobject.get_type(), pyobjects.PyClass): |
+ return pyobject.get_type().get_scope() |
+ |
+ def element_already_exists(self): |
+ if self.pyname is None or isinstance(self.pyname, pynames.UnboundName): |
+ return False |
+ return self.get_name() in self.goal_scope.get_defined_names() |
+ |
+ def is_static_method(self): |
+ return self.primary is not None and \ |
+ isinstance(self.primary.get_object(), pyobjects.PyClass) |
+ |
+ def is_method(self): |
+ return self.primary is not None and \ |
+ isinstance(self.primary.get_object().get_type(), pyobjects.PyClass) |
+ |
+ def is_constructor(self): |
+ return self.pyname is not None and \ |
+ isinstance(self.pyname.get_object(), pyobjects.PyClass) |
+ |
+ def is_instance(self): |
+ if self.pyname is None: |
+ return False |
+ pyobject = self.pyname.get_object() |
+ return isinstance(pyobject.get_type(), pyobjects.PyClass) |
+ |
+ def get_name(self): |
+ if self.is_constructor(): |
+ return '__init__' |
+ if self.is_instance(): |
+ return '__call__' |
+ return worder.get_name_at(self.resource, self.offset) |
+ |
+ def get_passed_args(self): |
+ result = [] |
+ source = self.source_pymodule.source_code |
+ finder = worder.Worder(source) |
+ if finder.is_a_function_being_called(self.offset): |
+ start, end = finder.get_primary_range(self.offset) |
+ parens_start, parens_end = finder.get_word_parens_range(end - 1) |
+ call = source[start:parens_end] |
+ parser = functionutils._FunctionParser(call, False) |
+ args, keywords = parser.get_parameters() |
+ for arg in args: |
+ if self._is_id(arg): |
+ result.append(arg) |
+ else: |
+ result.append('arg%d' % len(result)) |
+ for name, value in keywords: |
+ result.append(name) |
+ return result |
+ |
+ def _is_id(self, arg): |
+ def id_or_underline(c): |
+ return c.isalpha() or c == '_' |
+ for c in arg: |
+ if not id_or_underline(c) and not c.isdigit(): |
+ return False |
+ return id_or_underline(arg[0]) |