Python Development Standards
<metadata>- Load if: Python code, pytest, virtual env
- Prerequisites: @smith-principles/SKILL.md, @smith-standards/SKILL.md
CRITICAL (Primacy Zone)
<forbidden>- NEVER use relative imports (
from .module import) - NEVER use inline imports within functions
- NEVER use unittest-style TestCase classes
- NEVER use pytest class-based tests (
class TestFoo:) - NEVER execute pytest without virtual env runner (missing .env vars)
- NEVER execute directly:
.venv/bin/python -m pytest - NEVER mix package managers in same project
- NEVER use %-style formatting in log messages (use
extra=parameter for structured logging) - NEVER add
# noqato silence ruff/flake8 without meeting exception criteria in@smith-validation/SKILL.md - NEVER rename to
_prefix to suppress F841 unused-variable
- ALWAYS use absolute imports (
from package.module import) - ALWAYS use type hints for all function signatures
- ALWAYS use function-based tests:
def test_should_<action>_when_<condition>(): - ALWAYS use virtual env runner:
poetry runoruv run - ALWAYS use structured logging with
extra=parameter for all log data - ALWAYS prefer moderate defaults for enum parameters (e.g., "medium" not "low"/"high" unless spec requires)
- When refactoring, preserve existing parameter values and model references unless change is requested
Import Organization
- stdlib:
import os, sys - third-party:
import pytest - local:
from package.module import
Type Hints
# Python 3.10+ built-in syntax (preferred)
def process_docs(docs: list[str], max_count: int | None = None) -> bool:
pass
# Python 3.9 compatibility: use __future__ annotations
from __future__ import annotations
Testing with Pytest
# Function-based tests (required pattern)
def test_should_parse_pdf_when_valid_file_provided():
result = parse_pdf("valid.pdf")
assert result.success == True
# OK: Helper classes for test data (not test cases)
class TestDataBuilder:
@staticmethod
def create_valid_input() -> dict:
return {"key": "value"}
Environment Variables
import os
from pydantic_settings import BaseSettings
# Simple access
api_key = os.getenv("API_KEY", "default")
# Pydantic settings (preferred)
class Settings(BaseSettings):
api_key: str
timeout: int = 30
class Config:
env_file = ".env"
# CRITICAL: Set BEFORE importing library
os.environ["LIBRARY_CONFIG"] = "value"
import library # Now sees config
Common Patterns
- Error handling: Catch specific exceptions, log, re-raise
- Logging:
logger = logging.getLogger(__name__) - Dataclasses: Use
@dataclass(frozen=True)for immutable config
Claude Code LSP (Experimental)
<context>LSP plugins exist but are currently broken (race condition in initialization):
pyright-lsp@claude-plugins-official
When fixed, LSP provides: goToDefinition, findReferences, hover, documentSymbol, getDiagnostics
Workaround: Use Serena MCP for language server features (find_symbol, find_referencing_symbols)
- @smith-principles/SKILL.md - Core principles
- @smith-standards/SKILL.md - Universal coding standards
@smith-tests/SKILL.md- Testing standards (pytest patterns)@smith-dev/SKILL.md- Development workflow@smith-serena/SKILL.md- Serena MCP for language server features
ACTION (Recency Zone)
Before commit (Poetry):
poetry run ruff check --fix
poetry run ruff format
poetry run pytest
Before commit (uv):
uv run ruff check --fix
uv run ruff format
uv run pytest
Package management:
- Poetry:
poetry install,poetry add <pkg>,poetry remove <pkg> - uv:
uv sync,uv add <pkg>,uv remove <pkg>