Anonymous avatar Anonymous committed 966fe96

Getting started for 0.4m1

Comments (0)

Files changed (16)

 
 Some of the changes since 0.2
 
-* Unit-test running view
-* Previewing refactoring changes
-* Encapsulate field
-* Extract method/variable
-* Undoing/redoing refactorings
-* Convert local variable to field refactoring
-* Inline local variable
-* Rename function parameters/class/function/module/packages
-* Renaming methods in class hierarchies
-* Move refactoring for class/function/module/package
-* Import tools
-* Show PyDoc
-* Introduce factory method refactoring
-* Basic subversion support using pysvn
-* Transform module to package refactoring
-* Function argument dynamic object inference
-* Basic dynamic object inference
-* Code completions inside uncompleted ``try`` blocks
-* Hiding unappropriate menu items in different contexts
-
-Changes since 0.3rc1
-
-* Better code assist proposal sorting and dialog
-* Extract method works with normal selection
-* Basic python file encoding support
+* 
 
 
 Getting Started

docs/dev/contributing.txt

 -----------
 
 Always use the latest version of files from rope Subversion repository
-at https://svn.sourceforge.net/svnroot/rope
+from https://svn.sourceforge.net/svnroot/rope
 
 * Submit patches in the format returned by the ``svn diff`` command.
 * Follow :PEP:`8`.

docs/dev/done.txt

 ===========
 
 
+> Public Release 0.3 : November 5, 2006
+
+
 - Better code assist proposal sorting and dialog : November 3, 2006
 
 

docs/dev/issues.txt

 might be released before the ``x.y`` release.
 
 
-Version 0.3
+Version 0.4
 ===========
 
-From August 7, 2006 till November 5, 2006
+From November 6, 2006 till February 4, 2007
 
 
 Release Goals
 -------------
 
-Metaphor: Deliver the most interesting features
+Metaphor: Enhance features and make rope extensible
 
 
-Releases
---------
-
-0.3m1
-    Done.
-0.3m2
-    Done.
-0.3m3
-    Done.
-0.3m4
-    Done.
-0.3m5
-    Done.
-0.3rc1
-    Done.
-0.3
-    Working on.
-
-
-Possible Plans For 0.4
-======================
+Possible Plans
+--------------
 
 * Inline method
 * Move field/methods
 * Using a modification of `compiler` AST for simplifying refactorings
 
 
+Inline Method
+=============
+
+The simplest thing to do is to replace each method call with its
+body.  We should rename parameters to match the name of the passed
+variable in the method call.  When expressions are passed we can
+assign then to a new variable.
+
+But the problem is we should parse the method call ourselves, since
+we cannot find method calls in ASTs.  This problem happend once more
+for using Smalltalk Refactoring Browser's approach for finding
+occurances.  So it might worth the effort to see if this problem can
+be solved somehow.
+
+* Which of the variables should be renamed?
+* What to do about parameter assignments?
+* Removing the function after removing
+* Handling returns
+* Recursive calls
+* Default parameters
+* Keywords
+* Handling class methods
+* What to do about static or class methods
+* Moving used imports
+
+What to do for::
+
+  def func():
+      print 'hey'
+  
+  f = func
+  f()
+
+Should we inline `f`?  Can we use dynamically gathered information
+for this purpose?
+
+
+Using ASTs For Transformations
+==============================
+
+The main problem with AST nodes is that they only hold the line in
+which statements appear but we need the offset.  If we can add offset
+information to AST nodes, we would be able to use them for all of the
+tasks that we do right now using direct operations on program source
+code.
+
+Using ASTs for transforming programs requires making a new AST tree
+or altering the old one and writing AST trees.  We can use the latter
+in the formatter, too but it seems a lot of work.
+
+
 Using Rope As A Library
 =======================
 
 changes to the files, since it has to update its stored information.
 
 
