overview.rst 28.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
===============
 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
13
rope as a library might find library.rst_ more useful.
14 15

.. contents:: Table of Contents
16
.. _library.rst: library.rst
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50


``.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
-------------------

51 52 53
Consider we have:

.. code-block:: python
54 55 56 57 58 59 60 61 62 63 64 65 66

  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
67 68 69
``new_method`` we'll have:

.. code-block:: python
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

  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
------------------------------------

86 87 88
On:

.. code-block:: python
89 90 91 92 93 94 95 96

  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
97 98 99
result in:

.. code-block:: python
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

  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

117 118 119
``mod1.py`` contains:

.. code-block:: python
120 121 122 123 124 125 126 127

  import mod2
  from mod2 import AClass

  mod2.a_func()
  a_var = AClass()

After performing rename refactoring one of the ``mod2`` occurrences in
128 129 130
`mod1` we'll get:

.. code-block:: python
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

  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
151 152 153
strings only where the name is visible.  For example in:

.. code-block:: python
154 155 156 157 158 159 160 161 162

  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
163 164 165
would get:

.. code-block:: python
166 167 168 169 170 171 172 173 174 175 176

  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.

177 178 179
This also changes occurrences inside evaluated strings:

.. code-block:: python
180 181 182 183 184 185

  def func():
      print 'func() called'

  eval('func()')

186 187 188
After renaming ``func`` to ``newfunc`` we should have:

.. code-block:: python
189 190 191 192 193 194 195 196 197 198 199 200

  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
201 202 203
'rename when unsure' option is set in:

.. code-block:: python
204 205 206 207 208 209 210 211 212 213

  class C(object):

      def a_func(self):
          pass

  def a_func(arg):
      arg.a_func()

  C().a_func()
214 215 216 217

we would have:

.. code-block:: python
218 219 220 221 222 223 224 225 226 227 228

  class C(object):

      def new_func(self):
          pass

  def a_func(arg):
      arg.new_func()

  C().new_func()

229
Note that the global ``a_func`` was not renamed because we are sure that
230 231 232 233 234 235 236 237 238 239 240 241 242
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.

243 244 245
For instance if you perform move method on ``a_method`` in:

.. code-block:: python
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

  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
263 264 265 266
and press enter, you'll have:

.. code-block:: python

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
  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()

284 285 286 287
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
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307

  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
308 309 310
refactoring to move fields.  For instance:

.. code-block:: python
311 312 313 314 315 316 317 318 319 320 321 322 323

  class A(object):
      pass

  class B(object):

      def __init__(self):
          self.a = A()
          self.attr = 1

  b = B()
  print(b.attr)

324 325 326 327 328
consider we want to move ``attr`` to ``A``.  We can do that by renaming
``attr`` to ``a.attr``:

.. code-block:: python

329 330 331 332 333 334 335 336 337 338 339 340
  class A(object):
      pass

  class B(object):

      def __init__(self):
          self.a = A()
          self.a.attr = 1

  b = B()
  print(b.a.attr)

341
You can move the definition of ``attr`` manually.
342 343 344 345 346 347


Extract Method
--------------

In these examples ``${region_start}`` and ``${region_end}`` show the
348 349 350
selected region for extraction:

.. code-block:: python
351 352 353 354 355 356

  def a_func():
      a = 1
      b = 2 * a
      c = ${region_start}a * 2 + b * 3${region_end}

357 358 359
After performing extract method we'll have:

.. code-block:: python
360 361 362 363 364 365 366 367 368

  def a_func():
      a = 1
      b = 2 * a
      c = new_func(a, b)

  def new_func(a, b):
      return a * 2 + b * 3

369 370 371
For multi-line extractions if we have:

.. code-block:: python
372 373 374 375 376 377 378

  def a_func():
      a = 1
      ${region_start}b = 2 * a
      c = a * 2 + b * 3${region_end}
      print b, c

379 380 381
After performing extract method we'll have:

.. code-block:: python
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398

  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
399 400 401
in:

.. code-block:: python
402 403 404 405 406 407

  if True:
      x = 2 * 3
  else:
      x = 2 * 3 + 1

