Rename a python class with rope using a python script

268 Views Asked by At

Given a folder myproj with a file myclass.py

myproj
-- __init__.py
-- myclass.py

where myclass.py contains the following class definition

class MyClass:
    pass

I want to rename the class from MyClass to MyClass2 with rope.

If I know that the offset of the class name is 6, then I could rename the class as follows

import rope.base.project
import rope.refactor.rename


proj = rope.base.project.Project('myproj')
res = proj.get_module('myclass').get_resource()
change = rope.refactor.rename.Rename(proj, res, 6).get_changes('MyClass2')
print(change.get_description())

Question: How do I rename a class with rope knowing only the name of the class MyClass (but not knowing the offset of MyClass)?

Edit:

Here is one way to do it

offset = res.read().index('MyClass')
1

There are 1 best solutions below

0
On

Rope is primarily intended for use in an IDE, where the user is refactoring interactively with text editor cursor pointed to the object that the user wants to refactor, not for programmatic refactoring.

With that said, if you want to do something like this, you can use the get_definition_location() method to get the closest line number:

mod = proj.get_module('myclass')
name = mod.get_attribute('MyClass')
pymod, lineno = name.get_definition_location()
lineno_start, lineno_end = pymod.logical_lines.logical_line_in(lineno)
 
offset = pymod.resource.read().index(name.pyobject.get_name(), pymod.lines.get_line_start(lineno))

change = rope.refactor.rename.Rename(proj, pymod.get_resource(), offset).get_changes('MyClass2')

It's going to be slightly more reliable than trying to get the global offset using index(), which can be easily fooled by matching text in docstrings/comments.

Disclosure: I am the primary maintainer of Rope