Commits

Anonymous committed 5dac33f

Added support for builtin lists, dicts, and sets

Comments (0)

Files changed (25)

docs/dev/done.txt

 ===========
 
 
+- Basic support for builtin typs : December 29, 2006
+
+
+- Find occurrences; ``C-G`` : December 26, 2006
+
+
+- Ignoring ``*.pyc``, ``*~`` and ``.svn`` : December 26, 2006
+
+
 - Moving/renaming current module/package : December 25, 2006
 
 

docs/dev/issues.txt

 * Change method signature
 * Introduce parameter
 * Enhancing refactorings and testing
-* Move field/methods
 
 Exploring and analyzing possible solutions for:
 
 
 The second approach seems easier to implement.  We can save collected
 type information somewhere outside `PyName`\s.  Each time we need a
-`PyName`\'s object we use that data store it.  In this approach we
-should find someway of storing collected data that it can be used even
+`PyName`\'s object we use the stored data.  In this approach we
+should find someway of storing collected data so it can be used even
 if there are some small changes in a resource.  The simplest way of
 saving collected data is the ``(file, lineno)`` tuple.  The other is
 the hierarchical representation and in this approach we save the data
 `rope.ui.uihelpers` module and extend it.
 
 
-Not Resetting the Whole Editor
-------------------------------
-
-After actions like extract method, we reset the whole editor.  This is
-slow and makes the undo difficult.  Find someway of solving this.  I
-might be able to use `difflib` module.
-
-
 Isolating Text Widget Features
 ------------------------------
 

docs/dev/stories.txt

 * Introduce redirection
 * Changing signature in class hierarchies
 * Handling builtin functions and types
+* Moving fields/methods to attribute classes
 
 
 IDE And UI Stories
 * Auto-completing function parameter names when calling
 * Code contexts; context_finder.get_context(text, offset)
   This can be used when proposing code assists.
-* Formating Code
+* Formating code
 * Local history
 * Show PyDoc reST highlighting
 * Better list and tree navigation
 * Adding ignored file patterns in projects; ``*.pyc *~ .svn ...``
 
 
+* Commanding buffer
+
+
 * Sorting imports; standard, third party, project
 
 
-* Commanding buffer
+* Transforming to ``from w.x.y import z`` for long imports
 
 
 > Public Release 0.4m4 : December 31, 2006
-
-
-* Find occurances
-
-
-* Moving fields/methods to attribute classes

docs/dev/workingon.txt

-Having Ignored File Patterns
-============================
+Supporting Lists, Dicts And Sets
+================================
 
-- Ignoring ``*.pyc``, ``*~`` and ``.svn ``
-
+- ``l = [C(), C()]``
+- ``a_var = l.pop()``
+- ``a_var = l[x]``
+- ``a_list = l[x:y]``
+- ``__iter__``
+- ``for x in l:``
+- lists and DOI
+- ``d[x]``
+- ``d.pop``
+- ``d.keys``
+- ``d.values``
+- ``d.iterkeys``
+- ``d.itervalues``
+- ``for x in d``
+- ``d.copy``
+- dicts and DOI
+- ``a, b = a_tuple``
+- ``a, b = a_list``
+- ``d.items``
+- ``for x, y in l:``
+- ``a = (C1(), C2())``
+- tuples and DOI
+- add builtin names to global scopes
+- sets
 
 
 Remaining Stories
 * Allowing running code to call rope functions while rope is running?
 * Importing star and removing self imports; stack overflow
 * Definition location for variables inside loops
-* Supporting ``from w.x.y import z`` for organizing long imports;
-  ``Use long import list format`` refactoring
 * Change relative imports to ``2.5`` style
 * Extract constant
 * What to do if a file is removed while editing

rope/base/builtins.py

+"""This module trys to support some of the builtin types and
+functions.
+"""
+
+from rope.base import pyobjects
+from rope.base import pynames
+
+
+class List(pyobjects.PyObject):
+    
+    def __init__(self, holding=None):
+        super(List, self).__init__(pyobjects.PyObject.get_base_type('Type'))
+        self.holding = holding
+        self.attributes = {
+            '__getitem__': BuiltinName(BuiltinFunction(self.holding)),
+            '__getslice__': BuiltinName(BuiltinFunction(self)),
+            'pop': BuiltinName(BuiltinFunction(self.holding)),
+            '__iter__': BuiltinName(BuiltinFunction(Iterator(self.holding))),
+            'append': BuiltinName(BuiltinFunction()),
+            'count': BuiltinName(BuiltinFunction()),
+            'extend': BuiltinName(BuiltinFunction()),
+            'index': BuiltinName(BuiltinFunction()),
+            'insert': BuiltinName(BuiltinFunction()),
+            'remove': BuiltinName(BuiltinFunction()),
+            'reverse': BuiltinName(BuiltinFunction()),
+            'sort': BuiltinName(BuiltinFunction())}
+    
+    def get_attributes(self):
+        return self.attributes
+
+
+class Dict(pyobjects.PyObject):
+    
+    def __init__(self, keys=None, values=None):
+        super(Dict, self).__init__(pyobjects.PyObject.get_base_type('Type'))
+        self.keys = keys
+        self.values = values
+        item = Tuple(self.keys, self.values)
+        self.attributes = {
+            '__getitem__': BuiltinName(BuiltinFunction(self.values)),
+            '__iter__': BuiltinName(BuiltinFunction(Iterator(self.keys))),
+            'pop': BuiltinName(BuiltinFunction(self.values)),
+            'get': BuiltinName(BuiltinFunction(self.keys)),
+            'keys': BuiltinName(List(self.keys)),
+            'values': BuiltinName(List(self.values)),
+            'iterkeys': BuiltinName(Iterator(self.keys)),
+            'itervalues': BuiltinName(Iterator(self.values)),
+            'items': BuiltinName(List(item)),
+            'iteritems': BuiltinName(Iterator(item)),
+            'copy': BuiltinName(BuiltinFunction(self)),
+            'clear': BuiltinName(BuiltinFunction()),
+            'has_key': BuiltinName(BuiltinFunction()),
+            'popitem': BuiltinName(BuiltinFunction()),
+            'setdefault': BuiltinName(BuiltinFunction()),
+            'update': BuiltinName(BuiltinFunction())}
+    
+    def get_attributes(self):
+        return self.attributes
+
+
+class Tuple(pyobjects.PyObject):
+    
+    def __init__(self, *objects):
+        super(Tuple, self).__init__(pyobjects.PyObject.get_base_type('Type'))
+        self.objects = objects
+        first = None
+        if objects:
+            first = objects[0]
+        self.attributes = {
+            '__getitem__': BuiltinName(BuiltinFunction(first)),
+            '__getslice__': BuiltinName(BuiltinFunction(self)),
+            '__iter__': BuiltinName(BuiltinFunction(Iterator(first)))}
+    
+    def get_holding_objects(self):
+        return self.objects
+    
+    def get_attributes(self):
+        return self.attributes
+
+
+class Set(pyobjects.PyObject):
+
+    def __init__(self, holding=None):
+        super(Set, self).__init__(pyobjects.PyObject.get_base_type('Type'))
+        self.holding = holding
+        self.attributes = {
+            'pop': BuiltinName(BuiltinFunction(self.holding)),
+            '__iter__': BuiltinName(BuiltinFunction(Iterator(self.holding))),
+            'add': BuiltinName(BuiltinFunction()),
+            'copy': BuiltinName(BuiltinFunction(self)),
+            'difference': BuiltinName(BuiltinFunction(self)),
+            'intersection': BuiltinName(BuiltinFunction(self)),
+            'difference_update': BuiltinName(BuiltinFunction()),
+            'symmetric_difference': BuiltinName(BuiltinFunction(self)),
+            'symmetric_difference_update': BuiltinName(BuiltinFunction()),
+            'union': BuiltinName(BuiltinFunction(self)),
+            'discard': BuiltinName(BuiltinFunction()),
+            'remove': BuiltinName(BuiltinFunction()),
+            'issuperset': BuiltinName(BuiltinFunction()),
+            'issubset': BuiltinName(BuiltinFunction()),
+            'clear': BuiltinName(BuiltinFunction()),
+            'update': BuiltinName(BuiltinFunction())}
+    
+    def get_attributes(self):
+        return self.attributes
+
+
+class BuiltinName(pynames.PyName):
+    
+    def __init__(self, pyobject):
+        self.pyobject = pyobject
+    
+    def get_object(self):
+        return self.pyobject
+
+
+class BuiltinFunction(pyobjects.PyObject):
+    
+    def __init__(self, returned=None):
+        super(BuiltinFunction, self).__init__(
+            pyobjects.PyObject.get_base_type('Function'))
+        self.returned = returned
+    
+    def _get_returned_object(self):
+        return self.returned
+
+
+class Iterator(pyobjects.PyObject):
+
+    def __init__(self, holding=None):
+        super(Iterator, self).__init__(pyobjects.PyObject.get_base_type('Type'))
+        self.holding = holding
+        self.attributes = {
+            'next': BuiltinName(BuiltinFunction(self.holding)),
+            '__iter__': BuiltinName(BuiltinFunction(self))}
+    
+    def get_attributes(self):
+        return self.attributes
+
+    def _get_returned_object(self):
+        return self.holding
+