408 409 410
Extracting ``2 * 3`` will result in:

.. code-block:: python
411 412 413 414 415 416 417 418 419 420 421 422

  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
423 424 425
class methods better.  For instance in:

.. code-block:: python
426 427 428 429 430 431 432

  class A(object):

      @staticmethod
      def f(a):
          b = a * 2

433 434 435
if you extract ``a * 2`` as a method you'll get:

.. code-block:: python
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451

  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
452 453 454
instance consider ``mod1.py`` is:

.. code-block:: python
455 456 457 458 459 460 461 462 463 464 465

  import sys


  class C(object):
      pass

  def do_something():
      print sys.version
      return C()

466 467 468
and ``mod2.py`` is:

.. code-block:: python
469 470 471 472 473 474

  import mod1


  c = mod1.do_something()

475 476 477
After inlining ``do_something``, ``mod2.py`` would be:

.. code-block:: python
478 479 480 481 482 483 484 485

  import mod1
  import sys


  print sys.version
  c = mod1.C()

486 487 488
Rope can inline methods, too:

.. code-block:: python
489 490 491 492 493 494

  class C(object):

      var = 1

      def f(self, p):
495 496
          result = self.var + pn
          return result
497 498 499 500 501


  c = C()
  x = c.f(1)

502 503 504
After inlining ``C.f()``, we'll have:

.. code-block:: python
505 506 507 508 509 510 511 512 513

  class C(object):

      var = 1

  c = C()
  result = c.var + pn
  x = result

514 515 516
As another example we will inline a ``classmethod``:

.. code-block:: python
517 518 519 520 521 522 523

  class C(object):
      @classmethod
      def say_hello(cls, name):
          return 'Saying hello to %s from %s' % (name, cls.__name__)
  hello = C.say_hello('Rope')

524 525 526
Inlining ``say_hello`` will result in:

.. code-block:: python
527 528 529 530 531 532 533 534 535

  class C(object):
      pass
  hello = 'Saying hello to %s from %s' % ('Rope', C.__name__)


Inlining Parameters
-------------------

536
``rope.refactor.inline.create_inline()`` creates an ``InlineParameter``
537 538
object when performed on a parameter.  It passes the default value of
the parameter wherever its function is called without passing it.  For
539 540 541
instance in:

.. code-block:: python
542 543 544 545 546 547 548 549

  def f(p1=1, p2=1):
      pass

  f(3)
  f()
  f(3, 4)

550
after inlining p2 parameter will have:
551

552 553 554
.. code-block:: python

  def f(p1=1, p2=2):
555 556 557 558 559 560 561 562 563 564 565
      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
566 567 568
changes the code to call it instead.  For instance if mod1 is:

.. code-block:: python
569 570 571 572 573 574 575

  def square(p):
      return p ** 2

  my_var = 3 ** 2


576 577 578
and mod2 is:

.. code-block:: python
579 580 581

  another_var = 4 ** 2

582 583 584
if we perform "use function" on square function, mod1 will be:

.. code-block:: python
585 586 587 588 589 590

  def square(p):
      return p ** 2

  my_var = square(3)

591 592 593
and mod2 will be:

.. code-block:: python
594 595 596 597 598 599 600 601

  import mod1
  another_var = mod1.square(4)


Automatic Default Insertion In Change Signature
-----------------------------------------------

602 603
The ``rope.refactor.change_signature.ArgumentReorderer`` signature
changer takes a parameter called ``autodef``.  If not ``None``, its
604 605
value is used whenever rope needs to insert a default for a parameter
(that happens when an argument without default is moved after another
606 607 608
that has a default value).  For instance in:

.. code-block:: python
609 610 611 612

  def f(p1, p2=2):
      pass

613 614 615
if we reorder using:

.. code-block:: python
616 617 618

  changers = [ArgumentReorderer([1, 0], autodef='1')]

619 620 621
will result in:

.. code-block:: python
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658

  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
----------------------

659 660 661 662 663 664
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.
665 666 667 668 669 670 671 672 673


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
674 675 676
inheritance.  For instance:

.. code-block:: python
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693

  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())

