Path: blob/master/elisp/emacs-for-python/rope-dist/rope/refactor/method_object.py
1415 views
import warnings12from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze3from rope.refactor import sourceutils, occurrences, rename456class MethodObject(object):78def __init__(self, project, resource, offset):9self.pycore = project.pycore10this_pymodule = self.pycore.resource_to_pyobject(resource)11pyname = evaluate.eval_location(this_pymodule, offset)12if pyname is None or not isinstance(pyname.get_object(),13pyobjects.PyFunction):14raise exceptions.RefactoringError(15'Replace method with method object refactoring should be '16'performed on a function.')17self.pyfunction = pyname.get_object()18self.pymodule = self.pyfunction.get_module()19self.resource = self.pymodule.get_resource()2021def get_new_class(self, name):22body = sourceutils.fix_indentation(23self._get_body(), sourceutils.get_indent(self.pycore) * 2)24return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \25(name, self._get_init(),26' ' * sourceutils.get_indent(self.pycore), body)2728def get_changes(self, classname=None, new_class_name=None):29if new_class_name is not None:30warnings.warn(31'new_class_name parameter is deprecated; use classname',32DeprecationWarning, stacklevel=2)33classname = new_class_name34collector = codeanalyze.ChangeCollector(self.pymodule.source_code)35start, end = sourceutils.get_body_region(self.pyfunction)36indents = sourceutils.get_indents(37self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \38sourceutils.get_indent(self.pycore)39new_contents = ' ' * indents + 'return %s(%s)()\n' % \40(classname, ', '.join(self._get_parameter_names()))41collector.add_change(start, end, new_contents)42insertion = self._get_class_insertion_point()43collector.add_change(insertion, insertion,44'\n\n' + self.get_new_class(classname))45changes = change.ChangeSet('Replace method with method object refactoring')46changes.add_change(change.ChangeContents(self.resource,47collector.get_changed()))48return changes4950def _get_class_insertion_point(self):51current = self.pyfunction52while current.parent != self.pymodule:53current = current.parent54end = self.pymodule.lines.get_line_end(current.get_scope().get_end())55return min(end + 1, len(self.pymodule.source_code))5657def _get_body(self):58body = sourceutils.get_body(self.pyfunction)59for param in self._get_parameter_names():60body = param + ' = None\n' + body61pymod = self.pycore.get_string_module(body, self.resource)62pyname = pymod[param]63finder = occurrences.create_finder(self.pycore, param, pyname)64result = rename.rename_in_module(finder, 'self.' + param,65pymodule=pymod)66body = result[result.index('\n') + 1:]67return body6869def _get_init(self):70params = self._get_parameter_names()71indents = ' ' * sourceutils.get_indent(self.pycore)72if not params:73return ''74header = indents + 'def __init__(self'75body = ''76for arg in params:77new_name = arg78if arg == 'self':79new_name = 'host'80header += ', %s' % new_name81body += indents * 2 + 'self.%s = %s\n' % (arg, new_name)82header += '):'83return '%s\n%s\n' % (header, body)8485def _get_parameter_names(self):86return self.pyfunction.get_param_names()878889