Micro Serialization Utilities for Python
[!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:
- Direct function arguments: examples/function_args.py
- Nested dataclass command: examples/nested.py
- Multiple CLI commands: examples/multicli.py
- Simple CLI: examples/simple.py
- Pydantic v2 CLI: examples/pydantic_basic.py
- Regular-class and PyTorch construction: examples/pt_basic.py
Features
- Typed conversion and serialization
- Primitives:
str,int,float, andbool. - 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.namestrings for loading and serialization. from_dict,to_dict,from_json, andto_jsonconvert typed values.to_kwargsprepares matching constructor settings, for example fortorch.optim.Adam.to_json(locals(), type_class=handler)serializes only the handler's declared arguments, using its annotations.
- Primitives:
- 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 withopt=Falsereceives 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=...),--ArgsJSON (inline or from a.jsonfile), then the default.
- JSON I/O
from_jsonreads strings,StringIO, other file-like streams, and paths.to_jsonreturns JSON or writes to file-like streams and.jsonpaths.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b5b86550ad750ea8d6ec5bda09302da2fed89334bc792a935aa6ec5f965166c
|
|
| MD5 |
f3104e5bd26a8485db44c7427b5269fd
|
|
| BLAKE2b-256 |
451a90291d8b6b7cf5ffffdd745c1367aee191d00edd5b75a7d415256c2f52a9
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
451f277a354f5ac61ebdf2c27789c0de3f226ad7f9ee071cd34313224602b8f2
|
|
| MD5 |
f2b2b9ebb173d2e5b47f0f3dde585c58
|
|
| BLAKE2b-256 |
060a5838b8730844c86542268d814306353c7f6370f041b73fae9b09682b277c
|