Convenciones de Código Python¶
Type Hints (OBLIGATORIO)¶
from returns.result import Result
def extract_text(file_path: str, language: str = "spa") -> Result[str, OCRError]:
"""Extrae texto de PDF.
Args:
file_path: Ruta absoluta
language: Código ISO (default: spa)
Returns:
Result con texto extraído o OCRError
"""
Naming¶
| Elemento | Convención | Ejemplo |
|---|---|---|
| Clases | PascalCase | DocumentRepository |
| Funciones | snake_case | extract_entities() |
| Constantes | UPPER_SNAKE | OCR_TIMEOUT_SECONDS = 300 |
| Privadas | _prefijo | _normalize_text() |
| Enums | StrEnum | class DocumentType(StrEnum) |
| Booleans | is_/has_/can_ | is_valid, has_duplicates |
Inmutabilidad¶
@dataclass(frozen=True)
class ProcessDocumentRequest:
file_path: str
document_type: DocumentType = DocumentType.TUTELA
Todos los DTOs y value objects usan frozen=True.
Railway-Oriented Programming¶
from returns.result import Result, Success, Failure
# Composición fluida
result = (
process_ocr(file_path)
.bind(validate_text)
.bind(extract_entities)
.bind(detect_duplicates)
.map(build_document)
)
match result:
case Success(doc): save(doc)
case Failure(error): log_and_alert(error)
Nunca anidar try/except. Usar Result para errores de negocio.
Commits¶
Formato: <tipo>(<alcance>): <descripción en español>
Tipos: feat, fix, docs, refactor, test, chore, perf
# ✅ BUENO
git commit -m "feat(ocr): agregar fallback automático a PaddleOCR"
# ❌ MALO — No incluir firma de Claude
git commit -m "feat: add feature
Co-Authored-By: Claude <noreply@anthropic.com>"
Docstrings¶
Google-style, solo en funciones públicas:
def find_by_id(self, doc_id: str) -> Document | None:
"""Find a document by ID.
Args:
doc_id: Document identifier.
Returns:
Document if found, None otherwise.
"""
Imports Diferidos en GUI (ADR — S23.1-19)¶
Los archivos en interfaces/gui/pages/ contienen imports dentro de metodos (no en top-level). Esto es una decision arquitectonica intencional, no un code smell:
# CORRECTO en paginas GUI — import diferido
def _render_validation_form(self, doc: dict) -> None:
from sherlock_docs.interfaces.gui.config.constants import JUZGADOS_BELLO
...
Razon: Streamlit re-ejecuta el modulo completo en cada interaccion del usuario. Los imports pesados (pandas, json, constants grandes) dentro de metodos evitan carga innecesaria en imports que no se usan en cada render cycle.
Donde aplica: Solo en interfaces/gui/pages/. En application/, core/, infrastructure/ y persistence/ los imports DEBEN ser top-level.
No "arreglar": Mover estos imports a top-level puede causar imports circulares y degradar el tiempo de respuesta de la GUI.