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

Side by Side Diff: tools/telemetry/third_party/rope/rope/refactor/move.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 unified diff | Download patch
OLDNEW
(Empty)
1 """A module containing classes for move refactoring
2
3 `create_move()` is a factory for creating move refactoring objects
4 based on inputs.
5
6 """
7 from rope.base import (pyobjects, codeanalyze, exceptions, pynames,
8 taskhandle, evaluate, worder, libutils)
9 from rope.base.change import ChangeSet, ChangeContents, MoveResource
10 from rope.refactor import importutils, rename, occurrences, sourceutils, \
11 functionutils
12
13
14 def create_move(project, resource, offset=None):
15 """A factory for creating Move objects
16
17 Based on `resource` and `offset`, return one of `MoveModule`,
18 `MoveGlobal` or `MoveMethod` for performing move refactoring.
19
20 """
21 if offset is None:
22 return MoveModule(project, resource)
23 this_pymodule = project.get_pymodule(resource)
24 pyname = evaluate.eval_location(this_pymodule, offset)
25 if pyname is None:
26 raise exceptions.RefactoringError(
27 'Move only works on classes, functions, modules and methods.')
28 pyobject = pyname.get_object()
29 if isinstance(pyobject, pyobjects.PyModule) or \
30 isinstance(pyobject, pyobjects.PyPackage):
31 return MoveModule(project, pyobject.get_resource())
32 if isinstance(pyobject, pyobjects.PyFunction) and \
33 isinstance(pyobject.parent, pyobjects.PyClass):
34 return MoveMethod(project, resource, offset)
35 if isinstance(pyobject, pyobjects.PyDefinedObject) and \
36 isinstance(pyobject.parent, pyobjects.PyModule):
37 return MoveGlobal(project, resource, offset)
38 raise exceptions.RefactoringError(
39 'Move only works on global classes/functions, modules and methods.')
40
41
42 class MoveMethod(object):
43 """For moving methods
44
45 It makes a new method in the destination class and changes
46 the body of the old method to call the new method. You can
47 inline the old method to change all of its occurrences.
48
49 """
50
51 def __init__(self, project, resource, offset):
52 self.project = project
53 this_pymodule = self.project.get_pymodule(resource)
54 pyname = evaluate.eval_location(this_pymodule, offset)
55 self.method_name = worder.get_name_at(resource, offset)
56 self.pyfunction = pyname.get_object()
57 if self.pyfunction.get_kind() != 'method':
58 raise exceptions.RefactoringError('Only normal methods'
59 ' can be moved.')
60
61 def get_changes(self, dest_attr, new_name=None, resources=None,
62 task_handle=taskhandle.NullTaskHandle()):
63 """Return the changes needed for this refactoring
64
65 Parameters:
66
67 - `dest_attr`: the name of the destination attribute
68 - `new_name`: the name of the new method; if `None` uses
69 the old name
70 - `resources` can be a list of `rope.base.resources.File`\s to
71 apply this refactoring on. If `None`, the restructuring
72 will be applied to all python files.
73
74 """
75 changes = ChangeSet('Moving method <%s>' % self.method_name)
76 if resources is None:
77 resources = self.project.get_python_files()
78 if new_name is None:
79 new_name = self.get_method_name()
80 resource1, start1, end1, new_content1 = \
81 self._get_changes_made_by_old_class(dest_attr, new_name)
82 collector1 = codeanalyze.ChangeCollector(resource1.read())
83 collector1.add_change(start1, end1, new_content1)
84
85 resource2, start2, end2, new_content2 = \
86 self._get_changes_made_by_new_class(dest_attr, new_name)
87 if resource1 == resource2:
88 collector1.add_change(start2, end2, new_content2)
89 else:
90 collector2 = codeanalyze.ChangeCollector(resource2.read())
91 collector2.add_change(start2, end2, new_content2)
92 result = collector2.get_changed()
93 import_tools = importutils.ImportTools(self.project)
94 new_imports = self._get_used_imports(import_tools)
95 if new_imports:
96 goal_pymodule = libutils.get_string_module(
97 self.project, result, resource2)
98 result = _add_imports_to_module(
99 import_tools, goal_pymodule, new_imports)
100 if resource2 in resources:
101 changes.add_change(ChangeContents(resource2, result))
102
103 if resource1 in resources:
104 changes.add_change(ChangeContents(resource1,
105 collector1.get_changed()))
106 return changes
107
108 def get_method_name(self):
109 return self.method_name
110
111 def _get_used_imports(self, import_tools):
112 return importutils.get_imports(self.project, self.pyfunction)
113
114 def _get_changes_made_by_old_class(self, dest_attr, new_name):
115 pymodule = self.pyfunction.get_module()
116 indents = self._get_scope_indents(self.pyfunction)
117 body = 'return self.%s.%s(%s)\n' % (
118 dest_attr, new_name, self._get_passed_arguments_string())
119 region = sourceutils.get_body_region(self.pyfunction)
120 return (pymodule.get_resource(), region[0], region[1],
121 sourceutils.fix_indentation(body, indents))
122
123 def _get_scope_indents(self, pyobject):
124 pymodule = pyobject.get_module()
125 return sourceutils.get_indents(
126 pymodule.lines, pyobject.get_scope().get_start()) + \
127 sourceutils.get_indent(self.project)
128
129 def _get_changes_made_by_new_class(self, dest_attr, new_name):
130 old_pyclass = self.pyfunction.parent
131 if dest_attr not in old_pyclass:
132 raise exceptions.RefactoringError(
133 'Destination attribute <%s> not found' % dest_attr)
134 pyclass = old_pyclass[dest_attr].get_object().get_type()
135 if not isinstance(pyclass, pyobjects.PyClass):
136 raise exceptions.RefactoringError(
137 'Unknown class type for attribute <%s>' % dest_attr)
138 pymodule = pyclass.get_module()
139 resource = pyclass.get_module().get_resource()
140 start, end = sourceutils.get_body_region(pyclass)
141 pre_blanks = '\n'
142 if pymodule.source_code[start:end].strip() != 'pass':
143 pre_blanks = '\n\n'
144 start = end
145 indents = self._get_scope_indents(pyclass)
146 body = pre_blanks + sourceutils.fix_indentation(
147 self.get_new_method(new_name), indents)
148 return resource, start, end, body
149
150 def get_new_method(self, name):
151 return '%s\n%s' % (
152 self._get_new_header(name),
153 sourceutils.fix_indentation(self._get_body(),
154 sourceutils.get_indent(self.project)))
155
156 def _get_unchanged_body(self):
157 return sourceutils.get_body(self.pyfunction)
158
159 def _get_body(self, host='host'):
160 self_name = self._get_self_name()
161 body = self_name + ' = None\n' + self._get_unchanged_body()
162 pymodule = libutils.get_string_module(self.project, body)
163 finder = occurrences.create_finder(
164 self.project, self_name, pymodule[self_name])
165 result = rename.rename_in_module(finder, host, pymodule=pymodule)
166 if result is None:
167 result = body
168 return result[result.index('\n') + 1:]
169
170 def _get_self_name(self):
171 return self.pyfunction.get_param_names()[0]
172
173 def _get_new_header(self, name):
174 header = 'def %s(self' % name
175 if self._is_host_used():
176 header += ', host'
177 definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
178 others = definition_info.arguments_to_string(1)
179 if others:
180 header += ', ' + others
181 return header + '):'
182
183 def _get_passed_arguments_string(self):
184 result = ''
185 if self._is_host_used():
186 result = 'self'
187 definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
188 others = definition_info.arguments_to_string(1)
189 if others:
190 if result:
191 result += ', '
192 result += others
193 return result
194
195 def _is_host_used(self):
196 return self._get_body('__old_self') != self._get_unchanged_body()
197
198
199 class MoveGlobal(object):
200 """For moving global function and classes"""
201
202 def __init__(self, project, resource, offset):
203 self.project = project
204 this_pymodule = self.project.get_pymodule(resource)
205 self.old_pyname = evaluate.eval_location(this_pymodule, offset)
206 self.old_name = self.old_pyname.get_object().get_name()
207 pymodule = self.old_pyname.get_object().get_module()
208 self.source = pymodule.get_resource()
209 self.tools = _MoveTools(self.project, self.source,
210 self.old_pyname, self.old_name)
211 self.import_tools = self.tools.import_tools
212 self._check_exceptional_conditions()
213
214 def _check_exceptional_conditions(self):
215 if self.old_pyname is None or \
216 not isinstance(self.old_pyname.get_object(),
217 pyobjects.PyDefinedObject):
218 raise exceptions.RefactoringError(
219 'Move refactoring should be performed on a class/function.')
220 moving_pyobject = self.old_pyname.get_object()
221 if not self._is_global(moving_pyobject):
222 raise exceptions.RefactoringError(
223 'Move refactoring should be performed ' +
224 'on a global class/function.')
225
226 def _is_global(self, pyobject):
227 return pyobject.get_scope().parent == pyobject.get_module().get_scope()
228
229 def get_changes(self, dest, resources=None,
230 task_handle=taskhandle.NullTaskHandle()):
231 if resources is None:
232 resources = self.project.get_python_files()
233 if dest is None or not dest.exists():
234 raise exceptions.RefactoringError(
235 'Move destination does not exist.')
236 if dest.is_folder() and dest.has_child('__init__.py'):
237 dest = dest.get_child('__init__.py')
238 if dest.is_folder():
239 raise exceptions.RefactoringError(
240 'Move destination for non-modules should not be folders.')
241 if self.source == dest:
242 raise exceptions.RefactoringError(
243 'Moving global elements to the same module.')
244 return self._calculate_changes(dest, resources, task_handle)
245
246 def _calculate_changes(self, dest, resources, task_handle):
247 changes = ChangeSet('Moving global <%s>' % self.old_name)
248 job_set = task_handle.create_jobset('Collecting Changes',
249 len(resources))
250 for file_ in resources:
251 job_set.started_job(file_.path)
252 if file_ == self.source:
253 changes.add_change(self._source_module_changes(dest))
254 elif file_ == dest:
255 changes.add_change(self._dest_module_changes(dest))
256 elif self.tools.occurs_in_module(resource=file_):
257 pymodule = self.project.get_pymodule(file_)
258 # Changing occurrences
259 placeholder = '__rope_renaming_%s_' % self.old_name
260 source = self.tools.rename_in_module(placeholder,
261 resource=file_)
262 should_import = source is not None
263 # Removing out of date imports
264 pymodule = self.tools.new_pymodule(pymodule, source)
265 source = self.tools.remove_old_imports(pymodule)
266 # Adding new import
267 if should_import:
268 pymodule = self.tools.new_pymodule(pymodule, source)
269 source, imported = importutils.add_import(
270 self.project, pymodule, self._new_modname(dest),
271 self.old_name)
272 source = source.replace(placeholder, imported)
273 source = self.tools.new_source(pymodule, source)
274 if source != file_.read():
275 changes.add_change(ChangeContents(file_, source))
276 job_set.finished_job()
277 return changes
278
279 def _source_module_changes(self, dest):
280 placeholder = '__rope_moving_%s_' % self.old_name
281 handle = _ChangeMoveOccurrencesHandle(placeholder)
282 occurrence_finder = occurrences.create_finder(
283 self.project, self.old_name, self.old_pyname)
284 start, end = self._get_moving_region()
285 renamer = ModuleSkipRenamer(occurrence_finder, self.source,
286 handle, start, end)
287 source = renamer.get_changed_module()
288 if handle.occurred:
289 pymodule = libutils.get_string_module(
290 self.project, source, self.source)
291 # Adding new import
292 source, imported = importutils.add_import(
293 self.project, pymodule, self._new_modname(dest), self.old_name)
294 source = source.replace(placeholder, imported)
295 return ChangeContents(self.source, source)
296
297 def _new_modname(self, dest):
298 return libutils.modname(dest)
299
300 def _dest_module_changes(self, dest):
301 # Changing occurrences
302 pymodule = self.project.get_pymodule(dest)
303 source = self.tools.rename_in_module(self.old_name, pymodule)
304 pymodule = self.tools.new_pymodule(pymodule, source)
305
306 moving, imports = self._get_moving_element_with_imports()
307 source = self.tools.remove_old_imports(pymodule)
308 pymodule = self.tools.new_pymodule(pymodule, source)
309 pymodule, has_changed = self._add_imports2(pymodule, imports)
310
311 module_with_imports = self.import_tools.module_imports(pymodule)
312 source = pymodule.source_code
313 lineno = 0
314 if module_with_imports.imports:
315 lineno = module_with_imports.imports[-1].end_line - 1
316 else:
317 while lineno < pymodule.lines.length() and \
318 pymodule.lines.get_line(lineno + 1).\
319 lstrip().startswith('#'):
320 lineno += 1
321 if lineno > 0:
322 cut = pymodule.lines.get_line_end(lineno) + 1
323 result = source[:cut] + '\n\n' + moving + source[cut:]
324 else:
325 result = moving + source
326
327 # Organizing imports
328 source = result
329 pymodule = libutils.get_string_module(self.project, source, dest)
330 source = self.import_tools.organize_imports(pymodule, sort=False,
331 unused=False)
332 return ChangeContents(dest, source)
333
334 def _get_moving_element_with_imports(self):
335 return moving_code_with_imports(
336 self.project, self.source, self._get_moving_element())
337
338 def _get_module_with_imports(self, source_code, resource):
339 pymodule = libutils.get_string_module(
340 self.project, source_code, resource)
341 return self.import_tools.module_imports(pymodule)
342
343 def _get_moving_element(self):
344 start, end = self._get_moving_region()
345 moving = self.source.read()[start:end]
346 return moving.rstrip() + '\n'
347
348 def _get_moving_region(self):
349 pymodule = self.project.get_pymodule(self.source)
350 lines = pymodule.lines
351 scope = self.old_pyname.get_object().get_scope()
352 start = lines.get_line_start(scope.get_start())
353 end_line = scope.get_end()
354 while end_line < lines.length() and \
355 lines.get_line(end_line + 1).strip() == '':
356 end_line += 1
357 end = min(lines.get_line_end(end_line) + 1, len(pymodule.source_code))
358 return start, end
359
360 def _add_imports2(self, pymodule, new_imports):
361 source = self.tools.add_imports(pymodule, new_imports)
362 if source is None:
363 return pymodule, False
364 else:
365 resource = pymodule.get_resource()
366 pymodule = libutils.get_string_module(
367 self.project, source, resource)
368 return pymodule, True
369
370
371 class MoveModule(object):
372 """For moving modules and packages"""
373
374 def __init__(self, project, resource):
375 self.project = project
376 if not resource.is_folder() and resource.name == '__init__.py':
377 resource = resource.parent
378 if resource.is_folder() and not resource.has_child('__init__.py'):
379 raise exceptions.RefactoringError(
380 'Cannot move non-package folder.')
381 dummy_pymodule = libutils.get_string_module(self.project, '')
382 self.old_pyname = pynames.ImportedModule(dummy_pymodule,
383 resource=resource)
384 self.source = self.old_pyname.get_object().get_resource()
385 if self.source.is_folder():
386 self.old_name = self.source.name
387 else:
388 self.old_name = self.source.name[:-3]
389 self.tools = _MoveTools(self.project, self.source,
390 self.old_pyname, self.old_name)
391 self.import_tools = self.tools.import_tools
392
393 def get_changes(self, dest, resources=None,
394 task_handle=taskhandle.NullTaskHandle()):
395 if resources is None:
396 resources = self.project.get_python_files()
397 if dest is None or not dest.is_folder():
398 raise exceptions.RefactoringError(
399 'Move destination for modules should be packages.')
400 return self._calculate_changes(dest, resources, task_handle)
401
402 def _calculate_changes(self, dest, resources, task_handle):
403 changes = ChangeSet('Moving module <%s>' % self.old_name)
404 job_set = task_handle.create_jobset('Collecting changes',
405 len(resources))
406 for module in resources:
407 job_set.started_job(module.path)
408 if module == self.source:
409 self._change_moving_module(changes, dest)
410 else:
411 source = self._change_occurrences_in_module(dest,
412 resource=module)
413 if source is not None:
414 changes.add_change(ChangeContents(module, source))
415 job_set.finished_job()
416 if self.project == self.source.project:
417 changes.add_change(MoveResource(self.source, dest.path))
418 return changes
419
420 def _new_modname(self, dest):
421 destname = libutils.modname(dest)
422 if destname:
423 return destname + '.' + self.old_name
424 return self.old_name
425
426 def _new_import(self, dest):
427 return importutils.NormalImport([(self._new_modname(dest), None)])
428
429 def _change_moving_module(self, changes, dest):
430 if not self.source.is_folder():
431 pymodule = self.project.get_pymodule(self.source)
432 source = self.import_tools.relatives_to_absolutes(pymodule)
433 pymodule = self.tools.new_pymodule(pymodule, source)
434 source = self._change_occurrences_in_module(dest, pymodule)
435 source = self.tools.new_source(pymodule, source)
436 if source != self.source.read():
437 changes.add_change(ChangeContents(self.source, source))
438
439 def _change_occurrences_in_module(self, dest, pymodule=None,
440 resource=None):
441 if not self.tools.occurs_in_module(pymodule=pymodule,
442 resource=resource):
443 return
444 if pymodule is None:
445 pymodule = self.project.get_pymodule(resource)
446 new_name = self._new_modname(dest)
447 module_imports = importutils.get_module_imports(self.project, pymodule)
448 changed = False
449
450 source = None
451 if libutils.modname(dest):
452 changed = self._change_import_statements(dest, new_name,
453 module_imports)
454 if changed:
455 source = module_imports.get_changed_source()
456 source = self.tools.new_source(pymodule, source)
457 pymodule = self.tools.new_pymodule(pymodule, source)
458
459 new_import = self._new_import(dest)
460 source = self.tools.rename_in_module(
461 new_name, imports=True, pymodule=pymodule,
462 resource=resource if not changed else None)
463 should_import = self.tools.occurs_in_module(
464 pymodule=pymodule, resource=resource, imports=False)
465 pymodule = self.tools.new_pymodule(pymodule, source)
466 source = self.tools.remove_old_imports(pymodule)
467 if should_import:
468 pymodule = self.tools.new_pymodule(pymodule, source)
469 source = self.tools.add_imports(pymodule, [new_import])
470 source = self.tools.new_source(pymodule, source)
471 if source is not None and source != pymodule.resource.read():
472 return source
473 return None
474
475
476 def _change_import_statements(self, dest, new_name, module_imports):
477 moving_module = self.source
478 parent_module = moving_module.parent
479
480 changed = False
481 for import_stmt in module_imports.imports:
482 if not any(name_and_alias[0] == self.old_name
483 for name_and_alias in
484 import_stmt.import_info.names_and_aliases) and \
485 not any(name_and_alias[0] == libutils.modname(self.source)
486 for name_and_alias in
487 import_stmt.import_info.names_and_aliases):
488 continue
489
490 # Case 1: Look for normal imports of the moving module.
491 if isinstance(import_stmt.import_info, importutils.NormalImport):
492 continue
493
494 # Case 2: The moving module is from-imported.
495 changed = self._handle_moving_in_from_import_stmt(
496 dest, import_stmt, module_imports, parent_module) or changed
497
498 # Case 3: Names are imported from the moving module.
499 context = importutils.importinfo.ImportContext(self.project, None)
500 if not import_stmt.import_info.is_empty() and \
501 import_stmt.import_info.get_imported_resource(context) == \
502 moving_module:
503 import_stmt.import_info = importutils.FromImport(
504 new_name, import_stmt.import_info.level,
505 import_stmt.import_info.names_and_aliases)
506 changed = True
507
508 return changed
509
510 def _handle_moving_in_from_import_stmt(self, dest, import_stmt,
511 module_imports, parent_module):
512 changed = False
513 context = importutils.importinfo.ImportContext(self.project, None)
514 if import_stmt.import_info.get_imported_resource(context) == \
515 parent_module:
516 imports = import_stmt.import_info.names_and_aliases
517 new_imports = []
518 for name, alias in imports:
519 # The moving module was imported.
520 if name == self.old_name:
521 changed = True
522 new_import = importutils.FromImport(
523 libutils.modname(dest), 0,
524 [(self.old_name, alias)])
525 module_imports.add_import(new_import)
526 else:
527 new_imports.append((name, alias))
528
529 # Update the imports if the imported names were changed.
530 if new_imports != imports:
531 changed = True
532 if new_imports:
533 import_stmt.import_info = importutils.FromImport(
534 import_stmt.import_info.module_name,
535 import_stmt.import_info.level,
536 new_imports)
537 else:
538 import_stmt.empty_import()
539 return changed
540
541
542 class _ChangeMoveOccurrencesHandle(object):
543
544 def __init__(self, new_name):
545 self.new_name = new_name
546 self.occurred = False
547
548 def occurred_inside_skip(self, change_collector, occurrence):
549 pass
550
551 def occurred_outside_skip(self, change_collector, occurrence):
552 start, end = occurrence.get_primary_range()
553 change_collector.add_change(start, end, self.new_name)
554 self.occurred = True
555
556
557 class _MoveTools(object):
558
559 def __init__(self, project, source, pyname, old_name):
560 self.project = project
561 self.source = source
562 self.old_pyname = pyname
563 self.old_name = old_name
564 self.import_tools = importutils.ImportTools(self.project)
565
566 def remove_old_imports(self, pymodule):
567 old_source = pymodule.source_code
568 module_with_imports = self.import_tools.module_imports(pymodule)
569
570 class CanSelect(object):
571 changed = False
572 old_name = self.old_name
573 old_pyname = self.old_pyname
574
575 def __call__(self, name):
576 try:
577 if name == self.old_name and \
578 pymodule[name].get_object() == \
579 self.old_pyname.get_object():
580 self.changed = True
581 return False
582 except exceptions.AttributeNotFoundError:
583 pass
584 return True
585 can_select = CanSelect()
586 module_with_imports.filter_names(can_select)
587 new_source = module_with_imports.get_changed_source()
588 if old_source != new_source:
589 return new_source
590
591 def rename_in_module(self, new_name, pymodule=None,
592 imports=False, resource=None):
593 occurrence_finder = self._create_finder(imports)
594 source = rename.rename_in_module(
595 occurrence_finder, new_name, replace_primary=True,
596 pymodule=pymodule, resource=resource)
597 return source
598
599 def occurs_in_module(self, pymodule=None, resource=None, imports=True):
600 finder = self._create_finder(imports)
601 for occurrence in finder.find_occurrences(pymodule=pymodule,
602 resource=resource):
603 return True
604 return False
605
606 def _create_finder(self, imports):
607 return occurrences.create_finder(self.project, self.old_name,
608 self.old_pyname, imports=imports)
609
610 def new_pymodule(self, pymodule, source):
611 if source is not None:
612 return libutils.get_string_module(
613 self.project, source, pymodule.get_resource())
614 return pymodule
615
616 def new_source(self, pymodule, source):
617 if source is None:
618 return pymodule.source_code
619 return source
620
621 def add_imports(self, pymodule, new_imports):
622 return _add_imports_to_module(self.import_tools, pymodule, new_imports)
623
624
625 def _add_imports_to_module(import_tools, pymodule, new_imports):
626 module_with_imports = import_tools.module_imports(pymodule)
627 for new_import in new_imports:
628 module_with_imports.add_import(new_import)
629 return module_with_imports.get_changed_source()
630
631
632 def moving_code_with_imports(project, resource, source):
633 import_tools = importutils.ImportTools(project)
634 pymodule = libutils.get_string_module(project, source, resource)
635 origin = project.get_pymodule(resource)
636
637 imports = []
638 for stmt in import_tools.module_imports(origin).imports:
639 imports.append(stmt.import_info)
640
641 back_names = []
642 for name in origin:
643 if name not in pymodule:
644 back_names.append(name)
645 imports.append(import_tools.get_from_import(resource, back_names))
646
647 source = _add_imports_to_module(import_tools, pymodule, imports)
648 pymodule = libutils.get_string_module(project, source, resource)
649
650 source = import_tools.relatives_to_absolutes(pymodule)
651 pymodule = libutils.get_string_module(project, source, resource)
652 source = import_tools.organize_imports(pymodule, selfs=False)
653 pymodule = libutils.get_string_module(project, source, resource)
654
655 # extracting imports after changes
656 module_imports = import_tools.module_imports(pymodule)
657 imports = [import_stmt.import_info
658 for import_stmt in module_imports.imports]
659 start = 1
660 if module_imports.imports:
661 start = module_imports.imports[-1].end_line
662 lines = codeanalyze.SourceLinesAdapter(source)
663 while start < lines.length() and not lines.get_line(start).strip():
664 start += 1
665 moving = source[lines.get_line_start(start):]
666 return moving, imports
667
668
669 class ModuleSkipRenamerHandle(object):
670
671 def occurred_outside_skip(self, change_collector, occurrence):
672 pass
673
674 def occurred_inside_skip(self, change_collector, occurrence):
675 pass
676
677
678 class ModuleSkipRenamer(object):
679 """Rename occurrences in a module
680
681 This class can be used when you want to treat a region in a file
682 separately from other parts when renaming.
683
684 """
685
686 def __init__(self, occurrence_finder, resource, handle=None,
687 skip_start=0, skip_end=0, replacement=''):
688 """Constructor
689
690 if replacement is `None` the region is not changed. Otherwise
691 it is replaced with `replacement`.
692
693 """
694 self.occurrence_finder = occurrence_finder
695 self.resource = resource
696 self.skip_start = skip_start
697 self.skip_end = skip_end
698 self.replacement = replacement
699 self.handle = handle
700 if self.handle is None:
701 self.handle = ModuleSkipRenamerHandle()
702
703 def get_changed_module(self):
704 source = self.resource.read()
705 change_collector = codeanalyze.ChangeCollector(source)
706 if self.replacement is not None:
707 change_collector.add_change(self.skip_start, self.skip_end,
708 self.replacement)
709 for occurrence in self.occurrence_finder.find_occurrences(
710 self.resource):
711 start, end = occurrence.get_primary_range()
712 if self.skip_start <= start < self.skip_end:
713 self.handle.occurred_inside_skip(change_collector, occurrence)
714 else:
715 self.handle.occurred_outside_skip(change_collector, occurrence)
716 result = change_collector.get_changed()
717 if result is not None and result != source:
718 return result
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698