# Kheera

Kheera is a cucumber-themed playground for humans and machines. It bundles a reusable Python package, a FastAPI-powered REST backend, a command-line interface, and a handful of whimsical utilities that celebrate the humble kheera (cucumber).

## Contents
- [Highlights](#highlights)
- [Install](#install)
- [Quick Start](#quick-start)
- [Library API](#library-api)
- [Custom Error Codes](#custom-error-codes)
- [CLI Reference](#cli-reference)
- [REST API](#rest-api)
- [Example Workflows](#example-workflows)
- [Project Layout](#project-layout)
- [Development Guide](#development-guide)
- [Testing](#testing)
- [Packaging & Release](#packaging--release)
- [Docker](#docker)
- [Contributing](#contributing)
- [License](#license)

## Highlights
- Playful Python helpers for drawing cucumbers, slicing them, rating freshness, and more.
- Structured health checks and error codes (e.g., `KHEERA-SLICE-002`) for predictable automation.
- REST API exposing every feature, including PNG rendering for `/kheera/draw` and catalogue endpoints for error codes.
- CLI with zero-config commands for quick demos or fortune-cookie style output.
- Comprehensive unit and API tests ready for CI, along with a Dockerfile and GitHub Actions workflow.

## Install

Install from PyPI:

```
pip install kheera
```

Contribute locally:

```
git clone https://github.com/YourUsername/kheera.git
cd kheera
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
```

## Quick Start

### Library

```python
from kheera import slice, cool_down, calculate_coolness

print(slice(3))
print(cool_down(8))
print(calculate_coolness("Devs"))
```

### CLI

```
kheera --slice 4
kheera --draw
kheera --version
```

### REST API

```
uvicorn backend.app:app --reload
# Visit http://localhost:8000/docs for Swagger UI.
```

Sample call:

```
curl "http://localhost:8000/kheera/slice?count=3"
```

## Library API

Module `kheera.core` exposes the primary surface area. All public symbols are re-exported from `kheera.__init__`.

| Function | Description | Returns | Raises |
| --- | --- | --- | --- |
| `draw(return_bytes=False)` | Render a cucumber using Matplotlib. When `return_bytes=True`, a PNG byte stream is returned instead of opening a window. | `bytes` or `None` | — |
| `slice(count=5)` | Generate whimsical slice labels. | `List[str]` | `InvalidSliceCountError` if `count <= 0` |
| `cool_down(temp=10)` | Produce a cooling mantra referencing the requested temperature drop. | `str` | `CoolingNotEffectiveError` if `temp <= 0` |
| `rate_kheera()` | Random rating from 1 to 10. | `str` | — |
| `is_fresh()` | Randomly returns `"Fresh"` or `"Not Fresh"`. | `str` | — |
| `throw(target)` | Simulate throwing a cucumber at `target`. | `str` | `TargetNotFoundError` if target is empty |
| `calculate_coolness(name)` | Assign a random coolness score. | `str` | — |
| `cucumberify(text)` | Replace spaces with `" kheera "` for cucumber-flavored phrasing. | `str` | `TextTooLargeError` if input exceeds 4096 chars |
| `yoga_mode()` | Return a calming instruction for cucumber-based relaxation. | `str` | — |

Supporting helpers:

- `kheera.art.ascii_art()` – ASCII cucumber art.
- `kheera.health.health_status()` – Produce a `HealthStatus` dataclass with freshness metrics, occasionally raising `RottenCucumberError`.
- `kheera.errors` – Custom exception hierarchy and registry helpers.
- `kheera.cli.main()` – CLI entry point exposed by the console script.

## Custom Error Codes

All domain failures inherit from `KheeraError` and carry a `code`, `message`, and `status_code`. The static catalogue lives in `docs/errors.md` and is accessible at runtime via `kheera.errors.error_registry_as_dict()` or the `/kheera/error_codes` endpoint.

| Code | Meaning | HTTP Status |
| --- | --- | --- |
| `KHEERA-SLICE-002` | Invalid slice count | 400 |
| `KHEERA-COOL-403` | Cooling not effective (temperature too low) | 422 |
| `KHEERA-THROW-401` | Target not supplied | 400 |
| `KHEERA-CUCIFY-413` | Text too large for cucumberification | 413 |
| `KHEERA-HEALTH-500` | Rotten cucumber detected | 500 |

Clients should catch `KheeraError` (or subclasses) to access structured metadata.

## CLI Reference

```
kheera --help

usage: kheera [--draw] [--slice SLICE] [--version]

optional arguments:
    --draw               Render a cucumber figure using Matplotlib.
    --slice N            Print N cucumber slices.
    --version            Print the package version and exit.
```

Exit codes:
- `0` on success.
- `1` if a `KheeraError` is raised (message is written to stderr).

## REST API

The FastAPI backend lives under `backend/`. Default base URL: `http://localhost:8000`.

| Method & Path | Description | Query/Body | Response | Errors |
| --- | --- | --- | --- | --- |
| `GET /` | API heartbeat | — | `{ "message": "Kheera API is crisp and ready" }` | — |
| `GET /kheera/slice` | Generate slices | `count` (int, optional) | `{ "slices": [...] }` | 400 on invalid count |
| `GET /kheera/cool_down` | Cooling mantra | `temp` (int, optional) | `{ "message": "..." }` | 422 when ineffective |
| `GET /kheera/rate` | Random rating | — | `{ "rating": "..." }` | — |
| `GET /kheera/fresh` | Freshness status | — | `{ "status": "Fresh" }` | — |
| `GET /kheera/throw` | Throw at target | `target` (str) | `{ "result": "..." }` | 400 if target missing |
| `GET /kheera/coolness` | Coolness score | `name` (str) | `{ "result": "..." }` | — |
| `POST /kheera/cucumberify` | Cucumberify text | JSON `{ "text": str }` | `{ "result": "..." }` | 413 on oversized payload |
| `GET /kheera/yoga` | Yoga instructions | — | `{ "instruction": "..." }` | — |
| `GET /kheera/ascii` | ASCII art | — | `{ "art": "..." }` | — |
| `GET /kheera/draw` | Render PNG | — | `image/png` stream | — |
| `GET /kheera/health` | Health check | — | `{ "status": str, "details": {...} }` | 500 if rotten |
| `GET /kheera/error_codes` | Catalogue error codes | — | `{ "error_codes": [...] }` | — |

Additional behavior:
- Logging middleware records method, path, status, and duration.
- 404 responses return `{ "detail": "Kheera lost" }`.
- OpenAPI schema available at `/docs` (Swagger UI) and `/redoc`.

## Example Workflows

### Automated Test of Slice API

```python
from fastapi.testclient import TestClient
from backend.app import app

client = TestClient(app)
response = client.get("/kheera/slice", params={"count": 3})
assert response.json()["slices"][0] == "Kheera slice 1"
```

### Refresh Health Status

```python
from kheera.health import health_status
from kheera.errors import KheeraError

try:
    status = health_status()
    print(status.status, status.details)
except KheeraError as exc:
    print(exc.code, exc.message)
```

### Compose Services Using Docker

```
docker build -t kheera:latest .
docker run -p 8000:8000 kheera:latest
```

## Project Layout


```
kheera/
├── backend/                # FastAPI app and routers
├── kheera/                 # Python package (library + CLI)
├── tests/                  # Library tests
├── backend/tests/          # API tests
├── docs/errors.md          # Error catalogue
├── examples/demo.py        # Quick demo script
├── requirements.txt        # Dev requirements
├── pyproject.toml          # Packaging metadata
├── Dockerfile              # Production-ready container
└── .github/workflows/ci.yml
```

## Development Guide

1. Install dependencies: `pip install -r requirements.txt`.
2. Set `PYTHONPATH=.` when invoking API tests manually.
3. Use `uvicorn backend.app:app --reload` for local API development.
4. Run formatters or linters as needed (none enforced yet).

Notes:
- `kheera.core.draw` locks Matplotlib to the `Agg` backend for headless environments.
- All randomness uses Python's standard library RNG; seed via `random.seed` for reproducible demos.

## Testing

```
pytest
```

This runs both library and API suites. CI mirrors the same command.

## Packaging & Release

1. Update `__version__` in `kheera/__init__.py` and `version` in `pyproject.toml`.
2. Clean build artefacts: `rmdir /s /q build dist` and remove `kheera.egg-info`.
3. Build distributions: `python -m build`.
4. Upload with Twine using API tokens: `python -m twine upload dist/*`.
5. Verify by installing from PyPI in a clean virtual environment and running `pytest`.

## Docker

```
docker build -t kheera:latest .
docker run --rm -p 8000:8000 kheera:latest
```

The container installs runtime dependencies and serves the API via Uvicorn.

## Contributing

Issues and pull requests are welcome. Please include tests for any new behavior. For large changes, open an issue first to discuss the approach.

## License

MIT License. See [LICENSE](LICENSE).

