Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/emacs-for-python/rope-dist/ropemode/refactor.py
990 views
1
import re
2
3
import rope.base.change
4
import rope.contrib.generate
5
import rope.refactor.change_signature
6
import rope.refactor.extract
7
import rope.refactor.inline
8
import rope.refactor.introduce_factory
9
import rope.refactor.method_object
10
import rope.refactor.move
11
import rope.refactor.rename
12
import rope.refactor.restructure
13
import rope.refactor.usefunction
14
from rope.base import taskhandle
15
16
from ropemode import dialog, filter
17
18
19
class Refactoring(object):
20
key = None
21
confs = {}
22
optionals = {}
23
saveall = True
24
25
def __init__(self, interface, env):
26
self.interface = interface
27
self.env = env
28
29
def show(self, initial_asking=True):
30
self.interface._check_project()
31
self.interface._save_buffers(only_current=not self.saveall)
32
self._create_refactoring()
33
action, result = dialog.show_dialog(
34
self.interface._askdata, ['perform', 'preview', 'cancel'],
35
self._get_confs(), self._get_optionals(),
36
initial_asking=initial_asking)
37
if action == 'cancel':
38
self.env.message('Cancelled!')
39
return
40
def calculate(handle):
41
return self._calculate_changes(result, handle)
42
name = 'Calculating %s changes' % self.name
43
changes = runtask(self.env, calculate, name=name)
44
if action == 'perform':
45
self._perform(changes)
46
if action == 'preview':
47
if changes is not None:
48
diffs = changes.get_description()
49
if self.env.preview_changes(diffs):
50
self._perform(changes)
51
else:
52
self.env.message('Thrown away!')
53
else:
54
self.env.message('No changes!')
55
56
@property
57
def project(self):
58
return self.interface.project
59
60
@property
61
def resource(self):
62
return self.interface._get_resource()
63
64
@property
65
def offset(self):
66
return self.env.get_offset()
67
68
@property
69
def region(self):
70
return self.env.get_region()
71
72
@property
73
def name(self):
74
return refactoring_name(self.__class__)
75
76
def _calculate_changes(self, option_values, task_handle):
77
pass
78
79
def _create_refactoring(self):
80
pass
81
82
def _done(self):
83
pass
84
85
def _perform(self, changes):
86
if changes is None:
87
self.env.message('No changes!')
88
return
89
def perform(handle, self=self, changes=changes):
90
self.project.do(changes, task_handle=handle)
91
self.interface._reload_buffers(changes)
92
self._done()
93
runtask(self.env, perform, 'Making %s changes' % self.name,
94
interrupts=False)
95
self.env.message(str(changes.description) + ' finished')
96
97
def _get_confs(self):
98
return self.confs
99
100
def _get_optionals(self):
101
return self.optionals
102
103
@property
104
def resources_option(self):
105
return dialog.Data('Files to apply this refactoring on: ',
106
decode=self._decode_resources)
107
108
def _decode_resources(self, value):
109
return _resources(self.project, value)
110
111
112
class Rename(Refactoring):
113
key = 'r'
114
115
saveall = True
116
117
def _create_refactoring(self):
118
self.renamer = rope.refactor.rename.Rename(
119
self.project, self.resource, self.offset)
120
121
def _calculate_changes(self, values, task_handle):
122
return self.renamer.get_changes(task_handle=task_handle, **values)
123
124
def _get_optionals(self):
125
opts = {}
126
opts['docs'] = dialog.Boolean('Search comments and docs: ', True)
127
if self.renamer.is_method():
128
opts['in_hierarchy'] = dialog.Boolean('Rename methods in '
129
'class hierarchy: ')
130
opts['resources'] = self.resources_option
131
opts['unsure'] = dialog.Data('Unsure occurrences: ',
132
decode=self._decode_unsure,
133
values=['ignore', 'match'],
134
default='ignore')
135
return opts
136
137
def _get_confs(self):
138
oldname = str(self.renamer.get_old_name())
139
return {'new_name': dialog.Data('New name: ', default=oldname)}
140
141
def _decode_unsure(self, value):
142
unsure = value == 'match'
143
return lambda occurrence: unsure
144
145
146
class RenameCurrentModule(Rename):
147
key = '1 r'
148
offset = None
149
150
151
class Restructure(Refactoring):
152
key = 'x'
153
confs = {'pattern': dialog.Data('Restructuring pattern: '),
154
'goal': dialog.Data('Restructuring goal: ')}
155
156
def _calculate_changes(self, values, task_handle):
157
restructuring = rope.refactor.restructure.Restructure(
158
self.project, values['pattern'], values['goal'],
159
args=values['args'], imports=values['imports'])
160
return restructuring.get_changes(resources=values['resources'],
161
task_handle=task_handle)
162
163
def _get_optionals(self):
164
return {
165
'args': dialog.Data('Arguments: ', decode=self._decode_args),
166
'imports': dialog.Data('Imports: ', decode=self._decode_imports),
167
'resources': self.resources_option}
168
169
def _decode_args(self, value):
170
if value:
171
args = {}
172
for raw_check in value.split('\n'):
173
if raw_check:
174
key, value = raw_check.split(':', 1)
175
args[key.strip()] = value.strip()
176
return args
177
178
def _decode_imports(self, value):
179
if value:
180
return [line.strip() for line in value.split('\n')]
181
182
183
class UseFunction(Refactoring):
184
key = 'u'
185
186
def _create_refactoring(self):
187
self.user = rope.refactor.usefunction.UseFunction(
188
self.project, self.resource, self.offset)
189
190
def _calculate_changes(self, values, task_handle):
191
return self.user.get_changes(task_handle=task_handle, **values)
192
193
def _get_optionals(self):
194
return {'resources': self.resources_option}
195
196
197
class Move(Refactoring):
198
key = 'v'
199
200
def _create_refactoring(self):
201
self.mover = rope.refactor.move.create_move(self.project,
202
self.resource,
203
self.offset)
204
205
def _calculate_changes(self, values, task_handle):
206
destination = values['destination']
207
resources = values.get('resources', None)
208
if isinstance(self.mover, rope.refactor.move.MoveGlobal):
209
return self._move_global(destination, resources, task_handle)
210
if isinstance(self.mover, rope.refactor.move.MoveModule):
211
return self._move_module(destination, resources, task_handle)
212
if isinstance(self.mover, rope.refactor.move.MoveMethod):
213
return self._move_method(destination, resources, task_handle)
214
215
def _move_global(self, dest, resources, handle):
216
destination = self.project.pycore.find_module(dest)
217
return self.mover.get_changes(
218
destination, resources=resources, task_handle=handle)
219
220
def _move_method(self, dest, resources, handle):
221
return self.mover.get_changes(
222
dest, self.mover.get_method_name(),
223
resources=resources, task_handle=handle)
224
225
def _move_module(self, dest, resources, handle):
226
destination = self.project.pycore.find_module(dest)
227
return self.mover.get_changes(
228
destination, resources=resources, task_handle=handle)
229
230
def _get_confs(self):
231
if isinstance(self.mover, rope.refactor.move.MoveGlobal):
232
prompt = 'Destination module: '
233
if isinstance(self.mover, rope.refactor.move.MoveModule):
234
prompt = 'Destination package: '
235
if isinstance(self.mover, rope.refactor.move.MoveMethod):
236
prompt = 'Destination attribute: '
237
return {'destination': dialog.Data(prompt)}
238
239
def _get_optionals(self):
240
return {'resources': self.resources_option}
241
242
243
class MoveCurrentModule(Move):
244
key = '1 v'
245
offset = None
246
247
248
class ModuleToPackage(Refactoring):
249
key = '1 p'
250
saveall = False
251
252
def _create_refactoring(self):
253
self.packager = rope.refactor.ModuleToPackage(
254
self.project, self.resource)
255
256
def _calculate_changes(self, values, task_handle):
257
return self.packager.get_changes()
258
259
260
class Inline(Refactoring):
261
key = 'i'
262
263
def _create_refactoring(self):
264
self.inliner = rope.refactor.inline.create_inline(
265
self.project, self.resource, self.offset)
266
267
def _calculate_changes(self, values, task_handle):
268
return self.inliner.get_changes(task_handle=task_handle, **values)
269
270
def _get_optionals(self):
271
opts = {'resources': self.resources_option}
272
if self.inliner.get_kind() == 'parameter':
273
opts['in_hierarchy'] = dialog.Boolean(
274
'Apply on all matching methods in class hierarchy: ', False)
275
else:
276
opts['remove'] = dialog.Boolean('Remove the definition: ', True)
277
opts['only_current'] = dialog.Boolean('Inline this '
278
'occurrence only: ')
279
return opts
280
281
282
class _Extract(Refactoring):
283
saveall = False
284
optionals = {'similar': dialog.Boolean('Extract similar pieces: ', True),
285
'global_': dialog.Boolean('Make global: ')}
286
kind = None
287
constructor = None
288
289
def _create_refactoring(self):
290
start, end = self.region
291
self.extractor = self.constructor(self.project,
292
self.resource, start, end)
293
294
def _calculate_changes(self, values, task_handle):
295
similar = values.get('similar')
296
global_ = values.get('global_')
297
return self.extractor.get_changes(values['name'], similar=similar,
298
global_=global_)
299
300
def _get_confs(self):
301
return {'name': dialog.Data('Extracted %s name: ' % self.kind)}
302
303
304
class ExtractVariable(_Extract):
305
key = 'l'
306
kind = 'variable'
307
constructor = rope.refactor.extract.ExtractVariable
308
309
310
class ExtractMethod(_Extract):
311
key = 'm'
312
kind = 'method'
313
constructor = rope.refactor.extract.ExtractMethod
314
315
316
class OrganizeImports(Refactoring):
317
key = 'o'
318
saveall = False
319
320
def _create_refactoring(self):
321
self.organizer = rope.refactor.ImportOrganizer(self.project)
322
323
def _calculate_changes(self, values, task_handle):
324
return self.organizer.organize_imports(self.resource)
325
326
327
class MethodObject(Refactoring):
328
saveall = False
329
confs = {'classname': dialog.Data('New class name: ',
330
default='_ExtractedClass')}
331
332
def _create_refactoring(self):
333
self.objecter = rope.refactor.method_object.MethodObject(
334
self.project, self.resource, self.offset)
335
336
def _calculate_changes(self, values, task_handle):
337
classname = values.get('classname')
338
return self.objecter.get_changes(classname)
339
340
341
class IntroduceFactory(Refactoring):
342
saveall = True
343
key = 'f'
344
345
def _create_refactoring(self):
346
self.factory = rope.refactor.introduce_factory.IntroduceFactory(
347
self.project, self.resource, self.offset)
348
349
def _calculate_changes(self, values, task_handle):
350
return self.factory.get_changes(task_handle=task_handle, **values)
351
352
def _get_confs(self):
353
default = 'create_%s' % self.factory.old_name.lower()
354
return {'factory_name': dialog.Data('Factory name: ', default)}
355
356
def _get_optionals(self):
357
return {'global_factory': dialog.Boolean('Make global: ', True),
358
'resources': self.resources_option}
359
360
361
class ChangeSignature(Refactoring):
362
saveall = True
363
key = 's'
364
365
def _create_refactoring(self):
366
self.changer = rope.refactor.change_signature.ChangeSignature(
367
self.project, self.resource, self.offset)
368
369
def _calculate_changes(self, values, task_handle):
370
signature = values.get('signature')
371
args = re.sub(r'[\s\(\)]+', '', signature).split(',')
372
olds = [arg[0] for arg in self._get_args()]
373
374
changers = []
375
for arg in list(olds):
376
if arg in args:
377
continue
378
changers.append(rope.refactor.change_signature.
379
ArgumentRemover(olds.index(arg)))
380
olds.remove(arg)
381
382
order = []
383
for index, arg in enumerate(args):
384
if arg not in olds:
385
changers.append(rope.refactor.change_signature.
386
ArgumentAdder(index, arg))
387
olds.insert(index, arg)
388
order.append(olds.index(arg))
389
changers.append(rope.refactor.change_signature.
390
ArgumentReorderer(order, autodef='None'))
391
392
del values['signature']
393
return self.changer.get_changes(changers, task_handle=task_handle,
394
**values)
395
396
def _get_args(self):
397
if hasattr(self.changer, 'get_args'):
398
return self.changer.get_args()
399
return self.changer.get_definition_info().args_with_defaults
400
401
def _get_confs(self):
402
args = []
403
for arg, default in self._get_args():
404
args.append(arg)
405
signature = '(' + ', '.join(args) + ')'
406
return {'signature': dialog.Data('Change the signature: ',
407
default=signature)}
408
409
def _get_optionals(self):
410
opts = {'resources': self.resources_option}
411
if self.changer.is_method():
412
opts['in_hierarchy'] = dialog.Boolean('Rename methods in '
413
'class hierarchy: ')
414
return opts
415
416
417
class _GenerateElement(Refactoring):
418
419
def _create_refactoring(self):
420
kind = self.name.split('_')[-1]
421
self.generator = rope.contrib.generate.create_generate(
422
kind, self.project, self.resource, self.offset)
423
424
def _calculate_changes(self, values, task_handle):
425
return self.generator.get_changes()
426
427
def _done(self):
428
resource, lineno = self.generator.get_location()
429
self.interface._goto_location(resource, lineno)
430
431
432
class GenerateVariable(_GenerateElement):
433
key = 'n v'
434
435
436
class GenerateFunction(_GenerateElement):
437
key = 'n f'
438
439
440
class GenerateClass(_GenerateElement):
441
key = 'n c'
442
443
444
class GenerateModule(_GenerateElement):
445
key = 'n m'
446
447
448
class GeneratePackage(_GenerateElement):
449
key = 'n p'
450
451
452
def refactoring_name(refactoring):
453
classname = refactoring.__name__
454
result = []
455
for c in classname:
456
if result and c.isupper():
457
result.append('_')
458
result.append(c.lower())
459
name = ''.join(result)
460
return name
461
462
def _resources(project, text):
463
if text is None or text.strip() == '':
464
return None
465
return filter.resources(project, text)
466
467
468
def runtask(env, command, name, interrupts=True):
469
return RunTask(env, command, name, interrupts)()
470
471
class RunTask(object):
472
473
def __init__(self, env, task, name, interrupts=True):
474
self.env = env
475
self.task = task
476
self.name = name
477
self.interrupts = interrupts
478
479
def __call__(self):
480
handle = taskhandle.TaskHandle(name=self.name)
481
progress = self.env.create_progress(self.name)
482
def update_progress():
483
jobset = handle.current_jobset()
484
if jobset:
485
percent = jobset.get_percent_done()
486
if percent is not None:
487
progress.update(percent)
488
handle.add_observer(update_progress)
489
result = self.task(handle)
490
progress.done()
491
return result
492
493