Skip to main content

Micro Serialization Utilities for Python

coverage

[!TIP] msup can be used as a Python-based alternative to just. See run.py.

from typing import Annotated as A, Callable as C
from msup.base import to_json
from msup.cli import cli, CliArg

def sir(name: str) -> str:
    return f"Sir {name}"

def miss(name: str) -> str:
    return f"Miss {name}"

def show(name: A[str, CliArg(short="n", help="your name")], count: int = 1, name_fn: C[[str], str] = miss):
    print(to_json(locals(), type_class=show))  # encode the function args to JSON

def echo(name: A[str, CliArg(short="n", help="your name")], count: int = 1, name_fn: C[[str], str] = sir):
    print([name_fn(name)] * count)

if __name__ == "__main__":
    # creates a CLI interface with sub-commands 'show' and 'echo'
    cli({
        show: "show the input arguments as JSON", 
        echo: "echo your name N times", 
    })

Run the above:

./examples/function_args.py echo --name 'Bob' --count 2 --name_fn examples.function_args.sir

or, provide JSON, e.g. ./examples/function_args.py echo --Args '{"name": "bob", "count": 2}'; --Args can point to a filepath too. See More Examples below or in the examples folder.


With no required dependencies and only 891 LOC (wc -l msup/*.py), this library lets you:

  • create CLIs from typed functions and nested dataclass or Pydantic v2 definitions
  • construct regular Python classes from their __init__ parameters and serialize or deserialize regular classes, dataclasses, and Pydantic v2 models as JSON and Python dictionaries

Yes, the small LOC is an intentional feature.

More Examples

Nested dataclasses produce nested options, e.g. --class.field (source):

from dataclasses import dataclass, field
from msup.cli import cli

@dataclass
class Optimizer:
    lr: float = 0.1

@dataclass
class Train:
    optimizer: Optimizer = field(default_factory=Optimizer)

def train(args: Train):
    print(args)

cli(train)
./examples/readme/train.py --optimizer.lr 0.01

Pydantic can also be used for cli (source):

from typing import Annotated
from pydantic import BaseModel, Field
from msup.cli import CliArg, cli

class Args(BaseModel):
    name: Annotated[str, CliArg(help="name to greet")] = "world"
    values: Annotated[list[int], CliArg(help="values to show", short="v")] = Field(default_factory=lambda: [1, 2])

def greet(args: Args):
    print(f"hello, {args.name}: {args.values}")

cli(greet)
./examples/pydantic_basic.py --name 'wow pydantic' --values 1 2

Python classes can also drive a CLI, and be constructed and serialized to/from a dict or JSON.

from msup.base import from_dict, to_dict, to_json, to_kwargs

class Optimizer:
    def __init__(self, lr: float, steps: int = 1):
        self.lr = lr
        self.steps = steps

optimizer = from_dict(Optimizer, {"lr": 0.1})
payload = to_dict(optimizer)
json_text = to_json(optimizer)
kwargs = to_kwargs(Optimizer, optimizer)  # to construct a copy via `Optimizer(**kwargs)`
print(json_text)
./examples/readme/regular_class.py

A final positional list captures all remaining tokens, including option-like values (source):

from typing import Annotated

from msup.cli import CliArg, cli

def forward(
    command: Annotated[str, CliArg(pos=True)],
    cwd: str = ".",
    retries: int = 1,
    # opt=False makes this final list consume every remaining token.
    remaining: Annotated[list[str] | None, CliArg(pos=True, opt=False)] = None,
):
    print(f"{command=}: {cwd=}: {retries=}: {remaining=}")

cli(forward)
./examples/remainder.py --cwd build --retries 2 run --target staging --verbose

Here's some more examples:

Features

  • Typed conversion and serialization
    • Primitives: str, int, float, and bool.
    • Other types: Any, optionals, and unambiguous unions. Non-optional unions are conversion-only, not CLI annotations.
    • Collections: lists, dictionaries, and tuples convert recursively. The CLI supports lists and variable-length tuples; fixed-length tuples are conversion-only.
    • Importable callables use module.name strings for loading and serialization.
    • from_dict, to_dict, from_json, and to_json convert typed values. to_kwargs prepares matching constructor settings, for example for torch.optim.Adam.
    • to_json(locals(), type_class=handler) serializes only the handler's declared arguments, using its annotations.
  • CLI commands
    • Use direct typed functions or one dataclass or Pydantic v2 model parameter. A mapping of functions creates named subcommands.
    • CliArg(pos=True) makes a value positional. A final positional list or variable-length tuple with opt=False receives all remaining arguments.
  • CLI configuration and metadata
    • Annotated[T, CliArg(...)] sets help text, short options, environment variables, positional and optional behavior, and hides secret defaults from help.
    • Nested dataclass and Pydantic v2 values accept dotted options such as optimizer.lr, inline JSON objects, and JSON file paths.
    • Missing values use defaults and default factories. Precedence is: explicit option, CliArg(env=...), --Args JSON (inline or from a .json file), then the default.
  • JSON I/O
    • from_json reads strings, StringIO, other file-like streams, and paths. to_json returns JSON or writes to file-like streams and .json paths.

Design Philosophy

  • minimal LOC
  • no dependencies by default; dependencies are opt-in (i.e. Pydantic is optional)
  • opinionated to reduce boilerplate

Install

uv pip install msup

or with a pyproject.toml

uv add msup

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

msup-1.0.2.tar.gz (11.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

msup-1.0.2-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file msup-1.0.2.tar.gz.

File metadata

  • Download URL: msup-1.0.2.tar.gz
  • Upload date:
  • Size: 11.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for msup-1.0.2.tar.gz
Algorithm Hash digest
SHA256 7b5b86550ad750ea8d6ec5bda09302da2fed89334bc792a935aa6ec5f965166c
MD5 f3104e5bd26a8485db44c7427b5269fd
BLAKE2b-256 451a90291d8b6b7cf5ffffdd745c1367aee191d00edd5b75a7d415256c2f52a9

See more details on using hashes here.

File details

Details for the file msup-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: msup-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for msup-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 451f277a354f5ac61ebdf2c27789c0de3f226ad7f9ee071cd34313224602b8f2
MD5 f2b2b9ebb173d2e5b47f0f3dde585c58
BLAKE2b-256 060a5838b8730844c86542268d814306353c7f6370f041b73fae9b09682b277c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page