-Better Code Assist
-==================
-
-Was done for ``0.3``.
-
-
-Better Type Information
------------------------
-
-The problem with code assist is that we indicate only information
-about the scope a variable is defined in.  We can provide more
-information about its type, too::
-
-  def _get_pyname_type(self, pyname):
-      if isinstance(pyname, rope.base.pynames.AssignedName):
-          return 'variable'
-      if isinstance(pyname, rope.base.pynames.DefinedName):
-          pyobject = pyname.get_object()
-          if isinstance(pyobject, rope.base.pyobjects.PyFunction):
-              return 'function'
-          else:
-              return 'class'
-      if isinstance(pyname, rope.base.pynames.ImportedName) or \
-         isinstance(pyname, rope.base.pynames.ImportedModule):
-          return 'imported'
-      if isinstance(pyname, rope.base.pynames.ParameterName):
-          return 'parameter'
-
-So the type of completion proposals are:
-
-* ``variable``: AssignedName
-* ``class`` : DefinedName
-* ``function`` : DefinedName
-* ``imported``: ImportedModule, ImportedName
-* ``paramter``: Parameter
-* `None`: keywords, builtins and ...
-
-Note that actually each pyname may hold any kind of object, but we are
-not reporting the object a pyname holds.  Instead we only say if this
-pyname is defined here and if it is defined what its type is.  That is
-pynames types do not use object inference information.
-
-And as before proposal kind can be:
-
-* ``global``
-* ``local``
-* ``builtin``
-* ``attribute``
-* ``keyword``
-* ``template``
-
-
-Better Sorting
---------------
-
-Rope should prefer defined objects(classes and functions) over
-variables.  After the above change this would be easy.
-
-
 Designing Refactorings to Be Used in IDEs
 =========================================
 
-* Multi-step refactorings
-* Previewing refactorings
 * Finding available refactorings
 * A better facade
 * Better refactoring categoriztion
   Reduce the dependence to `rope.refactor` modules
 
 
-Multi-step Refactorings
------------------------
-
-A refactoring should be done in three steps.
-
-1. Getting immediate information
-   
-   After this step we can provide some useful information.  Like the
-   initial name for rename refactoring.
-   
-2. Getting user provided information
-
-   The problem with this step is that based on the first step we
-   might need different data.  For example for move refactoring we
-   need different information for moving a field versus moving a
-   class.
-   
-   This separation helps us to report some of the errors earlier.
-
-3. Finding the changes to be made
-
-   We perform the actual refactoring here.  After this step we can
-   preview the changes.
-
-4. Performing the refactoring
-
-
-What will happen to `PythonRefactoring` facade?
-
-
 A Common Refactoring Interface
 ------------------------------
 
 The question we need to answer before proceeding is to decide
 whether this belongs to UI or core.
 
+Making Adding New Refactorings Easier
+-------------------------------------
+
+Adding a new refactoring requires changing `Refactoring` facade and
+Adding the new refactoring class.  Duplications:
+
+* Duplicate parameters
+* We have the same refactoring class for inlines, extracts and
+  renames but we have to call their constructors separately.
+
 
 Undo Unification
 ================
 be inferred.
 
 
-Builtin Types And Functions
-===========================
-
-What should we do about builtin functions and types?
-
-Builtin types:
-
-* list, typle
-* dict
-* str, unicode
-* file
-* set, frozenset
-* int, float, long, complex
-* iterator types
-* boolean
-
-Builtin constants:
-
-* False
-* True
-* None
-* NotImplemented
-* Ellipsis
-
-Builtin functions:
-
-* range
-* super
-
-One approach to builtin types would be to use the `__builtin__` module
-dynamically.  The other might be to write classes for the most
-interesting ones like `list`\s, `dict`\s and `str`\s.
-
-
 Refactoring `rope.codeanalyze` Module
 =====================================
 

docs/dev/stories.txt

 * Pull up method
 
 
-* Type hierarchy
+* View type hierarchy
 
 
 * Push down method
 * Show PyDoc reST highlighting
 
 
-* Handling builtin functions and types
-
-
 * Better list and tree navigation
   Add filter texts and selection texts to trees and lists.
 
   * Reorder
 
 
+* Removing imports from the same module
+
+
+* Handling builtin functions and types
+
+
+> Public Release 0.4m1 : November 19, 2006
+
+
 * Sorting imports; standard, third party, project
 
 
-* Removing imports from the same module
-
-
 * Moving fields/methods to attribute classes
 
 
 * Inline method
 
-
-> Public Release 0.3 : November 5, 2006

docs/dev/workingon.txt

-Before 0.3 Release
-==================
+Exploring Inline Method
+=======================
 
-* Moving to Subversion repository on sourceforge.net
-* Testing on nt
+- Removing the function after inlining
+
+* Ignoring parameters and just putting function definition
+  
+  We should remove the following parameters, too.
+
+Have a look at the ``Inline Method`` section of ``issues.txt``
 
 
 Remaining Stories
 =================
 
