| Index: tools/telemetry/third_party/rope/docs/library.rst
|
| diff --git a/tools/telemetry/third_party/rope/docs/library.rst b/tools/telemetry/third_party/rope/docs/library.rst
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..390b9c87c69aa25038acdf051446b76f27d2eb71
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/rope/docs/library.rst
|
| @@ -0,0 +1,890 @@
|
| +=========================
|
| + Using Rope As A Library
|
| +=========================
|
| +
|
| +If you need other features, send a feature request. Have a look at
|
| +`contributing.rst`_.
|
| +
|
| +
|
| +.. contents:: Table of Contents
|
| +
|
| +
|
| +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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +* 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's ``ropefolder`` parameter. Passing ``None`` prevents rope
|
| + from making this folder.
|
| +* Rope uses the ``.ropeproject`` folder for things like saving object
|
| + information and loading project configurations.
|
| +* Project preferences can be configured by passing options to the
|
| + constructor or in ``.ropeproject/config.py``. See the default
|
| + ``config.py``, ``rope.base.default_config`` module, for more
|
| + information.
|
| +* All configurations that are available in the ``config.py`` file can
|
| + be specified as keyword parameters to the ``Project`` constructor.
|
| + These parameters override the ones in the ``config.py`` file.
|
| +* Each project has a set of ignored resource patterns. You can use it
|
| + to tell rope to ignore files and folders matching certain patterns.
|
| +* The ``.ropeproject`` folder can be safely copied in other clones of
|
| + a project if you don't want to lose your objectdb and history.
|
| +
|
| +
|
| +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.
|
| +
|
| +
|
| +What Are These `Resource`\s?
|
| +----------------------------
|
| +
|
| +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.
|
| +
|
| +There are two options for creating a ``Resource`` for a path in a project.
|
| +The first approach uses the `Project.get_resource()`_ method.
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +
|
| +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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + resource = libutils.path_to_resource(myproject, '/path/to/my/module.py')
|
| +
|
| +Now we can make our Refactoring class:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +Next, the IDE ask the user to configure refactoring options, like
|
| +specifying the name of the extracted variable.
|
| +
|
| +After that, we can calculate the changes:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +
|
| +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?
|
| +
|
| +*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.
|
| +
|
| +*Performing*:
|
| +
|
| +The easiest way for performing the refactoring is to use the
|
| +`Project.do()`_ method:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +1. The first approach is to use `rope.base.fscommands`_ (see `Writing A
|
| + FileSystemCommands`_). The changes can be performed as before using
|
| + `Project.do()`_.
|
| +
|
| +2. The second approach is to perform the changes manually based on the
|
| + returned ``changes`` object (again see the documentation in
|
| + ``rope.base.change`` module). If this approach is used you cannot undo
|
| + the refactoring using ``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.
|
| +
|
| +
|
| +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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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).
|
| +
|
| +
|
| +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.
|
| +
|
| +If you have ``automatic_soa`` set, which instructs rop 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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + # 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.
|
| +
|
| +
|
| +Closing The Project
|
| +-------------------
|
| +
|
| +`Project.close()`_ closes a project's open resources. Always call this
|
| +function when you don't need a project anymore:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +
|
| +``libutils.analyze_module()``
|
| +------------------------------
|
| +
|
| +Perform static object analysis on a Python file in the project. Note,
|
| +this may be a very time consuming task.
|
| +
|
| +.. code-block:: 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.
|
| +
|
| +.. code-block:: 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.
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +.. code-block:: python
|
| +
|
| + scope = libutils.get_string_scope(myproject, source)
|
| +
|
| +
|
| +``libutils.is_python_file()``
|
| +-----------------------------
|
| +
|
| +Returns ``True`` if the resource is a Python file.
|
| +
|
| +.. code-block:: python
|
| +
|
| + libutils.is_python_file(myproject, resource)
|
| +
|
| +
|
| +``libutils.modname()``
|
| +----------------------
|
| +
|
| +Retrieves the dotted path string to the module that contains that given
|
| +resource.
|
| +
|
| +.. code-block:: python
|
| +
|
| + # 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.
|
| +
|
| +.. code-block:: python
|
| +
|
| + # 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'``.
|
| +
|
| +.. code-block:: python
|
| +
|
| + # 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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + project = Project(root_address)
|
| +
|
| +Where the ``root_address`` is the root folder of your project.
|
| +
|
| +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.do()`
|
| +--------------
|
| +
|
| +Used to commit changes returned by refactorings:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +
|
| +`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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +
|
| +``.ropeproject`` Folder
|
| +=======================
|
| +
|
| +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``.
|
| +
|
| +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.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.
|
| +
|
| +``PyCore.run_module()`` runs a resource. When running, it collects type
|
| +information to do dynamic object inference. For this reason modules
|
| +run much slower.
|
| +
|
| +Also ``Pycore.analyze_module()`` collects object information for a
|
| +module. The collected information can be used to enhance rope's
|
| +static object inference.
|
| +
|
| +
|
| +`rope.base.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.
|
| +
|
| +Always pass ``task_handle`` as keyword argument. It will always be the
|
| +last argument, and new arguments of the refactoring are added before it.
|
| +
|
| +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.
|
| +
|
| +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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + def stop():
|
| + handle.stop()
|
| +
|
| +After calling ``stop()``, the thread that is executing the task will
|
| +be interrupted by a ``rope.base.exceptions.InterruptedTaskError``
|
| +exception.
|
| +
|
| +
|
| +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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + mover = Move(project, resource, offset)
|
| +
|
| +Where ``resource`` and ``offset`` is the location to perform the
|
| +refactoring.
|
| +
|
| +Then you can commit the changes by it using the ``get_changes()``
|
| +method:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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.
|
| +
|
| +
|
| +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.refactor.rename``:
|
| + Rename something in the project. See the example below.
|
| +
|
| +* ``rope.refactor.move``:
|
| + Move a python element in the project.
|
| +
|
| +* ``rope.refactor.restructure``:
|
| + Restructure code. See the example below.
|
| +
|
| +* ``rope.refactor.extract``:
|
| + Extract methods/variables.
|
| +
|
| +* ``rope.refactor.inline``:
|
| + Inline occurrences of a method/variable/parameter.
|
| +
|
| +* ``rope.refactor.usefunction``:
|
| + Try to use a function wherever possible.
|
| +
|
| +* ``rope.refactor.method_object``:
|
| + Transform a function or a method to a method object.
|
| +
|
| +* ``rope.refactor.change_signature``:
|
| + Change the signature of a function/method.
|
| +
|
| +* ``rope.refactor.introduce_factory``:
|
| + Introduce a factory for a class and changes all constructors to use
|
| + it.
|
| +
|
| +* ``rope.refactor.introduce_parameter``:
|
| + Introduce a parameter in a function.
|
| +
|
| +* ``rope.refactor.encapsulate_field``:
|
| + Generate a getter/setter for a field and changes its occurrences to
|
| + use them.
|
| +
|
| +* ``rope.refactor.localtofield``:
|
| + Change a local variable to field.
|
| +
|
| +* ``rope.refactor.topackage``:
|
| + Transform a module to a package with the same name.
|
| +
|
| +* ``rope.refactor.importutils``:
|
| + Perform actions like organize imports.
|
| +
|
| +
|
| +Refactoring Resources Parameter
|
| +-------------------------------
|
| +
|
| +Some refactorings, restructure and find occurrences accept an argument
|
| +called ``resources``. If it is a list of `File`\s, 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.
|
| +
|
| +
|
| +Examples
|
| +========
|
| +
|
| +Rename
|
| +------
|
| +
|
| +Using rename refactoring:
|
| +
|
| +.. code-block:: python
|
| +
|
| + # 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 the restructuring section of `overview.rst`_):
|
| +
|
| +.. code-block:: python
|
| +
|
| + # 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.
|
| +
|
| +.. _overview.rst: overview.rst
|
| +.. _contributing.rst: contributing.rst
|
| +
|
| +
|
| +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.
|
| +
|
| +Every change to the file-system in rope is commited 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.
|
| +
|
| +You can implement your own fscommands object:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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`"""
|
| + # ...
|
| +
|
| +And you can create a project like this:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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:
|
| +
|
| +.. code-block:: python
|
| +
|
| + 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-block:: python
|
| +
|
| + def f():
|
| + g(my^
|
| +
|
| + myvariable = None
|
| +
|
| + def g(p):
|
| + invalid syntax ...
|
| +
|
| +will report ``myvariable``, only if ``maxfixes`` is greater than 1.
|
| +
|
| +``later_locals``, if ``True``, forces rope to propose names that are
|
| +defined later in current scope. It is ``True`` by default. For
|
| +instance:
|
| +
|
| +.. code-block:: python
|
| +
|
| + def f():
|
| + my^
|
| + myvariable = None
|
| +
|
| +will not report ``myvariable``, if ``later_locals`` is ``False``.
|
| +
|
| +See pydocs and source code for more information (other functions in
|
| +this module might be interesting, too; like ``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.
|
| +
|
| +
|
| +`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.
|
| +
|
| +
|
| +Cross-Project Refactorings
|
| +--------------------------
|
| +
|
| +``rope.refactor.multiproject`` can be used to perform a refactoring
|
| +across multiple projects.
|
| +
|
| +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.
|
| +
|
| +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.
|
| +
|
| +First we need to create a multi-project refactoring constructor. As
|
| +an example consider that we want to perform a rename refactoring:
|
| +
|
| +.. code-block:: python
|
| +
|
| + from rope.refactor import multiproject, rename
|
| +
|
| +
|
| + CrossRename = multiproject.MultiProjectRefactoring(rename.Rename,
|
| + projects)
|
| +
|
| +
|
| +Here ``projects`` is the list of dependant projects. It does not
|
| +include the main project. The first argument is the refactoring class
|
| +(such as ``Rename``) or factory function (like ``create_move``).
|
| +
|
| +Next we can construct the refactoring:
|
| +
|
| +.. code-block:: python
|
| +
|
| + renamer = CrossRename(project, resource, offset)
|
| +
|
| +We create the rename refactoring as we do for normal refactoings. Note
|
| +that ``project`` is the main project.
|
| +
|
| +As mentioned above, other projects use the main project. Rope
|
| +automatically adds the main project to the python path of other
|
| +projects.
|
| +
|
| +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()``:
|
| +
|
| +.. code-block:: python
|
| +
|
| + project_and_changes = renamer.get_all_changes('newname')
|
| +
|
| + multiproject.perform(project_and_changes)
|
|
|