rope/base/codeanalyze.py

 import rope.base.pyobjects
 import rope.base.pynames
 import rope.base.exceptions
+from rope.base import builtins
+from rope.base import evaluate
 
 
 class WordRangeFinder(object):
         return operation
 
 
-class StatementEvaluator(object):
-
-    def __init__(self, scope):
-        self.scope = scope
-        self.result = None
-
-    def visitName(self, node):
-        self.result = self.scope.lookup(node.name)
-    
-    def visitGetattr(self, node):
-        pyname = StatementEvaluator.get_statement_result(self.scope, node.expr)
-        if pyname is not None:
-            try:
-                self.result = pyname.get_object().get_attribute(node.attrname)
-            except rope.base.exceptions.AttributeNotFoundException:
-                self.result = None
-
-    def visitCallFunc(self, node):
-        pyname = StatementEvaluator.get_statement_result(self.scope, node.node)
-        if pyname is None:
-            return
-        pyobject = pyname.get_object()
-        if pyobject.get_type() == rope.base.pyobjects.PyObject.get_base_type('Type'):
-            self.result = rope.base.pynames.AssignedName(
-                pyobject=rope.base.pyobjects.PyObject(type_=pyobject))
-        elif pyobject.get_type() == rope.base.pyobjects.PyObject.get_base_type('Function'):
-            self.result = rope.base.pynames.AssignedName(
-                pyobject=pyobject._get_returned_object())
-        elif '__call__' in pyobject.get_attributes():
-            call_function = pyobject.get_attribute('__call__')
-            self.result = rope.base.pynames.AssignedName(
-                pyobject=call_function.get_object()._get_returned_object())
-    
-    def visitAdd(self, node):
-        pass
-
-    def visitAnd(self, node):
-        pass
-
-    def visitBackquote(self, node):
-        pass
-
-    def visitBitand(self, node):
-        pass
-
-    def visitBitor(self, node):
-        pass
-
-    def visitXor(self, node):
-        pass
-
-    def visitCompare(self, node):
-        pass
-    
-    def visitDict(self, node):
-        pass
-    
-    def visitFloorDiv(self, node):
-        pass
-    
-    def visitList(self, node):
-        pass
-    
-    def visitListComp(self, node):
-        pass
-
-    def visitMul(self, node):
-        pass
-    
-    def visitNot(self, node):
-        pass
-    
-    def visitOr(self, node):
-        pass
-    
-    def visitPower(self, node):
-        pass
-    
-    def visitRightShift(self, node):
-        pass
-    
-    def visitLeftShift(self, node):
-        pass
-    
-    def visitSlice(self, node):
-        pass
-    
-    def visitSliceobj(self, node):
-        pass
-    
-    def visitTuple(self, node):
-        pass
-    
-    def visitSubscript(self, node):
-        pass
-
-    @staticmethod
-    def get_statement_result(scope, node):
-        evaluator = StatementEvaluator(scope)
-        compiler.walk(node, evaluator)
-        return evaluator.result
-    
-    @staticmethod
-    def get_string_result(scope, string):
-        evaluator = StatementEvaluator(scope)
-        node = compiler.parse(string)
-        compiler.walk(node, evaluator)
-        return evaluator.result
-
-
 class ScopeNameFinder(object):
     
     def __init__(self, pymodule):
         #ast = compiler.parse(name)
         # parenthesizing for handling cases like 'a_var.\nattr'
         ast = compiler.parse('(%s)' % name)
-        result = StatementEvaluator.get_statement_result(holding_scope, ast)
+        result = evaluate.StatementEvaluator.get_statement_result(holding_scope, ast)
         return result
 
 

rope/base/evaluate.py

+import compiler
+import rope.base.pyobjects
+import rope.base.pynames
+import rope.base.exceptions
+
+
+class StatementEvaluator(object):
+
+    def __init__(self, scope):
+        self.scope = scope
+        self.result = None
+
+    def visitName(self, node):
+        self.result = self.scope.lookup(node.name)
+    
+    def visitGetattr(self, node):
+        pyname = StatementEvaluator.get_statement_result(self.scope, node.expr)
+        if pyname is not None:
+            try:
+                self.result = pyname.get_object().get_attribute(node.attrname)
+            except rope.base.exceptions.AttributeNotFoundException:
+                self.result = None
+
+    def visitCallFunc(self, node):
+        pyobject = self._get_object_for_node(node.node)
+        if pyobject is None:
+            return
+        if pyobject.get_type() == rope.base.pyobjects.PyObject.get_base_type('Type'):
+            self.result = rope.base.pynames.AssignedName(
+                pyobject=rope.base.pyobjects.PyObject(type_=pyobject))
+        elif pyobject.get_type() == rope.base.pyobjects.PyObject.get_base_type('Function'):
+            self.result = rope.base.pynames.AssignedName(
+                pyobject=pyobject._get_returned_object())
+        elif '__call__' in pyobject.get_attributes():
+            call_function = pyobject.get_attribute('__call__')
+            self.result = rope.base.pynames.AssignedName(
+                pyobject=call_function.get_object()._get_returned_object())
+    
+    def visitAdd(self, node):
+        pass
+    
+    def visitAnd(self, node):
+        pass
+
+    def visitBackquote(self, node):
+        pass
+
+    def visitBitand(self, node):
+        pass
+
+    def visitBitor(self, node):
+        pass
+
+    def visitXor(self, node):
+        pass
+
+    def visitCompare(self, node):
+        pass
+    
+    def visitDict(self, node):
+        keys = None
+        values = None
+        if node.items:
+            item = node.items[0]
+            keys = self._get_object_for_node(item[0])
+            values = self._get_object_for_node(item[1])
+        self.result = rope.base.pynames.AssignedName(
+            pyobject=rope.base.builtins.Dict(keys, values))
+    
+    def visitFloorDiv(self, node):
+        pass
+    
+    def visitList(self, node):
+        holding = None
+        if node.nodes:
+            holding = self._get_object_for_node(node.nodes[0])
+        self.result = rope.base.pynames.AssignedName(
+            pyobject=rope.base.builtins.List(holding))
+    
+    def visitListComp(self, node):
+        pass
+
+    def visitMul(self, node):
+        pass
+    
+    def visitNot(self, node):
+        pass
+    
+    def visitOr(self, node):
+        pass
+    
+    def visitPower(self, node):
+        pass
+    
+    def visitRightShift(self, node):
+        pass
+    
+    def visitLeftShift(self, node):
+        pass
+    
+    def visitSlice(self, node):
+        self._call_function(node.expr, '__getslice__')
+    
+    def visitSliceobj(self, node):
+        pass
+    
+    def visitTuple(self, node):
+        objects = []
+        if len(node.nodes) < 4:
+            for stmt in node.nodes:
+                pyobject = self._get_object_for_node(stmt)
+                objects.append(pyobject)
+        else:
+            objects.append(self._get_object_for_node(node.nodes[0]))
+        self.result = rope.base.pynames.AssignedName(
+            pyobject=rope.base.builtins.Tuple(*objects))
+
+    def _get_object_for_node(self, stmt):
+        pyname = StatementEvaluator.get_statement_result(self.scope, stmt)
+        pyobject = None
+        if pyname is not None:
+            pyobject = pyname.get_object()
+        return pyobject
+    
+    def visitSubscript(self, node):
+        self._call_function(node.expr, '__getitem__')
+
+    def _call_function(self, node, function_name):
+        pyobject = self._get_object_for_node(node)
+        if pyobject is None:
+            return
+        if function_name in pyobject.get_attributes():
+            call_function = pyobject.get_attribute(function_name)
+            self.result = rope.base.pynames.AssignedName(
+                pyobject=call_function.get_object()._get_returned_object())
+
+    @staticmethod
+    def get_statement_result(scope, node):
+        evaluator = StatementEvaluator(scope)
+        compiler.walk(node, evaluator)
+        return evaluator.result
+    
+    @staticmethod
+    def get_string_result(scope, string):
+        evaluator = StatementEvaluator(scope)
+        node = compiler.parse(string)
+        compiler.walk(node, evaluator)
+        return evaluator.result

rope/base/oi/dynamicoi.py

 import threading
 
 import rope.base.pyobjects
