Commits

Ali Gholami Rudi  committed 07efce3

oi: renaming modules

The new names are:

* staticoi -> soa
* dynamicoi -> doa
* objectinfer -> soi

  • Participants
  • Parent commits 48417a8

Comments (0)

Files changed (9)

File rope/base/oi/doa.py

+import cPickle as pickle
+import marshal
+import os
+import socket
+import subprocess
+import sys
+import tempfile
+import threading
+
+
+class PythonFileRunner(object):
+    """A class for running python project files"""
+
+    def __init__(self, pycore, file_, args=None, stdin=None,
+                 stdout=None, analyze_data=None):
+        self.pycore = pycore
+        self.file = file_
+        self.analyze_data = analyze_data
+        self.observers = []
+        self.args = args
+        self.stdin = stdin
+        self.stdout = stdout
+
+    def run(self):
+        """Execute the process"""
+        env = dict(os.environ)
+        file_path = self.file.real_path
+        path_folders = self.pycore.get_source_folders() + \
+                       self.pycore.get_python_path_folders()
+        env['PYTHONPATH'] = os.pathsep.join(folder.real_path
+                                            for folder in path_folders)
+        runmod_path = self.pycore.find_module('rope.base.oi.runmod').real_path
+        self.receiver = None
+        self._init_data_receiving()
+        send_info = '-'
+        if self.receiver:
+            send_info = self.receiver.get_send_info()
+        args = [sys.executable, runmod_path, send_info,
+                self.pycore.project.address, self.file.real_path]
+        if self.analyze_data is None:
+            del args[1:4]
+        if self.args is not None:
+            args.extend(self.args)
+        self.process = subprocess.Popen(
+            executable=sys.executable, args=args, env=env,
+            cwd=os.path.split(file_path)[0], stdin=self.stdin,
+            stdout=self.stdout, stderr=self.stdout, close_fds=os.name != 'nt')
+
+    def _init_data_receiving(self):
+        if self.analyze_data is None:
+            return
+        # Disabling FIFO data transfer due to blocking when running
+        # unittests in the GUI.
+        # XXX: Handle FIFO data transfer for `rope.ui.testview`
+        if True or os.name == 'nt':
+            self.receiver = _SocketReceiver()
+        else:
+            self.receiver = _FIFOReceiver()
+        self.receiving_thread = threading.Thread(target=self._receive_information)
+        self.receiving_thread.setDaemon(True)
+        self.receiving_thread.start()
+
+    def _receive_information(self):
+        #temp = open('/dev/shm/info', 'w')
+        for data in self.receiver.receive_data():
+            self.analyze_data(data)
+            #temp.write(str(data) + '\n')
+        #temp.close()
+        for observer in self.observers:
+            observer()
+
+    def wait_process(self):
+        """Wait for the process to finish"""
+        self.process.wait()
+        if self.analyze_data:
+            self.receiving_thread.join()
+
+    def kill_process(self):
+        """Stop the process"""
+        if os.name != 'nt':
+            os.kill(self.process.pid, 9)
+        else:
+            import ctypes
+            ctypes.windll.kernel32.TerminateProcess(int(self.process._handle), -1)
+
+    def add_finishing_observer(self, observer):
+        """Notify this observer when execution finishes"""
+        self.observers.append(observer)
+
+
+class _MessageReceiver(object):
+
+    def receive_data(self):
+        pass
+
+    def get_send_info(self):
+        pass
+
+
+class _SocketReceiver(_MessageReceiver):
+
+    def __init__(self):
+        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.data_port = 3037
+        while self.data_port < 4000:
+            try:
+                self.server_socket.bind(('', self.data_port))
+                break
+            except socket.error, e:
+                self.data_port += 1
+        self.server_socket.listen(1)
+
+    def get_send_info(self):
+        return str(self.data_port)
+
+    def receive_data(self):
+        conn, addr = self.server_socket.accept()
+        self.server_socket.close()
+        my_file = conn.makefile('r')
+        while True:
+            try:
+                yield pickle.load(my_file)
+            except EOFError:
+                break
+        my_file.close()
+        conn.close()
+
+
+class _FIFOReceiver(_MessageReceiver):
+
+    def __init__(self):
+        # XXX: this is unsecure and might cause race conditions
+        self.file_name = self._get_file_name()
+        os.mkfifo(self.file_name)
+
+    def _get_file_name(self):
+        prefix = tempfile.gettempdir() + '/__rope_'
+        i = 0
+        while os.path.exists(prefix + str(i).rjust(4, '0')):
+            i += 1
+        return prefix + str(i).rjust(4, '0')
+
+    def get_send_info(self):
+        return self.file_name
+
+    def receive_data(self):
+        my_file = open(self.file_name, 'rb')
+        while True:
+            try:
+                yield marshal.load(my_file)
+            except EOFError:
+                break
+        my_file.close()
+        os.remove(self.file_name)

