best-practices-python
Repo-specific Python best practices for agentic coding: Loguru + Typer + uv + pyproject.toml, httpx over requests, functions-first, module docstrings, max 800 LOC per file, and non-mocked sanity tests.
- License 许可
- MIT
- 最近更新
- 2026-06-13
- Stars
- ★ 0
- Forks
- 2
01 前言 Front Matter
- name
- best-practices-python
- license
- MIT
- composes
- [ "task-monitor" ]
- metadata
- { "defaults": { "cli": "typer", "http": "httpx", "style": { "module_docstring": "required", "max_lines_per_file": 800, "functions_over_classes": true }, "logging": "loguru", "testing": { "include_sanity_tests": true }, "packaging": "uv + pyproject.toml" }, "language": "python", "python_versions": [ "3.11+", "3.12+" ] }
- provides
- [ "best-practices-python" ]
- triggers
- [ "best practices python", "python conventions", "loguru", "typer", "httpx", "python code review" ]
- description
- Repo-specific Python best practices for agentic coding: Loguru + Typer + uv + pyproject.toml, httpx over requests, functions-first, module docstrings, max 800 LOC per file, and non-mocked sanity tests.
02 资源文件 58
- 参考文档AGENTS.md37.7 KB
- 脚本analyze_packages.py6.8 KB
- 资产文件assets/pyproject.snippet.toml356 B
- 资产文件assets/ruff-docstrings-hint.toml253 B
- 参考文档docs/AGENTS.md37.7 KB
- 参考文档docs/PACKAGES.md7.3 KB
- 参考文档docs/README.md1.1 KB
- 参考文档docs/research/01_IDEA.md1.4 KB
- 其他pyproject.toml317 B
- 参考文档rules/_sections.md1.1 KB
- 参考文档rules/_template.md334 B
- 参考文档rules/async-limit-concurrency.md664 B
- 参考文档rules/async-no-blocking-in-event-loop.md1.8 KB
- 参考文档rules/async-prefer-asyncclient.md651 B
- 参考文档rules/async-single-asyncio-run.md1.9 KB
- 参考文档rules/async-timeouts-cancellation.md548 B
- 参考文档rules/conventions-dotenv-required.md2.7 KB
- 参考文档rules/conventions-functions-over-classes.md744 B
- 参考文档rules/conventions-httpx.md623 B
- 参考文档rules/conventions-loguru.md2.4 KB
- 参考文档rules/conventions-module-docstring-required.md689 B
- 参考文档rules/conventions-no-print.md433 B
- 参考文档rules/conventions-typer-cli.md694 B
- 参考文档rules/conventions-uv-pyproject.md536 B
- 参考文档rules/correctness-avoid-mutable-defaults.md528 B
- 参考文档rules/correctness-guard-invariants.md515 B
- 参考文档rules/correctness-no-bare-except.md650 B
- 参考文档rules/correctness-no-implicit-global-state.md532 B
- 参考文档rules/correctness-no-placeholder-error-handling.md3.8 KB
- 参考文档rules/correctness-raise-from.md528 B
- 参考文档rules/correctness-return-types.md659 B
- 参考文档rules/logging-bind-context.md462 B
- 参考文档rules/logging-no-giant-payloads.md503 B
- 参考文档rules/logging-use-exception.md563 B
- 参考文档rules/packaging-pin-major-deps.md410 B
- 参考文档rules/packaging-pyproject-central.md475 B
- 参考文档rules/packaging-uv-lockfile.md432 B
- 参考文档rules/perf-avoid-n2.md642 B
- 参考文档rules/perf-cache-pure.md603 B
- 参考文档rules/perf-stream-large-files.md532 B
- 参考文档rules/security-no-eval-exec.md598 B
- 参考文档rules/security-no-shell-true.md520 B
- 参考文档rules/security-redact-secrets.md493 B
- 参考文档rules/security-validate-untrusted-input.md549 B
- 参考文档rules/security-xml-safe-parsing.md473 B
- 参考文档rules/style-max-800-lines.md2.2 KB
- 参考文档rules/style-module-docstring.md2.1 KB
- 参考文档rules/style-pathlib.md411 B
- 参考文档rules/style-small-functions.md563 B
- 参考文档rules/testing-arrange-act-assert.md520 B
- 参考文档rules/testing-deterministic-time.md553 B
- 参考文档rules/testing-no-network-by-default.md571 B
- 参考文档rules/testing-non-mocked-sanity.md693 B
- 参考文档rules/testing-sanity-fixtures.md598 B
- 脚本sanity.sh2.2 KB
- 脚本sanity/lint_dotenv.sh3.6 KB
- 脚本scripts/check_file_limits.py1.1 KB
- 脚本scripts/compile_agents.py1.8 KB
03 SKILL.md 正文
Python Best Practices (Project Skill)
This skill is a curated set of atomic rules for writing and refactoring Python in this repo.
Project Defaults (apply unless explicitly overridden)
- Logging: Loguru (
from loguru import logger) - CLI: Typer (thin CLI; logic in functions)
- HTTP: httpx (not requests)
- Packaging: uv + pyproject.toml
- Structure: functions over classes unless state is required
- Files: no Python file over 800 lines
- Docs: every module begins with a clear module docstring describing purpose, inputs, outputs, and failure modes
- Tests: include non-mocked sanity tests in addition to unit tests
Package Reference
See PACKAGES.md for the full Python package reference — mandatory standards, standard toolkit (80+ packages across 15 categories), and anti-patterns. Generated from 1,414 pyproject.toml files. Also available via /memory recall "python packages".
When to Apply
Use this skill whenever you:
- create or refactor Python modules, CLIs, services, or pipelines
- add network calls, subprocess calls, or IO
- change packaging/tooling (uv, pyproject)
- add tests or fix bugs/flakiness
Categories (priority order)
- Correctness (CRITICAL/HIGH):
correctness- - Security (CRITICAL/HIGH):
security- - Conventions (HIGH):
conventions- - Testing & Sanity (HIGH/MEDIUM):
testing- - Async & Concurrency (HIGH/MEDIUM):
async- - Performance (MEDIUM):
perf- - Packaging (MEDIUM):
packaging- - Logging & Observability (MEDIUM):
logging- - Style & Maintainability (MEDIUM/LOW):
style-
Quick Reference (house rules)
style-max-800-linesstyle-module-docstringstyle-thin-init-pyconventions-loguruconventions-typer-cliconventions-httpxconventions-uv-pyprojectconventions-functions-over-classesconventions-pyproject-deps-completetesting-non-mocked-sanity
Thin __init__.py in Packages (NON-NEGOTIABLE)
__init__.py files must contain only re-exports and package metadata — never business logic.
Rule: style-thin-init-py
When logic is hidden in __init__.py, agents (and humans) searching for module_name.py won't find it. This causes misdiagnosis — an agent sees from probes import run_probes, looks for probes.py, doesn't find it, and concludes the module is missing. The logic is actually in probes/__init__.py but invisible to file-based search.
Correct pattern:
mypackage/
__init__.py # Only re-exports: from .registry import run_probes, ProbeResult
registry.py # Actual logic lives here (discoverable by name)
tier0.py
tier1.py
Anti-pattern:
mypackage/
__init__.py # 120 lines of logic, registries, runner functions
tier0.py
tier1.py
What belongs in __init__.py:
__all__list- Re-exports:
from .submodule import ClassName - Package-level constants (version, etc.)
- Max ~20 lines
What does NOT belong:
- Functions with business logic
- Class definitions with methods
- Registry patterns (register/lookup)
- Anything an agent would look for by name
Incident: On 2026-03-16, an agent misdiagnosed monitor-taxonomy as broken ("missing probes.py glue module") because run_probes() lived in probes/__init__.py (122 lines) instead of a named module. The code worked fine — but was invisible to agents doing file-based search.
pyproject.toml Dependency Completeness (NON-NEGOTIABLE)
Every import in a skill's .py files MUST have a corresponding entry in pyproject.toml [project.dependencies].
This is a hard gate. Missing dependencies cause ModuleNotFoundError at runtime after uv sync in a clean venv — a silent regression that only surfaces when the skill is invoked by another agent or in CI.
Rule: conventions-pyproject-deps-complete
When creating or modifying a Python skill with a pyproject.toml:
- Scan all
.pyfiles in the skill forimportandfrom X importstatements - Cross-reference each top-level import against
[project.dependencies] - Add any missing third-party packages to dependencies
- Run
uv syncafter adding to verify resolution
Common offenders (imports that look stdlib but aren't)
| Import | Package needed in pyproject.toml |
|---|---|
from loguru import logger |
loguru>=0.7.0 |
import typer |
typer>=0.9.0 |
import httpx |
httpx>=0.24.0 |
from rich import ... |
rich>=13.0.0 |
import pydantic |
pydantic>=2.0 |
from dotenv import ... |
python-dotenv>=1.0.0 |
import pytz |
pytz |
import tenacity |
tenacity>=8.0 |
Verification pattern
# After any pyproject.toml change:
cd /path/to/skill && uv sync && uv run python -c "import <every_module>"
Why this matters
The ops-chutes skill broke (Feb 2026) because loguru was imported by 3 files but
missing from pyproject.toml. After uv sync recreated the venv, loguru vanished
and every downstream skill that called ops-chutes got ModuleNotFoundError. This was
a silent regression — the skill worked in the shared system venv but failed in isolation.
uv Isolation in run.sh (NON-NEGOTIABLE)
If a skill has pyproject.toml, ALL Python invocations in run.sh MUST use uv run --project "$SCRIPT_DIR" python — never bare python3.
Rule: conventions-uv-run-in-runsh
Bare python3 uses the system Python, which picks up stale packages from ~/.local/lib/python3.12/site-packages/. The skill's .venv (managed by uv sync) has the correct pinned versions. Using bare python3 bypasses it entirely.
The alias python3='uv run ...' pattern is acceptable IF shopt -s expand_aliases is set at the top of run.sh. But aliases do NOT expand inside nohup, env, xargs, or $() — those contexts MUST use explicit uv run --project.
Incident: 2026-03-17 — /orchestrate failed with anyio version mismatch because run.sh called bare python3 structured_execute.py. System python3 had anyio 3.x from ~/.local/, but httpx 0.28+ requires anyio 4.x which was only in the skill's .venv.
Correct:
uv run --project "$SCRIPT_DIR" python "$SCRIPT_DIR/structured_execute.py" run plan.yaml
Wrong:
python3 "$SCRIPT_DIR/structured_execute.py" run plan.yaml # system python, wrong deps
nohup python3 "$SCRIPT_DIR/worker.py" & # alias doesn't expand in nohup
Common Mistakes
WRONG: Using import logging instead of loguru
import logging
logger = logging.getLogger(__name__)
RIGHT: Always use loguru
from loguru import logger
WRONG: Using import requests for HTTP calls
import requests
resp = requests.get("https://api.example.com")
RIGHT: Use httpx
import httpx
resp = httpx.get("https://api.example.com")
WRONG: Using bare python3 in run.sh when pyproject.toml exists
python3 "$SCRIPT_DIR/main.py"
RIGHT: Use uv run for proper dependency isolation
uv run --project "$SCRIPT_DIR" python "$SCRIPT_DIR/main.py"
WRONG: Missing dependency in pyproject.toml that the code imports
from loguru import logger # imported but not in pyproject.toml dependencies
RIGHT: Every import has a matching pyproject.toml entry
[project]
dependencies = ["loguru>=0.7.0"]
Docker Skills Must Have docker-compose.yml
If a skill launches a persistent Docker container (docker run -d), it MUST have a docker-compose.yml.
Rule: conventions-docker-compose
Container specs buried in docker run flags across 10+ lines of shell are:
- Unreadable by agents (who has to grep run.sh to understand the container config)
- Error-prone (one missing flag = broken container)
- Non-declarative (can't diff container changes across commits)
The compose file is the canonical spec. run.sh handles dynamic lifecycle (port allocation, multi-instance, health checks) on top of it.
Enforced by: /skills-ci scanner runtime.docker_no_compose
No Silent Fallbacks in Exception Handlers (NON-NEGOTIABLE)
Every except block MUST log at logger.error, NOT logger.debug. logger.debug is invisible in production — failures silently disappear.
Rule: correctness-no-silent-fallback
# WRONG — silent in production, hides failures
except Exception as exc:
logger.debug("search failed: {}", exc)
return []
# WRONG — bare except with no logging at all
except Exception:
pass
# RIGHT — visible in production logs
except Exception as exc:
logger.error("search failed: {}", exc)
return []
Exceptions:
dotenvimports at module top (line 1-10) — genuinely optional- Optional dependency imports (
sentence_transformers,torch) — log at WARNING - Health check retry loops —
continueis acceptable
Everything else MUST use logger.error. This includes:
- ArangoDB queries, view searches, collection operations
- Embedding service calls
- Entity extraction, taxonomy lookups
- Graph traversal, relationship scoring
- Edge creation, document upserts
Cross-ref: /best-practices-arangodb rule arango-no-silent-fallback.
Enforced by: /monitor-codebase scanner and /codex review gate.
No sync subprocess in async code
If a Python file uses asyncio, it MUST NOT import subprocess or call subprocess.run(). Use asyncio.create_subprocess_exec() or asyncio.create_subprocess_shell() instead.
Rule: async-no-sync-subprocess
Sync subprocess.run() blocks the entire event loop. In an async executor, this freezes ALL concurrent tasks — cancel signals, watchdog polling, other lanes — until the subprocess finishes.
Correct:
proc = await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
Wrong:
result = subprocess.run(cmd, capture_output=True) # blocks event loop
04 同仓库更多 Skills
best-practices-streamdeck
Project-specific best practices for the Stream Deck control suite: icon format constraints, socket vs config boundaries, widget button lifecycle, page creation via build_page, ArangoDB fallback patterns, and NVIS palette compliance.
best-practices-scillm
Error recovery and anti-patterns for scillm LLM proxy. Load this when scillm calls fail, timeout, or return unexpected results. Covers batch sizing, header requirements, model selection, and debugging workflow.
best-practices-rust
Repo-specific Rust best practices for agentic coding: thiserror + anyhow error handling, tokio async runtime, tracing for observability, clap for CLI, axum for HTTP, serde patterns, cargo workspace conventions, ownership and lifetimes, and idiomatic Rust 2024 edition patterns.
react-native-skills
React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.
react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
composition-patterns
React composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.