Files
breakpilot-core/.claude/AGENTS.python.md
Sharang Parnerkar e3b33ef596
Some checks failed
CI / go-lint (push) Has been cancelled
CI / python-lint (push) Has been cancelled
CI / nodejs-lint (push) Has been cancelled
CI / test-go-consent (push) Has been cancelled
CI / test-python-voice (push) Has been cancelled
CI / test-bqas (push) Has been cancelled
docs: add AGENTS.python/go/typescript.md and pre-push check rules
Mandatory pre-push gates for all three language stacks with exact
commands, common pitfalls, and architecture rules. CLAUDE.md updated
with quick-reference section linking to the new files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 08:35:12 +02:00

4.7 KiB

AGENTS.python.md — Python Agent Rules

Applies to: backend-compliance/, ai-compliance-sdk/ (Python path), compliance-tts-service/, document-crawler/, dsms-gateway/ (Python services)


NON-NEGOTIABLE: Pre-Push Checklist

BEFORE every git push, run ALL of the following from the service directory. A single failure blocks the push.

# 1. Fast lint (Ruff — catches syntax errors, unused imports, style violations)
ruff check .

# 2. Auto-fix safe issues, then re-check
ruff check --fix . && ruff check .

# 3. Type checking (mypy strict on new modules, standard on legacy)
mypy . --ignore-missing-imports --no-error-summary

# 4. Unit tests only (fast, no external deps)
pytest tests/unit/ -x -q --no-header

# 5. Verify the service starts (catches import errors, missing env vars with defaults)
python -c "import app" 2>/dev/null || python -c "import main" 2>/dev/null || true

One-liner pre-push gate (run from service root):

ruff check . && mypy . --ignore-missing-imports --no-error-summary && pytest tests/ -x -q --no-header

Why each check matters

Check Catches Time
ruff check Syntax errors, unused imports, undefined names <2s
mypy Type mismatches, wrong argument types 5-15s
pytest -x Logic errors, regressions 10-60s
import check Missing packages, circular imports <1s

Code Style (Ruff)

Config lives in pyproject.toml. Do not add per-file # noqa suppressions without a comment explaining why.

[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP", "B", "C4", "SIM", "TCH"]
ignore = ["E501"]  # line length handled by formatter

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["S101"]  # assert is fine in tests

Blocked patterns:

  • from module import * — always name imports explicitly
  • Bare except: — use except Exception as e: at minimum
  • print() in production code — use logger
  • Mutable default arguments: def f(x=[])def f(x=None)

Type Annotations

All new functions must have complete type annotations. Use from __future__ import annotations for forward references.

# Required
async def get_tenant(tenant_id: str, db: AsyncSession) -> TenantModel | None:
    ...

# Required for complex types
from typing import Sequence
def list_risks(filters: dict[str, str]) -> Sequence[RiskModel]:
    ...

Mypy rules:

  • --disallow-untyped-defs on new files
  • --strict on new modules (not legacy)
  • Never use type: ignore without a comment

FastAPI-Specific Rules

# Handlers stay thin — delegate to service layer
@router.get("/risks/{risk_id}", response_model=RiskResponse)
async def get_risk(risk_id: UUID, service: RiskService = Depends(get_risk_service)):
    return await service.get(risk_id)   # ≤5 lines per handler

# Always use response_model — never return raw dicts from endpoints
# Always validate input with Pydantic — no manual dict parsing
# Use HTTPException with specific status codes, never bare 500

Testing Requirements

tests/
├── unit/          # Pure logic tests, no DB/HTTP (run on every push)
├── integration/   # Requires running services (run in CI only)
└── contracts/     # OpenAPI snapshot tests (run on API changes)

Unit test requirements:

  • Every new function → at least one happy-path test
  • Every bug fix → regression test that would have caught it
  • Mock all I/O: DB calls, HTTP calls, filesystem reads
# Run unit tests only (fast, for pre-push)
pytest tests/unit/ -x -q

# Run with coverage (for CI)
pytest tests/ --cov=. --cov-report=term-missing --cov-fail-under=70

Dependency Management

# Check new package license before adding
pip show <package> | grep -E "License|Home-page"

# After adding to requirements.txt — verify no GPL/AGPL
pip-licenses --fail-on="GPL;AGPL" 2>/dev/null || echo "Check licenses manually"

Never add:

  • GPL/AGPL licensed packages
  • Packages with known CVEs (pip audit)
  • Packages that only exist for dev (pytest, ruff) to production requirements

Common Pitfalls That Break CI

Pitfall Prevention
const x = ... inside dict literal (wrong language!) Run ruff before push
Pydantic v1 syntax in v2 project Use model_config, not class Config
Sync function called inside async without run_in_executor mypy + async linter
Missing await on coroutine mypy catches this
datetime.utcnow() (deprecated) Use datetime.now(timezone.utc)
Bare except: swallowing errors silently ruff B001/E722 catches this
Unused imports left in committed code ruff F401 catches this