+* Problems for renaming vars in `__init__.py` of packages!
 * ``How to use rope as a library`` doc
 * Better `ropetest` package structure
 * Decide when to use `difflib` in `Editor.set_text`
 """rope, a python refactoring IDE"""
 
-VERSION = '0.3'
+VERSION = '0.4m1'

rope/base/pyobjects.py

             init_object._add_dependant(self)
         return result
 
+    def _create_concluded_attributes(self):
+        return {}
+
     def _get_child_resources(self):
         result = {}
         for child in self.resource.get_children():

rope/refactor/__init__.py

                   get_changes(dest_resource)
         self.add_and_commit_changes(changes)
     
-    def inline_local_variable(self, resource, offset):
-        changes = InlineRefactoring(self.pycore, resource, offset).inline()
+    def inline(self, resource, offset):
+        changes = InlineRefactoring(self.pycore, resource, offset).get_changes()
         self.add_and_commit_changes(changes)
     
     def encapsulate_field(self, resource, offset):

rope/refactor/inline.py

 import rope.base.codeanalyze
 import rope.base.exceptions
 import rope.base.pynames
+import rope.base.pyobjects
 from rope.refactor.change import ChangeSet, ChangeContents
 
 
     
     def __init__(self, pycore, resource, offset):
         self.pycore = pycore
-        self.resource = resource
-        self.pymodule = self.pycore.resource_to_pyobject(resource)
         self.pyname = rope.base.codeanalyze.get_pyname_at(self.pycore, resource, offset)
         self.name = rope.base.codeanalyze.get_name_at(resource, offset)
-        self._check_exceptional_conditions()
+        if self.name is None:
+            raise rope.base.exceptions.RefactoringException(
+                'Inline refactoring should be performed on a method/local variable.')
+        if self._is_variable():
+            self.performer = _VariableInliner(pycore, self.name, self.pyname)
+        elif self._is_method():
+            self.performer = _MethodInliner(pycore, self.name, self.pyname)
+        else:
+            raise rope.base.exceptions.RefactoringException(
+                'Inline refactoring should be performed on a method/local variable.')
+        self.performer.check_exceptional_conditions()
     
-    def inline(self):
+    def get_changes(self):
+        return self.performer.get_changes()
+    
+    def _is_variable(self):
+        return isinstance(self.pyname, rope.base.pynames.AssignedName)
+
+    def _is_method(self):
+        return isinstance(self.pyname.get_object(), rope.base.pyobjects.PyFunction)
+
+
+class _Inliner(object):
+    
+    def __init__(self, pycore, name, pyname):
+        self.pycore = pycore
+        self.name = name
+        self.pyname = pyname
+
+    def check_exceptional_conditions(self):
+        pass
+
+    def get_changes(self):
+        pass
+
+
+class _MethodInliner(_Inliner):
+    
+    def __init__(self, *args, **kwds):
+        super(_MethodInliner, self).__init__(*args, **kwds)
+    
+    def get_changes(self):
+        changes = ChangeSet()
+        self._change_defining_file(changes)
+        return changes
+
+    def _change_defining_file(self, changes):
+        pyfunction = self.pyname.get_object()
+        pymodule = pyfunction.get_module()
+        resource = pyfunction.get_module().get_resource()
+        scope = pyfunction.get_scope()
+        source = pymodule.source_code
+        lines = pymodule.lines
+        start_offset = lines.get_line_start(scope.get_start())
+        end_offset = lines.get_line_end(scope.get_end())
+        result = source[:start_offset] + source[end_offset + 1:]
+        changes.add_change(ChangeContents(resource, result))
+    
+    def _change_other_files(self, changes):
+        pass
+
+
+class _VariableInliner(_Inliner):
+    
+    def check_exceptional_conditions(self):
+        if len(self.pyname.assigned_asts) != 1:
+            raise rope.base.exceptions.RefactoringException(
+                'Local variable should be assigned once or inlining.')
+
+    def get_changes(self):
+        pymodule = self.pyname.get_definition_location()[0]
+        resource = pymodule.get_resource()
         definition_line = self.pyname.assigned_asts[0].lineno
-        lines = self.pymodule.lines
+        lines = pymodule.lines
         start, end = rope.base.codeanalyze.LogicalLineFinder(lines).\
                      get_logical_line_in(definition_line)
         definition_lines = []
         
         changed_source = rope.refactor.rename.RenameInModule(
             self.pycore, [self.pyname], self.name, definition, replace_primary=True).\
