Metadata-Version: 2.4
Name: interfacy
Version: 0.5.1
Summary: CLI framework for building command-line interfaces from Python callables
Project-URL: Repository, https://github.com/zigai/interfacy
Project-URL: Issues, https://github.com/zigai/interfacy/issues
Project-URL: Homepage, https://github.com/zigai/interfacy
Author-email: Žiga Ivanšek <ziga.ivansek@gmail.com>
License: MIT License
        
        Copyright (c) 2023 Žiga Ivanšek
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: argparse,cli,cli-builder,cli-framework,cli-generator,command-line,interfacy,type-hints
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: objinspect>=0.4.3
Requires-Dist: setproctitle>=1.3.7
Requires-Dist: stdl>=0.7.1
Requires-Dist: strto>=0.2.9
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: tomlkit>=0.12
Provides-Extra: click
Requires-Dist: click>=8.3.1; extra == 'click'
Provides-Extra: dev
Requires-Dist: argcomplete; extra == 'dev'
Requires-Dist: click>=8.3.1; extra == 'dev'
Requires-Dist: coverage>=7.13.5; extra == 'dev'
Requires-Dist: mypy>=1.19.1; extra == 'dev'
Requires-Dist: pre-commit>=4.5.1; extra == 'dev'
Requires-Dist: pytest-mock; extra == 'dev'
Requires-Dist: pytest>=9.0.2; extra == 'dev'
Requires-Dist: rattle-blank-lines>=0.2.6; extra == 'dev'
Requires-Dist: rattle-lint>=1.0.6; extra == 'dev'
Requires-Dist: ruff==0.15.8; extra == 'dev'
Provides-Extra: docs
Requires-Dist: click>=8.3.1; extra == 'docs'
Requires-Dist: myst-parser; extra == 'docs'
Requires-Dist: sphinx; extra == 'docs'
Requires-Dist: sphinx-book-theme; extra == 'docs'
Requires-Dist: sphinx-copybutton; extra == 'docs'
Requires-Dist: sphinx-notfound-page; extra == 'docs'
Requires-Dist: sphinxcontrib-mermaid; extra == 'docs'
Requires-Dist: sphinxext-opengraph; extra == 'docs'
Provides-Extra: full
Requires-Dist: argcomplete; extra == 'full'
Requires-Dist: click>=8.3.1; extra == 'full'
Provides-Extra: test
Requires-Dist: click>=8.3.1; extra == 'test'
Requires-Dist: coverage>=7.13.5; extra == 'test'
Requires-Dist: pytest-mock; extra == 'test'
Requires-Dist: pytest>=9.0.2; extra == 'test'
Description-Content-Type: text/markdown

# Interfacy

[![Tests](https://github.com/zigai/interfacy/actions/workflows/tests.yml/badge.svg)](https://github.com/zigai/interfacy/actions/workflows/tests.yml)
[![PyPI version](https://badge.fury.io/py/interfacy.svg)](https://badge.fury.io/py/interfacy)
![Supported versions](https://img.shields.io/badge/python-3.10+-blue.svg)
[![Downloads](https://static.pepy.tech/badge/interfacy)](https://pepy.tech/project/interfacy)
[![license](https://img.shields.io/github/license/zigai/interfacy.svg)](https://github.com/zigai/interfacy/blob/main/LICENSE)

Interfacy is a CLI framework that turns Python functions, classes, and class instances into command-line interfaces. It derives the CLI from signatures, type annotations, and docstrings instead of making you define it twice.

## Features

- Generate CLIs from functions, classes, class methods, and class instances.
- Nested subcommands and manual command groups with aliases.
- Type-driven parsing from annotations, with support for custom parsers.
- Model expansion for dataclasses, Pydantic models, and plain classes.
- `--help` text generated from docstrings.
- Highly customizable help output with multiple layouts, color themes, and configurable ordering.
- Stdin piping support with configurable routing to parameters.
- Optional tab completion via `argcomplete`.

## Installation

### From PyPI

```bash
pip install interfacy
```

```bash
uv add interfacy
```

### From source

```bash
pip install git+https://github.com/zigai/interfacy.git
```

```bash
uv add "git+https://github.com/zigai/interfacy.git"
```

## Quick Start

```python
from interfacy import Interfacy

def greet(name: str, times: int = 1) -> str:
    """Return a greeting."""
    return " ".join([f"Hello, {name}!" for _ in range(times)])

if __name__ == "__main__":
    Interfacy(print_result=True).run(greet)
```

```text
$ python app.py Ada
Hello, Ada!

$ python app.py Ada --times 2
Hello, Ada! Hello, Ada!
```

By default, required non-boolean parameters become positional arguments and optional parameters become flags.

## Class-Based Commands

Classes become command namespaces. `__init__` parameters live at the command level and public methods become subcommands.

```python
from interfacy import Interfacy

class Calculator:
    def __init__(self, precision: int = 2) -> None:
        self.precision = precision

    def add(self, a: float, b: float) -> float:
        return round(a + b, self.precision)

    def mul(self, a: float, b: float) -> float:
        return round(a * b, self.precision)

if __name__ == "__main__":
    Interfacy(print_result=True).run(Calculator)
```

```text
$ python app.py --precision 3 add 1.2345 2.3445
3.579
```

## Structured Parameters

Dataclasses, Pydantic models, and plain classes with typed `__init__` parameters can be expanded into nested flags and reconstructed before execution.

```python
from dataclasses import dataclass
from interfacy import Interfacy

@dataclass
class Address:
    city: str
    postal_code: int

@dataclass
class User:
    name: str
    age: int
    address: Address | None = None

def greet(user: User) -> str:
    return f"Hello {user.name}, age {user.age}"

if __name__ == "__main__":
    Interfacy(print_result=True).run(greet)
```

```text
$ python app.py --user.name Ada --user.age 32
Hello Ada, age 32
```

## Manual Groups

Use `CommandGroup` when your command tree is not naturally rooted in one callable:

```python
from interfacy import CommandGroup, Interfacy

def clone(url: str) -> str:
    return f"clone:{url}"

class Releases:
    def cut(self, version: str) -> str:
        return f"cut:{version}"

ops = CommandGroup("ops", description="Operational commands")
ops.add_command(clone)
ops.add_command(Releases)

if __name__ == "__main__":
    Interfacy(print_result=True).run(ops)
```

## Backend Selection

`Interfacy` uses the argparse backend by default. To use the Click backend,
install the optional dependency and pass `backend="click"`:

```bash
pip install "interfacy[click]"
```

```python
from interfacy import Interfacy

Interfacy(backend="click", print_result=True).run(greet)
```

## Interfacy CLI Entrypoint

Interfacy also ships a CLI that can run an existing function, class, or class instance directly from a module or Python file:

```text
$ interfacy app.py:greet Ada
$ interfacy app.py:greet --help
$ interfacy package.cli:Calculator add 1 2
```

The entrypoint supports configuration via TOML, loaded from `~/.config/interfacy/config.toml` or `INTERFACY_CONFIG`.

```text
usage: interfacy [--help] [--version] [--config-paths] [TARGET] ...

Interfacy is a CLI framework for building command-line interfaces from Python callables.

positional arguments:
  TARGET                      Python file or module with a function/class/instance symbol (e.g. main.py:main, pkg.cli:App, pkg.cli:service).
  ARGS                        Arguments passed through to the target command.

options:
  --help                      show this help message and exit
  --version                   show version and exit.
  --config-paths              print config file search paths and exit.

Use 'interfacy TARGET --help' to display the help text for the target.
```

## License

[MIT License](https://github.com/zigai/interfacy/blob/main/LICENSE)
