Skip to main content

maarg

CI License: MIT Python 3.9+ PyPI version

maarg - Zero-Boilerplate Experiment Tracking

Experiment tracking with zero logging code.

Put @track on a function. Every execution—arguments, returns, metrics, execution timing, and failures—is automatically saved to local storage for instant querying.


How It Works

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.

  ┌────────────────────────┐
  │  @track decorated fn   │  ──► (Intercepts arguments & execution context)
  └───────────┬────────────┘
              │
              ▼
  ┌────────────────────────┐
  │   Function Execution   │  ──► (Captures return dict / scalars / figures)
  └───────────┬────────────┘
              │
              ▼
  ┌────────────────────────┐
  │   SQLite Persistence   │  ──► Saves to .maarg/runs.db (or custom backend)
  └───────────┬────────────┘
              │
              ▼
  ┌────────────────────────┐
  │  Query & Analysis API  │  ──► maarg.get_runs() ──► top_n() / filter_runs()
  └────────────────────────┘

Quickstart

from maarg import track, get_runs, top_n

@track(experiment="learning-rate-sweep")
def fit(learning_rate, epochs=100):
    w = 0.0
    for _ in range(epochs):
        grad = sum(2 * (w * x - 3 * x) * x for x in range(1, 6)) / 5
        w -= learning_rate * grad
    return {"error": abs(w - 3)}

# Run experiments across hyperparameters
for lr in (0.001, 0.003, 0.01):
    fit(learning_rate=lr)

# Query top 3 runs directly from default storage
for run in top_n(get_runs(), "error", n=3, higher_is_better=False):
    print(f"lr={run.inputs['learning_rate']:<6} epochs={run.inputs['epochs']}  error={run.metrics['error']:.2e}")
lr=0.01   epochs=100  error=4.86e-11
lr=0.003  epochs=100  error=3.25e-03
lr=0.001  epochs=100  error=3.24e-01

Project & Storage Structure

maarg enforces a clean public package API while automatically managing runtime tracking databases and artifact outputs.

Repository Layout

maarg/
├── .github/
│   └── workflows/
│       └── ci.yaml
├── docs/
├── src/
│   └── maarg/
│       ├── storage/             # Storage backends package
│       │   ├── __init__.py
│       │   ├── _base.py         # StorageBackend base interface
│       │   └── _sqlite.py       # SQLiteStorage implementation
│       ├── __init__.py          # Public API exports (track, get_runs, top_n, etc.)
│       ├── _capture.py          # Value parsing & scalar payload truncation
│       ├── _convenience.py      # get_runs() wrapper & top-level defaults
│       ├── _models.py           # Core Run and Storage schema dataclasses
│       ├── _query.py            # Pure analytical query engine (top_n, filter_runs)
│       └── _tracking.py         # @track decorator implementation
├── tests/                       # Full test suite matching internal modules
│   ├── test_capture.py
│   ├── test_convenience.py
│   ├── test_models.py
│   ├── test_query.py
│   ├── test_storage.py
│   └── test_tracking.py
├── LICENSE
├── PLANNING.md
├── pyproject.toml
└── README.md

Runtime Storage Directory (.maarg/)

When you execute tracked functions, maarg initializes a local directory relative to your working workspace:

your_project/
├── .maarg/
│   ├── runs.db                  # Local SQLite database containing experiment runs
│   └── artifacts/               # Generated PNG plots & exported binary files
│       └── <run_id>/
│           └── figure_1.png
├── train.py
└── notebook.ipynb

Installation

pip install maarg

Supports Python 3.9+ with zero required external server dependencies. To automatically capture Matplotlib plots into .maarg/artifacts/, install with plotting support:

pip install "maarg[plotting]"

Querying Runs

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.

from maarg import get_runs, filter_runs, top_n, best_run, compare

# Fetch runs from default local storage (.maarg/runs.db)
runs = get_runs()