-            get_changed_module(pymodule=self.pymodule)
+            get_changed_module(pymodule=pymodule)
         if changed_source is None:
-            changed_source = self.pymodule.source_code
+            changed_source = pymodule.source_code
         lines = rope.base.codeanalyze.SourceLinesAdapter(changed_source)
         source = changed_source[:lines.get_line_start(start)] + \
                  changed_source[lines.get_line_end(end) + 1:]
         changes = ChangeSet()
-        changes.add_change(ChangeContents(self.resource, source))
+        changes.add_change(ChangeContents(resource, source))
         return changes
     
     def _is_tuple_assignment(self, line):
             return comma < assign
         except ValueError:
             return False
-
-    def _check_exceptional_conditions(self):
-        if self.pyname is None or not isinstance(self.pyname, rope.base.pynames.AssignedName):
-            raise rope.base.exceptions.RefactoringException(
-                'Inline local variable should be performed on a local variable.')
-        if len(self.pyname.assigned_asts) != 1:
-            raise rope.base.exceptions.RefactoringException(
-                'Local variable should be assigned Once.')

rope/ui/refactor.py

         fileeditor = context.get_active_editor()
         resource = fileeditor.get_file()
         editor = fileeditor.get_editor()
-        _get_refactoring(context).inline_local_variable(resource, editor.get_current_offset())
+        _get_refactoring(context).inline(resource, editor.get_current_offset())
     
 def encapsulate_field(context):
     if context.get_active_editor():
                             MenuAddress(['Refactor', 'Extract Method'], 'x'), ['python']))
 actions.append(SimpleAction('Move Refactoring', ConfirmAllEditorsAreSaved(move), 'M-V',
                             MenuAddress(['Refactor', 'Move'], 'm'), ['python']))
