|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +This is a Python development environment template using **uv** (fast Python package manager) and **Ruff** (linter/formatter). The repository serves dual purposes: |
| 8 | +1. A template for starting new Python projects |
| 9 | +2. A reusable `tools/` package with production-ready utilities (Logger, Config, Timer) |
| 10 | + |
| 11 | +## Development Commands |
| 12 | + |
| 13 | +### Package Management |
| 14 | +```bash |
| 15 | +# Install dependencies |
| 16 | +uv sync |
| 17 | + |
| 18 | +# Add new dependency |
| 19 | +uv add <package> |
| 20 | + |
| 21 | +# Add dev dependency |
| 22 | +uv add --dev <package> |
| 23 | + |
| 24 | +# Remove dependency |
| 25 | +uv remove <package> |
| 26 | +``` |
| 27 | + |
| 28 | +### Testing |
| 29 | +```bash |
| 30 | +# Run all tests with coverage (75% minimum required) |
| 31 | +uv run nox -s test |
| 32 | + |
| 33 | +# Run specific test file |
| 34 | +uv run pytest tests/tools/test__logger.py |
| 35 | + |
| 36 | +# Run with JUnit XML output for CI |
| 37 | +uv run nox -s test -- --junitxml=results.xml |
| 38 | + |
| 39 | +# Run pytest directly (bypasses nox) |
| 40 | +uv run pytest |
| 41 | +``` |
| 42 | + |
| 43 | +### Linting & Formatting |
| 44 | +```bash |
| 45 | +# Format code |
| 46 | +uv run nox -s fmt |
| 47 | + |
| 48 | +# Lint with both Pyright and Ruff |
| 49 | +uv run nox -s lint -- --pyright --ruff |
| 50 | + |
| 51 | +# Lint with Pyright only |
| 52 | +uv run nox -s lint -- --pyright |
| 53 | + |
| 54 | +# Lint with Ruff only |
| 55 | +uv run nox -s lint -- --ruff |
| 56 | + |
| 57 | +# Run Ruff directly |
| 58 | +uv run ruff check . --fix |
| 59 | +uv run ruff format . |
| 60 | + |
| 61 | +# Run Pyright directly |
| 62 | +uv run pyright |
| 63 | +``` |
| 64 | + |
| 65 | +### Pre-commit Hooks |
| 66 | +```bash |
| 67 | +# Install hooks |
| 68 | +uv run pre-commit install |
| 69 | + |
| 70 | +# Run all hooks manually |
| 71 | +uv run pre-commit run --all-files |
| 72 | + |
| 73 | +# Run specific hook |
| 74 | +uv run pre-commit run ruff-format |
| 75 | +``` |
| 76 | + |
| 77 | +### Documentation |
| 78 | +```bash |
| 79 | +# Serve docs locally at http://127.0.0.1:8000 |
| 80 | +uv run mkdocs serve |
| 81 | + |
| 82 | +# Build documentation |
| 83 | +uv run mkdocs build |
| 84 | + |
| 85 | +# Deploy to GitHub Pages |
| 86 | +uv run mkdocs gh-deploy |
| 87 | +``` |
| 88 | + |
| 89 | +## Architecture |
| 90 | + |
| 91 | +### Core Modules |
| 92 | + |
| 93 | +The `tools/` package provides three main utility modules: |
| 94 | + |
| 95 | +#### **tools/logger/** - Dual-Mode Logging System |
| 96 | +- `Logger` class extends `logging.Logger` with environment-aware formatting |
| 97 | +- **LogType.LOCAL**: Colored console output via `LocalFormatter` for development |
| 98 | +- **LogType.GOOGLE_CLOUD**: Structured JSON via `GoogleCloudFormatter` for production |
| 99 | +- Key pattern: Use `Settings.IS_LOCAL` to switch between modes automatically |
| 100 | + |
| 101 | +```python |
| 102 | +from tools.config import Settings |
| 103 | +from tools.logger import Logger, LogType |
| 104 | + |
| 105 | +settings = Settings() |
| 106 | +logger = Logger( |
| 107 | + __name__, |
| 108 | + log_type=LogType.LOCAL if settings.IS_LOCAL else LogType.GOOGLE_CLOUD |
| 109 | +) |
| 110 | +``` |
| 111 | + |
| 112 | +#### **tools/config/** - Environment-Based Configuration |
| 113 | +- `Settings` class uses Pydantic for type-safe configuration |
| 114 | +- Loads from `.env` (version controlled) and `.env.local` (local overrides, in .gitignore) |
| 115 | +- `FastAPIKwArgs` provides ready-to-use FastAPI initialization parameters |
| 116 | +- Pattern: Extend `Settings` to add project-specific configuration fields |
| 117 | + |
| 118 | +```python |
| 119 | +from tools.config import Settings |
| 120 | + |
| 121 | +settings = Settings() |
| 122 | +api_url = settings.api_prefix_v1 # Loaded from environment |
| 123 | +``` |
| 124 | + |
| 125 | +#### **tools/tracer/** - Performance Monitoring |
| 126 | +- `Timer` class works as both decorator and context manager |
| 127 | +- Automatically logs execution time in milliseconds at DEBUG level |
| 128 | +- Uses the `Logger` module for output (inherits logging configuration) |
| 129 | +- Pattern: Nest timers to measure both overall and component performance |
| 130 | + |
| 131 | +```python |
| 132 | +from tools.tracer import Timer |
| 133 | + |
| 134 | +@Timer("full_operation") |
| 135 | +def process(): |
| 136 | + with Timer("step1"): |
| 137 | + do_step1() |
| 138 | + with Timer("step2"): |
| 139 | + do_step2() |
| 140 | +``` |
| 141 | + |
| 142 | +### Test Structure |
| 143 | + |
| 144 | +Tests in `tests/tools/` mirror the package structure: |
| 145 | +- **Naming convention**: `test__*.py` (double underscore) |
| 146 | +- **Coverage requirement**: 75% minimum (including branch coverage) |
| 147 | +- **Test files exempt from**: `INP001` (namespace packages), `S101` (assert usage) |
| 148 | + |
| 149 | +### Configuration Philosophy |
| 150 | + |
| 151 | +**Ruff (ruff.toml)**: |
| 152 | +- ALL rules enabled by default with specific exclusions |
| 153 | +- Line length: 88 (Black-compatible) |
| 154 | +- Target Python: 3.14 |
| 155 | +- Per-file ignores for test files |
| 156 | + |
| 157 | +**Pyright (pyrightconfig.json)**: |
| 158 | +- Type checking mode: standard |
| 159 | +- Only includes `tools/` package (not tests) |
| 160 | +- venv: `.venv` |
| 161 | + |
| 162 | +**pytest (pytest.ini)**: |
| 163 | +- Coverage: 75% minimum with branch coverage |
| 164 | +- Reports: HTML + terminal |
| 165 | +- Import mode: importlib |
| 166 | + |
| 167 | +### Nox Task Automation |
| 168 | + |
| 169 | +The `noxfile.py` uses a custom `CLIArgs` parser (Pydantic-based): |
| 170 | +- All sessions use `python=False` (rely on `uv run`) |
| 171 | +- Arguments passed via `-- --flag value` syntax |
| 172 | +- Sessions: `fmt`, `lint`, `test` |
| 173 | + |
| 174 | +Example of the argument parsing pattern: |
| 175 | +```python |
| 176 | +# noxfile.py |
| 177 | +@nox.session(python=False) |
| 178 | +def lint(session: nox.Session) -> None: |
| 179 | + args = CLIArgs.parse(session.posargs) |
| 180 | + if args.pyright: |
| 181 | + session.run("uv", "run", "pyright") |
| 182 | + if args.ruff: |
| 183 | + session.run("uv", "run", "ruff", "check", ".", "--fix") |
| 184 | +``` |
| 185 | + |
| 186 | +## Key Patterns for Development |
| 187 | + |
| 188 | +### Adding New Configuration Fields |
| 189 | + |
| 190 | +Extend the `Settings` class in `tools/config/settings.py`: |
| 191 | + |
| 192 | +```python |
| 193 | +class Settings(BaseSettings): |
| 194 | + # Existing fields... |
| 195 | + |
| 196 | + # Add your new fields |
| 197 | + NEW_SETTING: str = "default_value" |
| 198 | + ANOTHER_SETTING: int = 42 |
| 199 | +``` |
| 200 | + |
| 201 | +Then add to `.env.local`: |
| 202 | +```bash |
| 203 | +NEW_SETTING=custom_value |
| 204 | +ANOTHER_SETTING=100 |
| 205 | +``` |
| 206 | + |
| 207 | +### Adding New Logger Formatters |
| 208 | + |
| 209 | +Create a new formatter in `tools/logger/`: |
| 210 | +1. Extend `logging.Formatter` |
| 211 | +2. Export from `tools/logger/__init__.py` |
| 212 | +3. Update `Logger.__init__()` to support the new type |
| 213 | + |
| 214 | +### Testing Utilities |
| 215 | + |
| 216 | +When testing the utilities themselves: |
| 217 | +- Logger: Capture logs using `assertLogs` context manager |
| 218 | +- Config: Use Pydantic's model instantiation with kwargs to override values |
| 219 | +- Timer: Check debug logs for execution time messages |
| 220 | + |
| 221 | +## Documentation Structure |
| 222 | + |
| 223 | +The `docs/` directory is organized for MkDocs: |
| 224 | +- **docs/index.md**: Main landing page |
| 225 | +- **docs/getting-started/**: Setup guides (Docker, VSCode, Dev Container) |
| 226 | +- **docs/guides/**: Tool usage guides (uv, Ruff, Pyright, pre-commit, tools package) |
| 227 | +- **docs/configurations/**: Detailed configuration references |
| 228 | +- **docs/usecases/**: Real-world examples (Jupyter, FastAPI, OpenCV) |
| 229 | + |
| 230 | +When adding new utilities to `tools/`, add corresponding documentation to `docs/guides/tools/`. |
| 231 | + |
| 232 | +## CI/CD Workflows |
| 233 | + |
| 234 | +GitHub Actions workflows in `.github/workflows/`: |
| 235 | +- **docker.yml**: Validate Docker build |
| 236 | +- **devcontainer.yml**: Validate Dev Container configuration |
| 237 | +- **format.yml**: Check Ruff formatting |
| 238 | +- **lint.yml**: Run Pyright + Ruff linting |
| 239 | +- **test.yml**: Run pytest with coverage |
| 240 | +- **gh-deploy.yml**: Deploy documentation to GitHub Pages |
| 241 | + |
| 242 | +All workflows use the same nox commands as local development. |
| 243 | + |
| 244 | +## Environment Variables |
| 245 | + |
| 246 | +Critical environment variables (set in `.env.local`): |
| 247 | +- `IS_LOCAL`: Boolean flag for local vs production (affects logging, configuration) |
| 248 | +- `DEBUG`: Boolean for debug mode |
| 249 | +- FastAPI settings: `TITLE`, `VERSION`, `API_PREFIX_V1`, etc. |
| 250 | + |
| 251 | +## Important Notes |
| 252 | + |
| 253 | +- **Coverage is enforced**: Tests must maintain 75% coverage (configured in pytest.ini) |
| 254 | +- **uv replaces pip/poetry**: Use `uv add` not `pip install`, use `uv.lock` not `requirements.txt` |
| 255 | +- **Ruff replaces multiple tools**: No need for Black, isort, Flake8, etc. |
| 256 | +- **nox is the task runner**: Prefer `uv run nox -s <session>` over direct tool calls |
| 257 | +- **Test naming**: Use `test__*.py` pattern (double underscore) |
| 258 | +- **Type checking targets tools/ only**: Pyright only checks the `tools/` package, not tests |
| 259 | + |
| 260 | +## Template Usage Pattern |
| 261 | + |
| 262 | +When using this as a template for a new project: |
| 263 | +1. Update `pyproject.toml` with new project name/description |
| 264 | +2. Modify or extend `tools/config/settings.py` for project-specific configuration |
| 265 | +3. Use the utilities from `tools/` or remove if not needed |
| 266 | +4. Update `.env` with base configuration, `.env.local` with local overrides |
| 267 | +5. Customize Ruff rules in `ruff.toml` if needed (but start with defaults) |
0 commit comments