694 695 696 697 698 699 700 701 702 703
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
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728

  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
--------------

729
``rope.refactor.restructure`` can be used for performing restructurings.
730 731 732 733
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:

734
* ``rope.refactor.restructure`` for more examples and features not
735
  described here like adding imports to changed modules.
736
* ``rope.refactor.wildcards`` for an overview of the arguments the
737 738 739 740 741 742 743 744 745 746 747
  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
748 749 750
aware of the ``**`` operator and wrote our own:

.. code-block:: python
751 752 753 754 755 756 757 758 759

  def pow(x, y):
      result = 1
      for i in range(y):
          result *= x
      return result

  print pow(2, 3)

760
Now that we know ``**`` exists we want to use it wherever ``pow`` is
761 762 763 764 765 766 767 768 769 770 771 772 773
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
774 775 776
restructuring will be:

.. code-block:: python
777 778 779 780 781 782 783 784 785

  def pow(x, y):
      result = 1
      for i in range(y):
          result *= x
      return result

  print 2 ** 3

786
It seems to be working but what if ``pow`` is imported in some module or
787 788 789 790 791 792 793 794 795 796
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
797 798
reference).  For instance for specifying ``pow`` in this example we can
use ``mod.pow``.  As you see, this string should start from module name.
799
For referencing python builtin types and functions you can use
800
``__builtin__`` module (for instance ``__builtin__.int``).
801

802 803
For solving the mentioned problem, we change our ``pattern``.  But
``goal`` remains the same::
804 805 806 807

  pattern: ${pow_func}(${param1}, ${param2})
  goal: ${param1} ** ${param2}

808 809
Consider the name of the module containing our ``pow`` function is
``mod``.  ``args`` can be::
810 811 812 813 814 815

  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``.

816 817 818
This restructuring handles aliases like in:

.. code-block:: python
819 820 821 822

  mypow = pow
  result = mypow(2, 3)

823 824 825
Transforms into:

.. code-block:: python
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842

  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).

843
For performing this refactoring using rope library see `library.rst`_.
844 845 846 847 848


Example 2
'''''''''

849 850 851
As another example consider:

.. code-block:: python
852 853 854 855 856 857 858 859 860 861 862

  class A(object):

      def f(self, p1, p2):
          print p1
          print p2


  a = A()
  a.f(1, 2)

863 864 865 866
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
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896

  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

897 898 899
After performing we will have:

.. code-block:: python
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922

  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 =
923 924 925
y`` when x is an instance of ``mod.A`` in:

.. code-block:: python
926 927 928 929 930 931 932 933 934 935 936 937 938 939

  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

940 941 942
After performing the above restructuring we'll have:

.. code-block:: python
943 944 945 946 947 948 949

  from mod import A

  a = A()
  b = A()
  a = b

950 951 952
Note that ``mod.py`` contains something like:

.. code-block:: python
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978

  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
-----------------------

979
.. code-block:: python
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999

  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}


1000 1001 1002
Basic support for builtin types:

.. code-block:: python
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015

  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}

1016 1017 1018
Enhanced static returned object inference:

.. code-block:: python
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029

    class C(object):

        def c_func(self):
            return ['']

    def a_func(arg):
        return arg.c_func()

    a_var = a_func(C())

1030 1031
Here rope knows that the type of a_var is a ``list`` that holds
``str``\s.
1032

1033 1034 1035
Supporting generator functions:

.. code-block:: python
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046

  class C(object):
      pass

  def a_generator():
      yield C()


  for c in a_generator():
      a_var = c

1047
Here the objects ``a_var`` and ``c`` hold are known.
1048 1049

Rope collects different types of data during SOA, like per name data
1050 1051 1052
for builtin container types:

.. code-block:: python
1053 1054 1055 1056 1057 1058 1059 1060

  l1 = [C()]
  var1 = l1.pop()

  l2 = []
  l2.append(C())
  var2 = l2.pop()

1061 1062 1063
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
1064 1065 1066 1067
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
1068 1069 1070
complex and dynamic situations.  For example in:

.. code-block:: python
1071 1072 1073 1074 1075 1076

  def f(arg):
      return eval(arg)

  a_var = f('C')

1077
SOA can no way conclude the object ``a_var`` holds but it is really
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
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
-----------------------

1088
``PyCore.run_module()`` runs a module and collects object information if
1089 1090 1091 1092 1093
``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.

1094 1095 1096
``mod1.py``:

.. code-block:: python
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106

  def f1(param):
      pass
      #param.${codeassist}
      #f2(param).${codeassist}

  def f2(param):
      #param.${codeassist}
      return param

1107 1108 1109
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``.
1110

1111 1112 1113
``mod2.py``:

.. code-block:: python
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124

  import mod1

  class A(object):

      def a_method(self):
          pass

  a_var = A()
  mod1.f1(a_var)

1125
Retry those code assists after performing DOA on ``mod2`` module.
1126 1127 1128 1129 1130


Builtin Container Types
'''''''''''''''''''''''

