Skip to content

metaist/castfit

Repository files navigation

castfit: basic type casting

Cuddles the Cat
Cuddles the Cat
"If it fits, I sits."

Build PyPI Supported Python Versions

Why?

castfit helps you convert things like command-line arguments (e.g., from docopt) and simple API responses into something more typed with low overhead.

Install

# modern (recommended)
uv add castfit

# classic
python -m pip install castfit

Alternatively, you can just download the single file and name it castfit.py.

Example: CLI-like Args

# Example: CLI-like args
from typing import Optional
from pathlib import Path
from castfit import castfit


class Args:
    host: str
    port: int
    timeout: Optional[float]
    log: Path


data = {
    "host": "localhost",
    "port": "8080",
    # "timeout": "5.0" # key can be missing
    "log": "app.log",
}

config = castfit(Args, data)
assert config.host == "localhost"
assert config.port == 8080
assert config.timeout is None
assert config.log == Path("app.log")

# if timeout was present:
data = {"host": "localhost", "port": "8080", "timeout": "5.0", "log": "app.log"}
config = castfit(Args, data)
assert config.host == "localhost"
assert config.port == 8080
assert config.timeout == 5.0
assert config.log == Path("app.log")

Example: Nested Types

# Example: nested types
from dataclasses import dataclass
from typing import Literal
from castfit import castfit


@dataclass
class Pet:
    name: str
    type: Literal["cat", "dog", "other"]
    age: int


@dataclass
class Owner:
    name: str
    pets: list[Pet]


owner_data = {
    "name": "Alice",
    "pets": [
        {"name": "Cuddles", "type": "cat", "age": "4"},
        {"name": "Buddy", "type": "dog", "age": "2.5"},  # age will be cast to int(2)
    ],
}

owner = castfit(Owner, owner_data)

assert owner.name == "Alice"
assert len(owner.pets) == 2
assert isinstance(owner.pets[0], Pet)
assert owner.pets[0].name == "Cuddles"
assert owner.pets[0].type == "cat"
assert owner.pets[0].age == 4
assert owner.pets[1].name == "Buddy"
assert owner.pets[1].age == 2  # Cast from "2.5" to int

Example: Custom Functions

# Example: adding a custom converter

from dataclasses import dataclass
import castfit


@dataclass
class LatLon:
    lat: float
    lon: float


@castfit.casts
def str_to_latlon(s: str) -> LatLon:
    lat, lon = map(float, s.split(","))
    return LatLon(lat, lon)


assert castfit.to_type("40.7,-74.0", LatLon) == LatLon(40.7, -74.0)

Other Projects

  • pydantic: comprehensive, but feels heavy.
  • cattrs: good simple cases, but has a complex set of converters.

License

MIT License

About

basic type casting

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Languages