feat: Enhance CSV cleaning service with new endpoints for CSV analysis and preview functionality. Introduce support for job management linked to extraction batches, and update the cleaning rules structure. Add new utility functions for handling CSV data and improve documentation for clarity on usage and available endpoints.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""Registro de reglas de limpieza.
|
||||
|
||||
Para agregar una regla nueva:
|
||||
1. Implementa ``fn(series: pd.Series) -> pd.Series`` (o passthrough si es especial).
|
||||
2. Llama a ``register_rule(...)`` en ``rules/builtins.py``.
|
||||
3. Si la regla es especial (añade columnas, usa config), maneja el id en ``apply.py``.
|
||||
4. Incluye el id en ``_applicable_rules_for_type`` (type_inference.py) si debe sugerirse.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
import pandas as pd
|
||||
|
||||
RuleFn = Callable[[pd.Series], pd.Series]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RuleSpec:
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
fn: RuleFn
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"description": self.description,
|
||||
"fn": self.fn,
|
||||
}
|
||||
|
||||
|
||||
_REGISTRY: dict[str, RuleSpec] = {}
|
||||
_ORDER: list[str] = []
|
||||
|
||||
|
||||
def register_rule(
|
||||
rule_id: str,
|
||||
*,
|
||||
name: str,
|
||||
description: str,
|
||||
fn: RuleFn,
|
||||
) -> RuleSpec:
|
||||
"""Registra una regla. Si el id ya existe, lo reemplaza manteniendo el orden."""
|
||||
spec = RuleSpec(id=rule_id, name=name, description=description, fn=fn)
|
||||
if rule_id not in _REGISTRY:
|
||||
_ORDER.append(rule_id)
|
||||
_REGISTRY[rule_id] = spec
|
||||
return spec
|
||||
|
||||
|
||||
def get_rule(rule_id: str) -> Optional[dict[str, Any]]:
|
||||
spec = _REGISTRY.get(rule_id)
|
||||
return spec.as_dict() if spec else None
|
||||
|
||||
|
||||
def get_rule_fn(rule_id: str) -> Optional[RuleFn]:
|
||||
spec = _REGISTRY.get(rule_id)
|
||||
return spec.fn if spec else None
|
||||
|
||||
|
||||
def get_rule_name(rule_id: str) -> str:
|
||||
spec = _REGISTRY.get(rule_id)
|
||||
return spec.name if spec else rule_id
|
||||
|
||||
|
||||
def list_rules() -> list[dict[str, Any]]:
|
||||
return [_REGISTRY[rid].as_dict() for rid in _ORDER if rid in _REGISTRY]
|
||||
|
||||
|
||||
# Compat: lista mutable usada por la API (se rellena al importar builtins).
|
||||
CLEANING_RULES: list[dict[str, Any]] = []
|
||||
|
||||
|
||||
def rebuild_cleaning_rules() -> list[dict[str, Any]]:
|
||||
CLEANING_RULES.clear()
|
||||
CLEANING_RULES.extend(list_rules())
|
||||
return CLEANING_RULES
|
||||
Reference in New Issue
Block a user