1131 1132 1133
Builtin types can be handled in a limited way, too:

.. code-block:: python
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153

  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
----------------------------------------------------

1154 1155 1156
``mod1.py``:

.. code-block:: python
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177

  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())

1178 1179 1180
After running ``mod1`` either SOA or DOA on this module you can test:

``mod2.py``:
1181

1182
.. code-block:: python
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211

  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``.


1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
Type Hinting
------------

Currently supported type hinting for:

- function parameter type, using function doctring (:type or @type)
- function return type, using function doctring (:rtype or @rtype)
- class attribute type, using class docstring (:type or @type). Attribute should by set to None or NotImplemented in class.
- any assignment, using type comments of PEP 0484 (in limited form).

If rope cannot detect the type of a function argument correctly (due to the
dynamic nature of Python), you can help it by hinting the type using
one of the following docstring syntax styles.


**Sphinx style**

http://sphinx-doc.org/domains.html#info-field-lists

::

    def myfunction(node, foo):
        """Do something with a ``node``.

        :type node: ProgramNode
        :param str foo: foo parameter description

        """
        node.| # complete here


**Epydoc**

http://epydoc.sourceforge.net/manual-fields.html

::

    def myfunction(node):
        """Do something with a ``node``.

        @type node: ProgramNode

        """
        node.| # complete here


**Numpydoc**

https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt

In order to support the numpydoc format, you need to install the `numpydoc
<https://pypi.python.org/pypi/numpydoc>`__ package.

::

    def foo(var1, var2, long_var_name='hi'):
        r"""A one-line summary that does not use variable names or the
        function name.

        ...

        Parameters
        ----------
        var1 : array_like
            Array_like means all those objects -- lists, nested lists,
            etc. -- that can be converted to an array. We can also
            refer to variables like `var1`.
        var2 : int
            The type above can either refer to an actual Python type
            (e.g. ``int``), or describe the type of the variable in more
            detail, e.g. ``(N,) ndarray`` or ``array_like``.
        long_variable_name : {'hi', 'ho'}, optional
            Choices in brackets, default first when optional.

        ...

        """
        var2.| # complete here


**PEP 0484**

https://www.python.org/dev/peps/pep-0484/#type-comments

::

   class Sample(object):
       def __init__(self):
           self.x = None  # type: random.Random
           self.x.| # complete here


Supported syntax of type hinting
''''''''''''''''''''''''''''''''

Currently rope supports the following syntax of type-hinting.

Parametrized objects:

- Foo
- foo.bar.Baz
- list[Foo] or list[foo.bar.Baz] etc.
- set[Foo]
- tuple[Foo]
- dict[Foo, Bar]
- collections.Iterable[Foo]
- collections.Iterator[Foo]

Nested expressions also allowed:

- collections.Iterable[list[Foo]]

TODO:

Callable objects:

- (Foo, Bar) -> Baz

Multiple interfaces implementation:

- Foo | Bar


1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
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
===============================

1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
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.
1359 1360

Adding support for other VCSs is easy; have a look at
1361
`library.rst`_.
1362 1363 1364

.. _pysvn: http://pysvn.tigris.org
.. _Mercurial: http://selenic.com/mercurial
1365 1366
.. _GIT: http://git.or.cz
.. _darcs: http://darcs.net