dagex 2026.12__cp312-cp312-manylinux_2_34_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dagex/__init__.py
ADDED
|
Binary file
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dagex
|
|
3
|
+
Version: 2026.12
|
|
4
|
+
Summary: A pure Rust DAG executor supporting implicit node connections, branching, and config sweeps
|
|
5
|
+
Keywords: dag,graph,execution,pipeline,workflow
|
|
6
|
+
Home-Page: https://github.com/briday1/dagex
|
|
7
|
+
Author: briday1 <your-email@example.com>
|
|
8
|
+
Author-email: briday1 <your-email@example.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
12
|
+
Project-URL: Source Code, https://github.com/briday1/dagex
|
|
13
|
+
|
|
14
|
+
<div align="center">
|
|
15
|
+
<img src="https://raw.githubusercontent.com/briday1/graph-sp/main/assets/logo-banner.png" alt="dagex" width="600"/>
|
|
16
|
+
<p><em>A pure Rust DAG executor with Python bindings</em></p>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
# dagex
|
|
20
|
+
|
|
21
|
+
A pure Rust DAG (Directed Acyclic Graph) executor with Python bindings for building and executing computational pipelines.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **Implicit Node Connections**: Nodes automatically connect based on execution order
|
|
26
|
+
- **Parallel Branching**: Create fan-out execution paths with `.branch()`
|
|
27
|
+
- **Configuration Variants**: Use `.variant()` to create parameter sweeps
|
|
28
|
+
- **Mermaid Visualization**: Generate diagrams with `.to_mermaid()`
|
|
29
|
+
- **Parallel Execution**: Execute independent branches concurrently
|
|
30
|
+
- **Native Performance**: Rust-powered execution with Python convenience
|
|
31
|
+
- **Memory Efficient**: Zero-copy data sharing between nodes using Arc (18x performance improvement for large datasets)
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install dagex
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
No Rust toolchain required - prebuilt wheels are available for all major platforms.
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
### Basic Pipeline
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import dagex
|
|
47
|
+
|
|
48
|
+
def data_source(inputs, variant_params):
|
|
49
|
+
"""Generate initial data"""
|
|
50
|
+
return {"value": 42}
|
|
51
|
+
|
|
52
|
+
def multiply(inputs, variant_params):
|
|
53
|
+
"""Process the data"""
|
|
54
|
+
val = inputs.get("x", 0)
|
|
55
|
+
return {"doubled": val * 2}
|
|
56
|
+
|
|
57
|
+
# Create graph
|
|
58
|
+
graph = dagex.Graph()
|
|
59
|
+
|
|
60
|
+
# Add nodes
|
|
61
|
+
graph.add(
|
|
62
|
+
function=data_source,
|
|
63
|
+
label="DataSource",
|
|
64
|
+
inputs=None,
|
|
65
|
+
outputs=[("value", "data")]
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
graph.add(
|
|
69
|
+
function=multiply,
|
|
70
|
+
label="Multiply",
|
|
71
|
+
inputs=[("data", "x")],
|
|
72
|
+
outputs=[("doubled", "result")]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Build and execute
|
|
76
|
+
dag = graph.build()
|
|
77
|
+
context = dag.execute()
|
|
78
|
+
|
|
79
|
+
print(f"Result: {context['result']}") # Output: Result: 84
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Parallel Branching
|
|
83
|
+
|
|
84
|
+
Create multiple parallel processing paths:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
import dagex
|
|
88
|
+
import time
|
|
89
|
+
|
|
90
|
+
def source(inputs, variant_params):
|
|
91
|
+
return {"data": 100}
|
|
92
|
+
|
|
93
|
+
def branch_a(inputs, variant_params):
|
|
94
|
+
time.sleep(0.1) # Simulate work
|
|
95
|
+
return {"result_a": inputs["x"] * 2}
|
|
96
|
+
|
|
97
|
+
def branch_b(inputs, variant_params):
|
|
98
|
+
time.sleep(0.1) # Simulate work
|
|
99
|
+
return {"result_b": inputs["x"] * 3}
|
|
100
|
+
|
|
101
|
+
def branch_c(inputs, variant_params):
|
|
102
|
+
time.sleep(0.1) # Simulate work
|
|
103
|
+
return {"result_c": inputs["x"] + 50}
|
|
104
|
+
|
|
105
|
+
graph = dagex.Graph()
|
|
106
|
+
|
|
107
|
+
# Source node
|
|
108
|
+
graph.add(source, label="Source", outputs=[("data", "shared_data")])
|
|
109
|
+
|
|
110
|
+
# Create parallel branches
|
|
111
|
+
graph.branch()
|
|
112
|
+
graph.add(branch_a, label="BranchA", inputs=[("shared_data", "x")], outputs=[("result_a", "a")])
|
|
113
|
+
|
|
114
|
+
graph.branch()
|
|
115
|
+
graph.add(branch_b, label="BranchB", inputs=[("shared_data", "x")], outputs=[("result_b", "b")])
|
|
116
|
+
|
|
117
|
+
graph.branch()
|
|
118
|
+
graph.add(branch_c, label="BranchC", inputs=[("shared_data", "x")], outputs=[("result_c", "c")])
|
|
119
|
+
|
|
120
|
+
dag = graph.build()
|
|
121
|
+
result = dag.execute(parallel=True)
|
|
122
|
+
|
|
123
|
+
print(f"Branch A (100*2): {result['a']}") # 200
|
|
124
|
+
print(f"Branch B (100*3): {result['b']}") # 300
|
|
125
|
+
print(f"Branch C (100+50): {result['c']}") # 150
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Visualization
|
|
129
|
+
|
|
130
|
+
Generate Mermaid diagrams to visualize your pipeline:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
print(dag.to_mermaid())
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Output:
|
|
137
|
+
```mermaid
|
|
138
|
+
graph TD
|
|
139
|
+
0["Source"]
|
|
140
|
+
1["BranchA"]
|
|
141
|
+
2["BranchB"]
|
|
142
|
+
3["BranchC"]
|
|
143
|
+
0 -->|shared_data → x| 1
|
|
144
|
+
0 -->|shared_data → x| 2
|
|
145
|
+
0 -->|shared_data → x| 3
|
|
146
|
+
style 1 fill:#e1f5ff
|
|
147
|
+
style 2 fill:#e1f5ff
|
|
148
|
+
style 3 fill:#e1f5ff
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Working with NumPy Arrays
|
|
152
|
+
|
|
153
|
+
dagex seamlessly handles NumPy arrays and complex numbers:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
import dagex
|
|
157
|
+
import numpy as np
|
|
158
|
+
|
|
159
|
+
def generate_signal(inputs, variant_params):
|
|
160
|
+
"""Generate a complex signal"""
|
|
161
|
+
samples = 256
|
|
162
|
+
t = np.linspace(0, 1, samples)
|
|
163
|
+
signal = np.exp(2j * np.pi * 10 * t) # 10 Hz complex exponential
|
|
164
|
+
return {
|
|
165
|
+
"signal": signal, # numpy array passed directly
|
|
166
|
+
"num_samples": samples
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
def process_signal(inputs, variant_params):
|
|
170
|
+
"""Process with FFT"""
|
|
171
|
+
signal = np.array(inputs["signal"], dtype=complex)
|
|
172
|
+
spectrum = np.fft.fft(signal)
|
|
173
|
+
magnitude = np.abs(spectrum)
|
|
174
|
+
peak_freq = np.argmax(magnitude)
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
"spectrum": spectrum,
|
|
178
|
+
"peak_frequency": int(peak_freq)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
graph = dagex.Graph()
|
|
182
|
+
|
|
183
|
+
graph.add(
|
|
184
|
+
generate_signal,
|
|
185
|
+
label="GenerateSignal",
|
|
186
|
+
outputs=[("signal", "sig"), ("num_samples", "n")]
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
graph.add(
|
|
190
|
+
process_signal,
|
|
191
|
+
label="ProcessSignal",
|
|
192
|
+
inputs=[("sig", "signal")],
|
|
193
|
+
outputs=[("spectrum", "spec"), ("peak_frequency", "peak")]
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
dag = graph.build()
|
|
197
|
+
result = dag.execute()
|
|
198
|
+
|
|
199
|
+
print(f"Peak frequency bin: {result['peak']}")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Data Types
|
|
203
|
+
|
|
204
|
+
dagex supports any Python data type:
|
|
205
|
+
|
|
206
|
+
- **Primitives**: int, float, str, bool
|
|
207
|
+
- **Complex numbers**: Built-in `complex` and `numpy.complex128`
|
|
208
|
+
- **Collections**: list, dict, tuple
|
|
209
|
+
- **NumPy arrays**: All dtypes including complex arrays
|
|
210
|
+
- **Custom objects**: Any Python object can be passed through the graph
|
|
211
|
+
|
|
212
|
+
The framework doesn't impose type restrictions - your node functions determine what data flows through the pipeline.
|
|
213
|
+
|
|
214
|
+
## API Reference
|
|
215
|
+
|
|
216
|
+
### Graph
|
|
217
|
+
|
|
218
|
+
- `Graph()` - Create a new graph builder
|
|
219
|
+
- `graph.add(function, label=None, inputs=None, outputs=None)` - Add a node
|
|
220
|
+
- `function`: Callable with signature `(inputs: dict, variant_params: dict) -> dict`
|
|
221
|
+
- `label`: Optional node name (str)
|
|
222
|
+
- `inputs`: List of `(broadcast_var, node_input_var)` tuples
|
|
223
|
+
- `outputs`: List of `(node_output_var, broadcast_var)` tuples
|
|
224
|
+
- `graph.branch(subgraph=None)` - Create a parallel branch
|
|
225
|
+
- `graph.build()` - Build the DAG and return a `Dag` object
|
|
226
|
+
|
|
227
|
+
### Dag
|
|
228
|
+
|
|
229
|
+
- `dag.execute(parallel=False, max_threads=None)` - Execute the graph
|
|
230
|
+
- `parallel`: Enable parallel execution of independent nodes
|
|
231
|
+
- `max_threads`: Limit concurrent threads (None = unlimited)
|
|
232
|
+
- Returns: `dict` with all broadcast variables
|
|
233
|
+
- `dag.to_mermaid()` - Generate Mermaid diagram (str)
|
|
234
|
+
|
|
235
|
+
## Examples
|
|
236
|
+
|
|
237
|
+
The package includes several example scripts:
|
|
238
|
+
|
|
239
|
+
- **`python_demo.py`** - Basic pipeline construction
|
|
240
|
+
- **`python_comprehensive_demo.py`** - Multiple pipeline patterns
|
|
241
|
+
- **`python_parallel_demo.py`** - Parallel execution examples
|
|
242
|
+
- **`python_data_types_demo.py`** - Working with various data types
|
|
243
|
+
- **`python_radar_demo.py`** - Signal processing pipeline with NumPy
|
|
244
|
+
|
|
245
|
+
Find them in the [examples/py directory](https://github.com/briday1/dagex/tree/main/examples/py) on GitHub.
|
|
246
|
+
|
|
247
|
+
## Performance Notes
|
|
248
|
+
|
|
249
|
+
- The DAG executor is written in Rust for performance
|
|
250
|
+
- Python functions are called from Rust with proper GIL handling
|
|
251
|
+
- Parallel execution releases the GIL during graph traversal
|
|
252
|
+
- For CPU-bound Python code, use libraries like NumPy that release the GIL internally
|
|
253
|
+
- Best performance gains with parallel execution of I/O-bound or NumPy-based operations
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT License - see [LICENSE](https://github.com/briday1/dagex/blob/main/LICENSE) for details.
|
|
258
|
+
|
|
259
|
+
## Links
|
|
260
|
+
|
|
261
|
+
- **GitHub**: https://github.com/briday1/dagex
|
|
262
|
+
- **Documentation**: https://docs.rs/dagex
|
|
263
|
+
- **PyPI**: https://pypi.org/project/dagex
|
|
264
|
+
- **Crates.io**: https://crates.io/crates/dagex
|
|
265
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
dagex-2026.12.dist-info/METADATA,sha256=AcacyuweCKo-CKJTEjFuxO8qyLZ7NgRhL-aGFBo-XWs,7431
|
|
2
|
+
dagex-2026.12.dist-info/WHEEL,sha256=1yEYBbXmDwFEQO9oQqlTf7hZ9LUC4WwG_ImbCBAYGT8,108
|
|
3
|
+
dagex/__init__.py,sha256=uHbe0OdI2RMIcYORKDaI9JvEPcs3Iqxzy3Z5gpiCOiM,103
|
|
4
|
+
dagex/dagex.cpython-312-x86_64-linux-gnu.so,sha256=pb6-EacQgJi9ZFNG0EdtiYRSvkSCbRt8yCnfIfwyIiM,862744
|
|
5
|
+
dagex-2026.12.dist-info/RECORD,,
|