clonf


Nameclonf JSON
Version 0.3.0 PyPI version JSON
download
home_pageNone
SummaryDeclaratively connect cli and config definition using pydantic
upload_time2025-10-19 16:59:01
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT
keywords cli click pydantic pydantic-settings declarative config
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # clonf

[![PyPI version](https://badge.fury.io/py/clonf.svg)](https://badge.fury.io/py/clonf)
[![GitHub license](https://img.shields.io/github/license/jvllmr/clonf)](https://github.com/jvllmr/clonf/blob/main/LICENSE)
![PyPI - Downloads](https://img.shields.io/pypi/dd/clonf)

Declaratively connect cli and config definition using pydantic.

## Why another?

There are a lot of tools out there which try to bring cli libraries and pydantic together, but they all seem to forget that more sophisticated applications need to be controlled via configuration files as well. `clonf` tries to solve this problem by focusing on compatibility with `pydantic-settings` and its configuration sources. This allows having a single source of truth for cli and configuration definition. `clonf` uses composition rather than inheritance and utilizes logic from `pydantic` and `pydantic-settings` to achieve this with as much simplicity and flexibility as possible. First versions focus on integration with click, but other cli libraries might receive interfaces as well in the future.

### Key differences to other pydantic x cli libraries

- CLI behavior is opt-in.
- As much as possible is done via annotations. Combined with pydantic best practices, this encourages creating a single source of truth inside your codebase.

## Installation

clonf can be installed via pip or your favorite python package manager with different extras:

```shell
pip install clonf[all,click,settings]
```

## Creating a CLI

### click

#### Quickstart

```python
from pydantic import BaseModel
from clonf import clonf_click, CliArgument, CliOption
from typing import Annotated
import click


class Arguments(BaseModel):
    name: Annotated[str, CliArgument()]


class Options(BaseModel):
    greeting: Annotated[str, CliOption()] = "Hello"


@click.command
@clonf_click
def cli(arguments: Arguments, options: Options) -> None:
    click.echo(f"{options.greeting} {arguments.name}")


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

#### Using click types

Similar to `pydanclick`, the following types will be converted automatically:
| Python type | Click type |
| :--------------------------------------- | :------------------- |
| `bool` | `click.BOOL` |
| `str` | `click.STRING` |
| `int` | `click.INT` |
| `float` | `click.FLOAT` |
| `Annotated[int, Field(lt=..., ge=...)` | `click.IntRange()` |
| `Annotated[float, Field(lt=..., ge=...)` | `click.FloatRange()` |
| `pathlib.Path` | `click.Path()` |
| `uuid.UUID` | `click.UUID` |
| `datetime.datetime`, `datetime.date` | `click.DateTime()` |
| `Literal` | `click.Choice` |

Additionally, custom click types can be passed via annotations to have finer control over the resulting click type:

```python
from pydantic import BaseModel
from typing import Annotated
from clonf import CliArgument
import pathlib
import click

class Config(BaseModel):
    file_path: Annotated[pathlib.Path, CliArgument(), click.Path(exists=True)]
```

## Contributing

This project uses PDM as a package manager and pre-commit for linting before commits.

Read more about the tools and how to use them:

- [`PDM`](https://pdm-project.org/en/latest)
- [`pre-commit`](https://pre-commit.com/)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "clonf",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "cli, click, pydantic, pydantic-settings, declarative, config",
    "author": null,
    "author_email": "Jan Vollmer <jan@vllmr.dev>",
    "download_url": "https://files.pythonhosted.org/packages/d2/4c/bd278778a03f488e6a262afb9908e6711b5f27432422e49bdbe05799cd95/clonf-0.3.0.tar.gz",
    "platform": null,
    "description": "# clonf\n\n[![PyPI version](https://badge.fury.io/py/clonf.svg)](https://badge.fury.io/py/clonf)\n[![GitHub license](https://img.shields.io/github/license/jvllmr/clonf)](https://github.com/jvllmr/clonf/blob/main/LICENSE)\n![PyPI - Downloads](https://img.shields.io/pypi/dd/clonf)\n\nDeclaratively connect cli and config definition using pydantic.\n\n## Why another?\n\nThere are a lot of tools out there which try to bring cli libraries and pydantic together, but they all seem to forget that more sophisticated applications need to be controlled via configuration files as well. `clonf` tries to solve this problem by focusing on compatibility with `pydantic-settings` and its configuration sources. This allows having a single source of truth for cli and configuration definition. `clonf` uses composition rather than inheritance and utilizes logic from `pydantic` and `pydantic-settings` to achieve this with as much simplicity and flexibility as possible. First versions focus on integration with click, but other cli libraries might receive interfaces as well in the future.\n\n### Key differences to other pydantic x cli libraries\n\n- CLI behavior is opt-in.\n- As much as possible is done via annotations. Combined with pydantic best practices, this encourages creating a single source of truth inside your codebase.\n\n## Installation\n\nclonf can be installed via pip or your favorite python package manager with different extras:\n\n```shell\npip install clonf[all,click,settings]\n```\n\n## Creating a CLI\n\n### click\n\n#### Quickstart\n\n```python\nfrom pydantic import BaseModel\nfrom clonf import clonf_click, CliArgument, CliOption\nfrom typing import Annotated\nimport click\n\n\nclass Arguments(BaseModel):\n    name: Annotated[str, CliArgument()]\n\n\nclass Options(BaseModel):\n    greeting: Annotated[str, CliOption()] = \"Hello\"\n\n\n@click.command\n@clonf_click\ndef cli(arguments: Arguments, options: Options) -> None:\n    click.echo(f\"{options.greeting} {arguments.name}\")\n\n\nif __name__ == \"__main__\":\n    cli()\n```\n\n#### Using click types\n\nSimilar to `pydanclick`, the following types will be converted automatically:\n| Python type | Click type |\n| :--------------------------------------- | :------------------- |\n| `bool` | `click.BOOL` |\n| `str` | `click.STRING` |\n| `int` | `click.INT` |\n| `float` | `click.FLOAT` |\n| `Annotated[int, Field(lt=..., ge=...)` | `click.IntRange()` |\n| `Annotated[float, Field(lt=..., ge=...)` | `click.FloatRange()` |\n| `pathlib.Path` | `click.Path()` |\n| `uuid.UUID` | `click.UUID` |\n| `datetime.datetime`, `datetime.date` | `click.DateTime()` |\n| `Literal` | `click.Choice` |\n\nAdditionally, custom click types can be passed via annotations to have finer control over the resulting click type:\n\n```python\nfrom pydantic import BaseModel\nfrom typing import Annotated\nfrom clonf import CliArgument\nimport pathlib\nimport click\n\nclass Config(BaseModel):\n    file_path: Annotated[pathlib.Path, CliArgument(), click.Path(exists=True)]\n```\n\n## Contributing\n\nThis project uses PDM as a package manager and pre-commit for linting before commits.\n\nRead more about the tools and how to use them:\n\n- [`PDM`](https://pdm-project.org/en/latest)\n- [`pre-commit`](https://pre-commit.com/)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Declaratively connect cli and config definition using pydantic",
    "version": "0.3.0",
    "project_urls": {
        "Source": "https://github.com/jvllmr/clonf"
    },
    "split_keywords": [
        "cli",
        " click",
        " pydantic",
        " pydantic-settings",
        " declarative",
        " config"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "baef2b3049c1c2b6fe29a6ab86501e28ce36e215493d32c1180cd37fa68b00dc",
                "md5": "3ad09534439ef5579c112dea4a83fd37",
                "sha256": "b20786ab9337546e689587c340019f893f6fa80b7c524d7443bdb28612d5042f"
            },
            "downloads": -1,
            "filename": "clonf-0.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3ad09534439ef5579c112dea4a83fd37",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 8601,
            "upload_time": "2025-10-19T16:59:00",
            "upload_time_iso_8601": "2025-10-19T16:59:00.236070Z",
            "url": "https://files.pythonhosted.org/packages/ba/ef/2b3049c1c2b6fe29a6ab86501e28ce36e215493d32c1180cd37fa68b00dc/clonf-0.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d24cbd278778a03f488e6a262afb9908e6711b5f27432422e49bdbe05799cd95",
                "md5": "1d7f2fd6b90557414a698248ab4a2933",
                "sha256": "7573364de6f2d3d02ba0cb73836020e23b9fdf9c034f1d533be591f2382a5dd2"
            },
            "downloads": -1,
            "filename": "clonf-0.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "1d7f2fd6b90557414a698248ab4a2933",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 9565,
            "upload_time": "2025-10-19T16:59:01",
            "upload_time_iso_8601": "2025-10-19T16:59:01.388091Z",
            "url": "https://files.pythonhosted.org/packages/d2/4c/bd278778a03f488e6a262afb9908e6711b5f27432422e49bdbe05799cd95/clonf-0.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-19 16:59:01",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jvllmr",
    "github_project": "clonf",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "clonf"
}
        
Elapsed time: 2.45459s