Skip to main content

Micro Serialization Utilities for Python

coverage

[!TIP] msup can be used as a just replacement. See just.py.

from typing import Annotated, Callable
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: Annotated[str, CliArg(short="n", help="your name")], count: int = 1, name_fn: Callable[[str], str] = miss):
    print(to_json(locals(), type_class=show))  # encode the function args to JSON

def echo(name: Annotated[str, CliArg(short="n", help="your name")], count: int = 1, name_fn: Callable[[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

A Pydantic v2 model provides typed CLI options (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 integration --values 1 2

Optimizer is a regular Python class that can 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.1.tar.gz (11.3 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.1-py3-none-any.whl (12.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: msup-1.0.1.tar.gz
  • Upload date:
  • Size: 11.3 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.1.tar.gz
Algorithm Hash digest
SHA256 0a4628bb3bd8efc802de49bcbeebc86038cf094673598c519fe6c83cecef89c3
MD5 f83c70c133731360be8fd242a246e36e
BLAKE2b-256 14b70f266c0e9f9ca60a15b9be0034a66774fc8597bf04e4d8e8743facd0ab40

See more details on using hashes here.

File details

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

File metadata

  • Download URL: msup-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 12.7 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4dd2d416233bf63662c34fd7b116b639bbc9bce14ca095b36b196f8c9215664f
MD5 860ddf2d0b3308163036c36540b04578
BLAKE2b-256 5ea2714aa8aeb423cd2b18fe635f9958688710cde406a4bb8107566f643b41d6

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