Skip to content

buchanan-solutions/pytools

Repository files navigation

🛠️ 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.

# 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:

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.

pytools.typer

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

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.

# 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.

About

A modular collection of Python utilities for high devEx baed on UV

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors