| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- import rope.base.evaluate
- 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.pycore, 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.pycore, 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(pycore, resource, imported):
- pymodule = pycore.resource_to_pyobject(resource)
- import_tools = importutils.ImportTools(pycore)
- module_imports = import_tools.module_imports(pymodule)
- module_name = pycore.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.resource_to_pyobject(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.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])
|