Metadata-Version: 2.4
Name: buchanan-solutions-pytools
Version: 0.2.4
Summary: Helpful tools for Logging, Typer, Pydantic, and Debugging
Project-URL: Homepage, https://github.com/buchanan-solutions/pytools
Project-URL: Issues, https://github.com/buchanan-solutions/pytools/issues
Author-email: Alex Buchanan <alex@buchanansolutions.ca>
License-Expression: MIT
License-File: LICENSE.md
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.13
Requires-Dist: pydantic>=2.0.0
Requires-Dist: rich>=14.2.0
Provides-Extra: core
Provides-Extra: debugging
Requires-Dist: icecream>=2.1.9; extra == 'debugging'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.115.0; extra == 'fastapi'
Provides-Extra: pydantic
Provides-Extra: pydantic-settings
Requires-Dist: pydantic-settings>=2.0.0; extra == 'pydantic-settings'
Provides-Extra: typer
Requires-Dist: python-dotenv>=1.0.1; extra == 'typer'
Requires-Dist: typer>=0.20.0; extra == 'typer'
Description-Content-Type: text/markdown

# 🛠️ pytools

A modular collection of Python utilities for **Typer**, **Pydantic**, and **Debugging**. Built for high-performance developer workflows using `uv` and `hatchling`.

`pytools` is designed as a "buffet" library—install only the submodules you need to keep your project dependencies lean.

## 🚀 Quick Start

Add `pytools` to your project using **uv**. You can choose specific "extras" to pull in only the dependencies required for that module.

```bash
# Install just the Typer utilities (and their deps)
uv add "pytools[typer] @ git+ssh://git@github.com/buchanan-solutions/pytools.git"

# Install everything
uv add "pytools[all] @ git+ssh://git@github.com/buchanan-solutions/pytools.git"

```

## 📦 Submodules

| Extra | Description | Key Dependencies |
| --- | --- | --- |
| `core` | Foundational logic used by all modules. | None (Std Lib only) |
| `typer` | CLI helpers, context management, and rich logging. | `typer`, `rich`, `python-dotenv` |
| `pydantic` | Custom validators and base model configurations. | `pydantic` |
| `pydantic-settings` | Environment management and config loading. | `pydantic-settings` |
| `debugging` | Enhanced print utilities and object inspection. | `icecream` |

## pytools.logging

Phased logging: build a pure `LoggingState` with `bootstrap`, adjust it, then call `apply_state` to activate the stdlib runtime. The same state can be exported for worker processes (for example Uvicorn `log_config`).

**Quick usage:**

```python
import logging

from pytools.logging import bootstrap, merge_logger_levels, set_root_level
from pytools.logging.apply import apply_state

state = bootstrap(root_level=logging.INFO, rich=True)
state = merge_logger_levels(state, {"my.package": logging.DEBUG})
state = set_root_level(state, logging.DEBUG)
apply_state(state)
```

**Important — handlers are not objects in config:** `bootstrap(..., handlers=...)` and `LoggingState.handlers` follow the standard library’s `logging.config.dictConfig` shape. You pass **handler definitions** (dicts), not live `logging.Handler` instances. Custom handlers are wired with a **`"()": "dotted.import.path.to_callable"`** entry: that string must resolve to a **callable that returns a `logging.Handler`** (often a zero-argument function). At apply time, `dictConfig` imports that callable and invokes it. Closures over module-level state in your package are fine; the constraint is that the config tree itself must stay serializable as plain dicts and strings (so worker processes and `export_config` stay coherent).

Default console handler when you omit `handlers`: colored stderr (`create_colored_level_handler`), or Rich (`create_rich_console_handler`) when `rich=True`.

For step-by-step examples (CLI, Uvicorn, custom handler factories), see [src/pytools/logging/USAGE.md](./src/pytools/logging/USAGE.md).

## pytools.typer

```python
from pytools.typer.utils.get_from_ctx import get_from_ctx
from my_app.models import Config

@app.command()
def run(ctx: typer.Context):
    config = get_from_ctx(ctx, "config", Config)
```

## pytools.debugging

```python
from pytools.debugging.debug_print import debug_print

data = {"status": "success", "meta": [1, 2, 3]}
debug_print(data)
```

## 🛠️ Development

This project uses the `src` layout and `hatchling` backend.

```bash
# Clone and sync environment
git clone https://github.com/your-org/pytools.git
cd pytools
uv sync --all-extras

# Run tests
uv run pytest

```

## 📜 License

MIT © 2026 Buchanan Information Systems Inc.