File rope/base/oi/dynamicoi.py

-import cPickle as pickle
-import marshal
-import os
-import socket
-import subprocess
-import sys
-import tempfile
-import threading
-
-
-class PythonFileRunner(object):
-    """A class for running python project files"""
-
-    def __init__(self, pycore, file_, args=None, stdin=None,
-                 stdout=None, analyze_data=None):
-        self.pycore = pycore
-        self.file = file_
-        self.analyze_data = analyze_data
-        self.observers = []
-        self.args = args
-        self.stdin = stdin
-        self.stdout = stdout
-
-    def run(self):
-        """Execute the process"""
-        env = dict(os.environ)
-        file_path = self.file.real_path
-        path_folders = self.pycore.get_source_folders() + \
-                       self.pycore.get_python_path_folders()
-        env['PYTHONPATH'] = os.pathsep.join(folder.real_path
-                                            for folder in path_folders)
-        runmod_path = self.pycore.find_module('rope.base.oi.runmod').real_path
-        self.receiver = None
-        self._init_data_receiving()
-        send_info = '-'
-        if self.receiver:
-            send_info = self.receiver.get_send_info()
-        args = [sys.executable, runmod_path, send_info,
-                self.pycore.project.address, self.file.real_path]
-        if self.analyze_data is None:
-            del args[1:4]
-        if self.args is not None:
-            args.extend(self.args)
-        self.process = subprocess.Popen(
-            executable=sys.executable, args=args, env=env,
-            cwd=os.path.split(file_path)[0], stdin=self.stdin,
-            stdout=self.stdout, stderr=self.stdout, close_fds=os.name != 'nt')
-
-    def _init_data_receiving(self):
-        if self.analyze_data is None:
-            return
-        # Disabling FIFO data transfer due to blocking when running
-        # unittests in the GUI.
-        # XXX: Handle FIFO data transfer for `rope.ui.testview`
-        if True or os.name == 'nt':
-            self.receiver = _SocketReceiver()
-        else:
-            self.receiver = _FIFOReceiver()
-        self.receiving_thread = threading.Thread(target=self._receive_information)
-        self.receiving_thread.setDaemon(True)
-        self.receiving_thread.start()
-
-    def _receive_information(self):
-        #temp = open('/dev/shm/info', 'w')
-        for data in self.receiver.receive_data():
-            self.analyze_data(data)
-            #temp.write(str(data) + '\n')
-        #temp.close()
-        for observer in self.observers:
-            observer()
-
-    def wait_process(self):
-        """Wait for the process to finish"""
-        self.process.wait()
-        if self.analyze_data:
-            self.receiving_thread.join()
-
-    def kill_process(self):
-        """Stop the process"""
-        if os.name != 'nt':
-            os.kill(self.process.pid, 9)
-        else:
-            import ctypes
-            ctypes.windll.kernel32.TerminateProcess(int(self.process._handle), -1)
-
-    def add_finishing_observer(self, observer):
-        """Notify this observer when execution finishes"""
-        self.observers.append(observer)
-
-
-class _MessageReceiver(object):
-
-    def receive_data(self):
-        pass
-
-    def get_send_info(self):
-        pass
-
-
-class _SocketReceiver(_MessageReceiver):
-
-    def __init__(self):
-        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.data_port = 3037
-        while self.data_port < 4000:
-            try:
-                self.server_socket.bind(('', self.data_port))
-                break
-            except socket.error, e:
-                self.data_port += 1
-        self.server_socket.listen(1)
-
-    def get_send_info(self):
-        return str(self.data_port)
-
-    def receive_data(self):
-        conn, addr = self.server_socket.accept()
-        self.server_socket.close()
-        my_file = conn.makefile('r')
-        while True:
-            try:
-                yield pickle.load(my_file)
-            except EOFError:
-                break
-        my_file.close()
-        conn.close()
-
-
-class _FIFOReceiver(_MessageReceiver):
-
-    def __init__(self):
-        # XXX: this is unsecure and might cause race conditions
-        self.file_name = self._get_file_name()
-        os.mkfifo(self.file_name)
-
-    def _get_file_name(self):
-        prefix = tempfile.gettempdir() + '/__rope_'
-        i = 0
-        while os.path.exists(prefix + str(i).rjust(4, '0')):
-            i += 1
-        return prefix + str(i).rjust(4, '0')
-
-    def get_send_info(self):
-        return self.file_name
-
-    def receive_data(self):
-        my_file = open(self.file_name, 'rb')
-        while True:
-            try:
-                yield marshal.load(my_file)
-            except EOFError:
-                break
-        my_file.close()
-        os.remove(self.file_name)

