|
| 1 | +--- |
| 2 | +name: interfacy |
| 3 | +description: High-level guidance for using Interfacy for creating CLIs. |
| 4 | +--- |
| 5 | + |
| 6 | +# Interfacy |
| 7 | + |
| 8 | +Interfacy is a Python CLI framework that builds command-line interfaces from existing typed functions, classes, class instances, signatures, defaults, and docstrings. |
| 9 | + |
| 10 | +Use it when a project needs a CLI without maintaining a separate parser tree. The normal workflow is to reuse or lightly shape ordinary Python callables, then pass them to `Interfacy`. |
| 11 | + |
| 12 | +## Installation |
| 13 | + |
| 14 | +### From PyPI |
| 15 | + |
| 16 | +```bash |
| 17 | +pip install interfacy |
| 18 | +``` |
| 19 | + |
| 20 | +```bash |
| 21 | +uv add interfacy |
| 22 | +``` |
| 23 | + |
| 24 | +## Basic Usage |
| 25 | + |
| 26 | +```python |
| 27 | +from interfacy import Interfacy |
| 28 | + |
| 29 | +def greet(name: str, times: int = 1) -> str: |
| 30 | + """Return a greeting. |
| 31 | +
|
| 32 | + Args: |
| 33 | + name: Person to greet. |
| 34 | + times: Number of greetings. |
| 35 | +
|
| 36 | + Returns: |
| 37 | + Greeting text. |
| 38 | + """ |
| 39 | + return " ".join(f"Hello, {name}!" for _ in range(times)) |
| 40 | + |
| 41 | +if __name__ == "__main__": |
| 42 | + Interfacy(print_result=True).run(greet) |
| 43 | +``` |
| 44 | + |
| 45 | +```text |
| 46 | +$ python app.py Ada --times 2 |
| 47 | +Hello, Ada! Hello, Ada! |
| 48 | +``` |
| 49 | + |
| 50 | +## Usage Strategy |
| 51 | + |
| 52 | +1. Choose the shape that matches the user's CLI: |
| 53 | + - One action: a typed function. |
| 54 | + - Several related actions sharing setup: a class. |
| 55 | + - Existing service object or injected dependencies: a class instance. |
| 56 | + - A manually composed command tree: `CommandGroup`. |
| 57 | +2. Reuse existing typed functions, classes, or instances when they already express the command behavior. Do not create new wrapper functions just to satisfy Interfacy. |
| 58 | +3. Make the callable signature describe the CLI: |
| 59 | + - Required inputs are positional parameters. |
| 60 | + - Options are keyword/defaulted parameters, often keyword-only. |
| 61 | + - Choices are `Literal[...]` or `Enum`. |
| 62 | + - Repeated values are `list[T]` or variadic parameters. |
| 63 | + - Grouped settings are small dataclasses, Pydantic models, or typed config classes. |
| 64 | + - Domain-specific scalar values can use `Interfacy.add_type_parser(...)` when a plain annotation is not enough. |
| 65 | +4. Put user-facing help in docstrings. The first line should read like command help, not implementation notes. Do not duplicate default values in docstrings; Interfacy can show defaults from signatures. |
| 66 | +5. Wire with the public API: |
| 67 | + |
| 68 | +```python |
| 69 | +from interfacy import Interfacy |
| 70 | + |
| 71 | +Interfacy(print_result=True).run(command) |
| 72 | +``` |
| 73 | + |
| 74 | +## What Good Interfacy Code Looks Like |
| 75 | + |
| 76 | +- The command function can be called normally from Python tests. |
| 77 | +- Existing functions/classes are reused directly when their signatures and docstrings are already CLI-ready. |
| 78 | +- The CLI does not duplicate parameter names, defaults, choices, or help in a second parser definition. |
| 79 | +- Parsing concerns stay at the boundary; business logic stays in ordinary Python functions/classes. |
| 80 | +- Return values are meaningful Python values. Use `print_result=True` when the CLI should display them. |
| 81 | +- Return values, including integers, are command results, not process exit codes. |
| 82 | +- Existing printed output, file writes, network calls, and exit behavior are preserved intentionally. |
| 83 | + |
| 84 | +## What To Avoid |
| 85 | + |
| 86 | +- Do not recreate parser trees by hand when Interfacy can infer them. |
| 87 | +- Use the public `Interfacy` API for normal application code. |
| 88 | +- Do not add manual printing just to show a returned value. |
| 89 | +- Do not add thin wrappers around existing callables unless adapting names, validation, parser-specific inputs, or user-facing behavior actually requires it. |
| 90 | +- Do not wrap Interfacy entrypoints in `raise SystemExit(main())` patterns that reinterpret command results as exit codes. |
| 91 | +- Do not run `.run(...)` at import time; guard executable entrypoints with `if __name__ == "__main__":`. |
| 92 | +- Do not hide parse or runtime failures with broad `except Exception` or `except SystemExit` wrappers. |
| 93 | +- Do not hide CLI-only transformations in decorators or global state; put them in the callable body or a small adapter. |
| 94 | +- Do not expose every method or field of a domain object just because Interfacy can. Design the CLI surface deliberately. |
| 95 | + |
| 96 | +## References |
| 97 | + |
| 98 | +- Read `references/api-patterns.md` when choosing between functions, classes, decorators, command groups, custom type parsers, entrypoints, result display, or tests. |
| 99 | +- Read `references/structured-parameters.md` when a command has grouped/nested inputs or config objects. |
| 100 | +- For large CLIs with many commands, use `CommandGroup` for real command namespaces and `help_group` constants for readable top-level help sections. |
0 commit comments