+from rope.base import builtins
 
 
 class DynamicObjectInference(object):
 
     def infer_parameter_objects(self, pyobject):
         organizer = self._find_organizer(pyobject)
-        if organizer:
+        if organizer and organizer.args is not None:
             pyobjects = [parameter.to_pyobject(self.pycore.project)
                          for parameter in organizer.args]
             return pyobjects
             return _PersistedFunction(*data[1:])
         if type_ == 'class':
             return _PersistedClass(*data[1:])
+        if type_ == 'builtin':
+            return _PersistedBuiltin(*data[1:])
         if type_ == 'instance':
             return _PersistedClass(is_instance=True, *data[1:])
         return _PersistedUnknown()
         return None
 
 
+class _PersistedBuiltin(_ObjectPersistedForm):
+    
+    def __init__(self, name, *data):
+        self.name = name
+        self.data = data
+
+    def to_pyobject(self, project):
+        if self.name == 'list':
+            holding = _ObjectPersistedForm.create_persistent_object(self.data[0])
+            return builtins.List(holding.to_pyobject(project))
+        if self.name == 'dict':
+            keys = _ObjectPersistedForm.create_persistent_object(self.data[0])
+            values = _ObjectPersistedForm.create_persistent_object(self.data[1])
+            return builtins.Dict(keys.to_pyobject(project), values.to_pyobject(project))
+        if self.name == 'tuple':
+            objects = []
+            for holding in self.data:
+                objects.append(_ObjectPersistedForm.
+                               create_persistent_object(holding).to_pyobject(project))
+            return builtins.Tuple(*objects)
+        if self.name == 'set':
+            holding = _ObjectPersistedForm.create_persistent_object(self.data[0])
+            return builtins.Set(holding.to_pyobject(project))
+        return None
+
+
 class _PersistedModule(_ObjectPersistedForm):
     
     def __init__(self, path):

rope/base/oi/objectinfer.py

 from rope.base.pyobjects import *
+from rope.base import builtins
 import rope.base.codeanalyze
+import rope.base.evaluate
 
 
 class ObjectInfer(object):
     
     def infer_object(self, pyname):
         """Infers the `PyObject` this `PyName` references"""
-        if not pyname.assigned_asts:
+        if not pyname.assignments:
             return
-        for assign_node in reversed(pyname.assigned_asts):
-            try:
-                lineno = 1
-                if hasattr(assign_node, 'lineno') and assign_node.lineno is not None:
-                    lineno = assign_node.lineno
-                holding_scope = pyname.module.get_scope().\
-                                get_inner_scope_for_line(lineno)
-                resulting_pyname = rope.base.codeanalyze.StatementEvaluator.\
-                                   get_statement_result(holding_scope, assign_node)
-                if resulting_pyname is None:
-                    return None
-                return resulting_pyname.get_object()
-            except IsBeingInferredException:
-                pass
+        for assignment in reversed(pyname.assignments):
+            result = self._infer_assignment(assignment, pyname.module)
+            if result is not None:
+                return result
     
+    def _infer_assignment(self, assignment, pymodule):
+        try:
+            pyname = self._infer_pyname_for_assign_node(
+                assignment.ast_node, pymodule)
+            if pyname is None:
+                return None
+            return self._infer_assignment_object(assignment, pyname.get_object())
+        except IsBeingInferredException:
+            pass
+
+    def _infer_assignment_object(self, assignment, pyobject):
+        if assignment.index is not None and isinstance(pyobject, builtins.Tuple):
+            holdings = pyobject.get_holding_objects()
+            return holdings[min(len(holdings) - 1, assignment.index)]
+        if assignment.index is not None and isinstance(pyobject, builtins.List):
+            return pyobject.holding
+        return pyobject
+    
+    def _infer_pyname_for_assign_node(self, assign_node, pymodule):
+        try:
+            lineno = 1
+            if hasattr(assign_node, 'lineno') and assign_node.lineno is not None:
+                lineno = assign_node.lineno
+            holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+            return rope.base.evaluate.StatementEvaluator.\
+                   get_statement_result(holding_scope, assign_node)
+        except IsBeingInferredException:
+            pass
+        
+
+    def infer_for_object(self, pyname):
+        """Infers the `PyObject` this `PyName` references"""
+        list_pyname = self._infer_pyname_for_assign_node(
+            pyname.assignment.ast_node, pyname.module)
+        resulting_pyname = self._call_function(
+            self._call_function(list_pyname, '__iter__'), 'next')
+        if resulting_pyname is None:
+            return None
+        return self._infer_assignment_object(pyname.assignment,
+                                             resulting_pyname.get_object())
+    
+    def _call_function(self, pyname, function_name):
+        if pyname is None:
+            return
+        pyobject = pyname.get_object()
+        if function_name in pyobject.get_attributes():
+            call_function = pyobject.get_attribute(function_name)
+            return rope.base.pynames.AssignedName(
+                pyobject=call_function.get_object()._get_returned_object())
+
     def infer_returned_object(self, pyobject):
         """Infers the `PyObject` this callable `PyObject` returns after calling"""
         dynamically_inferred_object = self.pycore.dynamicoi.infer_returned_object(pyobject)
             return
         for returned_node in reversed(scope._get_returned_asts()):
             try:
-                resulting_pyname = rope.base.codeanalyze.StatementEvaluator.\
+                resulting_pyname = rope.base.evaluate.StatementEvaluator.\
                                    get_statement_result(scope, returned_node)
                 if resulting_pyname is None:
                     return None

rope/base/oi/runmod.py

             for argname in code.co_varnames[:code.co_argcount]:
                 try:
                     args.append(self._object_to_persisted_form(frame.f_locals[argname]))
-                except TypeError:
-                    args.append(('unknown'))
-                except AttributeError:
+                except (TypeError, AttributeError):
                     args.append(('unknown'))
             try:
                 returned = self._object_to_persisted_form(arg)
-            except TypeError:
-                pass
-            except AttributeError:
+            except (TypeError, AttributeError):
                 pass
             try:
                 data = (self._object_to_persisted_form(frame.f_code),
                         args, returned)
                 self.sender.send_data(data)
-            except TypeError, e:
-                pass
-            except AttributeError, e:
+            except (TypeError, Error):
                 pass
             return self.on_function_call
         
             return ('function', os.path.abspath(object_.co_filename), object_.co_firstlineno)
     
         def _get_persisted_class(self, object_, type_):
-            return (type_, os.path.abspath(inspect.getsourcefile(object_)),
-                    object_.__name__)
+            try:
+                return (type_, os.path.abspath(inspect.getsourcefile(object_)),
+                        object_.__name__)
+            except (TypeError, AttributeError):
+                return ('unknown')
+    
+        def _get_persisted_builtin(self, object_):
+            if isinstance(object_, list):
+                holding = None
+                if len(object_) > 0:
+                    holding = object_[0]
+                return ('builtin', 'list', self._object_to_persisted_form(holding))
+            if isinstance(object_, dict):
+                keys = None
+                values = None
+                if len(object_) > 0:
+                    keys = object_.keys()[0]
+                    values = object_[keys]
+                return ('builtin', 'dict',
+                        self._object_to_persisted_form(keys),
+                        self._object_to_persisted_form(values))
+            if isinstance(object_, tuple):
+                objects = []
+                if len(object_) < 3:
+                    for holding in object_:
+                        objects.append(self._object_to_persisted_form(holding))
+                else:
+                    objects.append(self._object_to_persisted_form(object_[0]))
+                return tuple(['builtin', 'tuple'] + objects)
+            if isinstance(object_, set):
+                holding = None
+                if len(object_) > 0:
+                    for o in object_:
+                        holding = o
+                        break
+                return ('builtin', 'set', self._object_to_persisted_form(holding))
+            return ('unknown')
     
         def _object_to_persisted_form(self, object_):
             if object_ == None:
                 return self._get_persisted_code(object_.im_func.func_code)
             if isinstance(object_, types.ModuleType):
                 return ('module', os.path.abspath(object_.__file__))
+            if isinstance(object_, (list, dict, tuple, set)):
+                return self._get_persisted_builtin(object_)
             if isinstance(object_, (types.TypeType, types.ClassType)):
                 return self._get_persisted_class(object_, 'class')
             return self._get_persisted_class(type(object_), 'instance')
     
+    
     send_info = sys.argv[1]
     project_root = sys.argv[2]
     file_to_run = sys.argv[3]

rope/base/pynames.py

         self.lineno = lineno
         self.module = module
         self.is_being_inferred = False
-        self.assigned_asts = []
+        self.assignments = []
         self.pyobject = _get_concluded_data(module)
         self.pyobject.set(pyobject)
     
     
     def get_definition_location(self):
         """Returns a (module, lineno) tuple"""
