Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/emacs-for-python/rope-dist/rope/refactor/method_object.py
1415 views
1
import warnings
2
3
from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze
4
from rope.refactor import sourceutils, occurrences, rename
5
6
7
class MethodObject(object):
8
9
def __init__(self, project, resource, offset):
10
self.pycore = project.pycore
11
this_pymodule = self.pycore.resource_to_pyobject(resource)
12
pyname = evaluate.eval_location(this_pymodule, offset)
13
if pyname is None or not isinstance(pyname.get_object(),
14
pyobjects.PyFunction):
15
raise exceptions.RefactoringError(
16
'Replace method with method object refactoring should be '
17
'performed on a function.')
18
self.pyfunction = pyname.get_object()
19
self.pymodule = self.pyfunction.get_module()
20
self.resource = self.pymodule.get_resource()
21
22
def get_new_class(self, name):
23
body = sourceutils.fix_indentation(
24
self._get_body(), sourceutils.get_indent(self.pycore) * 2)
25
return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \
26
(name, self._get_init(),
27
' ' * sourceutils.get_indent(self.pycore), body)
28
29
def get_changes(self, classname=None, new_class_name=None):
30
if new_class_name is not None:
31
warnings.warn(
32
'new_class_name parameter is deprecated; use classname',
33
DeprecationWarning, stacklevel=2)
34
classname = new_class_name
35
collector = codeanalyze.ChangeCollector(self.pymodule.source_code)
36
start, end = sourceutils.get_body_region(self.pyfunction)
37
indents = sourceutils.get_indents(
38
self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \
39
sourceutils.get_indent(self.pycore)
40
new_contents = ' ' * indents + 'return %s(%s)()\n' % \
41
(classname, ', '.join(self._get_parameter_names()))
42
collector.add_change(start, end, new_contents)
43
insertion = self._get_class_insertion_point()
44
collector.add_change(insertion, insertion,
45
'\n\n' + self.get_new_class(classname))
46
changes = change.ChangeSet('Replace method with method object refactoring')
47
changes.add_change(change.ChangeContents(self.resource,
48
collector.get_changed()))
49
return changes
50
51
def _get_class_insertion_point(self):
52
current = self.pyfunction
53
while current.parent != self.pymodule:
54
current = current.parent
55
end = self.pymodule.lines.get_line_end(current.get_scope().get_end())
56
return min(end + 1, len(self.pymodule.source_code))
57
58
def _get_body(self):
59
body = sourceutils.get_body(self.pyfunction)
60
for param in self._get_parameter_names():
61
body = param + ' = None\n' + body
62
pymod = self.pycore.get_string_module(body, self.resource)
63
pyname = pymod[param]
64
finder = occurrences.create_finder(self.pycore, param, pyname)
65
result = rename.rename_in_module(finder, 'self.' + param,
66
pymodule=pymod)
67
body = result[result.index('\n') + 1:]
68
return body
69
70
def _get_init(self):
71
params = self._get_parameter_names()
72
indents = ' ' * sourceutils.get_indent(self.pycore)
73
if not params:
74
return ''
75
header = indents + 'def __init__(self'
76
body = ''
77
for arg in params:
78
new_name = arg
79
if arg == 'self':
80
new_name = 'host'
81
header += ', %s' % new_name
82
body += indents * 2 + 'self.%s = %s\n' % (arg, new_name)
83
header += '):'
84
return '%s\n%s\n' % (header, body)
85
86
def _get_parameter_names(self):
87
return self.pyfunction.get_param_names()
88
89