Using Rope As A Library
将绳索用作图书馆
If you need other features, send a feature request. Have a look at
Contributing to Rope.
如果您需要其他功能,请发送功能请求。查看为 Rope 贡献的指南。
Quick Start 快速入门指南
This section will help you get started as soon as possible.
本节将助您尽快入门。
Making A Project
制作一个项目
The first thing you should do is make a project:
您应该做的第一件事是创建一个项目:
import rope.base.project
myproject = rope.base.project.Project('/path/to/myproject')
It’s good to know that:
了解以下内容是好的:
A project is a folder in the file-system.
项目是文件系统中的一个文件夹。It can contain anything. 它能够包含任何内容。
Rope searches for python modules and packages inside a project when needed.
Rope 在需要时搜索项目内的 Python 模块和包。Refactorings only change files and folders inside the project that has been passed to them.
重构仅更改已传递给它们的项目的文件和文件夹。Out of project modules that are imported from a module inside a project are handled but never changed by refactorings.
从项目内部导入的项目模块在重构过程中会被处理,但永远不会被更改。Rope makes a rope folder inside projects. By default the name of this folder is
.ropeproject
, but that can be changed using the constructor’sropefolder
parameter. PassingNone
prevents rope from making this folder.
Rope 在项目内部创建一个绳索文件夹。默认情况下,该文件夹的名称为.ropeproject
,但可以通过构造函数的ropefolder
参数进行更改。传递None
可阻止 Rope 创建此文件夹。Rope uses the
.ropeproject
folder for things like saving object information and loading project configurations.
Rope 使用.ropeproject
文件夹来保存对象信息和加载项目配置等操作。Project preferences can be configured by passing options to the constructor or in
.ropeproject/config.py
. See the defaultconfig.py
,rope.base.default_config
module, for more information.
项目偏好可以通过向构造函数传递选项或在.ropeproject/config.py
中进行配置。有关更多信息,请参阅默认的config.py
、rope.base.default_config
模块。All configurations that are available in the
config.py
file can be specified as keyword parameters to theProject
constructor. These parameters override the ones in theconfig.py
file.
config.py
文件中提供的所有配置均可作为关键字参数传递给Project
构造函数。这些参数会覆盖config.py
文件中的相应设置。Each project has a set of ignored resource patterns. You can use it to tell rope to ignore files and folders matching certain patterns.
每个项目都有一组被忽略的资源模式。您可以使用它来告知 rope 忽略与某些模式匹配的文件和文件夹。The
.ropeproject
folder can be safely copied in other clones of a project if you don’t want to lose your objectdb and history.
如果您不想丢失对象数据库和历史记录,可以在项目的其他克隆副本中安全复制.ropeproject
文件夹。
Library Utilities 图书馆实用工具
The rope.base.libutils module provides tools that make using rope as a
library easier. We’ll talk more about this module later.
rope.base.libutils 模块提供了一些工具,使得将 rope 作为库使用更加便捷。我们将在后续内容中详细讨论此模块。
What Are These Resources?
这些资源是什么?
In rope, files and folders in a project are accessed through
rope.base.resources.Resource
objects. It has two subclasses
File
and Folder
. What we care about is that refactorings and
Change
s (we’ll talk about them later) use resources.
在 Rope 中,通过 rope.base.resources.Resource
对象访问项目中的文件和文件夹。它有两个子类 File
和 Folder
。我们关注的是,重构和 Change
(稍后会讨论)使用资源。
There are two options for creating a Resource
for a path in a project.
The first approach uses the Project.get_resource()
method.
在项目中为路径创建 Resource
有两种选择。第一种方法采用 Project.get_resource()
方法。
from rope.base import project
myresource = myproject.get_resource('/path/to/resource')
However, it’s preferable to use the libutils.path_to_resource()
function, because it’s more flexible and offers a unified way to create
resources. It takes a project
and path
as parameters with an
optional type
. The type
parameter, with values file
or
folder
, can create a resource for an object that doesn’t exist yet.
然而,使用 libutils.path_to_resource()
函数更为可取,因为它更具灵活性,并提供了一种统一的资源创建方式。该函数接受 project
和 path
作为参数,并可选择性地包含 type
。 type
参数,其值可以是 file
或 folder
,能够为尚不存在的对象创建资源。
from rope.base import libutils
myresource = libutils.path_to_resource(myproject, '/path/to/resource')
Consider we have a resource. How can we know anything about it? The
answer is to use its path
and real_path
attributes.
Resource.real_path
is the absolute path of the resource in the
file-system. The Resource.path
attribute contains the address of a
resource relative to the project’s root.
假设我们拥有一个资源,如何了解它的相关信息呢?答案是利用其 path
和 real_path
属性。 Resource.real_path
表示该资源在文件系统中的绝对路径。而 Resource.path
属性则包含了资源相对于项目根目录的地址。
Performing Refactorings
执行重构操作
As a short example of performing refactorings, we’ll show how to extract
a variable from a file. First we need the Resource
object that
points to a file in a project:
作为一个简短的演示,我们将展示如何从一个文件中提取变量。首先,我们需要一个指向项目中文件的 Resource
对象:
resource = libutils.path_to_resource(myproject, '/path/to/my/module.py')
Now we can make our Refactoring class:
现在我们可以创建我们的重构类:
from rope.refactor.extract import ExtractVariable
extractor = ExtractVariable(myproject, resource, start, end)
Where start
and end
are the offsets of the region to extract in
resource
. Be careful when calculating the offsets. DOS
line-endings and multi-byte characters are considered to be one
character. This is actually easier for IDEs, since most GUI libraries
handle those cases for you.
其中 start
和 end
是待提取区域在 resource
中的偏移量。计算偏移量时需谨慎,DOS 换行符和多字节字符均视为一个字符。这对 IDE 来说实际上更简便,因为大多数图形界面库会自动处理这些情况。
Next, the IDE ask the user to configure refactoring options, like
specifying the name of the extracted variable.
接下来,IDE 会提示用户配置重构选项,例如指定提取变量的名称。
After that, we can calculate the changes:
之后,我们可以计算这些变化:
changes = extractor.get_changes('extracted_variable')
Each refactoring returns a rope.base.change.Change
object that holds
the changes it made. Calculating those changes can be time consuming.
See the rope.base.taskhandle.TaskHandle section for measuring its
progress or interrupting it.
每次重构都会返回一个 rope.base.change.Change
对象,该对象保存其所做的更改。计算这些更改可能会耗时较长。如需衡量其进度或中断该过程,请参阅 rope.base.taskhandle.TaskHandle 部分。
Previewing And Performing Changes
预览与执行更改
As mentioned in the last section each refactoring returns a
rope.base.change.Change
object. Now how can we know what it
contains and how to perform it?
如上一节所述,每次重构都会返回一个 rope.base.change.Change
对象。那么,我们如何了解其内容以及如何执行它呢?
Previewing: 预览:
You can use changes.get_description()
to get a preview. It is useful
when you don’t care much about the format. Otherwise you can use the
changes
object directly. See the documentation in
rope.base.change
module.
您可以使用 changes.get_description()
来获取预览。当您不太关心格式时,这非常有用。否则,您可以直接使用 changes
对象。请参阅 rope.base.change
模块中的文档。
Performing: 演出中:
The easiest way for performing the refactoring is to use the
Project.do() method:
执行重构最简便的方法是使用 Project.do()方法:
myproject.do(changes)
If you want to perform the changes yourself, you have two options.
Note that the main reason for performing the changes manually is
handling version control systems that are not supported by rope.
如果您想自行执行这些更改,您有两个选择。请注意,手动执行更改的主要原因是处理不受 rope 支持的版本控制系统。
The first approach is to use rope.base.fscommands (see Writing A FileSystemCommands). The changes can be performed as before using Project.do().
第一种方法是使用 rope.base.fscommands(参见编写 FileSystemCommands)。可以像之前一样使用 Project.do()来执行更改。The second approach is to perform the changes manually based on the returned
changes
object (again see the documentation inrope.base.change
module). If this approach is used you cannot undo the refactoring usingproject.history.undo()
.
第二种方法是根据返回的changes
对象手动执行更改(同样,请参阅rope.base.change
模块中的文档)。如果采用这种方法,您将无法使用project.history.undo()
撤销重构。
Updating Open Buffers In IDEs:
在集成开发环境中更新打开的缓冲区:
Usually editors need to reload the files changed by rope. You can use
Change.get_changed_resources()
to get the list of resources that
need to be reloaded.
通常,编辑器需要重新加载由 rope 修改的文件。您可以使用 Change.get_changed_resources()
来获取需要重新加载的资源列表。
Validating The Project
验证项目
When using rope as a library, you probably change the files in it in
parallel (for example in IDEs). To force rope to invalidate cached
information about resources that have been removed or changed outside
rope, you should call the Project.validate() method. You can pass a
resource to this method. For example:
在使用 rope 作为库时,您可能会在其中并行更改文件(例如在 IDE 中)。为了强制 rope 使关于已删除或外部更改的资源的缓存信息失效,您应调用 Project.validate() 方法。您可以向此方法传递一个资源。例如:
myproject.validate(resource)
This validates all files and directories in resource. Call this
function every time you want use rope (i.e., before performing
refactorings).
这会验证资源中的所有文件和目录。每次想要使用 rope(即在进行重构之前)时,请调用此函数。
Performing Static Object Analysis
执行静态对象分析
One of the greatest strengths of rope is its Static Object Analysis
(SOA). It analyzes function calls and assignments to collect the types
of objects passed to the function. Rope uses the collected data to infer
the type of function parameters, return values, and the objects stored
in built-in containers. The function
rope.base.libutils.analyze_modules()
performs SOA on all modules in
the project. It is recommended that you call this function occasionally,
and especially before performing large refactorings. Note that analyzing
all modules of a project may take a long time.
绳索的一大优势在于其静态对象分析(SOA)。它通过分析函数调用和赋值来收集传递给函数对象的类型。绳索利用收集到的数据推断函数参数、返回值以及内置容器中存储对象的类型。函数 rope.base.libutils.analyze_modules()
会对项目中的所有模块执行 SOA。建议您偶尔调用此函数,特别是在进行大规模重构之前。请注意,分析项目所有模块可能需要较长时间。
If you have automatic_soa
set, which instructs rope to analyze the
changed scopes of modules, then you should report the changes by calling
rope.base.libutils.report_change()
when saving files, as follows:
如果你已设置 automatic_soa
,指示 rope 分析模块的变更范围,那么在保存文件时,应通过调用 rope.base.libutils.report_change()
来报告这些变更,具体如下:
# Save the new contents.
old_contents = resource.read()
resource.write(new_contents)
# Inform rope about the change.
libutils.report_change(myproject, path, old_contents)
Note, however, that the use of automatic_soa
is discouraged, because it may
slow down saving considerably.
请注意,不建议使用 automatic_soa
,因为它可能会显著降低保存速度。
Closing The Project
项目关闭
Project.close() closes a project’s open resources. Always call this
function when you don’t need a project anymore:
Project.close() 关闭一个项目的所有打开资源。当你不再需要某个项目时,务必调用此函数:
myproject.close()
rope.base.libutils
The rope.base.libutils
module contains functions that make life
easier for building refactoring tools. In some cases, the functions
offer a unified way to access or create objects. You’re encouraged to
use rope.base.libutils
functions whenever possible, because the APIs
here may not be as volatile as class methods.
rope.base.libutils
模块包含了一些功能,旨在简化构建重构工具的过程。在某些情况下,这些功能提供了一种统一的方式来访问或创建对象。建议尽可能使用 rope.base.libutils
功能,因为这里的 API 可能不像类方法那样容易发生变化。
libutils.analyze_module()
Perform static object analysis on a Python file in the project. Note,
this may be a very time consuming task.
对项目中的 Python 文件执行静态对象分析。请注意,这可能是一项非常耗时的任务。
libutils.analyze_module(myproject, resource)
libutils.analyze_modules()
Perform static object analysis on all Python files in the project. Note
that it might take a long time to finish.
对项目中的所有 Python 文件执行静态对象分析。请注意,完成此过程可能需要较长时间。
libutils.analyze_modules(myproject)
libutils.get_string_module()
Returns a rope.base.pyobjects.PyModule
object for the code string.
An optional resource
argument can be specified for the resource this
code is associated with. If force_errors
is True
, then
rope.base.exceptions.ModuleSyntaxError
is raised when the code has
syntax errors. Otherwise, syntax errors are silently ignored. Note that
force_errors
overrides the ignore_syntax_errors
project
configuration flag.
返回一个与代码字符串对应的 rope.base.pyobjects.PyModule
对象。可以指定一个可选的 resource
参数,用于关联此代码的资源。如果 force_errors
为 True
,则在代码存在语法错误时会引发 rope.base.exceptions.ModuleSyntaxError
。否则,语法错误将被静默忽略。请注意, force_errors
会覆盖 ignore_syntax_errors
项目配置标志。
pymodule = libutils.get_string_module(myproject, source)
libutils.get_string_scope()
Get the rope.base.pyscopes.GlobalScope
object for the code string.
This is the outermost scope of the code encompassing the whole module.
获取代码字符串的 rope.base.pyscopes.GlobalScope
对象。这是代码的最外层作用域,涵盖整个模块。
scope = libutils.get_string_scope(myproject, source)
libutils.is_python_file()
Returns True
if the resource is a Python file.
如果资源是 Python 文件,则返回 True
。
libutils.is_python_file(myproject, resource)
libutils.modname()
Retrieves the dotted path string to the module that contains that given
resource.
检索包含给定资源的模块的点路径字符串。
# If resource is 'path/to/resource.py' relative to the project's root
# directory, this returns the string: 'path.to.resource'.
module_name = libutils.modname(resource)
libutils.path_relative_to_project_root()
Retrieve the path relative to the project’s root directory.
检索相对于项目根目录的路径。
# Get the path relative to the project's root directory.
relpath = libutils.relative(myproject.address, path)
libutils.path_to_resource()
Get the resource — a file or folder — at the given path. An optional
type
argument can be used if the resource doesn’t yet exist. The
values for type
are the strings 'file'
or 'folder'
.
获取指定路径下的资源——文件或文件夹。如果资源尚不存在,可使用可选的 type
参数。 type
的取值为字符串 'file'
或 'folder'
。
# Resource for an existing file.
myfile = libutils.path_to_resource(myproject, '/path/to/file.py')
# Resource for a non-existing folder.
new_folder = libutils.path_to_resource(myproject, '/path/to/folder', type='folder')
rope.base.project.Project
You can create a project by:
您可以通过以下方式创建项目:
project = Project(root_address)
Where the root_address
is the root folder of your project.
root_address
是您项目的根文件夹。
A project has some useful attributes. Project.address
is the
address of the root folder of a project. Project.root
is a
Folder
object that points to that folder.
一个项目具有一些有用的属性。 Project.address
是项目根文件夹的地址。 Project.root
是一个指向该文件夹的 Folder
对象。
Project.do()
Used to commit changes returned by refactorings:
用于提交重构返回的更改:
project.do(changes)
Project.history 项目历史
A rope.base.history.History
object. You can use its undo
and
redo
methods for undoing or redoing changes. Note that you can use
this only if you have committed your changes using rope.
一个 rope.base.history.History
对象。您可以使用其 undo
和 redo
方法来撤销或重做更改。请注意,仅当您已使用 rope 提交更改时,才能使用此功能。
Project.validate() 项目.验证()
When using rope as a library, you will probably change the files in that
project in parallel (for example in IDEs). To force rope to validate
cached information about resources that have been removed or changed
outside rope, you should call Project.validate()
. You should pass a
resource to this method. For example:
在使用 rope 作为库时,您可能会在并行环境中更改该项目中的文件(例如在 IDE 中)。为了强制 rope 验证已删除或在外部更改的资源的缓存信息,您应调用 Project.validate()
。您需要向此方法传递一个资源。例如:
project.validate(project.root)
This validates all files and directories in the project and clears the
cache of all recorded changes.
这会验证项目中的所有文件和目录,并清除所有已记录更改的缓存。
Project.close() 项目.关闭()
Closes a project’s open resources. Always call this function when you
don’t need a project anymore. Currently it closes the files used for
storing object information and project history. Because some parts of
these files are in memory for efficiency, not closing a project might
put them in an inconsistent state.
关闭项目的开放资源。当不再需要某个项目时,始终调用此函数。目前,它会关闭用于存储对象信息和项目历史的文件。由于这些文件的某些部分为了效率而保留在内存中,不关闭项目可能会导致它们处于不一致状态。
rope.base.fscommands 绳索.基础.文件系统命令
The rope.base.fscommands
module implements basic file system
operations that rope needs to perform. The main reason for the
existence of this module is supporting version control systems. Have a
look at FileSystemCommands
and SubversionCommands
in the same
module. If you need other version control systems you can write a new
class that provides this interface. rope.base.project.Project
accepts an fscommands
argument. You can use this argument to force
rope to use your new class.
rope.base.fscommands
模块实现了 rope 所需执行的基本文件系统操作。该模块存在的主要原因是支持版本控制系统。请查看同一模块中的 FileSystemCommands
和 SubversionCommands
。如果您需要其他版本控制系统,可以编写一个新类来提供此接口。 rope.base.project.Project
接受一个 fscommands
参数。您可以使用此参数强制 rope 使用您的新类。
.ropeproject
Folder .ropeproject
文件夹
Since version 0.5
, rope makes a .ropeproject
folder in the
project by default for saving project configurations and data. The name
of this folder is passed to the constructor if you want to change that.
You can force rope not to make such a folder by passing None
.
自版本 0.5
起,rope 默认在项目中创建一个 .ropeproject
文件夹,用于保存项目配置和数据。如果你想更改该文件夹的名称,可以在构造函数中传递新的名称。你也可以通过传递 None
来强制 rope 不创建此类文件夹。
If such a folder exists, rope loads the config.py
file in that
folder. It might also use it for storing object information and
history.
如果存在这样的文件夹,rope 会加载该文件夹中的 config.py
文件。它还可能用于存储对象信息和历史记录。
rope.base.pycore.PyCore
rope.base.pycore.PyCore
Provides useful methods for managing python modules and packages. Each
project has a PyCore
that can be accessed using the
Project.pycore
attribute.
提供管理 Python 模块和包的有用方法。每个项目都有一个 PyCore
,可以通过 Project.pycore
属性进行访问。
PyCore.run_module()
runs a resource. When running, it collects type
information to do dynamic object inference. For this reason modules
run much slower.
PyCore.run_module()
运行一个资源。在运行过程中,它会收集类型信息以进行动态对象推断。因此,模块运行速度会慢得多。
Also Pycore.analyze_module()
collects object information for a
module. The collected information can be used to enhance rope’s
static object inference.
同时, Pycore.analyze_module()
收集模块的对象信息。收集到的信息可用于增强绳索的静态对象推断。
rope.base.taskhandle.TaskHandle
绳索基础任务句柄.TaskHandle
A TaskHandle can be used for stopping and monitoring the progress of
time consuming tasks, like some refactorings. The Project.do()
and
Refactoring.get_changes()
methods for most refactorings take a
keyword parameter called task_handle
. You can pass a TaskHandle
object to them. A TaskHandle
can be used for interrupting or
observing a task.
TaskHandle 可用于停止和监控耗时任务的进度,例如某些重构操作。大多数重构的 Project.do()
和 Refactoring.get_changes()
方法接受一个名为 task_handle
的关键字参数。您可以将一个 TaskHandle
对象传递给它们。 TaskHandle
可用于中断或观察任务。
Always pass task_handle
as keyword argument. It will always be the
last argument, and new arguments of the refactoring are added before it.
始终将 task_handle
作为关键字参数传递。它将始终是最后一个参数,重构中新添加的参数会位于它之前。
A task might consist of a few JobSet
s. Each JobSet
performs a
few jobs. For instance calculating the changes for renaming a method in
a class hierarchy has two job sets: one to find the classes for
constructing the class hierarchy and another to change the occurrences.
一个任务可能包含几个 JobSet
。每个 JobSet
执行几个作业。例如,计算类层次结构中重命名方法的更改涉及两个作业集:一个用于查找构建类层次结构的类,另一个用于更改出现的位置。
The TaskHandle.current_jobset()
returns the most recent JobSet
or None
if none has been started. You can use the methods of
JobSet
for obtaining information about the current job. So you
might want to do something like:
TaskHandle.current_jobset()
返回最近开始的 JobSet
或如果没有开始则返回 None
。您可以使用 JobSet
的方法来获取当前作业的信息。因此,您可能希望执行类似的操作:
import rope.base.taskhandle
handle = rope.base.taskhandle.TaskHandle("Test Task")
def update_progress():
jobset = handle.current_jobsets()
if jobset:
text = ''
# getting current job set name
if jobset.get_name() is not None:
text += jobset.get_name()
# getting active job name
if jobset.get_active_job_name() is not None:
text += ' : ' + jobset.get_active_job_name()
# adding done percent
percent = jobset.get_percent_done()
if percent is not None:
text += ' ... %s percent done' % percent
print(text)
handle.add_observer(update_progress)
changes = renamer.get_changes('new_name', task_handle=handle)
Also you can use something like this for stopping the task:
同样,您可以使用类似以下方法来停止任务:
def stop():
handle.stop()
After calling stop()
, the thread that is executing the task will
be interrupted by a rope.base.exceptions.InterruptedTaskError
exception.
在调用 stop()
之后,执行任务的线程将被 rope.base.exceptions.InterruptedTaskError
异常中断。
Refactorings 重构操作
Have a look at rope.refactor
package and its sub-modules. For
example for performing a move refactoring you can create a Move
object like this:
查看 rope.refactor
包及其子模块。例如,要执行移动重构,您可以创建一个 Move
对象,如下所示:
mover = Move(project, resource, offset)
Where resource
and offset
is the location to perform the
refactoring.
resource
和 offset
表示进行重构的位置。
Then you can commit the changes by it using the get_changes()
method:
然后,您可以使用 get_changes()
方法提交这些更改:
project.do(mover.get_changes(destination))
Where the destination
module/package is the destination resource for
move refactoring. Other refactorings classes have a similar interface.
destination
模块/包是移动重构的目标资源。其他重构类具有类似的接口。
List Of Refactorings
重构列表
Here is the list of refactorings rope provides. (Note that this list
might be out of date.) For more information about these refactoring see
pydocs in their modules and the unit-tests in the ropetest/refactor/
folder.
以下是 rope 提供的重构列表。(请注意,此列表可能已过时。)有关这些重构的更多信息,请参阅其模块中的 pydocs 以及 ropetest/refactor/
文件夹中的单元测试。
rope.refactor.rename
: Rename something in the project. See the example below.
rope.refactor.rename
: 在项目中重命名某项。请参见下面的示例。rope.refactor.move
: Move a python element in the project.
rope.refactor.move
: 在项目中移动 Python 元素。rope.refactor.restructure
: Restructure code. See the example below.
rope.refactor.restructure
: 重构代码。请参考以下示例。rope.refactor.extract
: Extract methods/variables.
rope.refactor.extract
: 提取方法/变量。rope.refactor.inline
: Inline occurrences of a method/variable/parameter.
rope.refactor.inline
: 方法/变量/参数的内联出现。rope.refactor.usefunction
: Try to use a function wherever possible.
rope.refactor.usefunction
: 尽可能地使用函数。rope.refactor.method_object
: Transform a function or a method to a method object.
rope.refactor.method_object
: 将函数或方法转换为方法对象。rope.refactor.change_signature
: Change the signature of a function/method.
rope.refactor.change_signature
: 修改函数/方法的签名。rope.refactor.introduce_factory
: Introduce a factory for a class and changes all constructors to use it.
rope.refactor.introduce_factory
: 引入一个类的工厂,并将所有构造函数改为使用该工厂。rope.refactor.introduce_parameter
: Introduce a parameter in a function.
rope.refactor.introduce_parameter
: 在函数中引入一个参数。rope.refactor.encapsulate_field
: Generate a getter/setter for a field and changes its occurrences to use them.
rope.refactor.encapsulate_field
: 为字段生成 getter/setter,并将其出现的地方改为使用它们。rope.refactor.localtofield
: Change a local variable to field.
rope.refactor.localtofield
: 将局部变量改为字段。rope.refactor.topackage
: Transform a module to a package with the same name.
rope.refactor.topackage
: 将模块转换为同名包。rope.refactor.importutils
: Perform actions like organize imports.
rope.refactor.importutils
: 执行诸如组织导入之类的操作。
Refactoring Resources Parameter
重构资源参数
Some refactorings, restructure and find occurrences accept an argument
called resources
. If it is a list of Files, all other
resources in the project are ignored and the refactoring only analyzes
them. If it is None
all python modules in the project will be
analyzed. Using this parameter, IDEs can let the user limit the files
on which a refactoring should be applied.
某些重构、重构和查找引用功能接受一个名为 resources
的参数。如果它是一个文件列表,项目中的所有其他资源将被忽略,重构仅分析这些文件。如果它是 None
,项目中的所有 Python 模块都将被分析。通过使用此参数,IDE 可以让用户限制应应用重构的文件范围。
Examples 示例
Rename 重命名
Using rename refactoring:
使用重命名重构:
# Creating a project
>>> from rope.base.project import Project
>>> project = Project('.')
# Working with files to create a module
>>> mod1 = project.root.create_file('mod1.py')
>>> mod1.write('a_var = 10\n')
# Alternatively you can use `generate` module.
# Creating modules and packages using `generate` module
>>> from rope.contrib import generate
>>> pkg = generate.create_package(project, 'pkg')
>>> mod2 = generate.create_module(project, 'mod2', pkg)
>>> mod2.write('import mod1\nprint(mod1.a_var)\n')
# We can use `Project.find_module` for finding modules, too
>>> assert mod2 == project.find_module('pkg.mod2')
# Performing rename refactoring on `mod1.a_var`
>>> from rope.refactor.rename import Rename
>>> changes = Rename(project, mod1, 1).get_changes('new_var')
>>> project.do(changes)
>>> mod1.read()
u'new_var = 10\n'
>>> mod2.read()
u'import mod1\nprint(mod1.new_var)\n'
# Undoing rename refactoring
>>> project.history.undo()
...
>>> mod1.read()
u'a_var = 10\n'
>>> mod2.read()
u'import mod1\nprint(mod1.a_var)\n'
# Cleaning up
>>> pkg.remove()
>>> mod1.remove()
>>> project.close()
Restructuring 重组
The example for replacing occurrences of our pow
function to **
operator (see ref:overview:Restructurings):
将我们的 pow
函数替换为 **
运算符的示例(参见参考:概览:重构):
# Setting up the project
>>> from rope.base.project import Project
>>> project = Project('.')
>>> mod1 = project.root.create_file('mod1.py')
>>> mod1.write('def pow(x, y):\n result = 1\n'
... ' for i in range(y):\n result *= x\n'
... ' return result\n')
>>> mod2 = project.root.create_file('mod2.py')
>>> mod2.write('import mod1\nprint(mod1.pow(2, 3))\n')
>>> from rope.refactor import restructure
>>> pattern = '${pow_func}(${param1}, ${param2})'
>>> goal = '${param1} ** ${param2}'
>>> args = {'pow_func': 'name=mod1.pow'}
>>> restructuring = restructure.Restructure(project, pattern, goal, args)
>>> project.do(restructuring.get_changes())
>>> mod2.read()
u'import mod1\nprint(2 ** 3)\n'
# Cleaning up
>>> mod1.remove()
>>> mod2.remove()
>>> project.close()
See code documentation and test suites for more information.
查看代码文档和测试套件以获取更多信息。
Other Topics 其他主题
Writing A FileSystemCommands
编写文件系统命令
The get_changes()
method of refactoring classes return a
rope.base.change.Change
object. You perform these changes by
calling Project.do()
. But as explained above some IDEs need to
perform the changes themselves.
重构类的 get_changes()
方法返回一个 rope.base.change.Change
对象。您通过调用 Project.do()
来执行这些更改。但如上所述,某些 IDE 需要自行执行这些更改。
Every change to the file-system in rope is committed using an object that
provides a rope.base.fscommands.FileSystemCommands
interface. As
explained above in rope.base.fscommands section, rope uses this
interface to handle different VCSs.
在 rope 中,对文件系统的每一次更改都是通过一个提供 rope.base.fscommands.FileSystemCommands
接口的对象来提交的。如前所述,在 rope.base.fscommands 部分中,rope 利用这一接口来处理不同的版本控制系统(VCSs)。
You can implement your own fscommands object:
您可以实现自己的 fscommands 对象:
class MyFileSystemCommands(object):
def create_file(self, path):
"""Create a new file"""
# ...
def create_folder(self, path):
"""Create a new folder"""
# ...
def move(self, path, new_location):
"""Move resource at `path` to `new_location`"""
# ...
def remove(self, path):
"""Remove resource"""
# ...
def write(self, path, data):
"""Write `data` to file at `path`"""
# ...
def read(self, path):
"""Read `data` from file at `path`"""
# ...
And you can create a project like this:
您可以创建一个类似的项目:
my_fscommands = MyFileSystemCommands()
project = rope.base.project.Project('~/myproject',
fscommands=my_fscommands)
rope.contrib.codeassist
The rope.contrib
package contains modules that use rope base parts
and provide useful features. rope.contrib.codeassist
module can be
used in IDEs:
rope.contrib
包包含使用绳索基础部件的模块,并提供有用的功能。 rope.contrib.codeassist
模块可在集成开发环境(IDEs)中使用:
from rope.ide import codeassist
# Get the proposals; you might want to pass a Resource
proposals = codeassist.code_assist(project, source_code, offset)
# Sorting proposals; for changing the order see pydoc
proposals = codeassist.sorted_proposals(proposals)
# Where to insert the completions
starting_offset = codeassist.starting_offset(source_code, offset)
# Applying a proposal
proposal = proposals[x]
replacement = proposal.name
new_source_code = (source_code[:starting_offset] +
replacement + source_code[offset:])
maxfixes
parameter of code_assist
decides how many syntax errors
to fix. The default value is one. For instance:
code_assist
的 maxfixes
参数决定了要修复多少个语法错误。默认值为 1。例如:
def f():
g(my^
myvariable = None
def g(p):
invalid syntax ...
will report myvariable
, only if maxfixes
is greater than 1.
将报告 myvariable
,仅当 maxfixes
大于 1 时。
later_locals
, if True
, forces rope to propose names that are
defined later in current scope. It is True
by default. For
instance:
later_locals
,如果 True
,会迫使绳索提出在当前作用域中稍后定义的名称。默认情况下,它是 True
。例如:
def f():
my^
myvariable = None
will not report myvariable
, if later_locals
is False
.
如果 later_locals
是 False
,则不会报告 myvariable
。
See pydocs and source code for more information (other functions in
this module might be interesting, too; like get_doc
,
get_definition_location
).
查看 pydocs 和源代码以获取更多信息(本模块中的其他函数也可能很有趣,例如 get_doc
、 get_definition_location
)。
rope.contrib.findit
findit
module provides find_occurrences()
for finding
occurrences of a name. Also the find_implementations()
function
finds the places in which a method is overridden.
findit
模块提供了 find_occurrences()
用于查找名称的出现位置。此外, find_implementations()
函数可以找到方法被重写的地方。
rope.contrib.autoimport
This module can be used to find the modules that provide a name. IDEs
can use this module to auto-import names. AutoImport.get_modules()
returns the list of modules with the given global name.
AutoImport.import_assist()
tries to find the modules that have a
global name that starts with the given prefix.
此模块可用于查找提供特定名称的模块。集成开发环境(IDE)可利用此模块实现名称的自动导入。 AutoImport.get_modules()
返回包含指定全局名称的模块列表。 AutoImport.import_assist()
则尝试寻找全局名称以给定前缀开头的模块。
There are currently two implementations of autoimport in rope, a deprecated
implementation that uses pickle-based storage
(rope.contrib.autoimport.pickle.AutoImport) and a new, experimental one that
uses sqlite3 database (rope.contrib.autoimport.sqlite.AutoImport). New and
existing integrations should migrate to the sqlite3 storage as the pickle-based
autoimport will be removed in the future.
目前,rope 中有两种自动导入实现方式:一种是使用基于 pickle 存储的已弃用实现(rope.contrib.autoimport.pickle.AutoImport),另一种是使用 sqlite3 数据库的新实验性实现(rope.contrib.autoimport.sqlite.AutoImport)。新旧集成应迁移至 sqlite3 存储,因为基于 pickle 的自动导入将在未来被移除。
rope.contrib.autoimport.sqlite
Currently, the sqlite3-based only stores autoimport cache in an in-memory
sqlite3 database, you can make it write the import cache to persistent storage
by passing memory=False to AutoImport constructor. This default will change in
the future, if you want to always store the autoimport cache in-memory, then
you need to explicitly pass memory=True.
目前,基于 sqlite3 的系统仅将自动导入缓存存储在内存中的 sqlite3 数据库中,您可以通过向 AutoImport 构造函数传递 memory=False 参数,使其将导入缓存写入持久存储。未来这一默认设置将会改变,如果您希望始终在内存中存储自动导入缓存,则需要显式传递 memory=True。
It must be closed when done with the AutoImport.close()
method.
使用完 AutoImport.close()
方法后必须关闭。
AutoImport can search for a name from both modules and statements you can import from them.
AutoImport 能够从模块及其可导入的语句中搜索名称。
from rope.base.project import Project
from rope.contrib.autoimport import AutoImport
project = Project("/path/to/project")
autoimport = AutoImport(project, memory=False)
autoimport.generate_resource_cache() # Generates a cache of the local modules, from the project you're working on
autoimport.generate_modules_cache() # Generates a cache of external modules
print(autoimport.search("Dict"))
autoimport.close()
project.close()
- It provides two new search methods:
它提供了两种新的搜索方法: search_full() - returns a list of mostly unsorted tuples. This has itemkind and source information.
search_full() - 返回一个大部分未排序的元组列表。包含物品类型和来源信息。search() - simpler wrapper around search_full with a basic sorting algorithm
search() - 基于基本排序算法的 search_full 简化封装
Cross-Project Refactorings
跨项目重构
rope.refactor.multiproject
can be used to perform a refactoring
across multiple projects.
rope.refactor.multiproject
可用于在多个项目中执行重构。
Usually refactorings have a main project. That is the project that
contains the definition of the changing python name. Other projects
depend on the main one, and the uses of the changed name in them should
be updated.
通常,重构操作有一个主项目,即包含被修改 Python 名称定义的项目。其他项目依赖于主项目,因此在这些项目中对被修改名称的使用也应进行更新。
Each refactoring changes only one project (the project passed to its
constructor). But we can use the MultiProjectRefactoring
proxy to
perform a refactoring on other projects, too.
每次重构仅更改一个项目(即传递给其构造函数的项目)。但我们可以利用 MultiProjectRefactoring
代理对其他项目也进行重构。
First we need to create a multi-project refactoring constructor. As
an example consider that we want to perform a rename refactoring:
首先,我们需要创建一个多项目重构构造器。以重命名重构为例:
from rope.refactor import multiproject, rename
CrossRename = multiproject.MultiProjectRefactoring(rename.Rename,
projects)
Here projects
is the list of dependent projects. It does not
include the main project. The first argument is the refactoring class
(such as Rename
) or factory function (like create_move
).
以下是依赖项目的列表,不包括主项目。第一个参数是重构类(如 Rename
)或工厂函数(如 create_move
)。
Next we can construct the refactoring:
接下来,我们可以构建重构:
renamer = CrossRename(project, resource, offset)
We create the rename refactoring as we do for normal refactoings. Note
that project
is the main project.
我们像对待常规重构一样创建重命名重构。请注意, project
是主项目。
As mentioned above, other projects use the main project. Rope
automatically adds the main project to the python path of other
projects.
如上所述,其他项目使用主项目。Rope 会自动将主项目添加到其他项目的 Python 路径中。
Finally we can calculate the changes. But instead of calling
get_changes()
(which returns main project changes only), we can
call get_all_changes()
with the same arguments. It returns a list
of (project, changes)
tuples. You can perform them manually by
calling project.do(changes)
for each tuple, or use
multiproject.perform()
:
最终我们可以计算变更。但与其调用 get_changes()
(该函数仅返回主项目的变更),我们可以用相同的参数调用 get_all_changes()
。它会返回一个由 (project, changes)
元组组成的列表。你可以通过为每个元组调用 project.do(changes)
来手动执行这些变更,或者使用 multiproject.perform()
来简化操作:
project_and_changes = renamer.get_all_changes('newname')
multiproject.perform(project_and_changes)