Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Unified Diff: tools/telemetry/third_party/rope/rope/contrib/generate.py

Issue 1132103009: Example of refactoring using rope library. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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])
« no previous file with comments | « tools/telemetry/third_party/rope/rope/contrib/fixsyntax.py ('k') | tools/telemetry/third_party/rope/rope/refactor/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698