maarg 0.2.0__tar.gz
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.
- maarg-0.2.0/LICENSE +21 -0
- maarg-0.2.0/PKG-INFO +290 -0
- maarg-0.2.0/README.md +255 -0
- maarg-0.2.0/pyproject.toml +48 -0
- maarg-0.2.0/setup.cfg +4 -0
- maarg-0.2.0/src/maarg/__init__.py +36 -0
- maarg-0.2.0/src/maarg/_capture.py +132 -0
- maarg-0.2.0/src/maarg/_convenience.py +104 -0
- maarg-0.2.0/src/maarg/_models.py +35 -0
- maarg-0.2.0/src/maarg/_query.py +101 -0
- maarg-0.2.0/src/maarg/_tracking.py +155 -0
- maarg-0.2.0/src/maarg/storage/__init__.py +2 -0
- maarg-0.2.0/src/maarg/storage/_base.py +52 -0
- maarg-0.2.0/src/maarg/storage/_sqlite.py +160 -0
- maarg-0.2.0/src/maarg.egg-info/PKG-INFO +290 -0
- maarg-0.2.0/src/maarg.egg-info/SOURCES.txt +23 -0
- maarg-0.2.0/src/maarg.egg-info/dependency_links.txt +1 -0
- maarg-0.2.0/src/maarg.egg-info/requires.txt +11 -0
- maarg-0.2.0/src/maarg.egg-info/top_level.txt +1 -0
- maarg-0.2.0/tests/test_capture.py +204 -0
- maarg-0.2.0/tests/test_convenience.py +88 -0
- maarg-0.2.0/tests/test_models.py +79 -0
- maarg-0.2.0/tests/test_query.py +171 -0
- maarg-0.2.0/tests/test_storage.py +151 -0
- maarg-0.2.0/tests/test_tracking.py +101 -0
maarg-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Moazzam Matin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
maarg-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: maarg
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Zero-instrumentation experiment tracking for Python — a decorator that auto-captures inputs and outputs, no logging calls required.
|
|
5
|
+
Author: Moazzam Matin
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Moazzam-Matin/maarg
|
|
8
|
+
Project-URL: Repository, https://github.com/Moazzam-Matin/maarg
|
|
9
|
+
Project-URL: Issues, https://github.com/Moazzam-Matin/maarg/issues
|
|
10
|
+
Keywords: experiment-tracking,mlops,machine-learning,decorator,introspection
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy; extra == "dev"
|
|
29
|
+
Requires-Dist: ruff; extra == "dev"
|
|
30
|
+
Requires-Dist: build; extra == "dev"
|
|
31
|
+
Requires-Dist: twine; extra == "dev"
|
|
32
|
+
Provides-Extra: plotting
|
|
33
|
+
Requires-Dist: matplotlib; extra == "plotting"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
[](https://github.com/Moazzam-Matin/maarg/actions)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
[](https://www.python.org/)
|
|
39
|
+
[](https://test.pypi.org/project/maarg/)
|
|
40
|
+
|
|
41
|
+
<p align="center">
|
|
42
|
+
<picture>
|
|
43
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/maarg_logo_dark.svg">
|
|
44
|
+
<img alt="maarg - Zero-Boilerplate Experiment Tracking"
|
|
45
|
+
src="docs/assets/maarg_logo.svg "width="320">
|
|
46
|
+
</picture>
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<h3 align="center">Experiment tracking with zero logging code.</h3>
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
Put <code>@track</code> on a function. Every execution—arguments,
|
|
53
|
+
returns, metrics, execution timing, and failures—is automatically saved
|
|
54
|
+
to local storage for instant querying.
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## How It Works
|
|
60
|
+
|
|
61
|
+
`maarg` sits transparently at function boundaries. It reads signature parameter defaults and runtime return payloads without requiring explicit parameter or metric logging statements inside your function logic.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
┌────────────────────────┐
|
|
66
|
+
│ @track decorated fn │ ──► (Intercepts arguments & execution context)
|
|
67
|
+
└───────────┬────────────┘
|
|
68
|
+
│
|
|
69
|
+
▼
|
|
70
|
+
┌────────────────────────┐
|
|
71
|
+
│ Function Execution │ ──► (Captures return dict / scalars / figures)
|
|
72
|
+
└───────────┬────────────┘
|
|
73
|
+
│
|
|
74
|
+
▼
|
|
75
|
+
┌────────────────────────┐
|
|
76
|
+
│ SQLite Persistence │ ──► Saves to .maarg/runs.db (or custom backend)
|
|
77
|
+
└───────────┬────────────┘
|
|
78
|
+
│
|
|
79
|
+
▼
|
|
80
|
+
┌────────────────────────┐
|
|
81
|
+
│ Query & Analysis API │ ──► maarg.get_runs() ──► top_n() / filter_runs()
|
|
82
|
+
└────────────────────────┘
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Quickstart
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from maarg import track, get_runs, top_n
|
|
91
|
+
|
|
92
|
+
@track(experiment="learning-rate-sweep")
|
|
93
|
+
def fit(learning_rate, epochs=100):
|
|
94
|
+
w = 0.0
|
|
95
|
+
for _ in range(epochs):
|
|
96
|
+
grad = sum(2 * (w * x - 3 * x) * x for x in range(1, 6)) / 5
|
|
97
|
+
w -= learning_rate * grad
|
|
98
|
+
return {"error": abs(w - 3)}
|
|
99
|
+
|
|
100
|
+
# Run experiments across hyperparameters
|
|
101
|
+
for lr in (0.001, 0.003, 0.01):
|
|
102
|
+
fit(learning_rate=lr)
|
|
103
|
+
|
|
104
|
+
# Query top 3 runs directly from default storage
|
|
105
|
+
for run in top_n(get_runs(), "error", n=3, higher_is_better=False):
|
|
106
|
+
print(f"lr={run.inputs['learning_rate']:<6} epochs={run.inputs['epochs']} error={run.metrics['error']:.2e}")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
lr=0.01 epochs=100 error=4.86e-11
|
|
111
|
+
lr=0.003 epochs=100 error=3.25e-03
|
|
112
|
+
lr=0.001 epochs=100 error=3.24e-01
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Project & Storage Structure
|
|
118
|
+
|
|
119
|
+
`maarg` enforces a clean public package API while automatically managing runtime tracking databases and artifact outputs.
|
|
120
|
+
|
|
121
|
+
### Repository Layout
|
|
122
|
+
```text
|
|
123
|
+
maarg/
|
|
124
|
+
├── .github/
|
|
125
|
+
│ └── workflows/
|
|
126
|
+
│ └── ci.yaml
|
|
127
|
+
├── docs/
|
|
128
|
+
├── src/
|
|
129
|
+
│ └── maarg/
|
|
130
|
+
│ ├── storage/ # Storage backends package
|
|
131
|
+
│ │ ├── __init__.py
|
|
132
|
+
│ │ ├── _base.py # StorageBackend base interface
|
|
133
|
+
│ │ └── _sqlite.py # SQLiteStorage implementation
|
|
134
|
+
│ ├── __init__.py # Public API exports (track, get_runs, top_n, etc.)
|
|
135
|
+
│ ├── _capture.py # Value parsing & scalar payload truncation
|
|
136
|
+
│ ├── _convenience.py # get_runs() wrapper & top-level defaults
|
|
137
|
+
│ ├── _models.py # Core Run and Storage schema dataclasses
|
|
138
|
+
│ ├── _query.py # Pure analytical query engine (top_n, filter_runs)
|
|
139
|
+
│ └── _tracking.py # @track decorator implementation
|
|
140
|
+
├── tests/ # Full test suite matching internal modules
|
|
141
|
+
│ ├── test_capture.py
|
|
142
|
+
│ ├── test_convenience.py
|
|
143
|
+
│ ├── test_models.py
|
|
144
|
+
│ ├── test_query.py
|
|
145
|
+
│ ├── test_storage.py
|
|
146
|
+
│ └── test_tracking.py
|
|
147
|
+
├── LICENSE
|
|
148
|
+
├── PLANNING.md
|
|
149
|
+
├── pyproject.toml
|
|
150
|
+
└── README.md
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Runtime Storage Directory (`.maarg/`)
|
|
154
|
+
When you execute tracked functions, `maarg` initializes a local directory relative to your working workspace:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
your_project/
|
|
158
|
+
├── .maarg/
|
|
159
|
+
│ ├── runs.db # Local SQLite database containing experiment runs
|
|
160
|
+
│ └── artifacts/ # Generated PNG plots & exported binary files
|
|
161
|
+
│ └── <run_id>/
|
|
162
|
+
│ └── figure_1.png
|
|
163
|
+
├── train.py
|
|
164
|
+
└── notebook.ipynb
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Installation
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pip install maarg
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Supports Python 3.9+ with zero required external server dependencies. To automatically capture Matplotlib plots into `.maarg/artifacts/`, install with plotting support:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
pip install "maarg[plotting]"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Querying Runs
|
|
184
|
+
|
|
185
|
+
Query functions operate as pure functions on collections of `Run` objects. You can fetch runs effortlessly using the top-level `get_runs()` helper or pass custom storage backends explicitly.
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from maarg import get_runs, filter_runs, top_n, best_run, compare
|
|
189
|
+
|
|
190
|
+
# Fetch runs from default local storage (.maarg/runs.db)
|
|
191
|
+
runs = get_runs()
|
|
192
|
+
|
|
193
|
+
# Optionally scope by experiment
|
|
194
|
+
exp_runs = get_runs(experiment="learning-rate-sweep")
|
|
195
|
+
|
|
196
|
+
# Identify top performers
|
|
197
|
+
best = best_run(runs, "error", higher_is_better=False)
|
|
198
|
+
top_3 = top_n(runs, "error", n=3, higher_is_better=False)
|
|
199
|
+
|
|
200
|
+
# Filter by input configuration
|
|
201
|
+
specific = filter_runs(runs, learning_rate=0.01)
|
|
202
|
+
|
|
203
|
+
# Tabulate run comparisons
|
|
204
|
+
comparison = compare(top_3)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
By default, failed runs are filtered out of ranking queries (`only_successful=True`). Pass `only_successful=False` to include failed executions.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## What Gets Recorded
|
|
212
|
+
|
|
213
|
+
| Field | Description |
|
|
214
|
+
| --- | --- |
|
|
215
|
+
| `run_id` | Unique UUID generated automatically per call |
|
|
216
|
+
| `timestamp` | ISO 8601 UTC timestamp of call execution |
|
|
217
|
+
| `function` | Name of the decorated function |
|
|
218
|
+
| `experiment` | Experiment grouping label (defaults to function name) |
|
|
219
|
+
| `inputs` | Captured function call parameters (including defaults) |
|
|
220
|
+
| `metrics` | Numeric dictionary outputs returned by the function |
|
|
221
|
+
| `artifacts` | Saved files/figures stored as `{name, path, type}` |
|
|
222
|
+
| `other` | Unclassified outputs, strings, booleans, or truncated `repr()` representations |
|
|
223
|
+
| `duration_sec` | Execution duration in seconds |
|
|
224
|
+
|
|
225
|
+
### Value Safety & Limits
|
|
226
|
+
- **Inputs:** Simple scalar values (numbers, strings, booleans) and collections with ≤ 20 elements or ≤ 1000 bytes are recorded. Large arrays, dataframes, or complex objects are automatically skipped to avoid database bloat.
|
|
227
|
+
- **Outputs:** Dictionary return values with numeric scalars become `metrics`. Returned Matplotlib figures are serialized to PNG artifacts inside `.maarg/artifacts/<run_id>/`.
|
|
228
|
+
- **Failures:** Exceptions are caught, recorded with `other["status"] = "failed"` along with the exception class and traceback message, and then re-raised unchanged.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Configuration
|
|
233
|
+
|
|
234
|
+
Pass optional controls directly to the `@track` decorator:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from maarg import track
|
|
238
|
+
from maarg.storage import SQLiteStorage
|
|
239
|
+
|
|
240
|
+
@track(
|
|
241
|
+
experiment="hyperparameter-sweep",
|
|
242
|
+
storage=SQLiteStorage("results/custom_experiment.db"),
|
|
243
|
+
artifacts_dir="results/artifacts"
|
|
244
|
+
)
|
|
245
|
+
def train(lr, batch_size):
|
|
246
|
+
...
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
| Option | Default | Description |
|
|
250
|
+
| --- | --- | --- |
|
|
251
|
+
| `experiment` | Function name | Label for grouping related runs |
|
|
252
|
+
| `storage` | SQLite at `.maarg/runs.db` | Target storage engine instance |
|
|
253
|
+
| `artifacts_dir` | `.maarg/artifacts` | Directory path for stored plots/files |
|
|
254
|
+
| `max_scalar_bytes` | `1000` | Max byte size allowed for individual scalar inputs |
|
|
255
|
+
| `max_collection_length` | `20` | Max items allowed in recorded input lists/dicts |
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Custom Storage Backends
|
|
260
|
+
|
|
261
|
+
You can define custom storage targets by subclassing `StorageBackend` and implementing `save`, `get_by_id`, `list_by_function`, `list_by_experiment`, and `list_all`:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
from maarg.storage import StorageBackend
|
|
265
|
+
|
|
266
|
+
class CustomStorage(StorageBackend):
|
|
267
|
+
# Implement persistence methods
|
|
268
|
+
...
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Roadmap
|
|
274
|
+
|
|
275
|
+
- Command-line interface (CLI) for browsing and inspecting runs directly in the terminal
|
|
276
|
+
- Event hooks triggered on run completion (e.g., Slack or webhook notifications)
|
|
277
|
+
- Web dashboard extension package
|
|
278
|
+
- Additional remote storage backends
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## About the Name
|
|
283
|
+
|
|
284
|
+
*maarg* (मार्ग) is Hindi for "path" or "route".
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## License
|
|
289
|
+
|
|
290
|
+
MIT — see [LICENSE](LICENSE).
|
maarg-0.2.0/README.md
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
[](https://github.com/Moazzam-Matin/maarg/actions)
|
|
2
|
+
[](LICENSE)
|
|
3
|
+
[](https://www.python.org/)
|
|
4
|
+
[](https://test.pypi.org/project/maarg/)
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
<picture>
|
|
8
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/maarg_logo_dark.svg">
|
|
9
|
+
<img alt="maarg - Zero-Boilerplate Experiment Tracking"
|
|
10
|
+
src="docs/assets/maarg_logo.svg "width="320">
|
|
11
|
+
</picture>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<h3 align="center">Experiment tracking with zero logging code.</h3>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
Put <code>@track</code> on a function. Every execution—arguments,
|
|
18
|
+
returns, metrics, execution timing, and failures—is automatically saved
|
|
19
|
+
to local storage for instant querying.
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## How It Works
|
|
25
|
+
|
|
26
|
+
`maarg` sits transparently at function boundaries. It reads signature parameter defaults and runtime return payloads without requiring explicit parameter or metric logging statements inside your function logic.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
┌────────────────────────┐
|
|
31
|
+
│ @track decorated fn │ ──► (Intercepts arguments & execution context)
|
|
32
|
+
└───────────┬────────────┘
|
|
33
|
+
│
|
|
34
|
+
▼
|
|
35
|
+
┌────────────────────────┐
|
|
36
|
+
│ Function Execution │ ──► (Captures return dict / scalars / figures)
|
|
37
|
+
└───────────┬────────────┘
|
|
38
|
+
│
|
|
39
|
+
▼
|
|
40
|
+
┌────────────────────────┐
|
|
41
|
+
│ SQLite Persistence │ ──► Saves to .maarg/runs.db (or custom backend)
|
|
42
|
+
└───────────┬────────────┘
|
|
43
|
+
│
|
|
44
|
+
▼
|
|
45
|
+
┌────────────────────────┐
|
|
46
|
+
│ Query & Analysis API │ ──► maarg.get_runs() ──► top_n() / filter_runs()
|
|
47
|
+
└────────────────────────┘
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Quickstart
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from maarg import track, get_runs, top_n
|
|
56
|
+
|
|
57
|
+
@track(experiment="learning-rate-sweep")
|
|
58
|
+
def fit(learning_rate, epochs=100):
|
|
59
|
+
w = 0.0
|
|
60
|
+
for _ in range(epochs):
|
|
61
|
+
grad = sum(2 * (w * x - 3 * x) * x for x in range(1, 6)) / 5
|
|
62
|
+
w -= learning_rate * grad
|
|
63
|
+
return {"error": abs(w - 3)}
|
|
64
|
+
|
|
65
|
+
# Run experiments across hyperparameters
|
|
66
|
+
for lr in (0.001, 0.003, 0.01):
|
|
67
|
+
fit(learning_rate=lr)
|
|
68
|
+
|
|
69
|
+
# Query top 3 runs directly from default storage
|
|
70
|
+
for run in top_n(get_runs(), "error", n=3, higher_is_better=False):
|
|
71
|
+
print(f"lr={run.inputs['learning_rate']:<6} epochs={run.inputs['epochs']} error={run.metrics['error']:.2e}")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
lr=0.01 epochs=100 error=4.86e-11
|
|
76
|
+
lr=0.003 epochs=100 error=3.25e-03
|
|
77
|
+
lr=0.001 epochs=100 error=3.24e-01
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Project & Storage Structure
|
|
83
|
+
|
|
84
|
+
`maarg` enforces a clean public package API while automatically managing runtime tracking databases and artifact outputs.
|
|
85
|
+
|
|
86
|
+
### Repository Layout
|
|
87
|
+
```text
|
|
88
|
+
maarg/
|
|
89
|
+
├── .github/
|
|
90
|
+
│ └── workflows/
|
|
91
|
+
│ └── ci.yaml
|
|
92
|
+
├── docs/
|
|
93
|
+
├── src/
|
|
94
|
+
│ └── maarg/
|
|
95
|
+
│ ├── storage/ # Storage backends package
|
|
96
|
+
│ │ ├── __init__.py
|
|
97
|
+
│ │ ├── _base.py # StorageBackend base interface
|
|
98
|
+
│ │ └── _sqlite.py # SQLiteStorage implementation
|
|
99
|
+
│ ├── __init__.py # Public API exports (track, get_runs, top_n, etc.)
|
|
100
|
+
│ ├── _capture.py # Value parsing & scalar payload truncation
|
|
101
|
+
│ ├── _convenience.py # get_runs() wrapper & top-level defaults
|
|
102
|
+
│ ├── _models.py # Core Run and Storage schema dataclasses
|
|
103
|
+
│ ├── _query.py # Pure analytical query engine (top_n, filter_runs)
|
|
104
|
+
│ └── _tracking.py # @track decorator implementation
|
|
105
|
+
├── tests/ # Full test suite matching internal modules
|
|
106
|
+
│ ├── test_capture.py
|
|
107
|
+
│ ├── test_convenience.py
|
|
108
|
+
│ ├── test_models.py
|
|
109
|
+
│ ├── test_query.py
|
|
110
|
+
│ ├── test_storage.py
|
|
111
|
+
│ └── test_tracking.py
|
|
112
|
+
├── LICENSE
|
|
113
|
+
├── PLANNING.md
|
|
114
|
+
├── pyproject.toml
|
|
115
|
+
└── README.md
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Runtime Storage Directory (`.maarg/`)
|
|
119
|
+
When you execute tracked functions, `maarg` initializes a local directory relative to your working workspace:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
your_project/
|
|
123
|
+
├── .maarg/
|
|
124
|
+
│ ├── runs.db # Local SQLite database containing experiment runs
|
|
125
|
+
│ └── artifacts/ # Generated PNG plots & exported binary files
|
|
126
|
+
│ └── <run_id>/
|
|
127
|
+
│ └── figure_1.png
|
|
128
|
+
├── train.py
|
|
129
|
+
└── notebook.ipynb
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Installation
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pip install maarg
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Supports Python 3.9+ with zero required external server dependencies. To automatically capture Matplotlib plots into `.maarg/artifacts/`, install with plotting support:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pip install "maarg[plotting]"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Querying Runs
|
|
149
|
+
|
|
150
|
+
Query functions operate as pure functions on collections of `Run` objects. You can fetch runs effortlessly using the top-level `get_runs()` helper or pass custom storage backends explicitly.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from maarg import get_runs, filter_runs, top_n, best_run, compare
|
|
154
|
+
|
|
155
|
+
# Fetch runs from default local storage (.maarg/runs.db)
|
|
156
|
+
runs = get_runs()
|
|
157
|
+
|
|
158
|
+
# Optionally scope by experiment
|
|
159
|
+
exp_runs = get_runs(experiment="learning-rate-sweep")
|
|
160
|
+
|
|
161
|
+
# Identify top performers
|
|
162
|
+
best = best_run(runs, "error", higher_is_better=False)
|
|
163
|
+
top_3 = top_n(runs, "error", n=3, higher_is_better=False)
|
|
164
|
+
|
|
165
|
+
# Filter by input configuration
|
|
166
|
+
specific = filter_runs(runs, learning_rate=0.01)
|
|
167
|
+
|
|
168
|
+
# Tabulate run comparisons
|
|
169
|
+
comparison = compare(top_3)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
By default, failed runs are filtered out of ranking queries (`only_successful=True`). Pass `only_successful=False` to include failed executions.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## What Gets Recorded
|
|
177
|
+
|
|
178
|
+
| Field | Description |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `run_id` | Unique UUID generated automatically per call |
|
|
181
|
+
| `timestamp` | ISO 8601 UTC timestamp of call execution |
|
|
182
|
+
| `function` | Name of the decorated function |
|
|
183
|
+
| `experiment` | Experiment grouping label (defaults to function name) |
|
|
184
|
+
| `inputs` | Captured function call parameters (including defaults) |
|
|
185
|
+
| `metrics` | Numeric dictionary outputs returned by the function |
|
|
186
|
+
| `artifacts` | Saved files/figures stored as `{name, path, type}` |
|
|
187
|
+
| `other` | Unclassified outputs, strings, booleans, or truncated `repr()` representations |
|
|
188
|
+
| `duration_sec` | Execution duration in seconds |
|
|
189
|
+
|
|
190
|
+
### Value Safety & Limits
|
|
191
|
+
- **Inputs:** Simple scalar values (numbers, strings, booleans) and collections with ≤ 20 elements or ≤ 1000 bytes are recorded. Large arrays, dataframes, or complex objects are automatically skipped to avoid database bloat.
|
|
192
|
+
- **Outputs:** Dictionary return values with numeric scalars become `metrics`. Returned Matplotlib figures are serialized to PNG artifacts inside `.maarg/artifacts/<run_id>/`.
|
|
193
|
+
- **Failures:** Exceptions are caught, recorded with `other["status"] = "failed"` along with the exception class and traceback message, and then re-raised unchanged.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Configuration
|
|
198
|
+
|
|
199
|
+
Pass optional controls directly to the `@track` decorator:
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from maarg import track
|
|
203
|
+
from maarg.storage import SQLiteStorage
|
|
204
|
+
|
|
205
|
+
@track(
|
|
206
|
+
experiment="hyperparameter-sweep",
|
|
207
|
+
storage=SQLiteStorage("results/custom_experiment.db"),
|
|
208
|
+
artifacts_dir="results/artifacts"
|
|
209
|
+
)
|
|
210
|
+
def train(lr, batch_size):
|
|
211
|
+
...
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
| Option | Default | Description |
|
|
215
|
+
| --- | --- | --- |
|
|
216
|
+
| `experiment` | Function name | Label for grouping related runs |
|
|
217
|
+
| `storage` | SQLite at `.maarg/runs.db` | Target storage engine instance |
|
|
218
|
+
| `artifacts_dir` | `.maarg/artifacts` | Directory path for stored plots/files |
|
|
219
|
+
| `max_scalar_bytes` | `1000` | Max byte size allowed for individual scalar inputs |
|
|
220
|
+
| `max_collection_length` | `20` | Max items allowed in recorded input lists/dicts |
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Custom Storage Backends
|
|
225
|
+
|
|
226
|
+
You can define custom storage targets by subclassing `StorageBackend` and implementing `save`, `get_by_id`, `list_by_function`, `list_by_experiment`, and `list_all`:
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from maarg.storage import StorageBackend
|
|
230
|
+
|
|
231
|
+
class CustomStorage(StorageBackend):
|
|
232
|
+
# Implement persistence methods
|
|
233
|
+
...
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Roadmap
|
|
239
|
+
|
|
240
|
+
- Command-line interface (CLI) for browsing and inspecting runs directly in the terminal
|
|
241
|
+
- Event hooks triggered on run completion (e.g., Slack or webhook notifications)
|
|
242
|
+
- Web dashboard extension package
|
|
243
|
+
- Additional remote storage backends
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## About the Name
|
|
248
|
+
|
|
249
|
+
*maarg* (मार्ग) is Hindi for "path" or "route".
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## License
|
|
254
|
+
|
|
255
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "maarg"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Zero-instrumentation experiment tracking for Python — a decorator that auto-captures inputs and outputs, no logging calls required."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Moazzam Matin"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["experiment-tracking", "mlops", "machine-learning", "decorator", "introspection"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
28
|
+
]
|
|
29
|
+
dependencies = []
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = ["pytest>=7.0", "pytest-cov", "mypy", "ruff", "build", "twine"]
|
|
33
|
+
plotting = ["matplotlib"]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/Moazzam-Matin/maarg"
|
|
37
|
+
Repository = "https://github.com/Moazzam-Matin/maarg"
|
|
38
|
+
Issues = "https://github.com/Moazzam-Matin/maarg/issues"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
where = ["src"]
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
testpaths = ["tests"]
|
|
45
|
+
|
|
46
|
+
[[tool.mypy.overrides]]
|
|
47
|
+
module = "matplotlib.*"
|
|
48
|
+
ignore_missing_imports = true
|
maarg-0.2.0/setup.cfg
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
maarg — zero-instrumentation experiment tracking for Python.
|
|
3
|
+
|
|
4
|
+
from maarg import track
|
|
5
|
+
|
|
6
|
+
@track
|
|
7
|
+
def train_model(learning_rate, epochs):
|
|
8
|
+
return {"accuracy": 0.95}
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
__version__ = version("maarg")
|
|
15
|
+
except PackageNotFoundError:
|
|
16
|
+
# Fallback for uninstalled local development mode
|
|
17
|
+
__version__ = "0.2.0"
|
|
18
|
+
|
|
19
|
+
from maarg._convenience import best_run, filter_runs, get_runs, top_n
|
|
20
|
+
from maarg._models import Run
|
|
21
|
+
from maarg._query import compare
|
|
22
|
+
from maarg._tracking import track
|
|
23
|
+
from maarg.storage._base import StorageBackend as StorageBackend
|
|
24
|
+
from maarg.storage._sqlite import SQLiteStorage as SQLiteStorage
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"Run",
|
|
28
|
+
"SQLiteStorage",
|
|
29
|
+
"StorageBackend",
|
|
30
|
+
"best_run",
|
|
31
|
+
"compare",
|
|
32
|
+
"filter_runs",
|
|
33
|
+
"get_runs",
|
|
34
|
+
"top_n",
|
|
35
|
+
"track",
|
|
36
|
+
]
|