File rope/base/oi/objectinfer.py

-"""A module for inferring objects
-
-For more information see the documentation in `rope.base.oi`
-package.
-
-"""
-import rope.base.builtins
-import rope.base.pynames
-import rope.base.pyobjects
-from rope.base import evaluate, utils, arguments
-
-
-_ignore_inferred = utils.ignore_exception(
-    rope.base.pyobjects.IsBeingInferredError)
-
-
-@_ignore_inferred
-def infer_returned_object(pyfunction, args):
-    """Infer the `PyObject` this `PyFunction` returns after calling"""
-    object_info = pyfunction.pycore.object_info
-    result = object_info.get_exact_returned(pyfunction, args)
-    if result is not None:
-        return result
-    result = _infer_returned(pyfunction, args)
-    if result is not None:
-        if args and pyfunction.get_module().get_resource() is not None:
-            params = args.get_arguments(
-                pyfunction.get_param_names(special_args=False))
-            object_info.function_called(pyfunction, params, result)
-        return result
-    return object_info.get_returned(pyfunction, args)
-
-@_ignore_inferred
-def infer_parameter_objects(pyfunction):
-    """Infer the `PyObject`\s of parameters of this `PyFunction`"""
-    object_info = pyfunction.pycore.object_info
-    result = object_info.get_parameter_objects(pyfunction)
-    if result is None:
-        result = _parameter_objects(pyfunction)
-    _handle_first_parameter(pyfunction, result)
-    return result
-
-def _handle_first_parameter(pyobject, parameters):
-    kind = pyobject.get_kind()
-    if parameters is None or kind not in ['method', 'classmethod']:
-        pass
-    if not parameters:
-        if not pyobject.get_param_names(special_args=False):
-            return
-        parameters.append(rope.base.pyobjects.get_unknown())
-    if kind == 'method':
-        parameters[0] = rope.base.pyobjects.PyObject(pyobject.parent)
-    if kind == 'classmethod':
-        parameters[0] = pyobject.parent
-
-@_ignore_inferred
-def infer_assigned_object(pyname):
-    if not pyname.assignments:
-        return
-    for assignment in reversed(pyname.assignments):
-        result = _infer_assignment(assignment, pyname.module)
-        if result is not None:
-            return result
-
-def get_passed_objects(pyfunction, parameter_index):
-    object_info = pyfunction.pycore.object_info
-    result = object_info.get_passed_objects(pyfunction,
-                                            parameter_index)
-    if not result:
-        statically_inferred = _parameter_objects(pyfunction)
-        if len(statically_inferred) > parameter_index:
-            result.append(statically_inferred[parameter_index])
-    return result
-
-def _infer_returned(pyobject, args):
-    if args:
-        # HACK: Setting parameter objects manually
-        # This is not thread safe and might cause problems if `args`
-        # does not come from a good call site
-        pyobject.get_scope().invalidate_data()
-        pyobject._set_parameter_pyobjects(
-            args.get_arguments(pyobject.get_param_names(special_args=False)))
-    scope = pyobject.get_scope()
-    if not scope._get_returned_asts():
-        return
-    maxtries = 3
-    for returned_node in reversed(scope._get_returned_asts()[-maxtries:]):
-        try:
-            resulting_pyname = evaluate.get_statement_result(scope,
-                                                             returned_node)
-            if resulting_pyname is None:
-                continue
-            pyobject = resulting_pyname.get_object()
-            if pyobject == rope.base.pyobjects.get_unknown():
-                continue
-            if not scope._is_generator():
-                return pyobject
-            else:
-                return rope.base.builtins.get_generator(pyobject)
-        except rope.base.pyobjects.IsBeingInferredError:
-            pass
-
-def _parameter_objects(pyobject):
-    params = pyobject.get_param_names(special_args=False)
-    return [rope.base.pyobjects.get_unknown()] * len(params)
-
-# handling `rope.base.pynames.AssignmentValue`
-
-@_ignore_inferred
-def _infer_assignment(assignment, pymodule):
-    result = _follow_pyname(assignment, pymodule)
-    if result is None:
-        return None
-    pyname, pyobject = result
-    pyobject = _follow_evaluations(assignment, pyname, pyobject)
-    if pyobject is None:
-        return None
-    return _follow_levels(assignment, pyobject)
-
-def _follow_levels(assignment, pyobject):
-    for index in assignment.levels:
-        if isinstance(pyobject.get_type(), rope.base.builtins.Tuple):
-            holdings = pyobject.get_type().get_holding_objects()
-            if holdings:
-                pyobject = holdings[min(len(holdings) - 1, index)]
-            else:
-                pyobject = None
-        elif isinstance(pyobject.get_type(), rope.base.builtins.List):
-            pyobject = pyobject.get_type().holding
-        else:
-            pyobject = None
-        if pyobject is None:
-            break
-    return pyobject
-
-@_ignore_inferred
-def _follow_pyname(assignment, pymodule, lineno=None):
-    assign_node = assignment.ast_node
-    if lineno is None:
-        lineno = _get_lineno_for_node(assign_node)
-    holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
-    pyname = evaluate.get_statement_result(holding_scope, assign_node)
-    if pyname is not None:
-        result = pyname.get_object()
-        if isinstance(result.get_type(), rope.base.builtins.Property) and \
-           holding_scope.get_kind() == 'Class':
-            arg = rope.base.pynames.UnboundName(
-                rope.base.pyobjects.PyObject(holding_scope.pyobject))
-            return pyname, result.get_type().get_property_object(
-                arguments.ObjectArguments([arg]))
-        return pyname, result
-
-@_ignore_inferred
-def _follow_evaluations(assignment, pyname, pyobject):
-    new_pyname = pyname
-    tokens = assignment.evaluation.split('.')
-    for token in tokens:
-        call = token.endswith('()')
-        if call:
-            token = token[:-2]
-        if token:
-            pyname = new_pyname
-            new_pyname = _get_attribute(pyobject, token)
-            if new_pyname is not None:
-                pyobject = new_pyname.get_object()
-        if pyobject is not None and call:
-            if isinstance(pyobject, rope.base.pyobjects.AbstractFunction):
-                args = arguments.ObjectArguments([pyname])
-                pyobject = pyobject.get_returned_object(args)
-            else:
-                pyobject = None
-        if pyobject is None:
-            break
-    if pyobject is not None and assignment.assign_type:
-        return rope.base.pyobjects.PyObject(pyobject)
-    return pyobject
-
-
-def _get_lineno_for_node(assign_node):
-    if hasattr(assign_node, 'lineno') and \
-       assign_node.lineno is not None:
-        return assign_node.lineno
-    return 1
-
-def _get_attribute(pyobject, name):
-    if pyobject is not None and name in pyobject:
-        return pyobject[name]