-        if self.lineno is None and self.assigned_asts:
-            self.lineno = self.assigned_asts[0].lineno
+        if self.lineno is None and self.assignments:
+            self.lineno = self.assignments[0].ast_node.lineno
         return (self.module, self.lineno)
 
 
+class _Assignment(object):
+    
+    def __init__(self, ast_node, index=None):
+        self.ast_node = ast_node
+        self.index = index
+
+
+class ForName(PyName):
+    
+    def __init__(self, assignment=None, module=None):
+        self.module = module
+        self.pyobject = _get_concluded_data(module)
+        self.assignment = assignment
+    
+    def get_object(self):
+        if self.pyobject.get() is None:
+            object_infer = self.module.pycore._get_object_infer()
+            inferred_object = object_infer.infer_for_object(self)
+            self.pyobject.set(inferred_object)
+        if self.pyobject.get() is None:
+            self.pyobject.set(rope.base.pyobjects.PyObject(
+                              rope.base.pyobjects.PyObject.get_base_type('Unknown')))
+        return self.pyobject.get()
+    
+    def get_definition_location(self):
+        return (self.module, self.assignment.ast_node.lineno)
+
+
+class ParameterName(PyName):
+    
+    def __init__(self, pyfunction, index):
+        self.pyfunction = pyfunction
+        self.index = index
+        self.pyobject = _get_concluded_data(self.pyfunction.get_module())
+    
+    def get_object(self):
+        if self.pyobject.get() is None:
+            self.pyobject.set(self.pyfunction._get_parameter(self.index))
+        return self.pyobject.get()
+    
+    def get_definition_location(self):
+        return (self.pyfunction.get_module(), self.pyfunction._get_ast().lineno)
+
+
 class ImportedModule(PyName):
     
     def __init__(self, importing_module, module_name=None, level=0, resource=None):
         return self._get_imported_pyname().get_definition_location()
 
 
-class ParameterName(PyName):
-    
-    def __init__(self, pyfunction, index):
-        self.pyfunction = pyfunction
-        self.index = index
-        self.pyobject = _get_concluded_data(self.pyfunction.get_module())
-    
-    def get_object(self):
-        if self.pyobject.get() is None:
-            self.pyobject.set(self.pyfunction._get_parameter(self.index))
-        return self.pyobject.get()
-    
-    def get_definition_location(self):
-        return (self.pyfunction.get_module(), self.pyfunction._get_ast().lineno)
-
-
 class StarImport(object):
     
     def __init__(self, imported_module):

rope/base/pyobjects.py

 import rope.base.pyscopes
 from rope.base.exceptions import (RopeException, AttributeNotFoundException)
 from rope.base.pynames import *
+from rope.base import pynames
+import rope.base.evaluate
 
 
 class PyObject(object):
     def _get_bases(self):
         result = []
         for base_name in self.ast_node.bases:
-            base = rope.base.codeanalyze.StatementEvaluator.\
+            base = rope.base.evaluate.StatementEvaluator.\
                    get_statement_result(self.parent.get_scope(), base_name)
             if base:
                 result.append(base.get_object())
         self.assigned_ast = node.expr
         for child_node in node.nodes:
             compiler.walk(child_node, self)
+    
+    def _assigned(self, name, assignment=None):
+        old_pyname = self.scope_visitor.names.get(name, None)
+        if old_pyname is None or not isinstance(old_pyname, AssignedName):
+            self.scope_visitor.names[name] = AssignedName(
+                module=self.scope_visitor.get_module())
+        if assignment is not None:
+            self.scope_visitor.names[name].assignments.append(assignment)
+        
+    def visitAssName(self, node):
+        assignment = None
+        if self.assigned_ast is not None:
+            assignment = pynames._Assignment(self.assigned_ast)
+        self._assigned(node.name, assignment)
+    
+    def visitAssTuple(self, node):
+        names = _AssignedNameCollector.get_assigned_names(node)
+        for index, name in enumerate(names):
+            assignment = None
+            if self.assigned_ast is not None:
+                assignment = pynames._Assignment(self.assigned_ast, index)
+            self._assigned(name, assignment)
 
+class _ForAssignVisitor(_AssignVisitor):
+    
+    def __init__(self, scope_visitor, assigned):
+        super(_ForAssignVisitor, self).__init__(scope_visitor)
+        self.assigned_ast = assigned
+
+    def _assigned(self, name, assignment=None):
+        self.scope_visitor.names[name] = ForName(
+            assignment=assignment, module=self.scope_visitor.get_module())
+        if assignment is not None:
+            self.scope_visitor.names[name].assignment = assignment
+        
+
+class _AssignedNameCollector(object):
+    
+    def __init__(self):
+        self.names = []
+    
     def visitAssName(self, node):
-        old_pyname = self.scope_visitor.names.get(node.name, None)
-        if old_pyname is None or not isinstance(old_pyname, AssignedName):
-            self.scope_visitor.names[node.name] = AssignedName(
-                module=self.scope_visitor.get_module())
-        if self.assigned_ast:
-            self.scope_visitor.names[node.name].assigned_asts.append(self.assigned_ast)
+        self.names.append(node.name)
+    
+    @staticmethod
+    def get_assigned_names(node):
+        visitor = _AssignedNameCollector()
+        compiler.walk(node, visitor)
+        return visitor.names
 
 
 class _ScopeVisitor(object):
         compiler.walk(node, _AssignVisitor(self))
     
     def visitFor(self, node):
-        self.visitAssign(node.assign)
+        visitor = _ForAssignVisitor(self, node.list)
+        compiler.walk(node.assign, visitor)
+#        names = _AssignedNameCollector.get_assigned_names(node.assign)
+#        for name in names:
+#            self.names[name] = ForName(pynames._Assignment(node.list),
+#                                       module=self.get_module(),
+#                                       lineno=node.lineno)
         compiler.walk(node.body, self)
-    
+        
     def visitImport(self, node):
         for import_pair in node.names:
             module_name, alias = import_pair
             if node.attrname not in self.scope_visitor.names:
                 self.scope_visitor.names[node.attrname] = AssignedName(
                     lineno=node.lineno, module=self.scope_visitor.get_module())
-            self.scope_visitor.names[node.attrname].assigned_asts.append(self.assigned_ast)
+            self.scope_visitor.names[node.attrname].assignments.append(
+                pynames._Assignment(self.assigned_ast))
     
     def visitAssName(self, node):
         pass

rope/base/pyscopes.py

     
     def get_names(self):
         """Return the names defined in this scope"""
-        return self.pyobject.get_attributes()
+        return self.pyobject.get_attributes() 
 
     def get_name(self, name):
         """Return name `PyName` defined in this scope"""
     def __init__(self, pycore, module):
         super(GlobalScope, self).__init__(pycore, module, None)
         self.scope_finder = None
+        self.names = module._get_concluded_data()
 
     def get_start(self):
         return 1
         try:
             return self.pyobject.get_attribute(name)
         except rope.base.exceptions.AttributeNotFoundException:
+            if name in self.builtin_names:
+                return self.builtin_names[name]
             raise rope.base.exceptions.NameNotFoundException('name %s not found' % name)
+    
+    def get_names(self):
+        if self.names.get() is None:
+            result = dict(super(GlobalScope, self).get_names())
+            result.update(self.builtin_names)
+            self.names.set(result)
+        return self.names.get()
 
     def get_inner_scope_for_line(self, lineno, indents=None):
         return self._get_scope_finder().get_holding_scope(self, lineno, indents)
             self.scope_finder = _HoldingScopeFinder(self.pyobject)
         return self.scope_finder
 
+    def _get_builtin_names(self):
+        if GlobalScope._builtin_names is None:
+            builtins = {
+                'list': rope.base.builtins.BuiltinName(rope.base.builtins.List()),
+                'dict': rope.base.builtins.BuiltinName(rope.base.builtins.Dict()),
+                'tuple': rope.base.builtins.BuiltinName(rope.base.builtins.Tuple()),
+                'set': rope.base.builtins.BuiltinName(rope.base.builtins.Set())}
+            self._builtin_names = builtins
+        return self._builtin_names
+    
+    _builtin_names = None
+    builtin_names = property(_get_builtin_names)
+    
 
 class FunctionScope(Scope):
     

rope/ide/codeassist.py

 from rope.base.codeanalyze import (StatementRangeFinder, ArrayLinesAdapter, 
                                    WordRangeFinder, ScopeNameFinder,
                                    SourceLinesAdapter)
+from rope.refactor import occurrences
 
 
 class RopeSyntaxError(RopeException):
             else:
                 return _trim_docstring(pyobject._get_ast().doc)
         return None
