Skip to main content

mlflow-toolkit

CI PyPI Python License: MIT

Symmetric log_* / load_* helpers for MLflow artifacts.

MLflow lets you log a dict or a text file, but getting artifacts back always means download_artifacts() → temp dir → manual deserialization. And logging an in-memory DataFrame means saving it to disk first. mlflow-toolkit closes that gap:

worker.log_dataframe(run_id, df, 'data/train.parquet')          # object in ──┐
df = worker.load_dataframe(run_id, 'data/train.parquet')        # object out ─┘

One call in, one call out — the file format, the serialization backend and the temp-file juggling are handled for you, inferred from the artifact path suffix.

Highlights

  • 📤 Log objects straight from memory — DataFrames, dicts, numpy arrays, figures, arbitrary picklable objects. No manual temp files.
  • 📥 Load them back into memory — the missing half of the MLflow artifact API.
  • 🐼 pandas and polars — polars DataFrame / Series / LazyFrame are first-class citizens; choose the output library with backend='polars'.
  • 🧩 Extensible format registry — one register_format() call teaches log_file / load_file / load_files a new suffix.
  • 📦 Batch operations — load_files(run_id) pulls a whole run's artifacts (recursively) into a dict of live objects.
  • ⚡ Parallel by default — batch upload/download runs on a thread pool, which makes a real difference against remote artifact stores (S3, GCS, ...).
  • 🔢 Typed run params — get_run_params returns 100, not "100".
  • 🔌 Drop-in — MLflowWorker subclasses mlflow.MlflowClient: everything the client does, plus the helpers.

Installation

pip install mlflow-toolkit
# with dill/joblib pickle backends:
pip install "mlflow-toolkit[extras]"
# with polars support:
pip install "mlflow-toolkit[polars]"

Requires Python ≥ 3.10.

Quickstart

import mlflow
import numpy as np
import pandas as pd

from mlflow_toolkit import MLflowWorker

mlflow.set_tracking_uri('http://localhost:5000')   # or your MLflow server URI
mlflow.set_experiment('my-awesome-project')

worker = MLflowWorker()

df = pd.DataFrame(np.random.random((100, 4)), columns=['a', 'b', 'c', 'd'])
params = {'iterations': 100, 'depth': 5, 'cat_features': ['a', 'b']}

with mlflow.start_run() as run:
    run_id = run.info.run_id
    worker.log_dataframe(run_id, df, 'data/train.parquet')   # format from suffix
    worker.log_dict(run_id, params, 'params.yml')
    worker.log_as_pickle(run_id, params, 'params.pkl')
    worker.log_text(run_id, 'first experiment', 'notes.txt')

# ...days later, from anywhere:
df = worker.load_dataframe(run_id, 'data/train.parquet')
params = worker.load_dict(run_id, 'params.yml')
notes = worker.load_text_artifact(run_id, 'notes.txt')

All log_* methods take (run_id, data, artifact_path); all load_* methods take (run_id, artifact_path).

One entry point: log_file / load_file

Don't want to remember method names? log_file and load_file route any supported suffix through the format registry:

worker.log_file(run_id, df, 'data/train.parquet')       # dataframe → parquet
worker.log_file(run_id, df, 'data/train.csv', index=False)
worker.log_file(run_id, df, 'data/train.feather')       # arrow ipc
worker.log_file(run_id, params, 'config.json')          # dict → json (indented)
worker.log_file(run_id, model, 'model.joblib')          # object → joblib
worker.log_file(run_id, np.eye(3), 'matrix.npy')        # numpy array
worker.log_file(run_id, {'x': xs, 'y': ys}, 'arrays.npz')
worker.log_file(run_id, fig, 'plots/loss.png')          # matplotlib or plotly figure

train = worker.load_file(run_id, 'data/train.parquet')
config = worker.load_file(run_id, 'config.json')
model = worker.load_file(run_id, 'model.joblib')

Built-in formats:

Suffixes Data Backed by
.parquet, .parq DataFrame / Series pandas · polars · pyarrow
.csv DataFrame / Series pandas · polars
.feather DataFrame / Series pandas · polars (Arrow IPC)
.json, .yml, .yaml dict json · PyYAML
.pkl, .pickle, .dill, .joblib any object pickle · dill · joblib
.txt, .md, .html str —
.npy, .npz numpy array / dict of arrays numpy
.png, .jpg, .jpeg, .bmp, .svg matplotlib / plotly figure save-only

Register your own format

The registry is public — one call and your suffix behaves like a built-in one everywhere (log_file, load_file, load_files):

import pandas as pd
from mlflow_toolkit import register_format

register_format(
    'excel', ['.xlsx'],
    save=lambda df, path, **kw: df.to_excel(path, **kw),
    load=lambda path, **kw: pd.read_excel(path, **kw),
)

