Metadata-Version: 2.4
Name: interfacy
Version: 0.7.0
Summary: Framework for building CLIs from Python callables
Keywords: interfacy,cli,command-line,argparse,cli-generator,cli-builder,cli-framework,type-hints
Author: Žiga Ivanšek
Author-email: Žiga Ivanšek <ziga.ivansek@gmail.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
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 :: Python Modules
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Typing :: Typed
Requires-Dist: stdl>=0.7.1
Requires-Dist: objinspect>=0.4.3
Requires-Dist: strto>=0.2.9
Requires-Dist: tomlkit>=0.12
Requires-Dist: tomli>=2.0 ; python_full_version < '3.11'
Requires-Dist: setproctitle>=1.3.7
Requires-Dist: click>=8.3.1 ; extra == 'click'
Requires-Dist: pytest>=9.0.3 ; extra == 'dev'
Requires-Dist: pytest-mock ; extra == 'dev'
Requires-Dist: ruff==0.16.1 ; extra == 'dev'
Requires-Dist: pre-commit>=4.6.0 ; extra == 'dev'
Requires-Dist: coverage>=7.14.1 ; extra == 'dev'
Requires-Dist: pyrefly>=1.0.0 ; extra == 'dev'
Requires-Dist: click>=8.3.1 ; extra == 'dev'
Requires-Dist: argcomplete ; extra == 'dev'
Requires-Dist: rattle-lint>=2.5.1 ; extra == 'dev'
Requires-Dist: beautifulsoup4 ; extra == 'docs'
Requires-Dist: click>=8.3.1 ; extra == 'docs'
Requires-Dist: furo ; extra == 'docs'
Requires-Dist: jinja2==3.1.6 ; extra == 'docs'
Requires-Dist: myst-parser==4.0.1 ; extra == 'docs'
Requires-Dist: sphinx==8.0.2 ; 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'
Requires-Dist: argcomplete ; extra == 'full'
Requires-Dist: click>=8.3.1 ; extra == 'full'
Requires-Dist: pytest>=9.0.3 ; extra == 'test'
Requires-Dist: pytest-mock ; extra == 'test'
Requires-Dist: coverage>=7.14.1 ; extra == 'test'
Requires-Dist: click>=8.3.1 ; extra == 'test'
Requires-Python: >=3.10
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
Provides-Extra: click
Provides-Extra: dev
Provides-Extra: docs
Provides-Extra: full
Provides-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/master/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) -> None:
    """Print a greeting."""
    print(" ".join([f"Hello, {name}!" for _ in range(times)]))


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

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

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

## Agent Skill

The official AI agent skill can be installed from this repo.

```bash
npx skills add https://github.com/zigai/interfacy/tree/master/interfacy/.agents/skills/interfacy
```

or

```bash
uvx library-skills
```

## 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)
```

## 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 framework for building CLIs 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).
  ...             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/master/LICENSE)
