Ali Gholami Rudi  committed e1a6268

The main project may not contain the definitions in cross-project refactorings

  • Participants
  • Parent commits d3cda29

Comments (0)

Files changed (4)

File docs/dev/todo.txt

+* Inlining a single occurrence
 > Public Release 0.7.2 : December 13, 2007
-* Inlining a single occurrence

File docs/library.txt

 `rope.refactor.multiproject` can be used to perform a refactoring
 across multiple projects.
-Before we begin, note that there should always be a main project.
-That is the project that contains the definition of the changing
-python name.  Other projects depend on the main one and uses of the
-changed name in them should be updated.
+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 uses of the changed name in them should be
 Each refactoring changes only one project (the project passed to its
 constructor).  But we can use `MultiProjectRefactoring` proxy to
 perform a refactoring on other projects, too.
-First we need create a multi-project refactoring constructor.  As an
-example consider we want to perform a rename refactoring::
+First we need to create a multi-project refactoring constructor.  As
+an example consider we want to perform a rename refactoring::
   from rope.refactor import multiproject, rename
 We create the rename refactoring as we do for normal refactorings.
 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
 Finally we can calculate the changes.  But instead of calling
-`get_changes()` (which returns main project changes, only), we should
+`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 ```` for each tuple or use

File rope/refactor/

-from rope.base import resources, project
+from rope.base import resources, project, libutils
 class MultiProjectRefactoring(object):
     def __call__(self, project, *args, **kwds):
         """Create the refactoring"""
-        return _MultiRefactoring(self.refactoring, self.projects, self.addpath,
-                                 project, *args, **kwds)
+        return _MultiRefactoring(self.refactoring, self.projects,
+                                 self.addpath, project, *args, **kwds)
 class _MultiRefactoring(object):
     def __init__(self, refactoring, other_projects, addpath,
                  project, *args, **kwds):
         self.refactoring = refactoring
-        self.projects = other_projects
-        self.project = project
-        for other_project in self.projects:
-            other_project.get_prefs().add('python_path', self.project.address)
-        self.main_refactoring = self.refactoring(project, *args, **kwds)
-        args, kwds = self._change_project_resources_for_args(args, kwds)
-        self.other_refactorings = [self.refactoring(other, *args, **kwds)
-                                   for other in self.projects]
+        self.projects = [project] + other_projects
+        for other_project in other_projects:
+            for folder in self.project.pycore.get_source_folders():
+                other_project.get_prefs().add('python_path', folder.real_path)
+        self.refactorings = []
+        for other in self.projects:
+            args, kwds = self._resources_for_args(other, args, kwds)
+            self.refactorings.append(
+                self.refactoring(other, *args, **kwds))
     def get_all_changes(self, *args, **kwds):
         """Get a project to changes dict"""
         result = []
-        result.append((self.project,
-                       self.main_refactoring.get_changes(*args, **kwds)))
-        args, kwds = self._change_project_resources_for_args(args, kwds)
-        for project, refactoring in zip(self.projects,
-                                        self.other_refactorings):
+        for project, refactoring in zip(self.projects, self.refactorings):
+            args, kwds = self._resources_for_args(project, args, kwds)
             result.append((project, refactoring.get_changes(*args, **kwds)))
         return result
     def __getattr__(self, name):
         return getattr(self.main_refactoring, name)
-    def _change_project_resources_for_args(self, args, kwds):
-        newargs = [self._change_project_resource(arg) for arg in args]
-        newkwds = dict((name, self._change_project_resource(value))
+    def _resources_for_args(self, project, args, kwds):
+        newargs = [self._change_project_resource(project, arg) for arg in args]
+        newkwds = dict((name, self._change_project_resource(project, value))
                        for name, value in kwds.items())
         return newargs, newkwds
-    def _change_project_resource(self, obj):
+    def _change_project_resource(self, project, obj):
         if isinstance(obj, resources.Resource) and \
-           obj.project == self.project:
-            return project.get_no_project().get_resource(obj.real_path)
+           obj.project != project:
+            return libutils.path_to_resource(project, obj.real_path)
         return obj
+    @property
+    def project(self):
+        return self.projects[0]
+    @property
+    def main_refactoring(self):
+        return self.refactorings[0]
 def perform(project_changes):
     for project, changes in project_changes:

File ropetest/refactor/

             'import mod1\nimport other\nmyvar = other.a_func()\n',
+    def test_rename_from_the_project_not_containing_the_change(self):
+        self.project2.get_prefs().add('python_path', self.project1.address)
+        self.mod1.write('var = 1\n')
+        self.mod2.write('import mod1\nmyvar = mod1.var\n')
+        refactoring = multiproject.MultiProjectRefactoring(
+            rename.Rename, [self.project1])
+        renamer = refactoring(self.project2, self.mod2,
+                    'var'))
+        multiproject.perform(renamer.get_all_changes('newvar'))
+        self.assertEquals('newvar = 1\n',
+        self.assertEquals('import mod1\nmyvar = mod1.newvar\n',
 if __name__ == '__main__':