This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
- The data returned from Metrc collection API endpoints may slightly change over time. Extra fields may be added. Don't write python classes that assume an exact data shape, they should fall back gracefully.
This project uses uv for Python package management:
# Create virtual environment and install dependencies
uv venv
source .venv/bin/activate
uv pip install -e .[dev]# Testing
pytest # Run all tests
pytest tests/specific/ # Run specific test directory
# Type checking
mypy t3api_utils tests # Type check source and tests
# Type generation (if needed)
python bin/generate_types.py # Update TypedDict definitions from OpenAPI spec
# Documentation
mkdocs serve # Local preview at http://127.0.0.1:8000
mkdocs build # Build static site to site/
mkdocs gh-deploy # Deploy to GitHub PagesThe t3api_utils package is organized into focused modules:
auth/- Authentication utilities for T3 API credentials and client creationapi/- httpx-based T3 API client with async support and enhanced featuresdb/- Database utilities using DuckDB for data processing and table creationfile/- File I/O operations including CSV/JSON serializationhttp/- HTTP utilities using httpx with retry policies and rate limitingmain/- Main utility functions that orchestrate other modules
HasData[T]- Protocol for objects with adataattribute containing listsSerializableObject- Protocol for objects withindex,license_number, andto_dict()methodT3Credentials- Authentication credentials interfacePaginatedResponse[T]- Protocol for paginated API responses
- Authentication (
auth/) - Create authenticated httpx-based API clients - Collection (
api/) - Enhanced parallel data fetching with rate limiting - Processing (
db/) - Flatten nested data and create relational tables - Output (
file/) - Export to CSV/JSON formats
- httpx >= 0.25.0 - HTTP client with async support
- DuckDB + PyArrow - High-performance data operations
- Typer + Rich - CLI interfaces with purple-themed output
- MyPy - Strict typing enforced with
disallow_untyped_defs
from t3api_utils.main.utils import get_authenticated_client_or_error
# Shows interactive picker with authentication options
client = get_authenticated_client_or_error()Picker Features:
- Rich table display with consistent purple styling
- Clear descriptions for each authentication method
- Input validation and keyboard interrupt handling
- Automatic routing to appropriate auth flow
Credentials Authentication:
client = create_credentials_authenticated_client_or_error(
hostname="...",
username="...",
password="..."
)- Interactive prompts for hostname, username, password
- Automatic credential saving to
.t3.envfile - Environment variable support for automation
JWT Token Authentication:
# Basic JWT authentication
client = get_jwt_authenticated_client_or_error(jwt_token="your_jwt_token_here")
# JWT with validation (recommended)
client = get_jwt_authenticated_client_or_error_with_validation(jwt_token="your_jwt_token_here")- Automatic token validation via
/v2/auth/whoamiendpoint - Clear error messages for expired/invalid tokens
- Automatic client cleanup on validation failure
The interfaces/ directory contains auto-generated TypedDict definitions from the OpenAPI specification:
# Import specific types
from interfaces import MetrcLicense, MetrcPackage, SearchResponse
# Use in type annotations
def process_licenses(licenses: List[MetrcLicense]) -> None:
for license in licenses:
print(license["licenseName"]) # Full type safety with dict accessBenefits:
- Always up-to-date from live OpenAPI spec
- Complete API schema coverage
- Full MyPy support with TypedDict
- Flexible handling of optional fields with
NotRequired[]
Unit test coverage should be 100%
Primary Purple Theme:
primary-#8B5CF6(Violet-500) - Headers, titles, primary actionsaccent-#A855F7(Purple-500) - Highlights, emphasis, interactive elementsmuted-#C4B5FD(Violet-300) - Secondary text, subdued informationbright-#DDD6FE(Violet-200) - Backgrounds, subtle highlights
Status Colors:
success-#10B981(Emerald-500) - Success messages, completed actionserror-#EF4444(Red-500) - Error messages, failureswarning-#F59E0B(Amber-500) - Warnings, cautionsinfo-#6366F1(Indigo-500) - Information, help text
Message Types:
# Success, Error, Warning, Info, Progress
console.print("[bold green]✓[/bold green] Operation completed successfully")
console.print("[bold red]✗[/bold red] Operation failed: {error_message}")
console.print("[bold yellow]⚠[/bold yellow] Warning: {warning_message}")
console.print("[bold blue]ℹ[/bold blue] {info_message}")
console.print("[bold magenta]⋯[/bold magenta] {status_message}")Headers and Structure:
# Main headers, section headers, sub-headers
console.print("[bold magenta]═══ {title} ═══[/bold magenta]")
console.print("[bold bright_magenta]── {section_name} ──[/bold bright_magenta]")
console.print("[magenta]{sub_header}:[/magenta]")Interactive Elements:
# Tables, prompts, file paths
table = Table(border_style="magenta", header_style="bold magenta")
user_input = typer.prompt("[magenta]Enter your choice[/magenta]")
console.print(f"[cyan]{file_path}[/cyan]")Centralized Styling:
- Use
t3api_utils.stylemodule for all styling constants - Import styled console:
from t3api_utils.style import console, style - Never use plain
print()- always use Rich console
Consistency Rules:
- All success messages use green with checkmark:
[bold green]✓[/bold green] - All error messages use red with X mark:
[bold red]✗[/bold red] - All progress/status use purple with dots:
[bold magenta]⋯[/bold magenta] - All headers use magenta with decorative borders
Accessibility:
- Always include symbols (✓, ✗, ⚠, ℹ, ⋯) alongside colors
- Use
boldfor important messages to improve readability - Maintain good contrast ratios
All selection interfaces should use consistent Rich Table formatting:
Standard Implementation:
from rich.table import Table
from t3api_utils.style import console
def pick_something(items: List[SomeType]) -> SomeType:
"""Standard picker implementation."""
table = Table(title="Available Items", border_style="magenta", header_style="bold magenta")
table.add_column("#", style="magenta", justify="right")
table.add_column("Name", style="bright_white")
table.add_column("Details", style="cyan") # Optional third column
for i, item in enumerate(items, 1):
table.add_row(str(i), item.name, item.details)
console.print(table)
choice = typer.prompt("Select item (number)", type=int)
# ... validation and return logicRequirements:
- Rich Table with magenta border styling
- Numbered selection column with
style="magenta", justify="right" - Primary content column with
style="bright_white" - Optional details column with
style="cyan" - Always validate user input range
- Always handle keyboard interruption gracefully
Examples in Codebase:
pick_license()int3api_utils/main/utils.pypick_file()int3api_utils/main/utils.pypick_collection()int3api_utils/openapi/collection_picker.pyinteractive_collection_handler()int3api_utils/main/utils.py