cotyper 0.8.0
Wrapper around Typer to create command line interfaces for Pydantic models
License: MIT
Requires Python: >=3.10

# CoTyper

[![CI Status](https://gitlab.opencode.de/lgln/cotyper/badges/master/pipeline.svg)](https://gitlab.opencode.de/lgln/cotyper/-/pipelines)
[![Coverage](https://gitlab.opencode.de/lgln/cotyper/badges/master/coverage.svg)](https://gitlab.opencode.de/lgln/cotyper/-/commits/master)
[![PyPI](https://img.shields.io/pypi/v/cotyper?label=PyPI%20version)](https://pypi.org/project/cotyper/)
[![Downloads](https://img.shields.io/pypi/dm/cotyper)](https://pypi.org/project/cotyper/)
[![Release](https://img.shields.io/github/release-date/lgln/cotyper)](https://pypi.org/project/cotyper/)

Inspired by [Typer](https://github.com/tiangolo/typer)
and [Pydantic](https://github.com/pydantic/pydantic).
**Co**Typer since you add a lot of _co_ in category theory.

CoTyper is a wrapper around Typer but with support for (nested) pydantic models as
function arguments.

❗ Note this project is in early development

## Install
Install the package via `pip`:

```shell
pip install cotyper
```

Or install the package via `uv`:
```shell
uv add cotyper
```

### Build from Source
Clone the repository and build the package as wheel file

```shell
git clone https://gitlab.opencode.de/lgln/cotyper
cd cotyper
python -m build --wheel # or pip install .
```

## 🧑‍💻 Examples
For the examples it is recommended to use the `uv` command line tool, but feel free to
build the environment with `pip` or `poetry` as well.

```python
import datetime

from pydantic import BaseModel

from cotyper import App, unfold_cls

app = App()


class MetaData(BaseModel):
    date: datetime.datetime = "2023-10-01T00:00:00"


class Config(BaseModel):
    user_name: str
    url: str
    meta: MetaData = MetaData()

    
class Foo(BaseModel):
    bar: str = "baz"


@app.struct_command("example")
@unfold_cls(Config) # this will unfold the Config model into command line options, hence, exposing the fields of the model itself
def example_command(config: Config, foo: Foo = Foo()):
    """
    Example command that takes a nested pydantic model as argument.

    Args:
        config (Config): Configuration model with user_name, url, and meta data.
        foo (Foo): Another model with a bar attribute.
    """
    print(f"User: {config.user_name}, URL: {config.url}, Meta Date: {config.meta.date}")
    print(f"Foo Bar: {foo.bar}")


if __name__ == "__main__":
    app()
```

And requesting help will show the nested models as options:

```shell
uv run examples/readme.py --help
                                                                               
Usage: readme.py [OPTIONS]                                                                           
                                                                                                      
╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────╮
│ *  --url                       TEXT  [default: None] [required]                                    │
│    --install-completion              Install completion for the current shell.                     │
│    --show-completion                 Show completion for the current shell, to copy it or          │
│                                      customize the installation.                                   │
│    --help                            Show this message and exit.                                   │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ User ─────────────────────────────────────────────────────────────────────────────────────────────╮
│ *  --user-name        TEXT  [default: None] [required]                                             │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Meta ─────────────────────────────────────────────────────────────────────────────────────────────╮
│ --meta-date        [%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d    [default: 2023-10-01 00:00:00]          │
│                    %H:%M:%S]                                                                       │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Foo ──────────────────────────────────────────────────────────────────────────────────────────────╮
│ --foo-bar        TEXT  [default: baz]                                                              │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯```
```

🗒️ Note, that the `@unfold_cls(Config)` decorator is used to unfold the `Config` model into
the fields of the model directly.


And running the command with the toy information provides

```shell
uv run examples/readme.py --url "pydantic.dev" --user-name "Monty Python"
User: Monty Python, URL: pydantic.dev, Meta Date: 2023-10-01 00:00:00
Foo Bar: baz
```

## Extensive Examples
See `examples/` for more examples. For example

```shell
uv run examples/extensive.py --help
```

## 🧑‍🔬 Tests
Run
```shell
uv run pytest
```

## 📋 ToDo
-[ ] documentation 

## 🐍 Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.

## 🗝️ License
MIT License