Object Inference (OI) Engine
Relevant source files
The following files were used as context for generating this wiki page:
The Object Inference (OI) Engine is a core component of the Rope refactoring library designed to analyze Python programs and determine the types of objects passed to and returned from functions. Because Python is dynamically typed, Rope relies on the OI engine to provide the necessary type information for safe and accurate refactoring operations. The engine assumes a simplified model of Python programs focused primarily on assignments and function calls.
The engine employs three distinct strategies to collect object information: Static Object Analysis (SOA), Dynamic Object Analysis (DOA), and Static Object Inference (SOI). These strategies work together to populate a persistent or in-memory database (ObjectDB) that Rope consults during code analysis.
Sources: rope/base/oi/init.py:1-35, rope/base/oi/objectinfo.py:10-18
Architecture and Components
The OI Engine is managed by the ObjectInfoManager, which acts as the primary interface for storing and retrieving object data. It utilizes an ObjectDB for underlying storage, which can be backed by different implementations like MemoryDB.
Core Components
| Component | Description |
|---|---|
ObjectInfoManager | Orchestrates data transformation between Python objects and textual representations for storage. |
ObjectDB | The database layer that stores call information (parameters and return values) and per-name object data. |
MemoryDB | A specific database implementation that stores information in memory, with optional persistence to disk. |
SOA | Analyzes source code statically to find function calls and infer types. |
DOA | Collects runtime type information by executing the module or test suite. |
SOI | Inferred return values by analyzing function bodies when no database information is available. |
Sources: rope/base/oi/objectinfo.py:10-25, rope/base/oi/memorydb.py:6-15, rope/base/oi/init.py:7-30
Data Flow Diagram
The following diagram illustrates how different analysis methods feed data into the ObjectInfoManager.
The ObjectInfoManager transforms data using PyObjectToTextual and TextualToPyObject before interacting with the database.
Sources: rope/base/oi/objectinfo.py:20-24, rope/base/oi/init.py:7-35
Static Object Analysis (SOA)
SOA performs static analysis on Python modules to obtain information about functions by examining call sites within the module or scope. This process is triggered manually or automatically when modules are changed.
SOA Workflow
- Scope Iteration: The engine traverses the module's scopes, starting from inner scopes.
- Node Visiting: A
SOAVisitor(extendingRopeNodeVisitor) identifiesFunctionDef,ClassDef,Call, andAssignnodes. - Call Analysis: For each function call found, the visitor resolves the function being called and analyzes the arguments passed.
- Data Recording: The call information is sent to
ObjectInfoManager.function_called()for storage.
Sources: rope/base/oi/soa.py:7-60
SOA Sequence Diagram
Dynamic Object Analysis (DOA)
DOA collects high-fidelity type information by running the Python code. While highly accurate, it is significantly slower than static analysis due to the overhead of runtime collection.
- Data Reception: The
ObjectInfoManager.doa_data_received()method handles incoming runtime data, converting textual dynamic data back into Python object representations for storage. - Persistence: Data collected via DOA is saved into the
ObjectDBjust like SOA data, allowing future static lookups to benefit from previous runtime executions.
Sources: rope/base/oi/objectinfo.py:112-124, rope/base/oi/init.py:18-25, rope/base/pycore.py:148-163
Data Storage and Retrieval
The ObjectDB stores two primary types of information: call_info (tracking parameters and return values) and per_name (tracking objects held by specific names in a scope).
Database Structure
The storage is organized hierarchically by file path and scope key.
Retrieval Logic
When Rope needs the return value of a function (get_returned), it follows this logic:
- Exact Match: Checks for a call with identical parameter types in the database.
- Heuristic Fallback: If no exact match exists, it iterates through known
call_infosfor that function and returns the first valid (non-unknown) return type found. - Validation: The
TextualValidationclass ensures that retrieved values are still valid within the current project context (e.g., the referenced file still exists).
Sources: rope/base/oi/objectinfo.py:60-80, rope/base/oi/objectinfo.py:157-175
Configuration and Management
The behavior of the OI engine is governed by project preferences.
| Preference | Type | Description |
|---|---|---|
automatic_soa | boolean | If enabled, SOA is performed automatically when files are changed. |
save_objectdb | boolean | Determines if the ObjectDB should be persisted to the .ropeproject folder. |
soa_followed_calls | integer | The depth of calls to follow during static analysis. |
perform_doa | boolean | Whether to enable dynamic object analysis during module execution. |
Sources: rope/base/pycore.py:44-55, rope/base/pycore.py:150-155, rope/base/oi/objectinfo.py:27-38
Conclusion
The Object Inference Engine provides the backbone for Rope's understanding of Python's dynamic types. By combining static analysis (SOA) for speed, dynamic analysis (DOA) for accuracy, and on-the-fly inference (SOI), the engine maintains a comprehensive database of object relationships. This multi-pronged approach allows Rope to perform complex refactorings like renaming or moving methods with a high degree of safety, despite the lack of static type declarations in many Python codebases.