File rope/base/oi/soa.py

+import rope.base.ast
+import rope.base.oi.soi
+import rope.base.pynames
+from rope.base import pyobjects, evaluate, astutils, arguments
+
+
+def analyze_module(pycore, pymodule, should_analyze,
+                   search_subscopes, followed_calls):
+    """Analyze `pymodule` for static object inference
+
+    Analyzes scopes for collecting object information.  The analysis
+    starts from inner scopes.
+
+    """
+    _analyze_node(pycore, pymodule, should_analyze,
+                  search_subscopes, followed_calls)
+
+
+def _analyze_node(pycore, pydefined, should_analyze,
+                  search_subscopes, followed_calls):
+    if search_subscopes(pydefined):
+        for scope in pydefined.get_scope().get_scopes():
+            _analyze_node(pycore, scope.pyobject, should_analyze,
+                          search_subscopes, followed_calls)
+    if should_analyze(pydefined):
+        new_followed_calls = max(0, followed_calls - 1)
+        def _called(pyfunction):
+            if followed_calls:
+                _analyze_node(pycore, pyfunction, should_analyze,
+                              search_subscopes, new_followed_calls)
+        visitor = SOIVisitor(pycore, pydefined, _called)
+        for child in rope.base.ast.get_child_nodes(pydefined.get_ast()):
+            rope.base.ast.walk(child, visitor)
+
+
+class SOIVisitor(object):
+
+    def __init__(self, pycore, pydefined, called_callback=None):
+        self.pycore = pycore
+        self.pymodule = pydefined.get_module()
+        self.scope = pydefined.get_scope()
+        self.called = called_callback
+
+    def _FunctionDef(self, node):
+        pass
+
+    def _ClassDef(self, node):
+        pass
+
+    def _Call(self, node):
+        for child in rope.base.ast.get_child_nodes(node):
+            rope.base.ast.walk(child, self)
+        primary, pyname = evaluate.get_primary_and_result(self.scope,
+                                                          node.func)
+        if pyname is None:
+            return
+        pyfunction = pyname.get_object()
+        if isinstance(pyfunction, pyobjects.AbstractFunction):
+            args = arguments.create_arguments(primary, pyfunction,
+                                              node, self.scope)
+        elif isinstance(pyfunction, pyobjects.PyClass):
+            pyclass = pyfunction
+            if '__init__' in pyfunction:
+                pyfunction = pyfunction['__init__'].get_object()
+            pyname = rope.base.pynames.UnboundName(pyobjects.PyObject(pyclass))
+            args = self._args_with_self(primary, pyname, pyfunction, node)
+        elif '__call__' in pyfunction:
+            pyfunction = pyfunction['__call__'].get_object()
+            args = self._args_with_self(primary, pyname, pyfunction, node)
+        else:
+            return
+        self._call(pyfunction, args)
+
+    def _args_with_self(self, primary, self_pyname, pyfunction, node):
+        base_args = arguments.create_arguments(primary, pyfunction,
+                                               node, self.scope)
+        return arguments.MixedArguments(self_pyname, base_args, self.scope)
+
+    def _call(self, pyfunction, args):
+        if isinstance(pyfunction, pyobjects.PyFunction):
+            self.pycore.object_info.function_called(
+                pyfunction, args.get_arguments(pyfunction.get_param_names()))
+            pyfunction._set_parameter_pyobjects(None)
+            if self.called is not None:
+                self.called(pyfunction)
+        # XXX: Maybe we should not call every builtin function
+        if isinstance(pyfunction, rope.base.builtins.BuiltinFunction):
+            pyfunction.get_returned_object(args)
+
+    def _Assign(self, node):
+        for child in rope.base.ast.get_child_nodes(node):
+            rope.base.ast.walk(child, self)
+        visitor = _SOIAssignVisitor()
+        nodes = []
+        for child in node.targets:
+            rope.base.ast.walk(child, visitor)
+            nodes.extend(visitor.nodes)
+        for subscript, levels in nodes:
+            instance = evaluate.get_statement_result(self.scope, subscript.value)
+            args_pynames = []
+            args_pynames.append(evaluate.get_statement_result(
+                                self.scope, subscript.slice.value))
+            value = rope.base.oi.soi._infer_assignment(
+                rope.base.pynames.AssignmentValue(node.value, levels), self.pymodule)
+            args_pynames.append(rope.base.pynames.UnboundName(value))
+            if instance is not None and value is not None:
+                pyobject = instance.get_object()
+                if '__setitem__' in pyobject:
+                    pyfunction = pyobject['__setitem__'].get_object()
+                    args = arguments.ObjectArguments([instance] + args_pynames)
+                    self._call(pyfunction, args)
+                # IDEA: handle `__setslice__`, too
+
+
+class _SOIAssignVisitor(astutils._NodeNameCollector):
+
+    def __init__(self):
+        super(_SOIAssignVisitor, self).__init__()
+        self.nodes = []
+
+    def _added(self, node, levels):
+        if isinstance(node, rope.base.ast.Subscript) and \
+           isinstance(node.slice, rope.base.ast.Index):
+            self.nodes.append((node, levels))

