Skip to content

Commit b755799

Browse files
author
devsamikhan
committed
Implement safe and robust Python Interoperability using PyO3 stable ABI and global caching
1 parent 0ebf0af commit b755799

9 files changed

Lines changed: 655 additions & 21 deletions

File tree

‎Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ clap = { version = "4.4", features = ["derive"] }
1616
serde = { version = "1.0", features = ["derive"] }
1717
serde_json = "1.0"
1818
thiserror = "1.0"
19+
pyo3 = { version = "0.21", features = ["auto-initialize", "macros", "abi3-py38"] }
1920

2021
# For CRDT library
2122
hashbrown = "0.14"

‎README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ All structures are verified under integration tests to satisfy join-semilattice
122122
- `time` - Operations on timestamps.
123123
- `system` - OS environment checks.
124124

125+
### Python Interoperability
126+
Python Interoperability: AETHER can interface with the Python ecosystem via FFI, allowing access to libraries like NumPy and Pandas. For more details, see the [Python Interoperability Guide](file:///c:/Users/Latif%20Ullah%20Khan/Documents/Project%20AETHER/docs/interop/python.md).
127+
125128
---
126129

127130
## Experimental Features
@@ -192,6 +195,7 @@ These are long-term research directions, not current capabilities:
192195
- [x] Module system
193196
- [x] Better error messages
194197
- [x] Improved documentation
198+
- [x] Python Interoperability (FFI-based)
195199

196200
### Version 0.3
197201
- [ ] Enhanced package manager

‎docs/interop/python.md‎

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Python Interoperability Guide
2+
3+
Python Interoperability: AETHER can interface with the Python ecosystem via FFI, allowing access to libraries like NumPy and Pandas. This capability is powered by a GIL-safe dynamic bridge using the `pyo3` library.
4+
5+
---
6+
7+
## Prerequisites
8+
9+
To use Python interoperability features, the following requirements must be met:
10+
1. Python 3.8 or higher must be installed on your system.
11+
2. The Python dynamic library must be accessible in your system's path.
12+
3. Required Python modules (e.g., `numpy`, `pandas`) must be installed in your system's active Python environment.
13+
14+
---
15+
16+
## Installation & Configuration
17+
18+
AETHER automatically attempts to locate and initialize the system Python interpreter at runtime. Under the hood:
19+
- The compiler compiles with PyO3 targeting the stable ABI (using feature `abi3-py38`).
20+
- This guarantees compatibility with Python versions newer than the build-time environment.
21+
- If no Python runtime is installed, calls to Python interop features will fail gracefully and raise a compiler diagnostic error.
22+
23+
---
24+
25+
## Usage Examples
26+
27+
### 1. Function-Based Interop
28+
29+
The AETHER standard library includes three built-in interop functions:
30+
- `py_import(module_name: String)`: Imports a Python module and caches it for future calls.
31+
- `py_eval(expression: String)`: Evaluates a Python expression and returns the resulting value.
32+
- `py_call(function_name: String, arguments: List)`: Invokes a specific Python function with the given arguments.
33+
34+
```aether
35+
intent PythonInteropDemo {
36+
fn main() {
37+
// Import module
38+
py_import("math");
39+
40+
// Evaluate expression
41+
let val = py_eval("math.sqrt(25)");
42+
println(val); // Output: 5.0
43+
44+
// Direct function call
45+
let result = py_call("math.pow", [2, 10]);
46+
println(result); // Output: 1024.0
47+
}
48+
}
49+
```
50+
51+
### 2. Inline Block-Based Interop
52+
53+
For more complex scripts, AETHER supports block-based inline Python execution using the `python { ... } => target;` syntax. This compiles the block into a callback execution context and assigns the returned value to the target variable.
54+
55+
```aether
56+
intent NumPyDemo {
57+
fn main() {
58+
python {
59+
import numpy as np
60+
arr = np.array([10, 20, 30, 40, 50])
61+
return arr.mean()
62+
} => result;
63+
64+
println(result); // Output: 30.0
65+
}
66+
}
67+
```
68+
69+
---
70+
71+
## Type Mapping Table
72+
73+
Data types are marshaled between AETHER and Python according to the following mapping:
74+
75+
| AETHER Type | Python Type | Direction |
76+
|-------------|-------------|-----------|
77+
| `Integer(i64)` | `int` | Bi-directional |
78+
| `Float(f64)` | `float` | Bi-directional |
79+
| `String(String)` | `str` | Bi-directional |
80+
| `Boolean(bool)` | `bool` | Bi-directional |
81+
| `List(Vec<RuntimeValue>)` | `list` | Bi-directional |
82+
| `Null` | `None` | Bi-directional |
83+
84+
*Note: Nested structures (like lists containing lists or basic primitives) are recursively converted.*
85+
86+
---
87+
88+
## Error Handling Guide
89+
90+
AETHER intercepts Python runtime exceptions and redirect streams (stdout and stderr) to prevent silent execution failures. Exceptions are mapped to AETHER compiler diagnostic codes:
91+
92+
- **E0400 (PythonInteropError)**: Raised during execution of Python blocks, evaluations, or function calls.
93+
- **E0401 (PythonImportFailed)**: Raised if a requested module could not be found or loaded.
94+
95+
```
96+
error[E0401]: Failed to import Python module 'non_existent': No module named 'non_existent'
97+
--> src/main.aether:3:9
98+
|
99+
3 | py_import("non_existent");
100+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
101+
```
102+
103+
---
104+
105+
## Performance Considerations
106+
107+
1. **GIL Synchronization**: Every call across the FFI boundary acquires the Global Interpreter Lock (GIL). For performance-critical loops, group Python operations into a single inline block rather than calling individual functions repeatedly.
108+
2. **Module Caching**: Imported modules are cached in a thread-safe global namespace. This avoids duplicate loading times for standard libraries and external packages.

‎src/error/codes.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ pub enum ErrorCode {
2121
ModuleNotFound, // E0300
2222
CircularDependency, // E0301
2323
ImportNotFound, // E0302
24+
25+
// Python Interop errors (E0400-E0499)
26+
PythonInteropError, // E0400
27+
PythonImportFailed, // E0401
2428
}
2529

2630
impl ErrorCode {
@@ -40,6 +44,8 @@ impl ErrorCode {
4044
ErrorCode::ModuleNotFound => "E0300",
4145
ErrorCode::CircularDependency => "E0301",
4246
ErrorCode::ImportNotFound => "E0302",
47+
ErrorCode::PythonInteropError => "E0400",
48+
ErrorCode::PythonImportFailed => "E0401",
4349
}
4450
}
4551
}

‎src/interop/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod python;

0 commit comments

Comments
 (0)