+    
+    def find_occurrences(self, resource, offset):
+        name = rope.base.codeanalyze.get_name_at(resource, offset)
+        pyname = rope.base.codeanalyze.get_pyname_at(self.project.get_pycore(),
+                                                     resource, offset)
+        finder = occurrences.FilteredOccurrenceFinder(
+            self.project.get_pycore(), name, [pyname])
+        result = []
+        for resource in self.project.get_pycore().get_python_files():
+            for occurrence in finder.find_occurrences(resource):
+                result.append((resource, occurrence.get_word_range()[0]))
+        return result
+
 
 def _get_class_docstring(pyclass):
     node = pyclass._get_ast()

rope/refactor/extract.py

 import compiler
+import re
 
 import rope.base.pyobjects
 from rope.base import codeanalyze
 class ExtractMethodRefactoring(_ExtractRefactoring):
     
     def get_changes(self, extracted_name):
-        info = _ExtractInformation(self.pycore, self.resource,
+        info = _ExtractingPartOffsets(self.pycore, self.resource,
                                    self.start_offset, self.end_offset)
         if info.is_one_line_extract():
             new_contents = _OneLineExtractPerformer(self.pycore, self.resource, info,
 class ExtractVariableRefactoring(_ExtractRefactoring):
     
     def get_changes(self, extracted_name):
-        info = _ExtractInformation(self.pycore, self.resource,
+        info = _ExtractingPartOffsets(self.pycore, self.resource,
                                    self.start_offset, self.end_offset)
         new_contents = _OneLineExtractPerformer(self.pycore, self.resource, info, 
                                                 extracted_name, True).extract()
         return changes
 
 
-class _ExtractInformation(object):
+class _ExtractPerformer(object):
+    """Perform extract method/variable refactoring
+    
+    We devide program source code into these parts::
+      
+      [...]
+        scope_start
+            [before_line]
+        start_line
+          start
+            [call]
+          end
+        end_line
+        scope_end
+            [after_scope]
+      [...]
+    
+    For extract function the new method is inserted in start_line,
+    while in extract method it is inserted in scope_end.
+    
+    Note that start and end are in the same line for one line
+    extractions, so start_line and end_line are in the same line,
+    too.
+    
+    The parts marked as before_line, call and after_scope are
+    used in refactoring and we use `ExtractInfo` to find the
+    new contents of these parts.
+
+    """
+    
+    def __init__(self, pycore, resource, parts, extracted_name, extract_variable=False):
+        self.source_code = source_code = resource.read()
+        self.extracted_name = extracted_name
+        self.extract_variable = extract_variable
+        self.parts = parts
+        
+        self.lines = parts.lines
+        
+        self.first_line_indents = self._get_indents(self.parts.region_linenos[0])
+        self.scope = pycore.get_string_scope(source_code, resource)
+        self.holding_scope = self._find_holding_scope(self.parts.region_linenos[0])
+        
+        self.extract_info = self._create_extract_info()
+        
+        self._check_exceptional_conditions()
+        self.info_collector = self._create_info_collector()
+    
+    def _create_extract_info(self):
+        if self.extract_variable:
+            return _ExtractedVariablePieces(self)
+        else:
+            return _ExtractedMethodPieces(self)
+
+    def _find_holding_scope(self, start_line):
+        holding_scope = self.scope.get_inner_scope_for_line(start_line)
+        if holding_scope.get_kind() != 'Module' and \
+           holding_scope.get_start() == start_line:
+            holding_scope = holding_scope.parent
+        return holding_scope
+    
+    def _is_global(self):
+        return self.holding_scope.pyobject.get_type() == \
+               rope.base.pyobjects.PyObject.get_base_type('Module')
+
+    def _is_method(self):
+        return self.holding_scope.parent is not None and \
+               self.holding_scope.parent.pyobject.get_type() == \
+               rope.base.pyobjects.PyObject.get_base_type('Type')
+    
+    def _check_exceptional_conditions(self):
+        if self.holding_scope.pyobject.get_type() == rope.base.pyobjects.PyObject.get_base_type('Type'):
+            raise RefactoringException('Can not extract methods in class body')
+        if self.parts.region[1] > self.parts.scope[1]:
+            raise RefactoringException('Bad range selected for extract method')
+        end_line = self.parts.region_linenos[1]
+        end_scope = self.scope.get_inner_scope_for_line(end_line)
+        if end_scope != self.holding_scope and end_scope.get_end() != end_line:
+            raise RefactoringException('Bad range selected for extract method')
+        try:
+            if _ReturnOrYieldFinder.does_it_return(
+                self.source_code[self.parts.region[0]:self.parts.region[1]]):
+                raise RefactoringException('Extracted piece should not contain return statements')
+        except SyntaxError:
+            raise RefactoringException('Extracted piece should contain complete statements.')
+
+    def _is_on_a_word(self, offset):
+        prev = self.source_code[offset]
+        next = self.source_code[offset + 1]
+        return (prev.isalnum() or prev == '_') and (next.isalnum() or next == '_')
+
+    def _create_info_collector(self):
+        zero = self.holding_scope.get_start() - 1
+        start_line = self.parts.region_linenos[0] - zero
+        end_line = self.parts.region_linenos[1] - zero
+        info_collector = _FunctionInformationCollector(start_line, end_line,
+                                                       self._is_global())
+        indented_body = self.source_code[self.parts.scope[0]:self.parts.scope[1]]
+        body = sourceutils.indent_lines(indented_body,
+                                        -sourceutils.find_minimum_indents(indented_body))
+        ast = _parse_text(body)
+        compiler.walk(ast, info_collector)
+        return info_collector
+
+    def extract(self):
+        result = []
+        result.append(self.source_code[:self.parts.region_lines[0]])
+        result.append(self.extract_info.get_before_line())
+        if self.parts.region_lines[0] != self.parts.region[0]:
+            result.append(self.source_code[self.parts.region_lines[0]:self.parts.region[0]])
+        else:
+            result.append(' ' * self.first_line_indents)
+        result.append(self.extract_info.get_call())
+        result.append(self.source_code[self.parts.region[1]:self.parts.region_lines[1]])
+        result.append(self.source_code[self.parts.region_lines[1]:self.parts.scope[1]])
+        result.append(self.extract_info.get_after_scope())
+        result.append(self.source_code[self.parts.scope[1]:])
+        return ''.join(result)
+
+    def _get_scope_indents(self):
+        if self._is_global():
+            return 0
+        else:
+            return self._get_indents(self.holding_scope.get_start()) + 4
+    
+    def _get_function_indents(self):
+        if self._is_global():
+            return 4
+        else:
+            return self._get_scope_indents()
+    
+    def _get_function_definition(self):
+        args = self._find_function_arguments()
+        returns = self._find_function_returns()
+        function_indents = self._get_function_indents()
+        result = []
+        result.append('%sdef %s:\n' %
+                      (' ' * self._get_indents(self.holding_scope.get_start()),
+                       self._get_function_signature(args)))
+        unindented_body = self._get_unindented_function_body(returns)
+        function_body = sourceutils.indent_lines(unindented_body, function_indents)
+        result.append(function_body)
+        definition = ''.join(result)
+        
+        return definition + '\n'
+
+    def _get_one_line_definition(self):
+        extracted_body = self.source_code[self.parts.region[0]:self.parts.region[1]]
+        lines = []
+        for line in extracted_body.splitlines():
+            if line.endswith('\\'):
+                lines.append(line[:-1].strip())
+            else:
+                lines.append(line.strip())
+        return ' '.join(lines)
+    
+    def _get_function_signature(self, args):
+        args = list(args)
+        if self._is_method():
+            if 'self' in args:
+                args.remove('self')
+            args.insert(0, 'self')
+        return self.extracted_name + '(%s)' % self._get_comma_form(args)
+    
+    def _get_function_call(self, args):
+        prefix = ''
+        if self._is_method():
+            if  'self' in args:
+                args.remove('self')
+            prefix = 'self.'
+        return prefix + '%s(%s)' % (self.extracted_name, self._get_comma_form(args))
+
+    def _get_comma_form(self, names):
+        result = ''
+        if names:
+            result += names[0]
+            for name in names[1:]:
+                result += ', ' + name
+        return result
+    
+    def _get_indents(self, lineno):
+        return sourceutils.get_indents(self.lines, lineno)
+
+
+class _OneLineExtractPerformer(_ExtractPerformer):
+    
+    def __init__(self, *args, **kwds):
+        super(_OneLineExtractPerformer, self).__init__(*args, **kwds)
+
+    def _check_exceptional_conditions(self):
+        super(_OneLineExtractPerformer, self)._check_exceptional_conditions()
+        if (self.parts.region[0] > 0 and self._is_on_a_word(self.parts.region[0] - 1)) or \
+           (self.parts.region[1] < len(self.source_code) and self._is_on_a_word(self.parts.region[1] - 1)):
+            raise RefactoringException('Should extract complete statements.')
+        if self.extract_variable and not self.parts.is_one_line_extract():
+            raise RefactoringException('Extract variable should not span multiple lines.')
+    
+    def _get_call(self):
+        args = self._find_function_arguments()
+        return self._get_function_call(args)
+
+    def _find_function_arguments(self):
+        start = self.parts.region[0]
+        if start == self.parts.region_lines[0]:
+            start = start + re.search('\S', self.source_code[start:self.parts.region[1]]).start()
+        function_definition = self.source_code[start:self.parts.region[1]]
+        read = _VariableReadsAndWritesFinder.find_reads_for_one_liners(
+            function_definition)
+        return list(self.info_collector.prewritten.intersection(read))
+    
+    def _find_function_returns(self):
+        return []
+        
+    def _get_unindented_function_body(self, returns):
+        return 'return ' + self._get_one_line_definition()
+    
+
+class _MultiLineExtractPerformer(_ExtractPerformer):
+    
+    def __init__(self, *args, **kwds):
+        super(_MultiLineExtractPerformer, self).__init__(*args, **kwds)
+
+    def _check_exceptional_conditions(self):
+        super(_MultiLineExtractPerformer, self)._check_exceptional_conditions()
+        if self.parts.region[0] != self.parts.region_lines[0] or \
+           self.parts.region[1] != self.parts.region_lines[1]:
+            raise RefactoringException('Extracted piece should contain complete statements.')
+    
+    def _get_call(self):
+        args = self._find_function_arguments()
+        returns = self._find_function_returns()
+        call_prefix = ''
+        if returns:
+            call_prefix = self._get_comma_form(returns) + ' = '
+        return call_prefix + self._get_function_call(args)
+
+    def _find_function_arguments(self):
+        return list(self.info_collector.prewritten.intersection(self.info_collector.read))
+    
+    def _find_function_returns(self):
+        return list(self.info_collector.written.intersection(self.info_collector.postread))
+        
+    def _get_unindented_function_body(self, returns):
+        extracted_body = self.source_code[self.parts.region[0]:self.parts.region[1]]
+        unindented_body = sourceutils.indent_lines(
+            extracted_body, -sourceutils.find_minimum_indents(extracted_body))
+        if returns:
+            unindented_body += '\nreturn %s' % self._get_comma_form(returns)
+        return unindented_body
+    
+
+class _ExtractedMethodPieces(object):
+    
+    def __init__(self, performer):
+        self.performer = performer
+    
+    def get_before_line(self):
+        if self.performer._is_global():
+            return '\n%s\n' % self.performer._get_function_definition()
+        return ''
+    
+    def get_call(self):
+        return self.performer._get_call()
+    
+    def get_after_scope(self):
+        if not self.performer._is_global():
+            return '\n%s' % self.performer._get_function_definition()
+        return ''
+
+
+class _ExtractedVariablePieces(object):
+    
+    def __init__(self, performer):
+        self.performer = performer
+    
+    def get_before_line(self):
+        result = ' ' * self.performer.first_line_indents + \
+                 self.performer.extracted_name + ' = ' + \
+                 self.performer._get_one_line_definition() + '\n'
+        return result
+    
+    def get_call(self):
+        return self.performer.extracted_name
+    
+    def get_after_scope(self):
+        return ''
+
+
+class _ExtractingPartOffsets(object):
     
     def __init__(self, pycore, resource, start_offset, end_offset):
         self.source_code = source_code = resource.read()
                 self.line_finder.get_logical_line_in(self.region_linenos[1]))
 
 
-class _ExtractPerformer(object):
-    """Perform extract method/variable refactoring
-    
-    We devide program source code into these parts::
-      
-      [...]
-        scope_start
-            [before_line]
-        start_line
-          start
-            [call]
-          end
-        end_line
-        scope_end
-            [after_scope]
-      [...]
-    
-    For extract function the new method is inserted in start_line,
-    while in extract method it is inserted in scope_end.
-    
-    Note that start and end are in the same line for one line
-    extractions, so start_line and end_line are in the same line,
-    too.
-    
-    The parts marked as before_line, call and after_scope are
-    used in refactoring and we use `ExtractInfo` to find the
-    new contents of these parts.
-
-    """
-    
-    def __init__(self, pycore, resource, info, extracted_name, extract_variable=False):
-        self.source_code = source_code = resource.read()
-        self.extracted_name = extracted_name
-        self.extract_variable = extract_variable
-        self.info = info
-        
-        self.lines = info.lines
-        
-        self.first_line_indents = self._get_indents(self.info.region_linenos[0])
-        self.scope = pycore.get_string_scope(source_code, resource)
-        self.holding_scope = self._find_holding_scope(self.info.region_linenos[0])
-        
-        self.extract_info = self._create_extract_info()
-        
-        self._check_exceptional_conditions()
-        self.info_collector = self._create_info_collector()
-    
-    def _create_extract_info(self):
-        if self.extract_variable:
-            return _ExtractedVariablePieces(self)
-        else:
-            return _ExtractedPieces(self)
-
-    def _find_holding_scope(self, start_line):
-        holding_scope = self.scope.get_inner_scope_for_line(start_line)
-        if holding_scope.get_kind() != 'Module' and \
-           holding_scope.get_start() == start_line:
-            holding_scope = holding_scope.parent
-        return holding_scope
-    
-    def _is_global(self):
-        return self.holding_scope.pyobject.get_type() == \
-               rope.base.pyobjects.PyObject.get_base_type('Module')
-
-    def _is_method(self):
-        return self.holding_scope.parent is not None and \
-               self.holding_scope.parent.pyobject.get_type() == \
-               rope.base.pyobjects.PyObject.get_base_type('Type')
-    
-    def _check_exceptional_conditions(self):
-        if self.holding_scope.pyobject.get_type() == rope.base.pyobjects.PyObject.get_base_type('Type'):
-            raise RefactoringException('Can not extract methods in class body')
-        if self.info.region[1] > self.info.scope[1]:
-            raise RefactoringException('Bad range selected for extract method')
-        end_line = self.info.region_linenos[1]
-        end_scope = self.scope.get_inner_scope_for_line(end_line)
-        if end_scope != self.holding_scope and end_scope.get_end() != end_line:
-            raise RefactoringException('Bad range selected for extract method')
-        try:
-            if _ReturnOrYieldFinder.does_it_return(
-                self.source_code[self.info.region[0]:self.info.region[1]]):
-                raise RefactoringException('Extracted piece should not contain return statements')
-        except SyntaxError:
-            raise RefactoringException('Extracted piece should contain complete statements.')
-
-    def _is_on_a_word(self, offset):
-        prev = self.source_code[offset]
-        next = self.source_code[offset + 1]
-        return (prev.isalnum() or prev == '_') and (next.isalnum() or next == '_')
-
-    def _create_info_collector(self):
-        zero = self.holding_scope.get_start() - 1
-        start_line = self.info.region_linenos[0] - zero
-        end_line = self.info.region_linenos[1] - zero
-        info_collector = _FunctionInformationCollector(start_line, end_line,
-                                                       self._is_global())
-        indented_body = self.source_code[self.info.scope[0]:self.info.scope[1]]
-        body = sourceutils.indent_lines(indented_body,
-                                        -sourceutils.find_minimum_indents(indented_body))
-        ast = _parse_text(body)
-        compiler.walk(ast, info_collector)
-        return info_collector
-
-    def extract(self):
-        result = []
-        result.append(self.source_code[:self.info.region_lines[0]])
-        result.append(self.extract_info.get_before_line())
-        result.append(self.source_code[self.info.region_lines[0]:self.info.region[0]])
-        result.append(self.extract_info.get_call())
-        result.append(self.source_code[self.info.region[1]:self.info.region_lines[1]])
-        result.append(self.source_code[self.info.region_lines[1]:self.info.scope[1]])
-        result.append(self.extract_info.get_after_scope())
-        result.append(self.source_code[self.info.scope[1]:])
-        return ''.join(result)
-
-    def _get_scope_indents(self):
-        if self._is_global():
-            return 0
-        else:
-            return self._get_indents(self.holding_scope.get_start()) + 4
-    
-    def _get_function_indents(self):
-        if self._is_global():
-            return 4
-        else:
-            return self._get_scope_indents()
-    
-    def _get_function_definition(self):
-        args = self._find_function_arguments()
-        returns = self._find_function_returns()
-        function_indents = self._get_function_indents()
-        result = []
-        result.append('%sdef %s:\n' %
-                      (' ' * self._get_indents(self.holding_scope.get_start()),
-                       self._get_function_signature(args)))
-        unindented_body = self._get_unindented_function_body(returns)
-        function_body = sourceutils.indent_lines(unindented_body, function_indents)
-        result.append(function_body)
-        definition = ''.join(result)
-        
-        return definition + '\n'
-
-    def _get_one_line_definition(self):
-        extracted_body = self.source_code[self.info.region[0]:self.info.region[1]]
-        lines = []
-        for line in extracted_body.splitlines():
-            if line.endswith('\\'):
-                lines.append(line[:-1].strip())
-            else:
-                lines.append(line.strip())
-        return ' '.join(lines)
-    
-    def _get_function_signature(self, args):
-        args = list(args)
-        if self._is_method():
-            if 'self' in args:
-                args.remove('self')
-            args.insert(0, 'self')
-        return self.extracted_name + '(%s)' % self._get_comma_form(args)
-    
-    def _get_function_call(self, args):
-        prefix = ''
-        if self._is_method():
-            if  'self' in args:
-                args.remove('self')
-            prefix = 'self.'
-        return prefix + '%s(%s)' % (self.extracted_name, self._get_comma_form(args))
-
-    def _get_comma_form(self, names):
-        result = ''
-        if names:
-            result += names[0]
-            for name in names[1:]:
-                result += ', ' + name
-        return result
-    
-    def _get_indents(self, lineno):
-        return sourceutils.get_indents(self.lines, lineno)
-
-
-class _OneLineExtractPerformer(_ExtractPerformer):
-    
-    def __init__(self, *args, **kwds):
-        super(_OneLineExtractPerformer, self).__init__(*args, **kwds)
-
-    def _check_exceptional_conditions(self):
-        super(_OneLineExtractPerformer, self)._check_exceptional_conditions()
-        if (self.info.region[0] > 0 and self._is_on_a_word(self.info.region[0] - 1)) or \
-           (self.info.region[1] < len(self.source_code) and self._is_on_a_word(self.info.region[1] - 1)):
-            raise RefactoringException('Should extract complete statements.')
-        if self.extract_variable and not self.info.is_one_line_extract():
-            raise RefactoringException('Extract variable should not span multiple lines.')
-    
-    def _get_call(self, returns, args):
-        return self._get_function_call(args)
-
-    def _find_function_arguments(self):
-        function_definition = self.source_code[self.info.region[0]:self.info.region[1]]
-        read = _VariableReadsAndWritesFinder.find_reads_for_one_liners(
-            function_definition)
-        return list(self.info_collector.prewritten.intersection(read))
-    
-    def _find_function_returns(self):
-        return []
-        
-    def _get_unindented_function_body(self, returns):
-        return 'return ' + self._get_one_line_definition()
-    
-
-class _MultiLineExtractPerformer(_ExtractPerformer):
-    
-    def __init__(self, *args, **kwds):
-        super(_MultiLineExtractPerformer, self).__init__(*args, **kwds)
-
-    def _check_exceptional_conditions(self):
-        super(_MultiLineExtractPerformer, self)._check_exceptional_conditions()
-        if self.info.region[0] != self.info.region_lines[0] or \
-           self.info.region[1] != self.info.region_lines[1]:
-            raise RefactoringException('Extracted piece should contain complete statements.')
-    
-    def _get_call(self, returns, args):
-        call_prefix = ''
-        if returns:
-            call_prefix = self._get_comma_form(returns) + ' = '
-        return ' ' * self.first_line_indents + call_prefix + \
-               self._get_function_call(args)
-
-    def _find_function_arguments(self):
-        return list(self.info_collector.prewritten.intersection(self.info_collector.read))
-    
-    def _find_function_returns(self):
-        return list(self.info_collector.written.intersection(self.info_collector.postread))
-        
-    def _get_unindented_function_body(self, returns):
-        extracted_body = self.source_code[self.info.region[0]:self.info.region[1]]
-        unindented_body = sourceutils.indent_lines(
-            extracted_body, -sourceutils.find_minimum_indents(extracted_body))
-        if returns:
-            unindented_body += '\nreturn %s' % self._get_comma_form(returns)
-        return unindented_body
-    
-
-class _ExtractedPieces(object):
-    
-    def __init__(self, performer):
-        self.performer = performer
-    
-    def get_before_line(self):
-        if self.performer._is_global():
-            return '\n%s\n' % self.performer._get_function_definition()
-        return ''
-    
-    def get_call(self):
-        args = self.performer._find_function_arguments()
-        returns = self.performer._find_function_returns()
-        return self.performer._get_call(returns, args)
-    
-    def get_after_scope(self):
-        if not self.performer._is_global():
-            return '\n%s' % self.performer._get_function_definition()
-        return ''
-
-
-class _ExtractedVariablePieces(object):
-    
-    def __init__(self, performer):
-        self.performer = performer
-    
-    def get_before_line(self):
-        result = ' ' * self.performer.first_line_indents + \
-                 self.performer.extracted_name + ' = ' + \
-                 self.performer._get_one_line_definition() + '\n'
-        return result
-    
-    def get_call(self):
-        return self.performer.extracted_name
-    
-    def get_after_scope(self):
-        return ''
-
-
 class _FunctionInformationCollector(object):
     
     def __init__(self, start, end, is_global):

rope/refactor/importutils/__init__.py

 from rope.refactor.importutils.importinfo import \
      (NormalImport, FromImport, get_module_name)
 from rope.refactor.importutils import module_imports
+import rope.base.evaluate
 
 
 class ImportTools(object):
 
     def _rename_in_module(self, pymodule, name, new_name, till_dot=False):
         old_name = name.split('.')[-1]
-        old_pyname = rope.base.codeanalyze.StatementEvaluator.get_string_result(
+        old_pyname = rope.base.evaluate.StatementEvaluator.get_string_result(
             pymodule.get_scope(), name)
         occurrence_finder = rope.refactor.occurrences.FilteredOccurrenceFinder(
             self.pycore, old_name, [old_pyname], imports=False)

rope/refactor/inline.py

         self.resource = self.pymodule.get_resource()
     
     def check_exceptional_conditions(self):
-        if len(self.pyname.assigned_asts) != 1:
+        if len(self.pyname.assignments) != 1:
             raise rope.base.exceptions.RefactoringException(
                 'Local variable should be assigned once or inlining.')
 
         return changes
 
     def _get_changed_module(self):
-        definition_line = self.pyname.assigned_asts[0].lineno
+        assignment = self.pyname.assignments[0]
+        definition_line = assignment.ast_node.lineno
         lines = self.pymodule.lines
         start, end = codeanalyze.LogicalLineFinder(lines).\
                      get_logical_line_in(definition_line)
                 line = line[:-1]
             definition_lines.append(line)
         definition_with_assignment = ' '.join(definition_lines)
-        if self._is_tuple_assignment(definition_with_assignment):
+        if assignment.index is not None:
             raise rope.base.exceptions.RefactoringException(
                 'Cannot inline tuple assignments.')
         definition = definition_with_assignment[definition_with_assignment.\
                  changed_source[lines.get_line_end(end) + 1:]
         return source
     
-    def _is_tuple_assignment(self, line):
-        try:
-            comma = line.index(',')
-            assign = line.index('=')
-            return comma < assign
-        except ValueError:
-            return False
-
 
 class _InlineFunctionCallsForModule(object):
     

rope/ui/codeassist.py

         _comment_line(editor, i, action)
 
 
+class _OccurrenceListHandle(EnhancedListHandle):
+
+    def __init__(self, toplevel, core, focus_set):
+        self.toplevel = toplevel
+        self.editor_manager = core.get_editor_manager()
+        self.focus_set = focus_set
+
+    def entry_to_string(self, entry):
+        return entry[0].get_path() + ' : ' + str(entry[1])
+
+    def canceled(self):
+        self.toplevel.destroy()
+
+    def selected(self, selected):
+        editor = self.editor_manager.get_resource_editor(selected[0]).get_editor()
+        editor.set_insert(editor.get_index(selected[1]))
+        self.focus_set()
+
+    def focus_went_out(self):
+        pass
+
+
+def find_occurrences(context):
+    toplevel = Tkinter.Toplevel()
+    toplevel.title('Code Assist Proposals')
+    resource = context.resource
+    offset = context.editor.get_current_offset()
+    result = context.editingtools.codeassist.find_occurrences(resource, offset)
+    enhanced_list = None
+    def focus_set():
+        enhanced_list.list.focus_set()
+        toplevel.grab_set()
+    enhanced_list = EnhancedList(
+        toplevel, _OccurrenceListHandle(toplevel, context.get_core(), focus_set),
+        title='Occurrences')
+    for occurrence in result:
+        enhanced_list.add_entry(occurrence)
+    def close(event):
+        toplevel.destroy()
+    toplevel.bind('<Escape>', close)
+    toplevel.bind('<Control-g>', close)
+    enhanced_list.list.focus_set()
+    toplevel.grab_set()
+
+
 # Registering code assist actions
 core = rope.ui.core.Core.get_core()
 core._add_menu_cascade(MenuAddress(['Code'], 'o'), ['python', 'rest'])
                             MenuAddress(['Code', 'Show Doc'], 's'), ['python']))
 actions.append(SimpleAction('Quick Outline', do_quick_outline, 'C-o',
                             MenuAddress(['Code', 'Quick Outline'], 'q'), ['python']))
+actions.append(SimpleAction('Find Occurrences', find_occurrences, 'C-G',
+                            MenuAddress(['Code', 'Find Occurrences'], 'f'), ['python']))
 
 actions.append(SimpleAction('Correct Line Indentation',
                             do_correct_line_indentation, 'C-i',

rope/ui/editor.py

             self.text.mark_set(INSERT, textIndex)
         else:
             self.text.mark_set(INSERT, textIndex._getIndex())
+        self.text.see(INSERT)
 
     def get(self, start=None, end=None):
         startIndex = INSERT

rope/ui/extension.py

     def _get_active_editor_resource(self):
         return self.get_active_editor().get_file()
     
+    def _get_active_editor_editor(self):
+        return self.get_active_editor().get_editor()
+    
     def _get_editing_context(self):
         return self.get_active_editor().get_editor().get_editing_context().editingtools
     
     project = property(_get_open_project)
+    fileeditor = property(get_active_editor)
+    editor = property(_get_active_editor_editor)
     resource = property(_get_active_editor_resource)
     editingtools = property(_get_editing_context)
 

rope/ui/highlighter.py

     def get_styles(self):
         return {}
 
-    def highlights(self, editor, startIndex, endIndex):
+    def highlights(self, editor, start_index, end_index):
         if False:
             yield None
 

ropetest/codeassisttest.py

         result = self.assist.get_doc(code, len(code) - 2, mod2)
         self.assertTrue(result.endswith('hey'))
         
+    def test_finding_occurrences(self):
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        mod.write('a_var = 1\n')
+        result = self.assist.find_occurrences(mod, 1)
+        self.assertEquals([(mod, 0)], result)
+
+    def test_finding_occurrences_in_more_than_one_module(self):
+        mod1 = self.pycore.create_module(self.project.get_root_folder(), 'mod1')
+        mod2 = self.pycore.create_module(self.project.get_root_folder(), 'mod2')
+        mod1.write('a_var = 1\n')
+        mod2.write('import mod1\nmy_var = mod1.a_var')
+        result = self.assist.find_occurrences(mod1, 1)
+        self.assertEquals(2, len(result))
+        self.assertTrue((mod1, 0) in result and (mod2, mod2.read().index('a_var')) in result)
+
 
 class TemplateTest(unittest.TestCase):
 

ropetest/objectinfertest.py

         self.assertEquals(pymod.get_attribute('a_func').get_object(),
                           pymod.get_attribute('a_var').get_object())
 
+    def test_list_objects_and_dynamicoi(self):
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        code = 'class C(object):\n    pass\ndef a_func(arg):\n    return arg\n' \
+               'a_var = a_func([C()])[0]\n'
+        mod.write(code)
+        self.pycore.run_module(mod).wait_process()
+        pymod = self.pycore.resource_to_pyobject(mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_for_loops_and_dynamicoi(self):
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        code = 'class C(object):\n    pass\ndef a_func(arg):\n    return arg\n' \
+               'for c in a_func([C()]):\n    a_var = c\n'
+        mod.write(code)
+        self.pycore.run_module(mod).wait_process()
+        pymod = self.pycore.resource_to_pyobject(mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_dict_objects_and_dynamicoi(self):
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        code = 'class C(object):\n    pass\n' \
+               'def a_func(arg):\n    return arg\n' \
+               'a_var = a_func({1: C()})[1]\n'
+        mod.write(code)
+        self.pycore.run_module(mod).wait_process()
+        pymod = self.pycore.resource_to_pyobject(mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_dict_keys_and_dynamicoi(self):
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        code = 'class C(object):\n    pass\n' \
+               'def a_func(arg):\n    return arg\n' \
+               'a_var = a_func({C(): 1}).keys()[0]\n'
+        mod.write(code)
+        self.pycore.run_module(mod).wait_process()
+        pymod = self.pycore.resource_to_pyobject(mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_dict_keys_and_dynamicoi(self):
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        code = 'class C1(object):\n    pass\nclass C2(object):\n    pass\n' \
+               'def a_func(arg):\n    return arg\n' \
+               'a, b = a_func((C1(), C2()))\n'
+        mod.write(code)
+        self.pycore.run_module(mod).wait_process()
+        pymod = self.pycore.resource_to_pyobject(mod)
+        c1_class = pymod.get_attribute('C1').get_object()
+        c2_class = pymod.get_attribute('C2').get_object()
+        a_var = pymod.get_attribute('a').get_object()
+        b_var = pymod.get_attribute('b').get_object()
+        self.assertEquals(c1_class, a_var.get_type())
+        self.assertEquals(c2_class, b_var.get_type())
+
+    def test_sets_and_dynamicoi(self):
+        mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+        code = 'class C(object):\n    pass\n' \
+               'def a_func(arg):\n    return arg\n' \
+               'a_var = a_func(set([C()])).pop()\n'
+        mod.write(code)
+        self.pycore.run_module(mod).wait_process()
+        pymod = self.pycore.resource_to_pyobject(mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
 
 class CartesianProductDynamicOITest(unittest.TestCase):
 

ropetest/pycoretest.py

         self.assertEquals([b_class], self.pycore.get_subclasses(a_class))
 
 
+class BuiltinTypesTest(unittest.TestCase):
+
+    def setUp(self):
+        super(BuiltinTypesTest, self).setUp()
+        testutils.remove_recursively(self.project_root)
+        self.project = Project(self.project_root)
+        self.pycore = self.project.get_pycore()
+        self.mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+    
+    project_root = 'sample_project'
+
+    def tearDown(self):
+        testutils.remove_recursively(self.project_root)
+        super(BuiltinTypesTest, self).tearDown()
+    
+    def test_simple_case(self):
+        self.mod.write('l = []\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        self.assertTrue('append' in pymod.get_attribute('l').get_object().get_attributes())
+
+    def test_holding_type_information(self):
+        self.mod.write('class C(object):\n    pass\nl = [C()]\na_var = l.pop()\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_get_items(self):
+        self.mod.write('class C(object):\n    def __getitem__(self, i):\n        return C()\n'
+                       'c = C()\na_var = c[0]')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_get_items_for_lists(self):
+        self.mod.write('class C(object):\n    pass\nl = [C()]\na_var = l[0]\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_get_items_from_slices(self):
+        self.mod.write('class C(object):\n    pass\nl = [C()]\na_var = l[:].pop()\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_simple_for_loops(self):
+        self.mod.write('class C(object):\n    pass\nl = [C()]\n'
+                       'for c in l:\n    a_var = c\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_definition_location_for_loop_variables(self):
+        self.mod.write('class C(object):\n    pass\nl = [C()]\n'
+                       'for c in l:\n    pass\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_var = pymod.get_attribute('c')
+        self.assertEquals((pymod, 4), c_var.get_definition_location())
+
+    def test_simple_case_for_dicts(self):
+        self.mod.write('d = {}\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        self.assertTrue('get' in pymod.get_attribute('d').get_object().get_attributes())
+
+    def test_get_item_for_dicts(self):
+        self.mod.write('class C(object):\n    pass\nd = {1: C()}\na_var = d[1]\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_popping_dicts(self):
+        self.mod.write('class C(object):\n    pass\nd = {1: C()}\na_var = d.pop(1)\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_getting_keys_from_dicts(self):
+        self.mod.write('class C1(object):\n    pass\nclass C2(object):\n    pass\n'
+                       'd = {C1(): C2()}\nfor c in d.keys():\n    a_var = c\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C1').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_getting_values_from_dicts(self):
+        self.mod.write('class C1(object):\n    pass\nclass C2(object):\n    pass\n'
+                       'd = {C1(): C2()}\nfor c in d.values():\n    a_var = c\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C2').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_getting_iterkeys_from_dicts(self):
+        self.mod.write('class C1(object):\n    pass\nclass C2(object):\n    pass\n'
+                       'd = {C1(): C2()}\nfor c in d.iterkeys():\n    a_var = c\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C1').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_getting_itervalues_from_dicts(self):
+        self.mod.write('class C1(object):\n    pass\nclass C2(object):\n    pass\n'
+                       'd = {C1(): C2()}\nfor c in d.itervalues():\n    a_var = c\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C2').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())
+
+    def test_using_copy_for_dicts(self):
+        self.mod.write('class C1(object):\n    pass\nclass C2(object):\n    pass\n'
+                       'd = {C1(): C2()}\nfor c in d.copy():\n    a_var = c\n')
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c_class = pymod.get_attribute('C1').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c_class, a_var.get_type())