File rope/base/oi/soi.py

+"""A module for inferring objects
+
+For more information see the documentation in `rope.base.oi`
+package.
+
+"""
+import rope.base.builtins
+import rope.base.pynames
+import rope.base.pyobjects
+from rope.base import evaluate, utils, arguments
+
+
+_ignore_inferred = utils.ignore_exception(
+    rope.base.pyobjects.IsBeingInferredError)
+
+
+@_ignore_inferred
+def infer_returned_object(pyfunction, args):
+    """Infer the `PyObject` this `PyFunction` returns after calling"""
+    object_info = pyfunction.pycore.object_info
+    result = object_info.get_exact_returned(pyfunction, args)
+    if result is not None:
+        return result
+    result = _infer_returned(pyfunction, args)
+    if result is not None:
+        if args and pyfunction.get_module().get_resource() is not None:
+            params = args.get_arguments(
+                pyfunction.get_param_names(special_args=False))
+            object_info.function_called(pyfunction, params, result)
+        return result
+    return object_info.get_returned(pyfunction, args)
+
+@_ignore_inferred
+def infer_parameter_objects(pyfunction):
+    """Infer the `PyObject`\s of parameters of this `PyFunction`"""
+    object_info = pyfunction.pycore.object_info
+    result = object_info.get_parameter_objects(pyfunction)
+    if result is None:
+        result = _parameter_objects(pyfunction)
+    _handle_first_parameter(pyfunction, result)
+    return result
+
+def _handle_first_parameter(pyobject, parameters):
+    kind = pyobject.get_kind()
+    if parameters is None or kind not in ['method', 'classmethod']:
+        pass
+    if not parameters:
+        if not pyobject.get_param_names(special_args=False):
+            return
+        parameters.append(rope.base.pyobjects.get_unknown())
+    if kind == 'method':
+        parameters[0] = rope.base.pyobjects.PyObject(pyobject.parent)
+    if kind == 'classmethod':
+        parameters[0] = pyobject.parent
+
+@_ignore_inferred
+def infer_assigned_object(pyname):
+    if not pyname.assignments:
+        return
+    for assignment in reversed(pyname.assignments):
+        result = _infer_assignment(assignment, pyname.module)
+        if result is not None:
+            return result
+
+def get_passed_objects(pyfunction, parameter_index):
+    object_info = pyfunction.pycore.object_info
+    result = object_info.get_passed_objects(pyfunction,
+                                            parameter_index)
+    if not result:
+        statically_inferred = _parameter_objects(pyfunction)
+        if len(statically_inferred) > parameter_index:
+            result.append(statically_inferred[parameter_index])
+    return result
+
+def _infer_returned(pyobject, args):
+    if args:
+        # HACK: Setting parameter objects manually
+        # This is not thread safe and might cause problems if `args`
+        # does not come from a good call site
+        pyobject.get_scope().invalidate_data()
+        pyobject._set_parameter_pyobjects(
+            args.get_arguments(pyobject.get_param_names(special_args=False)))
+    scope = pyobject.get_scope()
+    if not scope._get_returned_asts():
+        return
+    maxtries = 3
+    for returned_node in reversed(scope._get_returned_asts()[-maxtries:]):
+        try:
+            resulting_pyname = evaluate.get_statement_result(scope,
+                                                             returned_node)
+            if resulting_pyname is None:
+                continue
+            pyobject = resulting_pyname.get_object()
+            if pyobject == rope.base.pyobjects.get_unknown():
+                continue
+            if not scope._is_generator():
+                return pyobject
+            else:
+                return rope.base.builtins.get_generator(pyobject)
+        except rope.base.pyobjects.IsBeingInferredError:
+            pass
+
+def _parameter_objects(pyobject):
+    params = pyobject.get_param_names(special_args=False)
+    return [rope.base.pyobjects.get_unknown()] * len(params)
+
+# handling `rope.base.pynames.AssignmentValue`
+
+@_ignore_inferred
+def _infer_assignment(assignment, pymodule):
+    result = _follow_pyname(assignment, pymodule)
+    if result is None:
+        return None
+    pyname, pyobject = result
+    pyobject = _follow_evaluations(assignment, pyname, pyobject)
+    if pyobject is None:
+        return None
+    return _follow_levels(assignment, pyobject)
+
+def _follow_levels(assignment, pyobject):
+    for index in assignment.levels:
+        if isinstance(pyobject.get_type(), rope.base.builtins.Tuple):
+            holdings = pyobject.get_type().get_holding_objects()
+            if holdings:
+                pyobject = holdings[min(len(holdings) - 1, index)]
+            else:
+                pyobject = None
+        elif isinstance(pyobject.get_type(), rope.base.builtins.List):
+            pyobject = pyobject.get_type().holding
+        else:
+            pyobject = None
+        if pyobject is None:
+            break
+    return pyobject
+
+@_ignore_inferred
+def _follow_pyname(assignment, pymodule, lineno=None):
+    assign_node = assignment.ast_node
+    if lineno is None:
+        lineno = _get_lineno_for_node(assign_node)
+    holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+    pyname = evaluate.get_statement_result(holding_scope, assign_node)
+    if pyname is not None:
+        result = pyname.get_object()
+        if isinstance(result.get_type(), rope.base.builtins.Property) and \
+           holding_scope.get_kind() == 'Class':
+            arg = rope.base.pynames.UnboundName(
+                rope.base.pyobjects.PyObject(holding_scope.pyobject))
+            return pyname, result.get_type().get_property_object(
+                arguments.ObjectArguments([arg]))
+        return pyname, result
+
+@_ignore_inferred
+def _follow_evaluations(assignment, pyname, pyobject):
+    new_pyname = pyname
+    tokens = assignment.evaluation.split('.')
+    for token in tokens:
+        call = token.endswith('()')
+        if call:
+            token = token[:-2]
+        if token:
+            pyname = new_pyname
+            new_pyname = _get_attribute(pyobject, token)
+            if new_pyname is not None:
+                pyobject = new_pyname.get_object()
+        if pyobject is not None and call:
+            if isinstance(pyobject, rope.base.pyobjects.AbstractFunction):
+                args = arguments.ObjectArguments([pyname])
+                pyobject = pyobject.get_returned_object(args)
+            else:
+                pyobject = None
+        if pyobject is None:
+            break
+    if pyobject is not None and assignment.assign_type:
+        return rope.base.pyobjects.PyObject(pyobject)
+    return pyobject
+
+
+def _get_lineno_for_node(assign_node):
+    if hasattr(assign_node, 'lineno') and \
+       assign_node.lineno is not None:
+        return assign_node.lineno
+    return 1
+
+def _get_attribute(pyobject, name):
+    if pyobject is not None and name in pyobject:
+        return pyobject[name]