# Optionally scope by experiment
exp_runs = get_runs(experiment="learning-rate-sweep")

# Identify top performers
best = best_run(runs, "error", higher_is_better=False)
top_3 = top_n(runs, "error", n=3, higher_is_better=False)

# Filter by input configuration
specific = filter_runs(runs, learning_rate=0.01)

# Tabulate run comparisons
comparison = compare(top_3)

By default, failed runs are filtered out of ranking queries (only_successful=True). Pass only_successful=False to include failed executions.


What Gets Recorded

Field Description
run_id Unique UUID generated automatically per call
timestamp ISO 8601 UTC timestamp of call execution
function Name of the decorated function
experiment Experiment grouping label (defaults to function name)
inputs Captured function call parameters (including defaults)
metrics Numeric dictionary outputs returned by the function
artifacts Saved files/figures stored as {name, path, type}
other Unclassified outputs, strings, booleans, or truncated repr() representations
duration_sec Execution duration in seconds

Value Safety & Limits

  • 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.
  • Outputs: Dictionary return values with numeric scalars become metrics. Returned Matplotlib figures are serialized to PNG artifacts inside .maarg/artifacts/<run_id>/.
  • Failures: Exceptions are caught, recorded with other["status"] = "failed" along with the exception class and traceback message, and then re-raised unchanged.

Configuration

Pass optional controls directly to the @track decorator:

from maarg import track
from maarg.storage import SQLiteStorage

@track(
    experiment="hyperparameter-sweep",
    storage=SQLiteStorage("results/custom_experiment.db"),
    artifacts_dir="results/artifacts"
)
def train(lr, batch_size):
    ...
Option Default Description
experiment Function name Label for grouping related runs
storage SQLite at .maarg/runs.db Target storage engine instance
artifacts_dir .maarg/artifacts Directory path for stored plots/files
max_scalar_bytes 1000 Max byte size allowed for individual scalar inputs
max_collection_length 20 Max items allowed in recorded input lists/dicts

Custom Storage Backends

You can define custom storage targets by subclassing StorageBackend and implementing save, get_by_id, list_by_function, list_by_experiment, and list_all:

from maarg.storage import StorageBackend

class CustomStorage(StorageBackend):
    # Implement persistence methods
    ...

Roadmap

  • Command-line interface (CLI) for browsing and inspecting runs directly in the terminal
  • Event hooks triggered on run completion (e.g., Slack or webhook notifications)
  • Web dashboard extension package
  • Additional remote storage backends

About the Name

maarg (मार्ग) is Hindi for "path" or "route".


License

MIT — see LICENSE.

Metadata

Release files for maarg 0.2.0.post1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maarg 0.2.0.post1
File Size Uploaded
maarg-0.2.0.post1.tar.gz 22.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for maarg 0.2.0.post1
File Interpreter ABI Platform
maarg-0.2.0.post1-py3-none-any.whl Python 3 none any Details

Total release size: 38.4 kB

Release files / maarg-0.2.0.post1.tar.gz

Download URL maarg-0.2.0.post1.tar.gz
Size 22.6 kB
Tags Source
SHA-256 checksum
How to use checksums
dc32e6c8b4a201b2e67074b8cab341a61665863315ee8cdb1c9dfe0e5038dba1
BLAKE2b-256 checksum
How to use checksums
7f1c0094d2c3f241358a9dba3a4eac41d323bbb2d22ab68ab6b87444ee67fe75
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / maarg-0.2.0.post1-py3-none-any.whl

Download URL maarg-0.2.0.post1-py3-none-any.whl
Size 15.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a8f87682b36219f2cb11ebf820d0ff2ab1309334cda363520cf222e8370a466b
BLAKE2b-256 checksum
How to use checksums
ecf5329ccc84d9bc03175d2942889f27ba88521c4fed3b3ac903b760c33eefed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.2.0.post1 This release

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page