-actions.append(SimpleAction('Inline Local Variable', ConfirmAllEditorsAreSaved(inline), 'M-I',
-                            MenuAddress(['Refactor', 'Inline Local Variable'], 'i'), ['python']))
+actions.append(SimpleAction('Inline', ConfirmAllEditorsAreSaved(inline), 'M-I',
+                            MenuAddress(['Refactor', 'Inline'], 'i'), ['python']))
 actions.append(SimpleAction('Extract Local Variable', ConfirmAllEditorsAreSaved(extract_variable), None,
                             MenuAddress(['Refactor', 'Extract Local Variable'], 'l'), ['python']))
 actions.append(SimpleAction('Rename in File', ConfirmAllEditorsAreSaved(local_rename), None,

ropetest/pycoretest.py

         mod2 = self.pycore.get_module('mod')
         self.assertTrue('var' in mod2.get_attributes())
 
+    def test_invalidating_cache_after_resource_change_for_init_do_pys(self):
+        pkg = self.pycore.create_package(self.project.get_root_folder(), 'pkg')
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        init_dot_py = pkg.get_child('__init__.py')
+        init_dot_py.write('a_var = 10\n')
+        mod.write('import pkg\n')
+        pymod = self.pycore.get_module('mod')
+        self.assertTrue('a_var' in pymod.get_attribute('pkg').get_object().get_attributes())
+        init_dot_py.write('new_var = 10\n')
+        self.assertTrue('a_var' not in pymod.get_attribute('pkg').get_object().get_attributes())
+
     def test_from_import_nonexistant_module(self):
         mod = self.pycore.get_string_module('from doesnotexistmod import DoesNotExistClass\n')
         self.assertTrue('DoesNotExistClass' in mod.get_attributes())

ropetest/refactor/__init__.py

     result.addTests(unittest.makeSuite(IntroduceFactoryTest))
     result.addTests(unittest.makeSuite(ropetest.refactor.movetest.MoveRefactoringTest))
     result.addTests(unittest.makeSuite(RefactoringUndoTest))
-    result.addTests(unittest.makeSuite(ropetest.refactor.inlinetest.InlineLocalVariableTest))
+    result.addTests(ropetest.refactor.inlinetest.suite())
     result.addTests(unittest.makeSuite(EncapsulateFieldTest))
     result.addTests(unittest.makeSuite(LocalToFieldTest))
     return result

ropetest/refactor/inlinetest.py

 import ropetest
 
 
-class InlineLocalVariableTest(unittest.TestCase):
+class InlineTest(unittest.TestCase):
 
     def setUp(self):
-        super(InlineLocalVariableTest, self).setUp()
+        super(InlineTest, self).setUp()
         self.project_root = 'sample_project'
         ropetest.testutils.remove_recursively(self.project_root)
         self.project = rope.base.project.Project(self.project_root)
 
     def tearDown(self):
         ropetest.testutils.remove_recursively(self.project_root)
-        super(InlineLocalVariableTest, self).tearDown()
+        super(InlineTest, self).tearDown()
     
-    def _inline_local_variable(self, code, offset):
+    def _inline(self, code, offset):
         self.mod.write(code)
-        self.refactoring.inline_local_variable(self.mod, offset)
+        self.refactoring.inline(self.mod, offset)
         return self.mod.read()
     
     def test_simple_case(self):
         code = 'a_var = 10\nanother_var = a_var\n'
-        refactored = self._inline_local_variable(code, code.index('a_var') + 1)
+        refactored = self._inline(code, code.index('a_var') + 1)
         self.assertEquals('another_var = 10\n', refactored)        
 
     def test_empty_case(self):
         code = 'a_var = 10\n'
-        refactored = self._inline_local_variable(code, code.index('a_var') + 1)
+        refactored = self._inline(code, code.index('a_var') + 1)
         self.assertEquals('', refactored)        
 
     def test_long_definition(self):
         code = 'a_var = 10 + (10 + 10)\nanother_var = a_var\n'
-        refactored = self._inline_local_variable(code, code.index('a_var') + 1)
+        refactored = self._inline(code, code.index('a_var') + 1)
         self.assertEquals('another_var = 10 + (10 + 10)\n', refactored)        
 
     def test_explicit_continuation(self):
         code = 'a_var = (10 +\n 10)\nanother_var = a_var\n'
-        refactored = self._inline_local_variable(code, code.index('a_var') + 1)
+        refactored = self._inline(code, code.index('a_var') + 1)
         self.assertEquals('another_var = (10 + 10)\n', refactored)        
 
     def test_implicit_continuation(self):
         code = 'a_var = 10 +\\\n       10\nanother_var = a_var\n'
-        refactored = self._inline_local_variable(code, code.index('a_var') + 1)
+        refactored = self._inline(code, code.index('a_var') + 1)
         self.assertEquals('another_var = 10 + 10\n', refactored)        
 
     def test_inlining_at_the_end_of_input(self):
         code = 'a = 1\nb = a'
-        refactored = self._inline_local_variable(code, code.index('a') + 1)
+        refactored = self._inline(code, code.index('a') + 1)
         self.assertEquals('b = 1', refactored)
 
     @ropetest.testutils.assert_raises(rope.base.exceptions.RefactoringException)
     def test_on_classes(self):
-        code = 'def AClass(object):\n    pass\n'
-        refactored = self._inline_local_variable(code, code.index('AClass') + 1)
+        code = 'class AClass(object):\n    pass\n'
+        refactored = self._inline(code, code.index('AClass') + 1)
 
     @ropetest.testutils.assert_raises(rope.base.exceptions.RefactoringException)
     def test_multiple_assignments(self):
         code = 'a_var = 10\na_var = 20\n'
-        refactored = self._inline_local_variable(code, code.index('a_var') + 1)
+        refactored = self._inline(code, code.index('a_var') + 1)
 
     @ropetest.testutils.assert_raises(rope.base.exceptions.RefactoringException)
     def test_on_parameters(self):
         code = 'def a_func(a_param):\n    pass\n'
-        refactored = self._inline_local_variable(code, code.index('a_param') + 1)
+        refactored = self._inline(code, code.index('a_param') + 1)
 
     @ropetest.testutils.assert_raises(rope.base.exceptions.RefactoringException)
     def test_tuple_assignments(self):
         code = 'a_var, another_var = (20, 30)\n'
-        refactored = self._inline_local_variable(code, code.index('a_var') + 1)
+        refactored = self._inline(code, code.index('a_var') + 1)
 
     def test_attribute_inlining(self):
         code = 'class A(object):\n    def __init__(self):\n' \
                '        self.an_attr = 3\n        range(self.an_attr)\n'
-        refactored = self._inline_local_variable(code, code.index('an_attr') + 1)
+        refactored = self._inline(code, code.index('an_attr') + 1)
         expected = 'class A(object):\n    def __init__(self):\n' \
                    '        range(3)\n'
         self.assertEquals(expected, refactored)
         code = 'class A(object):\n    def __init__(self):\n' \
                '        self.an_attr = 3\n        range(self.an_attr)\n' \
                'a = A()\nrange(a.an_attr)'
-        refactored = self._inline_local_variable(code, code.index('an_attr') + 1)
+        refactored = self._inline(code, code.index('an_attr') + 1)
         expected = 'class A(object):\n    def __init__(self):\n' \
                    '        range(3)\n' \
                    'a = A()\nrange(3)'
         self.assertEquals(expected, refactored)
 
 
+    def test_a_function_with_no_occurance(self):
+        self.mod.write('def a_func():\n    pass\n')
+        self.refactoring.inline(self.mod, self.mod.read().index('a_func') + 1)
+        self.assertEquals('', self.mod.read())
+
+    def test_a_function_with_no_occurance2(self):
+        self.mod.write('a_var = 10\ndef a_func():\n    pass\nprint a_var\n')
+        self.refactoring.inline(self.mod, self.mod.read().index('a_func') + 1)
+        self.assertEquals('a_var = 10\nprint a_var\n', self.mod.read())
+
+    # Implement this
+    def xxx_test_a_function_with_no_occurance2(self):
+        self.mod.write('def a_func():\n    print 1\n')
+        mod1 = self.pycore.create_module(self.project.get_root_folder(), 'mod1')
+        mod1.write('import mod\nmod.a_func()\n')
+        self.refactoring.inline(self.mod, self.mod.read().index('a_func') + 1)
+        self.assertEquals('import mod\nprint 1\n', self.mod.read())
+
+    
+def suite():
+    result = unittest.TestSuite()
+    result.addTests(unittest.makeSuite(InlineTest))
+    return result
+
+
 if __name__ == '__main__':
     unittest.main()

ropetest/refactor/renametest.py

         refactored = self.do_local_rename(code, code.rfind('param') + 1, 'new_param')
         self.assertEquals('def a_func(new_param):\n    print new_param\n'
                           'a_func  (new_param=hey)\n', refactored)
-
+    
+    def test_renaming_variables_in_init_do_pys(self):
+        pkg = self.pycore.create_package(self.project.get_root_folder(), 'pkg')
+        init_dot_py = pkg.get_child('__init__.py')
+        init_dot_py.write('a_var = 10\n')
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        mod.write('import pkg\nprint pkg.a_var\n')
+        self.refactoring.rename(mod, mod.read().index('a_var') + 1, 'new_var')
+        self.assertEquals('new_var = 10\n', init_dot_py.read())
+        self.assertEquals('import pkg\nprint pkg.new_var\n', mod.read())
+    
+    def test_renaming_variables_in_init_do_pys2(self):
+        pkg = self.pycore.create_package(self.project.get_root_folder(), 'pkg')
+        init_dot_py = pkg.get_child('__init__.py')
+        init_dot_py.write('a_var = 10\n')
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        mod.write('import pkg\nprint pkg.a_var\n')
+        self.refactoring.rename(
+            init_dot_py, init_dot_py.read().index('a_var') + 1, 'new_var')
+        self.assertEquals('new_var = 10\n', init_dot_py.read())
+        self.assertEquals('import pkg\nprint pkg.new_var\n', mod.read())
+    
+    def test_renaming_variables_in_init_do_pys3(self):
+        pkg = self.pycore.create_package(self.project.get_root_folder(), 'pkg')
+        init_dot_py = pkg.get_child('__init__.py')
+        init_dot_py.write('a_var = 10\n')
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        mod.write('import pkg\nprint pkg.a_var\n')
+        self.refactoring.rename(mod, mod.read().index('a_var') + 1, 'new_var')
+        self.assertEquals('new_var = 10\n', init_dot_py.read())
+        self.assertEquals('import pkg\nprint pkg.new_var\n', mod.read())
+    
 
 if __name__ == '__main__':
     unittest.main()
              'Topic :: Software Development',
              'Topic :: Text Editors :: Integrated Development Environments (IDE)']
 
+long_description = """
+Rope is a python refactoring IDE and library.
+"""
+
 setup(name='rope',
       version=rope.VERSION,
       description='a python refactoring IDE...',
+      long_description=long_description,
       author='Ali Gholami Rudi',
       author_email='aligrudi@users.sourceforge.net',
       url='http://rope.sf.net/',
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.