File rope/base/oi/staticoi.py

-import rope.base.ast
-import rope.base.oi.objectinfer
-import rope.base.pynames
-from rope.base import pyobjects, evaluate, astutils, arguments
-
-
-def analyze_module(pycore, pymodule, should_analyze,
-                   search_subscopes, followed_calls):
-    """Analyze `pymodule` for static object inference
-
-    Analyzes scopes for collecting object information.  The analysis
-    starts from inner scopes.
-
-    """
-    _analyze_node(pycore, pymodule, should_analyze,
-                  search_subscopes, followed_calls)
-
-
-def _analyze_node(pycore, pydefined, should_analyze,
-                  search_subscopes, followed_calls):
-    if search_subscopes(pydefined):
-        for scope in pydefined.get_scope().get_scopes():
-            _analyze_node(pycore, scope.pyobject, should_analyze,
-                          search_subscopes, followed_calls)
-    if should_analyze(pydefined):
-        new_followed_calls = max(0, followed_calls - 1)
-        def _called(pyfunction):
-            if followed_calls:
-                _analyze_node(pycore, pyfunction, should_analyze,
-                              search_subscopes, new_followed_calls)
-        visitor = SOIVisitor(pycore, pydefined, _called)
-        for child in rope.base.ast.get_child_nodes(pydefined.get_ast()):
-            rope.base.ast.walk(child, visitor)
-
-
-class SOIVisitor(object):
-
-    def __init__(self, pycore, pydefined, called_callback=None):
-        self.pycore = pycore
-        self.pymodule = pydefined.get_module()
-        self.scope = pydefined.get_scope()
-        self.called = called_callback
-
-    def _FunctionDef(self, node):
-        pass
-
-    def _ClassDef(self, node):
-        pass
-
-    def _Call(self, node):
-        for child in rope.base.ast.get_child_nodes(node):
-            rope.base.ast.walk(child, self)
-        primary, pyname = evaluate.get_primary_and_result(self.scope,
-                                                          node.func)
-        if pyname is None:
-            return
-        pyfunction = pyname.get_object()
-        if isinstance(pyfunction, pyobjects.AbstractFunction):
-            args = arguments.create_arguments(primary, pyfunction,
-                                              node, self.scope)
-        elif isinstance(pyfunction, pyobjects.PyClass):
-            pyclass = pyfunction
-            if '__init__' in pyfunction:
-                pyfunction = pyfunction['__init__'].get_object()
-            pyname = rope.base.pynames.UnboundName(pyobjects.PyObject(pyclass))
-            args = self._args_with_self(primary, pyname, pyfunction, node)
-        elif '__call__' in pyfunction:
-            pyfunction = pyfunction['__call__'].get_object()
-            args = self._args_with_self(primary, pyname, pyfunction, node)
-        else:
-            return
-        self._call(pyfunction, args)
-
-    def _args_with_self(self, primary, self_pyname, pyfunction, node):
-        base_args = arguments.create_arguments(primary, pyfunction,
-                                               node, self.scope)
-        return arguments.MixedArguments(self_pyname, base_args, self.scope)
-
-    def _call(self, pyfunction, args):
-        if isinstance(pyfunction, pyobjects.PyFunction):
-            self.pycore.object_info.function_called(
-                pyfunction, args.get_arguments(pyfunction.get_param_names()))
-            pyfunction._set_parameter_pyobjects(None)
-            if self.called is not None:
-                self.called(pyfunction)
-        # XXX: Maybe we should not call every builtin function
-        if isinstance(pyfunction, rope.base.builtins.BuiltinFunction):
-            pyfunction.get_returned_object(args)
-
-    def _Assign(self, node):
-        for child in rope.base.ast.get_child_nodes(node):
-            rope.base.ast.walk(child, self)
-        visitor = _SOIAssignVisitor()
-        nodes = []
-        for child in node.targets:
-            rope.base.ast.walk(child, visitor)
-            nodes.extend(visitor.nodes)
-        for subscript, levels in nodes:
-            instance = evaluate.get_statement_result(self.scope, subscript.value)
-            args_pynames = []
-            args_pynames.append(evaluate.get_statement_result(
-                                self.scope, subscript.slice.value))
-            value = rope.base.oi.objectinfer._infer_assignment(
-                rope.base.pynames.AssignmentValue(node.value, levels), self.pymodule)
-            args_pynames.append(rope.base.pynames.UnboundName(value))
-            if instance is not None and value is not None:
-                pyobject = instance.get_object()
-                if '__setitem__' in pyobject:
-                    pyfunction = pyobject['__setitem__'].get_object()
-                    args = arguments.ObjectArguments([instance] + args_pynames)
-                    self._call(pyfunction, args)
-                # IDEA: handle `__setslice__`, too
-
-
-class _SOIAssignVisitor(astutils._NodeNameCollector):
-
-    def __init__(self):
-        super(_SOIAssignVisitor, self).__init__()
-        self.nodes = []
-
-    def _added(self, node, levels):
-        if isinstance(node, rope.base.ast.Subscript) and \
-           isinstance(node.slice, rope.base.ast.Index):
-            self.nodes.append((node, levels))

