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
from msup.base import to_json
from msup.cli import cli, CliArg

# NOTE: help shows up when `--help` is provided
def show(name: Annotated[str, CliArg(short="n", help="your name")], count: int = 1):
    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):
    print([name] * count)

# creates a CLI interface with commands 'show' and 'echo'
cli({
    show: "show the input arguments as JSON", 
    echo: "echo your name N times", 
})
# or for a single command CLI
# cli(show)

Run the above:

./examples/function_args.py echo --name 'bob' --count 2

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.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-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: msup-1.0.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.tar.gz
Algorithm Hash digest
SHA256 2c02e4ebb61195735a58c71f198bff29650f947e650db53ccd916c88c4e69028
MD5 8752a6b82c9173dc763e2a5269c0eb0c
BLAKE2b-256 f5397feb774a48e667f45873c4b939dd38809b85489cf4b006c08fc7259850e2

See more details on using hashes here.

File details

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

File metadata

  • Download URL: msup-1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.6 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-py3-none-any.whl
Algorithm Hash digest
SHA256 76dad66ccf85c29df5171c3224003c900f210faf991ebef9b249a2d1a2f6f395
MD5 bc6c8c71c92116015849b32eef052c8f
BLAKE2b-256 235bb4ac6befe20db08d0572d5162de6f129bd35049d898504d3e6765cd8d6c7

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