worker.log_file(run_id, report_df, 'reports/q3.xlsx')
report = worker.load_file(run_id, 'reports/q3.xlsx')

Save-only and load-only formats are fine — pass just one of save / load:

import onnx
from mlflow_toolkit import register_format

register_format(
    'onnx', ['.onnx'],
    save=lambda model, path, **kw: onnx.save(model, str(path)),
    load=lambda path, **kw: onnx.load(str(path)),
)

Replacing a built-in handler is explicit, so you can't shadow one by accident:

register_format('csv-semicolon', ['.csv'],
                save=lambda df, path, **kw: df.to_csv(path, sep=';', **kw),
                load=lambda path, **kw: pd.read_csv(path, sep=';', **kw),
                overwrite=True)

Introspection helpers: registered_suffixes() lists everything the registry knows, get_format_handler('some/file.xlsx') returns the matching handler (or None). Compressed names resolve too: data.csv.gz → the csv handler.

Polars

Polars objects are detected automatically on save — including LazyFrame, which is collected for you. Pick the library you want back with backend:

import polars as pl

pl_df = pl.DataFrame({'user': ['a', 'b'], 'score': [0.9, 0.7]})

worker.log_dataframe(run_id, pl_df, 'data/scores.parquet')            # polars in
worker.log_dataframe(run_id, pl_df.lazy().filter(pl.col('score') > 0.8),
                     'data/top.parquet')                              # lazy in

df = worker.load_dataframe(run_id, 'data/scores.parquet')                     # pandas out
pl_df = worker.load_dataframe(run_id, 'data/scores.parquet', backend='polars')  # polars out

Whole runs at once

# log several artifacts in one call
worker.log_files(run_id, {
    'data/train.parquet': train_df,
    'data/test.parquet': test_df,
    'params.yml': params,
    'features.txt': '\n'.join(features),
})

# ...and pull every artifact of the run back as a dict (recursive)
artifacts = worker.load_files(run_id)
# {'data/train.parquet': <DataFrame>, 'params.yml': {...}, 'features.txt': '...'}

# or just one directory
data = worker.load_files(run_id, 'data')

Both methods serialize and transfer files in parallel (a thread pool of up to 8 workers by default) — on S3-like artifact stores a batch of N files costs roughly one round-trip instead of N. Tune or disable it per call:

worker.log_files(run_id, artifacts, max_workers=16)  # more concurrency
worker.load_files(run_id, max_workers=1)             # strictly sequential

Files with no registered loader are skipped with a warning instead of failing the whole batch; an upload error cancels the remaining uploads and re-raises.

Typed run params

MLflow stores every param as a string. get_run_params gives you Python back:

worker.log_param(run_id, 'iterations', 100)
worker.log_param(run_id, 'lr', 0.05)
worker.log_param(run_id, 'cat_features', ['a', 'b'])

worker.get_run_params(run_id)
# {'iterations': 100, 'lr': 0.05, 'cat_features': ['a', 'b']}   ← not strings

Model registry

latest = worker.get_latest_model_version('churn-model')   # highest version or None
if latest is not None:
    print(latest.version, latest.source)

Development

git clone https://github.com/dubovikmaster/mlflow-toolkit.git
cd mlflow-toolkit
pip install -e ".[dev]"
pytest
ruff check .

Pull requests are welcome — main is protected, CI (tests on Python 3.10–3.13 + lint) must be green to merge.

License

MIT

Metadata

Release files for mlflow-toolkit 0.3.0

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

Source distribution (sdist)

Source distribution for mlflow-toolkit 0.3.0
File Size Uploaded
mlflow_toolkit-0.3.0.tar.gz 19.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mlflow-toolkit 0.3.0
File Interpreter ABI Platform
mlflow_toolkit-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 37.3 kB

Release files / mlflow_toolkit-0.3.0.tar.gz

Download URL mlflow_toolkit-0.3.0.tar.gz
Size 19.0 kB
Tags Source
SHA-256 checksum
How to use checksums
35f1d6485552ab3e10cdce9c1229c93cf123b1511150d738a6278fcca5fb984c
BLAKE2b-256 checksum
How to use checksums
2314b59fbc93cf5933e4599681fabee784f3d514e9dec6426d4115a4528043d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.

Transparency log

Release files / mlflow_toolkit-0.3.0-py3-none-any.whl

Download URL mlflow_toolkit-0.3.0-py3-none-any.whl
Size 18.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
60c63aafd7bc4b13e02840f14ee434d083df81dbd5f5bf99fdc4496ae18d5ce9
BLAKE2b-256 checksum
How to use checksums
6455af3f528b99f668b435737d5b9619231d2e75e474408b0fcbd1db1df3ae05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.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