File rope/base/pycore.py

 import sys
 import warnings
 
-import rope.base.oi.dynamicoi
+import rope.base.oi.doa
 import rope.base.oi.objectinfo
-import rope.base.oi.staticoi
+import rope.base.oi.soa
 from rope.base import ast, exceptions, taskhandle
 from rope.base.exceptions import ModuleNotFoundError
 from rope.base.pyobjectsdef import PyModule, PyPackage, PyClass
     def run_module(self, resource, args=None, stdin=None, stdout=None):
         """Run `resource` module
 
-        Returns a `rope.base.oi.dynamicoi.PythonFileRunner` object for
+        Returns a `rope.base.oi.doa.PythonFileRunner` object for
         controlling the process.
 
         """
         receiver = self.object_info.doi_data_received
         if not self.project.get_prefs().get('perform_doi', True):
             receiver = None
-        runner = rope.base.oi.dynamicoi.PythonFileRunner(
+        runner = rope.base.oi.doa.PythonFileRunner(
             self, resource, args, stdin, stdout, receiver)
         runner.add_finishing_observer(self.module_cache.forget_all_data)
         runner.run()
         """
         pymodule = self.resource_to_pyobject(resource)
         self.module_cache.forget_all_data()
-        rope.base.oi.staticoi.analyze_module(
+        rope.base.oi.soa.analyze_module(
             self, pymodule, should_analyze, search_subscopes, followed_calls)
 
     def get_subclasses(self, pyclass, task_handle=taskhandle.NullTaskHandle()):

File rope/base/pynamesdef.py

-import rope.base.oi.objectinfer
+import rope.base.oi.soi
 from rope.base import pynames
 from rope.base.pynames import *
 
 
     def _get_inferred(self):
         if self.module is not None:
-            return rope.base.oi.objectinfer.infer_assigned_object(self)
+            return rope.base.oi.soi.infer_assigned_object(self)
 
     def get_object(self):
         return self.pyobject.get()
 
     def get_objects(self):
         """Returns the list of objects passed as this parameter"""
-        return rope.base.oi.objectinfer.get_passed_objects(
+        return rope.base.oi.soi.get_passed_objects(
             self.pyfunction, self.index)
 
     def get_definition_location(self):

File rope/base/pyobjectsdef.py

 import rope.base.codeanalyze
 import rope.base.evaluate
 import rope.base.builtins
-import rope.base.oi.objectinfer
+import rope.base.oi.soi
 import rope.base.pyscopes
 from rope.base import pynamesdef as pynames, exceptions, ast, astutils, pyobjects, fscommands, arguments
 from rope.base.pyobjects import *
                                                 _FunctionVisitor)
 
     def _infer_parameters(self):
-        pyobjects = rope.base.oi.objectinfer.infer_parameter_objects(self)
+        pyobjects = rope.base.oi.soi.infer_parameter_objects(self)
         self._handle_special_args(pyobjects)
         return pyobjects
 
     def _infer_returned(self, args=None):
-        return rope.base.oi.objectinfer.infer_returned_object(self, args)
+        return rope.base.oi.soi.infer_returned_object(self, args)
 
     def _handle_special_args(self, pyobjects):
         if len(pyobjects) == len(self.arguments.args):