Metadata-Version: 2.4
Name: aniket_tools
Version: 0.1.1
Summary: Reusable API response and exception handling utilities with FastAPI integration.
Author: Aniket Modi
License: MIT
Project-URL: Homepage, https://github.com/aniketmodi123/reusable_code_lib
Project-URL: Repository, https://github.com/aniketmodi123/reusable_code_lib
Keywords: api,fastapi,error-handling,responses,utilities
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Framework :: FastAPI
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.110; extra == "fastapi"
Provides-Extra: pydantic
Requires-Dist: pydantic>=1.10; extra == "pydantic"
Provides-Extra: database
Requires-Dist: sqlalchemy>=1.4; extra == "database"
Requires-Dist: asyncpg>=0.29; extra == "database"
Requires-Dist: psycopg2-binary>=2.9; extra == "database"
Provides-Extra: full
Requires-Dist: fastapi>=0.110; extra == "full"
Requires-Dist: pydantic>=1.10; extra == "full"
Requires-Dist: sqlalchemy>=1.4; extra == "full"
Requires-Dist: asyncpg>=0.29; extra == "full"
Requires-Dist: psycopg2-binary>=2.9; extra == "full"
Dynamic: license-file

# aniket_tools

`aniket_tools` is a reusable Python library for centralized API responses, logging, and exception handling.

It gives you one place to manage:

- `create_response`
- `value_correction`
- `logs`
- `ExceptionHandler`
- `unified_exception_handler`

## Install

```bash
pip install aniket_tools
```

For local development:

```bash
pip install .
```

Optional extras:

```bash
pip install ".[fastapi]"
pip install ".[pydantic]"
pip install ".[database]"
pip install ".[full]"
```

## Quick usage

```python
from fastapi import FastAPI
from aniket_tools import create_response, register_exception_handlers

app = FastAPI()
register_exception_handlers(app)


@app.get("/health")
async def health():
    return create_response(200, data={"status": "ok"})
```

## Public API

Import from the published package like this:

Use only this import style in other projects:

```python
from aniket_tools import (
    ApiError,
    ErrorHandler,
    ExceptionHandler,
    create_response,
    explain_error,
    get_logger,
    get_status_code,
    handle_exception,
    logs,
    register_exception_handlers,
    unified_exception_handler,
    value_correction,
)
```

### `create_response`

Params:

- `response_code: int`
- `data: Any = None`
- `schema: Any | None = None`
- `pagination: Mapping[str, Any] | None = None`
- `error_message: str | None = None`
- `error_code: str | None = None`
- `details: Sequence[Mapping[str, Any]] | None = None`
- `as_json_response: bool = True`

Usage:

```python
from aniket_tools import create_response

return create_response(
    200,
    data={"name": "Aniket"},
    pagination={"page": 1, "rows": 10, "total_rows": 100},
)
```

### `value_correction`

Params:

- `data: Any`

Usage:

```python
from decimal import Decimal
from aniket_tools import value_correction

cleaned = value_correction({"amount": Decimal("10.50"), "name": "  demo  "})
```

### `logs`

Params:

- `msg: object = ""`
- `type: str = "info"`
- `file_name: str | Path | None = None`
- `logger: logging.Logger | None = None`

Usage:

```python
from aniket_tools import logs

logs("report created", type="info")
logs("database failed", type="error", file_name="logs/app")
```

### `get_logger`

Params:

- `name: str = "aniket_tools"`
- `file_name: str | Path | None = None`

Usage:

```python
from aniket_tools import get_logger

logger = get_logger("my_app", file_name="logs/app.log")
logger.info("started")
```

### `unified_exception_handler`

Params:

- `request`
- `exc: Exception`

Usage:

```python
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from aniket_tools import unified_exception_handler

app = FastAPI()

app.add_exception_handler(HTTPException, unified_exception_handler)
app.add_exception_handler(Exception, unified_exception_handler)
app.add_exception_handler(RequestValidationError, unified_exception_handler)
```

### `register_exception_handlers`

Params:

- `app`
- `handler: ErrorHandler | None = None`

Usage:

```python
from fastapi import FastAPI
from aniket_tools import register_exception_handlers

app = FastAPI()
register_exception_handlers(app)
```

### `ExceptionHandler`

Params:

- `exc: Exception`

Usage:

```python
from aniket_tools import ExceptionHandler

try:
    raise ValueError("invalid meter id")
except Exception as exc:
    ExceptionHandler(exc)
```

### `handle_exception`

Params:

- `exc: Exception`
- `request = None`

Usage:

```python
from aniket_tools import handle_exception

payload_or_response = handle_exception(ValueError("invalid input"))
```

### `explain_error`

Params:

- `exc: Exception`

Usage:

```python
from aniket_tools import explain_error

message = explain_error(ValueError("invalid input"))
```

### `get_status_code`

Params:

- `exc: Exception`

Usage:

```python
from aniket_tools import get_status_code

status_code = get_status_code(ValueError("invalid input"))
```

### `ErrorHandler`

Params:

- `logger_name: str = "aniket_tools.errors"`

Usage:

```python
from aniket_tools import ErrorHandler

handler = ErrorHandler()
payload = handler.build_payload(ValueError("invalid input"))
```

### `ApiError`

Params:

- `message: str`
- `status_code: int = 400`
- `code: str = "api_error"`
- `details: list[dict[str, Any]] | None = None`
- `log_message: str | None = None`

Usage:

```python
from aniket_tools import ApiError

raise ApiError(
    "Report is not ready.",
    status_code=409,
    code="report_pending",
    details=[{"field": "report_id", "message": "still processing"}],
)
```

## Error response format

Every API failure uses one consistent structure:

```json
{
  "success": false,
  "status_code": 422,
  "error": {
    "code": "validation_error",
    "type": "RequestValidationError",
    "message": "One or more fields are invalid.",
    "details": [
      {
        "field": "email",
        "message": "field required"
      }
    ]
  }
}
```

## Package structure

```text
src/aniket_tools/
  __init__.py
  _compat.py
  exceptions.py
  logging.py
  responses.py
```

## Extending it

Add new shared functionality inside `src/aniket_tools/` and re-export it from `src/aniket_tools/__init__.py`. That keeps imports stable across every project that uses the package.

## Import Rule

For installed usage, import from `aniket_tools` only.

Correct:

```python
from aniket_tools import create_response, unified_exception_handler
```

Do not rely on local-only paths like `utils` or `exception_handler` in other projects.

## Auto Publish From `prod`

This repo is configured so that a merged pull request into the `prod` branch publishes the package to PyPI through GitHub Actions.

Required setup:

1. Create the package on PyPI if needed.
2. In PyPI, configure a Trusted Publisher with these values:
   - Project name: `aniket_tools`
   - Owner: `aniketmodi123`
   - Repository: `reusable_code_lib`
   - Workflow: `publish-pypi.yml`
3. Before merging into `prod`, increase the version in `pyproject.toml`. PyPI will reject duplicate versions.

Workflow file:

- `.github/workflows/publish-pypi.yml`

Release flow:

```bash
git checkout dev
# make code changes
# update version in pyproject.toml when this is a release
git add .
git commit -m "release: 0.1.1"
git push origin dev
```

Then:

1. Create a pull request from `dev` to `prod`
2. Review and approve it
3. Merge the pull request

When the PR is merged into `prod`, GitHub Actions will use Trusted Publishing to:

- build the wheel and source distribution
- validate the package
- upload it to PyPI
