data-platform-toolkit 0.6.0
Opinionated decorators that turn callables into CLI commands with structured logging.
Requires Python: >=3.9
Keywords: decorators, cli, logging, structured-logging

# Data Platform Toolkit

Набор инструментов, которые помогают:

- превращать функции в CLI команды c помощью `argparse`;
- автоматически добавлять структурированные JSON-логи вокруг вызова;
- переиспользовать один и тот же стек в разных проектах с минимальными зависимостями.

## Установка

```bash
pip install data-platform-toolkit
```

## Быстрый старт

```python
from decorators import cli, configure_toolkit, get_logger

configure_toolkit(logger_structured_messages=True)  # один раз на старте приложения
logger = get_logger()  # использует настройки из configure_toolkit

@cli.command()
def greet(name: str, excited: bool = False):
    """Простое приветствие."""
    message = f"Hello, {name}"
    return message.upper() if excited else message

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

```bash
$ python app.py greet Artem --excited
HELLO, ARTEM
```

Каждый запуск создаёт три лог-события (`start`, `success`, `error`) в JSON-формате; адаптер добавляет `timestamp` и `invocation_id`:

```json
{"event": "start", "function": "greet", "call": {"args": ["Artem"], "kwargs": {"excited": true}}, "timestamp": "<ts>", "invocation_id": "<id>"}
{"event": "success", "function": "greet", "duration": 0.000021, "message": "HELLO, ARTEM", "timestamp": "<ts>", "invocation_id": "<id>"}
```

## Примеры: позиционные и опции

Правила формирования CLI-аргументов берутся из `CLIRegistry._add_argument`:

- Параметры без значения по умолчанию добавляются как позиционные.
- Параметры со значением по умолчанию добавляются как именованные опции `--name`.

Это влияет на способ вызова команды:

1) Позиционный аргумент (без дефолта)

```python
from decorators import cli

@cli.command()
def hello(name: str) -> str:
    return f"Hello, {name}!"

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

Запуск:

```bash
python app.py hello artem
```

2) Именованная опция (с дефолтом)

```python
from decorators import cli

@cli.command()
def hello(name: str = "World") -> str:
    return f"Hello, {name}!"

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

Запуски:

```bash
# Использовать дефолтное значение
python app.py hello

# Явно передать значение через опцию
python app.py hello --name artem
```

3) Булевы флаги (`--flag` / `--no-flag`)

```python
from decorators import cli

@cli.command()
def toggle(verbose: bool = False) -> bool:
    return verbose

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

Запуски:

```bash
python app.py toggle --verbose    # → True
python app.py toggle --no-verbose # → False
```

## Дополнительные возможности

- `CLIRegistry()` — создаёт собственный реестр команд (удобно для библиотек).
- `@cli.command(log=False)` — отключает логирование, если оно не требуется.
- `@structured` — декоратор для обычных функций, которым не нужен CLI, но нужны структурированные логи.

## Dry-run (стандартный тестовый режим)

Каждая CLI‑команда поддерживает флаг `--dry-run`, который выводит структурированный JSON‑превью вызова и пропускает выполнение функции. Чтобы реестр распознал флаг как глобальный, его нужно указывать **до** имени команды. Это удобно для тестирования интеграций в проектах, импортирующих библиотеку.

```bash
$ python app.py --dry-run greet Artem --excited
{"event": "dry_run", "function": "greet", "call": {"kwargs": {"name": "Artem", "excited": true}}}
```

Также поддерживается глобальный вызов без указания команды:

```bash
$ python app.py --dry-run
{"event": "dry_run", "function": null, "available": ["greet", "toggle", "..."]}
```

Флаг доступен для всех команд автоматически и не влияет на сигнатуру функций.

## Ограничения

- Поддерживаются только позиционные и именованные аргументы (без `*args` и `**kwargs`).
- Для булевых параметров автоматически добавляются флаги `--flag/--no-flag`.
- Типы аргументов выводятся из аннотаций или значений по умолчанию и ограничены `str`, `int`, `float`, `bool`.

## Лицензия

MIT License.