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

Unified Diff: tools/telemetry/third_party/rope/docs/overview.rst

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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/telemetry/third_party/rope/docs/library.rst ('k') | tools/telemetry/third_party/rope/docs/rope.rst » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/telemetry/third_party/rope/docs/overview.rst
diff --git a/tools/telemetry/third_party/rope/docs/overview.rst b/tools/telemetry/third_party/rope/docs/overview.rst
new file mode 100644
index 0000000000000000000000000000000000000000..3863c9d5e05d9a9c2cbd9a6f9f24a79766d777f5
--- /dev/null
+++ b/tools/telemetry/third_party/rope/docs/overview.rst
@@ -0,0 +1,1243 @@
+===============
+ Rope Overview
+===============
+
+
+The purpose of this file is to give an overview of some of rope's
+features. It is incomplete. And some of the features shown here are
+old and do not show what rope can do in extremes. So if you really
+want to feel the power of rope try its features and see its unit
+tests.
+
+This file is more suitable for the users. Developers who plan to use
+rope as a library might find library.rst_ more useful.
+
+.. contents:: Table of Contents
+.. _library.rst: library.rst
+
+
+``.ropeproject`` Folder
+=======================
+
+Rope uses a folder inside projects for holding project configuration
+and data. Its default name is ``.ropeproject``, but it can be
+changed (you can even tell rope not to create this folder).
+
+Currently it is used for things such as:
+
+* There is a ``config.py`` file in this folder in which you can change
+ project configurations. Have look at the default ``config.py`` file
+ (is created when it does not exist) for more information.
+* It can be used for saving project history, so that the next time you
+ open the project you can undo past changes.
+* It can be used for saving object information to help rope object
+ inference.
+* It can be used for saving global names cache which is used in
+ auto-import.
+
+You can change what to save and what not to in the ``config.py`` file.
+
+
+Refactorings
+============
+
+This section shows some random refactorings that you can perform using
+rope.
+
+
+Renaming Attributes
+-------------------
+
+Consider we have:
+
+.. code-block:: python
+
+ class AClass(object):
+
+ def __init__(self):
+ self.an_attr = 1
+
+ def a_method(self, arg):
+ print self.an_attr, arg
+
+ a_var = AClass()
+ a_var.a_method(a_var.an_attr)
+
+After renaming ``an_attr`` to ``new_attr`` and ``a_method`` to
+``new_method`` we'll have:
+
+.. code-block:: python
+
+ class AClass(object):
+
+ def __init__(self):
+ self.new_attr = 1
+
+ def new_method(self, arg):
+ print self.new_attr, arg
+
+ a_var = AClass()
+ a_var.new_method(a_var.new_attr)
+
+
+Renaming Function Keyword Parameters
+------------------------------------
+
+On:
+
+.. code-block:: python
+
+ def a_func(a_param):
+ print a_param
+
+ a_func(a_param=10)
+ a_func(10)
+
+performing rename refactoring on any occurrence of ``a_param`` will
+result in:
+
+.. code-block:: python
+
+ def a_func(new_param):
+ print new_param
+
+ a_func(new_param=10)
+ a_func(10)
+
+
+Renaming modules
+----------------
+
+Consider the project tree is something like::
+
+ root/
+ mod1.py
+ mod2.py
+
+``mod1.py`` contains:
+
+.. code-block:: python
+
+ import mod2
+ from mod2 import AClass
+
+ mod2.a_func()
+ a_var = AClass()
+
+After performing rename refactoring one of the ``mod2`` occurrences in
+`mod1` we'll get:
+
+.. code-block:: python
+
+ import newmod
+ from newmod import AClass
+
+ newmod.a_func()
+ a_var = AClass()
+
+and the new project tree would be::
+
+ root/
+ mod1.py
+ newmod.py
+
+
+Renaming Occurrences In Strings And Comments
+--------------------------------------------
+
+You can tell rope to rename all occurrences of a name in comments and
+strings. This can be done by passing ``docs=True`` to
+`Rename.get_changes()` method. Rope renames names in comments and
+strings only where the name is visible. For example in:
+
+.. code-block:: python
+
+ def f():
+ a_var = 1
+ # INFO: I'm printing `a_var`
+ print 'a_var = %s' % a_var
+
+ # f prints a_var
+
+after we rename the `a_var` local variable in `f()` to `new_var` we
+would get:
+
+.. code-block:: python
+
+ def f():
+ new_var = 1
+ # INFO: I'm printing `new_var`
+ print 'new_var = %s' % new_var
+
+ # f prints a_var
+
+This makes it safe to assume that this option does not perform wrong
+renames most of the time.
+
+This also changes occurrences inside evaluated strings:
+
+.. code-block:: python
+
+ def func():
+ print 'func() called'
+
+ eval('func()')
+
+After renaming ``func`` to ``newfunc`` we should have:
+
+.. code-block:: python
+
+ def newfunc():
+ print 'newfunc() called'
+
+ eval('newfunc()')
+
+
+Rename When Unsure
+------------------
+
+This option tells rope to rename when it doesn't know whether it is an
+exact match or not. For example after renaming `C.a_func` when the
+'rename when unsure' option is set in:
+
+.. code-block:: python
+
+ class C(object):
+
+ def a_func(self):
+ pass
+
+ def a_func(arg):
+ arg.a_func()
+
+ C().a_func()
+
+we would have:
+
+.. code-block:: python
+
+ class C(object):
+
+ def new_func(self):
+ pass
+
+ def a_func(arg):
+ arg.new_func()
+
+ C().new_func()
+
+Note that the global ``a_func`` was not renamed because we are sure that
+it is not a match. But when using this option there might be some
+unexpected renames. So only use this option when the name is almost
+unique and is not defined in other places.
+
+Move Method Refactoring
+-----------------------
+
+It happens when you perform move refactoring on a method of a class.
+In this refactoring, a method of a class is moved to the class of one
+of its attributes. The old method will call the new method. If you
+want to change all of the occurrences of the old method to use the new
+method you can inline it afterwards.
+
+For instance if you perform move method on ``a_method`` in:
+
+.. code-block:: python
+
+ class A(object):
+ pass
+
+ class B(object):
+
+ def __init__(self):
+ self.attr = A()
+
+ def a_method(self):
+ pass
+
+ b = B()
+ b.a_method()
+
+You will be asked for the destination field and the name of the new
+method. If you use ``attr`` and ``new_method`` in these fields
+and press enter, you'll have:
+
+.. code-block:: python
+
+ class A(object):
+
+ def new_method(self):
+ pass
+
+ class B(object):
+
+ def __init__(self):
+ self.attr = A()
+
+ def a_method(self):
+ return self.attr.new_method()
+
+
+ b = B()
+ b.a_method()
+
+Now if you want to change the occurrences of ``B.a_method()`` to use
+``A.new_method()``, you can inline ``B.a_method()``:
+
+.. code-block:: python
+
+ class A(object):
+
+ def new_method(self):
+ pass
+
+ class B(object):
+
+ def __init__(self):
+ self.attr = A()
+
+ b = B()
+ b.attr.new_method()
+
+
+Moving Fields
+-------------
+
+Rope does not have a separate refactoring for moving fields. Rope's
+refactorings are very flexible, though. You can use the rename
+refactoring to move fields. For instance:
+
+.. code-block:: python
+
+ class A(object):
+ pass
+
+ class B(object):
+
+ def __init__(self):
+ self.a = A()
+ self.attr = 1
+
+ b = B()
+ print(b.attr)
+
+consider we want to move ``attr`` to ``A``. We can do that by renaming
+``attr`` to ``a.attr``:
+
+.. code-block:: python
+
+ class A(object):
+ pass
+
+ class B(object):
+
+ def __init__(self):
+ self.a = A()
+ self.a.attr = 1
+
+ b = B()
+ print(b.a.attr)
+
+You can move the definition of ``attr`` manually.
+
+
+Extract Method
+--------------
+
+In these examples ``${region_start}`` and ``${region_end}`` show the
+selected region for extraction:
+
+.. code-block:: python
+
+ def a_func():
+ a = 1
+ b = 2 * a
+ c = ${region_start}a * 2 + b * 3${region_end}
+
+After performing extract method we'll have:
+
+.. code-block:: python
+
+ def a_func():
+ a = 1
+ b = 2 * a
+ c = new_func(a, b)
+
+ def new_func(a, b):
+ return a * 2 + b * 3
+
+For multi-line extractions if we have:
+
+.. code-block:: python
+
+ def a_func():
+ a = 1
+ ${region_start}b = 2 * a
+ c = a * 2 + b * 3${region_end}
+ print b, c
+
+After performing extract method we'll have:
+
+.. code-block:: python
+
+ def a_func():
+ a = 1
+ b, c = new_func(a)
+ print b, c
+
+ def new_func(a):
+ b = 2 * a
+ c = a * 2 + b * 3
+ return b, c
+
+
+Extracting Similar Expressions/Statements
+-----------------------------------------
+
+When performing extract method or local variable refactorings you can
+tell rope to extract similar expressions/statements. For instance
+in:
+
+.. code-block:: python
+
+ if True:
+ x = 2 * 3
+ else:
+ x = 2 * 3 + 1
+
+Extracting ``2 * 3`` will result in:
+
+.. code-block:: python
+
+ six = 2 * 3
+ if True:
+ x = six
+ else:
+ x = six + 1
+
+
+Extract Method In staticmethods/classmethods
+--------------------------------------------
+
+The extract method refactoring has been enhanced to handle static and
+class methods better. For instance in:
+
+.. code-block:: python
+
+ class A(object):
+
+ @staticmethod
+ def f(a):
+ b = a * 2
+
+if you extract ``a * 2`` as a method you'll get:
+
+.. code-block:: python
+
+ class A(object):
+
+ @staticmethod
+ def f(a):
+ b = A.twice(a)
+
+ @staticmethod
+ def twice(a):
+ return a * 2
+
+
+Inline Method Refactoring
+-------------------------
+
+Inline method refactoring can add imports when necessary. For
+instance consider ``mod1.py`` is:
+
+.. code-block:: python
+
+ import sys
+
+
+ class C(object):
+ pass
+
+ def do_something():
+ print sys.version
+ return C()
+
+and ``mod2.py`` is:
+
+.. code-block:: python
+
+ import mod1
+
+
+ c = mod1.do_something()
+
+After inlining ``do_something``, ``mod2.py`` would be:
+
+.. code-block:: python
+
+ import mod1
+ import sys
+
+
+ print sys.version
+ c = mod1.C()
+
+Rope can inline methods, too:
+
+.. code-block:: python
+
+ class C(object):
+
+ var = 1
+
+ def f(self, p):
+ result = self.var + pn
+ return result
+
+
+ c = C()
+ x = c.f(1)
+
+After inlining ``C.f()``, we'll have:
+
+.. code-block:: python
+
+ class C(object):
+
+ var = 1
+
+ c = C()
+ result = c.var + pn
+ x = result
+
+As another example we will inline a ``classmethod``:
+
+.. code-block:: python
+
+ class C(object):
+ @classmethod
+ def say_hello(cls, name):
+ return 'Saying hello to %s from %s' % (name, cls.__name__)
+ hello = C.say_hello('Rope')
+
+Inlining ``say_hello`` will result in:
+
+.. code-block:: python
+
+ class C(object):
+ pass
+ hello = 'Saying hello to %s from %s' % ('Rope', C.__name__)
+
+
+Inlining Parameters
+-------------------
+
+``rope.refactor.inline.create_inline()`` creates an ``InlineParameter``
+object when performed on a parameter. It passes the default value of
+the parameter wherever its function is called without passing it. For
+instance in:
+
+.. code-block:: python
+
+ def f(p1=1, p2=1):
+ pass
+
+ f(3)
+ f()
+ f(3, 4)
+
+after inlining p2 parameter will have:
+
+.. code-block:: python
+
+ def f(p1=1, p2=1):
+ pass
+
+ f(3, 2)
+ f(p2=2)
+ f(3, 4)
+
+
+Use Function Refactoring
+------------------------
+
+It tries to find the places in which a function can be used and
+changes the code to call it instead. For instance if mod1 is:
+
+.. code-block:: python
+
+ def square(p):
+ return p ** 2
+
+ my_var = 3 ** 2
+
+
+and mod2 is:
+
+.. code-block:: python
+
+ another_var = 4 ** 2
+
+if we perform "use function" on square function, mod1 will be:
+
+.. code-block:: python
+
+ def square(p):
+ return p ** 2
+
+ my_var = square(3)
+
+and mod2 will be:
+
+.. code-block:: python
+
+ import mod1
+ another_var = mod1.square(4)
+
+
+Automatic Default Insertion In Change Signature
+-----------------------------------------------
+
+The ``rope.refactor.change_signature.ArgumentReorderer`` signature
+changer takes a parameter called ``autodef``. If not ``None``, its
+value is used whenever rope needs to insert a default for a parameter
+(that happens when an argument without default is moved after another
+that has a default value). For instance in:
+
+.. code-block:: python
+
+ def f(p1, p2=2):
+ pass
+
+if we reorder using:
+
+.. code-block:: python
+
+ changers = [ArgumentReorderer([1, 0], autodef='1')]
+
+will result in:
+
+.. code-block:: python
+
+ def f(p2=2, p1=1):
+ pass
+
+
+Sorting Imports
+---------------
+
+Organize imports sorts imports, too. It does that according to
+:PEP:`8`::
+
+ [__future__ imports]
+
+ [standard imports]
+
+ [third-party imports]
+
+ [project imports]
+
+
+ [the rest of module]
+
+
+Handling Long Imports
+---------------------
+
+``Handle long imports`` command trys to make long imports look better by
+transforming ``import pkg1.pkg2.pkg3.pkg4.mod1`` to ``from
+pkg1.pkg2.pkg3.pkg4 import mod1``. Long imports can be identified
+either by having lots of dots or being very long. The default
+configuration considers imported modules with more than 2 dots or with
+more than 27 characters to be long.
+
+
+Stoppable Refactorings
+----------------------
+
+Some refactorings might take a long time to finish (based on the size of
+your project). The ``get_changes()`` method of these refactorings take
+a parameter called ``task_handle``. If you want to monitor or stop
+these refactoring you can pass a ``rope.refactor.taskhandle.TaskHandle``
+to this method. See ``rope.refactor.taskhandle`` module for more
+information.
+
+
+Basic Implicit Interfaces
+-------------------------
+
+Implicit interfaces are the interfaces that you don't explicitly
+define; But you expect a group of classes to have some common
+attributes. These interfaces are very common in dynamic languages;
+Since we only have implementation inheritance and not interface
+inheritance. For instance:
+
+.. code-block:: python
+
+ class A(object):
+
+ def count(self):
+ pass
+
+ class B(object):
+
+ def count(self):
+ pass
+
+ def count_for(arg):
+ return arg.count()
+
+ count_for(A())
+ count_for(B())
+
+Here we know that there is an implicit interface defined by the function
+``count_for`` that provides ``count()``. Here when we rename
+``A.count()`` we expect ``B.count()`` to be renamed, too. Currently
+rope supports a basic form of implicit interfaces. When you try to
+rename an attribute of a parameter, rope renames that attribute for all
+objects that have been passed to that function in different call sites.
+That is renaming the occurrence of ``count`` in ``count_for`` function
+to ``newcount`` will result in:
+
+.. code-block:: python
+
+ class A(object):
+
+ def newcount(self):
+ pass
+
+ class B(object):
+
+ def newcount(self):
+ pass
+
+ def count_for(arg):
+ return arg.newcount()
+
+ count_for(A())
+ count_for(B())
+
+This also works for change method signature. Note that this feature
+relies on rope's object analysis mechanisms to find out the parameters
+that are passed to a function.
+
+
+Restructurings
+--------------
+
+``rope.refactor.restructure`` can be used for performing restructurings.
+A restructuring is a program transformation; not as well defined as
+other refactorings like rename. In this section, we'll see some
+examples. After this example you might like to have a look at:
+
+* ``rope.refactor.restructure`` for more examples and features not
+ described here like adding imports to changed modules.
+* ``rope.refactor.wildcards`` for an overview of the arguments the
+ default wildcard supports.
+
+Finally, restructurings can be improved in many ways (for instance
+adding new wildcards). You might like to discuss your ideas in the
+mailing list.
+
+
+Example 1
+'''''''''
+
+In its basic form we have a pattern and a goal. Consider we were not
+aware of the ``**`` operator and wrote our own:
+
+.. code-block:: python
+
+ def pow(x, y):
+ result = 1
+ for i in range(y):
+ result *= x
+ return result
+
+ print pow(2, 3)
+
+Now that we know ``**`` exists we want to use it wherever ``pow`` is
+used (there might be hundreds of them!). We can use a pattern like::
+
+ pattern: pow(${param1}, ${param2})
+
+Goal can be something like::
+
+ goal: ${param1} ** ${param2}
+
+Note that ``${...}`` can be used to match expressions. By default
+every expression at that point will match.
+
+You can use the matched names in goal and they will be replaced with
+the string that was matched in each occurrence. So the outcome of our
+restructuring will be:
+
+.. code-block:: python
+
+ def pow(x, y):
+ result = 1
+ for i in range(y):
+ result *= x
+ return result
+
+ print 2 ** 3
+
+It seems to be working but what if ``pow`` is imported in some module or
+we have some other function defined in some other module that uses the
+same name and we don't want to change it. Wildcard arguments come to
+rescue. Wildcard arguments is a mapping; Its keys are wildcard names
+that appear in the pattern (the names inside ``${...}``).
+
+The values are the parameters that are passed to wildcard matchers.
+The arguments a wildcard takes is based on its type.
+
+For checking the type of a wildcard, we can pass ``type=value`` as an
+argument; ``value`` should be resolved to a python variable (or
+reference). For instance for specifying ``pow`` in this example we can
+use ``mod.pow``. As you see, this string should start from module name.
+For referencing python builtin types and functions you can use
+``__builtin__`` module (for instance ``__builtin__.int``).
+
+For solving the mentioned problem, we change our ``pattern``. But
+``goal`` remains the same::
+
+ pattern: ${pow_func}(${param1}, ${param2})
+ goal: ${param1} ** ${param2}
+
+Consider the name of the module containing our ``pow`` function is
+``mod``. ``args`` can be::
+
+ pow_func: name=mod.pow
+
+If we need to pass more arguments to a wildcard matcher we can use
+``,`` to separate them. Such as ``name: type=mod.MyClass,exact``.
+
+This restructuring handles aliases like in:
+
+.. code-block:: python
+
+ mypow = pow
+ result = mypow(2, 3)
+
+Transforms into:
+
+.. code-block:: python
+
+ mypow = pow
+ result = 2 ** 3
+
+If we want to ignore aliases we can pass ``exact`` as another wildcard
+argument::
+
+ pattern: ${pow}(${param1}, ${param2})
+ goal: ${param1} ** ${param2}
+ args: pow: name=mod.pow, exact
+
+``${name}``, by default, matches every expression at that point; if
+``exact`` argument is passed to a wildcard only the specified name
+will match (for instance, if ``exact`` is specified , ``${name}``
+matches ``name`` and ``x.name`` but not ``var`` nor ``(1 + 2)`` while
+a normal ``${name}`` can match all of them).
+
+For performing this refactoring using rope library see `library.rst`_.
+
+
+Example 2
+'''''''''
+
+As another example consider:
+
+.. code-block:: python
+
+ class A(object):
+
+ def f(self, p1, p2):
+ print p1
+ print p2
+
+
+ a = A()
+ a.f(1, 2)
+
+Later we decide that ``A.f()`` is doing too much and we want to divide
+it to ``A.f1()`` and ``A.f2()``:
+
+.. code-block:: python
+
+ class A(object):
+
+ def f(self, p1, p2):
+ print p1
+ print p2
+
+ def f1(self, p):
+ print p
+
+ def f2(self, p):
+ print p
+
+
+ a = A()
+ a.f(1, 2)
+
+But who's going to fix all those nasty occurrences (actually this
+situation can be handled using inline method refactoring but this is
+just an example; consider inline refactoring is not implemented yet!).
+Restructurings come to rescue::
+
+ pattern: ${inst}.f(${p1}, ${p2})
+ goal:
+ ${inst}.f1(${p1})
+ ${inst}.f2(${p2})
+
+ args:
+ inst: type=mod.A
+
+After performing we will have:
+
+.. code-block:: python
+
+ class A(object):
+
+ def f(self, p1, p2):
+ print p1
+ print p2
+
+ def f1(self, p):
+ print p
+
+ def f2(self, p):
+ print p
+
+
+ a = A()
+ a.f1(1)
+ a.f2(2)
+
+
+Example 3
+'''''''''
+
+If you like to replace every occurrences of ``x.set(y)`` with ``x =
+y`` when x is an instance of ``mod.A`` in:
+
+.. code-block:: python
+
+ from mod import A
+
+ a = A()
+ b = A()
+ a.set(b)
+
+We can perform a restructuring with these information::
+
+ pattern: ${x}.set(${y})
+ goal: ${x} = ${y}
+
+ args: x: type=mod.A
+
+After performing the above restructuring we'll have:
+
+.. code-block:: python
+
+ from mod import A
+
+ a = A()
+ b = A()
+ a = b
+
+Note that ``mod.py`` contains something like:
+
+.. code-block:: python
+
+ class A(object):
+
+ def set(self, arg):
+ pass
+
+Issues
+''''''
+
+Pattern names can appear only at the start of an expression. For
+instance ``var.${name}`` is invalid. These situations can usually be
+fixed by specifying good checks, for example on the type of `var` and
+using a ``${var}.name``.
+
+
+Object Inference
+================
+
+This section is a bit out of date. Static object inference can do
+more than described here (see unittests). Hope to update this
+someday!
+
+
+Static Object Inference
+-----------------------
+
+.. code-block:: python
+
+ class AClass(object):
+
+ def __init__(self):
+ self.an_attr = 1
+
+ def call_a_func(self):
+ return a_func()
+
+ def a_func():
+ return AClass()
+
+ a_var = a_func()
+ #a_var.${codeassist}
+
+ another_var = a_var
+ #another_var.${codeassist}
+ #another_var.call_a_func().${codeassist}
+
+
+Basic support for builtin types:
+
+.. code-block:: python
+
+ a_list = [AClass(), AClass()]
+ for x in a_list:
+ pass
+ #x.${codeassist}
+ #a_list.pop().${codeassist}
+
+ a_dict = ['text': AClass()]
+ for key, value in a_dict.items():
+ pass
+ #key.${codeassist}
+ #value.${codeassist}
+
+Enhanced static returned object inference:
+
+.. code-block:: python
+
+ class C(object):
+
+ def c_func(self):
+ return ['']
+
+ def a_func(arg):
+ return arg.c_func()
+
+ a_var = a_func(C())
+
+Here rope knows that the type of a_var is a ``list`` that holds
+``str``\s.
+
+Supporting generator functions:
+
+.. code-block:: python
+
+ class C(object):
+ pass
+
+ def a_generator():
+ yield C()
+
+
+ for c in a_generator():
+ a_var = c
+
+Here the objects ``a_var`` and ``c`` hold are known.
+
+Rope collects different types of data during SOA, like per name data
+for builtin container types:
+
+.. code-block:: python
+
+ l1 = [C()]
+ var1 = l1.pop()
+
+ l2 = []
+ l2.append(C())
+ var2 = l2.pop()
+
+Here rope can easily infer the type of ``var1``. But for knowing the
+type of ``var2``, it needs to analyze the items inserted into ``l2``
+which might happen in other modules. Rope can do that by running SOA on
+that module.
+
+You might be wondering is there any reason for using DOA instead of
+SOA. The answer is that DOA might be more accurate and handles
+complex and dynamic situations. For example in:
+
+.. code-block:: python
+
+ def f(arg):
+ return eval(arg)
+
+ a_var = f('C')
+
+SOA can no way conclude the object ``a_var`` holds but it is really
+trivial for DOA. What's more SOA only analyzes calls in one module
+while DOA analyzes any call that happens when running a module. That
+is, for achieving the same result as DOA you might need to run SOA on
+more than one module and more than once (not considering dynamic
+situations.) One advantage of SOA is that it is much faster than DOA.
+
+
+Dynamic Object Analysis
+-----------------------
+
+``PyCore.run_module()`` runs a module and collects object information if
+``perform_doa`` project config is set. Since as the program runs rope
+gathers type information, the program runs much slower. After the
+program is run, you can get better code assists and some of the
+refactorings perform much better.
+
+``mod1.py``:
+
+.. code-block:: python
+
+ def f1(param):
+ pass
+ #param.${codeassist}
+ #f2(param).${codeassist}
+
+ def f2(param):
+ #param.${codeassist}
+ return param
+
+Using code assist in specified places does not give any information and
+there is actually no information about the return type of ``f2`` or
+``param`` parameter of ``f1``.
+
+``mod2.py``:
+
+.. code-block:: python
+
+ import mod1
+
+ class A(object):
+
+ def a_method(self):
+ pass
+
+ a_var = A()
+ mod1.f1(a_var)
+
+Retry those code assists after performing DOA on ``mod2`` module.
+
+
+Builtin Container Types
+'''''''''''''''''''''''
+
+Builtin types can be handled in a limited way, too:
+
+.. code-block:: python
+
+ class A(object):
+
+ def a_method(self):
+ pass
+
+ def f1():
+ result = []
+ result.append(A())
+ return result
+
+ returned = f()
+ #returned[0].${codeassist}
+
+Test the the proposed completions after running this module.
+
+
+Guessing Function Returned Value Based On Parameters
+----------------------------------------------------
+
+``mod1.py``:
+
+.. code-block:: python
+
+ class C1(object):
+
+ def c1_func(self):
+ pass
+
+ class C2(object):
+
+ def c2_func(self):
+ pass
+
+
+ def func(arg):
+ if isinstance(arg, C1):
+ return C2()
+ else:
+ return C1()
+
+ func(C1())
+ func(C2())
+
+After running ``mod1`` either SOA or DOA on this module you can test:
+
+``mod2.py``:
+
+.. code-block:: python
+
+ import mod1
+
+ arg = mod1.C1()
+ a_var = mod1.func(arg)
+ a_var.${codeassist}
+ mod1.func(mod1.C2()).${codeassist}
+
+
+Automatic SOA
+-------------
+
+When turned on, it analyzes the changed scopes of a file when saving
+for obtaining object information; So this might make saving files a
+bit more time consuming. By default, this feature is turned on, but
+you can turn it off by editing your project ``config.py`` file, though
+that is not recommended.
+
+
+Validating Object DB
+--------------------
+
+Since files on disk change over time project objectdb might hold
+invalid information. Currently there is a basic incremental objectdb
+validation that can be used to remove or fix out of date information.
+Rope uses this feature by default but you can disable it by editing
+``config.py``.
+
+
+Custom Source Folders
+=====================
+
+By default rope searches the project for finding source folders
+(folders that should be searched for finding modules). You can add
+paths to that list using ``source_folders`` project config. Note that
+rope guesses project source folders correctly most of the time. You
+can also extend python path using ``python_path`` config.
+
+
+Version Control Systems Support
+===============================
+
+When performing refactorings some files might need to be moved (when
+renaming a module) or new files might be created. When using a VCS,
+rope detects and uses it to perform file system actions.
+
+Currently Mercurial_, GIT_, Darcs_ and SVN (using pysvn_ library) are
+supported. They are selected based on dot files in project root
+directory. For instance, Mercurial will be used if `mercurial` module
+is available and there is a ``.hg`` folder in project root. Rope
+assumes either all files are under version control in a project or
+there is no version control at all. Also don't forget to commit your
+changes yourself, rope doesn't do that.
+
+Adding support for other VCSs is easy; have a look at
+`library.rst`_.
+
+.. _pysvn: http://pysvn.tigris.org
+.. _Mercurial: http://selenic.com/mercurial
+.. _GIT: http://git.or.cz
+.. _darcs: http://darcs.net
« no previous file with comments | « tools/telemetry/third_party/rope/docs/library.rst ('k') | tools/telemetry/third_party/rope/docs/rope.rst » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698