Estándares Python
Esta habilidad es la fuente de verdad para las herramientas Python y las reglas entre proyectos. Las habilidades de arquitectura, estilo, pruebas y revisión deben referenciarla en lugar de repetirla.
Para la prosa del proyecto, cargue también escritura-técnica. Esta invoca al humanizador y es dueña de la ubicación del documento, marcas de tiempo, metadatos de revisión, accesibilidad y calidad de escritura.
Precedencia de reglas
Aplique las reglas en este orden:
- Requisitos explícitos del usuario o la organización
- Configuración del repositorio y decisiones de arquitectura aceptadas
- Esta habilidad y las otras habilidades Python
- PEP 8 y valores predeterminados de las herramientas
No debilite el piso de seguridad en silencio. Registre una excepción requerida, su alcance, riesgo, propietario cuando se conozca y condición de eliminación en el registro de decisiones del proyecto.
Entorno en tiempo de ejecución y estructura
- Apunte a Python 3.11 o más reciente. Respete un repositorio que apunte a una versión más nueva.
- Use
from __future__ import annotationscuando mejore la compatibilidad hacia adelante o resuelva el orden de las anotaciones. No lo agregue mecánicamente a archivos que no lo necesiten. - Prefiera una estructura
src/para paquetes distribuibles nuevos. - Mantenga los metadatos del proyecto y la configuración de herramientas compatible en
pyproject.toml. - Use
uvpara entornos, resolución de dependencias, bloqueo y ejecución de comandos.
Cadena de herramientas compatible
| Propósito | Predeterminado | Uso requerido |
|---|---|---|
| Formato y linting | Ruff | Todos los proyectos mantenidos |
| Verificación de tipos | mypy estricto | Paquetes de producción y APIs públicas |
| Pruebas y cobertura | pytest, pytest-cov, coverage.py | Todos los cambios de comportamiento |
| Linting de seguridad | Reglas S de Ruff y Bandit | Paquetes de producción |
| SAST | Semgrep con reglas del repositorio | CI para productos mantenidos |
| Auditoría de dependencias | pip-audit | CI y comprobaciones de lanzamiento |
| Registro estructurado | structlog | Aplicaciones y servicios |
| Trazabilidad | OpenTelemetry | Servicios en red y pipelines trazados |
| Gestión de paquetes | uv | Todos los proyectos |
| Hooks de Git | pre-commit | Repositorios mantenidos |
| Entrega de secretos | Infisical por defecto de la organización | Cargas de trabajo que usan secretos |
Una decisión de arquitectura aceptada puede seleccionar un proveedor equivalente u omitir una herramienta operativa que no se ajuste a una pequeña biblioteca local o script. Ruff, el tipado, las pruebas y el manejo seguro de dependencias siguen siendo la línea base.
Las herramientas experimentales, incluidos los escáneres de vulnerabilidades basados en modelos y los revisores de IA, son consultivos. No deben ser puntos de control obligatorios hasta que el equipo defina una versión compatible, comando, política de fallos y propietario.
Política de dependencias y versiones
- Declare rangos de ejecución compatibles en
pyproject.toml. - Confirme
uv.lockpara aplicaciones y entornos de desarrollo reproducibles. El archivo de bloqueo es dueño de las versiones exactas resueltas. - Para bibliotecas publicadas, declare límites inferiores honestos, pruebe las versiones de Python compatibles y los límites inferiores importantes, y no confíe en el archivo de bloqueo como contrato del consumidor.
- Coloque las herramientas de calidad y prueba en grupos de dependencias con nombre.
- Ejecute los comandos de calidad a través del entorno uv bloqueado. No mantenga un segundo conjunto de versiones de herramientas Python en pre-commit.
- Actualice intencionalmente con
uv lock --upgrade-package <nombre>o una actualización completa revisada del bloqueo.
Auditoría de dependencias canónica para un proyecto uv:
archivo_requisitos="$(mktemp)"
trap 'rm -f "$archivo_requisitos"' EXIT
uv export \
--frozen \
--no-dev \
--no-emit-project \
--no-hashes \
--format requirements.txt \
--output-file "$archivo_requisitos"
uv run --frozen pip-audit \
--strict \
--no-deps \
--requirement "$archivo_requisitos"
La exportación audita las dependencias de ejecución exactas bloqueadas sin pedirle a pip-audit que resuelva un segundo grafo. El descubrimiento de proyectos actual de pip-audit --locked soporta pyproject.toml y pylock.*.toml, no uv.lock, por lo que no use pip-audit --locked . como una auditoría uv.
pip-audit debe estar presente en el grupo de dependencias de calidad. Una exención de vulnerabilidad debe nombrar el aviso, el alcance afectado, el control compensatorio, el propietario cuando se conozca y la fecha de vencimiento o revisión.
Comandos de calidad canónicos
Adapte las rutas de los paquetes al repositorio, pero mantenga una fuente de comandos para uso local y CI:
uv sync --frozen
uv run --frozen ruff check .
uv run --frozen ruff format --check .
uv run --frozen mypy <raíces-del-paquete>
uv run --frozen bandit -c pyproject.toml -r <raíces-del-paquete>
uv run --frozen semgrep scan --config .semgrep.yml <raíces-del-paquete>
uv run --frozen pytest
# Ejecute la auditoría de dependencias de bloqueo exportado canónica anterior.
CI registra el comando y el resultado. Una herramienta o configuración faltante es no disponible, no un pase.
Propiedad de pre-commit
Fije los hooks de higiene no Python por lanzamiento. Invoque las herramientas de calidad Python como hooks locales a través de uv run --frozen, para que los hooks locales y CI usen las versiones exactas en uv.lock.
repos:
- repo: local
hooks:
- id: ruff-check
name: ruff check
entry: uv run --frozen ruff check --fix
language: system
types_or: [python, pyi]
- id: ruff-format
name: ruff format
entry: uv run --frozen ruff format
language: system
types_or: [python, pyi]
- id: mypy
name: mypy
entry: uv run --frozen mypy
language: system
pass_filenames: false
args: [<raíces-del-paquete>]
Ejecute Bandit, Semgrep, pruebas y auditoría de dependencias en CI. Agréguelos a pre-commit solo cuando su latencia y dependencias se ajusten al repositorio.
Decisiones mínimas de pyproject.toml
Use los nombres y raíces de los paquetes del repositorio en lugar de copiar marcadores de posición.
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "B", "S", "UP", "C4", "SIM", "RUF", "D"]
ignore = ["E501"]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = false
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-ra --strict-markers --tb=short --import-mode=importlib"
[tool.coverage.run]
branch = true
source_pkgs = ["tu_paquete"]
[tool.coverage.report]
fail_under = 80
show_missing = true
[tool.bandit]
exclude_dirs = ["tests"]
skips = ["B101"]
Documente cada ignorado con un alcance y razón estrechos. Prefiera ignorados por archivo sobre ignorados globales.
Contrato de registro estructurado
Las aplicaciones emiten estos campos. Las bibliotecas pueden usar la fachada de registro de la aplicación anfitriona y no deben configurar manejadores globales al importar.
| Campo | Requisito | Significado |
|---|---|---|
timestamp | Siempre | ISO 8601 UTC |
level | Siempre | DEBUG, INFO, WARNING, ERROR o CRITICAL |
event | Siempre | Nombre de evento estable en snake_case |
service | Siempre para aplicaciones | Nombre del servicio o aplicación |
trace_id | Cuando existe una traza | ID de traza de OpenTelemetry |
span_id | Cuando existe un span | ID de span de OpenTelemetry |
error | En fallos | Tipo de excepción y mensaje seguros |
duration_ms | En operaciones medidas | Milisegundos transcurridos |
Los procesadores de nivel de structlog comúnmente reciben nombres de métodos en minúsculas. Normalice después de agregar el nivel:
from typing import Any
import structlog
def nivel_log_mayusculas(
_logger: Any,
_method_name: str,
event_dict: dict[str, Any],
) -> dict[str, Any]:
"""Normaliza el nivel de log estructurado al esquema compartido."""
level = event_dict.get("level")
if isinstance(level, str):
event_dict["level"] = level.upper()
return event_dict
processors = [
structlog.processors.add_log_level,
nivel_log_mayusculas,
structlog.processors.TimeStamper(fmt="iso", utc=True),
]
Pruebe el evento final renderizado, no solo el procesador de forma aislada.
Piso de seguridad
Nunca:
- confirmar o hardcodear credenciales, tokens, claves privadas o valores secretos reales
- almacenar secretos reales en
.envo archivos TOML - registrar secretos, tokens de acceso, datos personales sensibles o cuerpos de solicitud sin restricciones
- interpolar valores externos en SQL
- usar
shell=Truecon entrada externa o variable - deserializar datos pickle no confiables
- ejecutar entrada no confiable con
eval,execocompile - usar argumentos predeterminados mutables
- usar importaciones comodín excepto una reexportación pública documentada
- descartar silenciosamente un valor de retorno o excepción sensible a la seguridad
- usar un
except:desnudo
Atrape Exception solo en un límite de proceso, worker, tarea o framework donde el manejador registre de forma segura y luego vuelva a lanzar, mapee el fallo a un estado de salida o devuelva un error de protocolo definido. Atrape excepciones específicas dentro de la lógica de la aplicación.
Almacene configuraciones ordinarias y referencias a secretos en archivos de configuración. Entregue valores secretos al inicio a través de inyección de Infisical o un equivalente aprobado. Valide la configuración requerida antes de aceptar trabajo.