gue*_*tli 5 python refactoring automated-refactoring
我们正在重构我们的代码库。
老的:
from a.b import foo_method
Run Code Online (Sandbox Code Playgroud)
新的:
from b.d import bar_method
Run Code Online (Sandbox Code Playgroud)
两种方法 (foo_method()和bar_method()) 是相同的。它只是更改了名称和包。
由于上面的示例只是导入方法的多种方式的一个示例,因此我认为简单的正则表达式在这里没有帮助。
如何使用命令行工具重构模块的导入?
很多源代码行需要更改,因此 IDE 在这里没有帮助。
在幕后,IDE 只不过是带有一堆窗口和附加二进制文件的文本编辑器,用于执行不同类型的工作,例如编译、调试、标记代码、linting 等。最终,其中一个库可用于重构代码。Jedi 就是这样的一个库,但还有一个专门用于处理重构的库,那就是Rope。
pip3 install rope
Run Code Online (Sandbox Code Playgroud)
您可以尝试使用他们的 API,但由于您要求使用命令行工具,但没有,请将以下文件保存在可访问的任何位置(用户 bin 的已知相对文件夹等)并使其可执行chmod +x pyrename.py。
pip3 install rope
Run Code Online (Sandbox Code Playgroud)
让我们创建一个与问题中所示场景完全相同的测试环境(这里假设一个 Linux 用户):
#!/usr/bin/env python3
from rope.base.project import Project
from rope.refactor.rename import Rename
from argparse import ArgumentParser
def renamodule(old, new):
prj.do(Rename(prj, prj.find_module(old)).get_changes(new))
def renamethod(mod, old, new, instance=None):
mod = prj.find_module(mod)
modtxt = mod.read()
pos, inst = -1, 0
while True:
pos = modtxt.find('def '+old+'(', pos+1)
if pos < 0:
if instance is None and prepos > 0:
pos = prepos+4 # instance=None and only one instance found
break
print('found', inst, 'instances of method', old+',', ('tell which to rename by using an extra integer argument in the range 0..' if (instance is None) else 'could not use instance=')+str(inst-1))
pos = -1
break
if (type(instance) is int) and inst == instance:
pos += 4
break # found
if instance is None:
if inst == 0:
prepos = pos
else:
prepos = -1
inst += 1
if pos > 0:
prj.do(Rename(prj, mod, pos).get_changes(new))
argparser = ArgumentParser()
#argparser.add_argument('moduleormethod', choices=['module', 'method'], help='choose between module or method')
subparsers = argparser.add_subparsers()
subparsermod = subparsers.add_parser('module', help='moduledottedpath newname')
subparsermod.add_argument('moduledottedpath', help='old module full dotted path')
subparsermod.add_argument('newname', help='new module name only')
subparsermet = subparsers.add_parser('method', help='moduledottedpath oldname newname')
subparsermet.add_argument('moduledottedpath', help='module full dotted path')
subparsermet.add_argument('oldname', help='old method name')
subparsermet.add_argument('newname', help='new method name')
subparsermet.add_argument('instance', nargs='?', help='instance count')
args = argparser.parse_args()
if 'moduledottedpath' in args:
prj = Project('.')
if 'oldname' not in args:
renamodule(args.moduledottedpath, args.newname)
else:
renamethod(args.moduledottedpath, args.oldname, args.newname)
else:
argparser.error('nothing to do, please choose module or method')
Run Code Online (Sandbox Code Playgroud)
现在使用脚本重命名模块和方法:
# be sure that you are in the project root folder
# rename package (here called module)
../pyrename.py module a b
# package folder 'a' renamed to 'b' and also all references
# rename module
../pyrename.py module b.b d
# 'b.b' (previous 'a.b') renamed to 'd' and also all references also
# important - oldname is the full dotted path, new name is name only
# rename method
../pyrename.py method b.d foo_method bar_method
# 'foo_method' in package 'b.d' renamed to 'bar_method' and also all references
# important - if there are more than one occurence of 'def foo_method(' in the file,
# it is necessary to add an extra argument telling which (zero-indexed) instance to use
# you will be warned if multiple instances are found and you don't include this extra argument
# testing again:
./main.py
# yesterday i was foo, tomorrow i will be bar
cat main.py
cat b/d.py
Run Code Online (Sandbox Code Playgroud)
这个例子确实符合问题的意思。
仅重命名模块和方法,因为它是问题范围。如果您需要更多,您可以增加脚本或从头开始创建一个新脚本,从他们的文档和该脚本本身中学习。为简单起见,我们使用当前文件夹作为项目文件夹,但您可以在脚本中添加额外的参数以使其更加灵活。
| 归档时间: |
|
| 查看次数: |
1177 次 |
| 最近记录: |