Comparación profunda y guía práctica (implementación legacy → src)¶
Este documento es exhaustivo: explica las piezas de la implementación legacy (código anterior usado como referencia), su propósito y cómo se implementa cada responsabilidad en la nueva estructura src/. Incluye ejemplos de migración, puntos débiles del legacy y mejoras introducidas.
Índice¶
credentialsy autenticación- Manejo de parámetros y nombres (
timeseriesvstime_series) - Peticiones HTTP y reintentos
- Validación y parseo de respuestas
- Modelado de datos
- Errores y jerarquía de excepciones
- Concurrencia y SDK
- Tests y cómo cubrir cambios
- Recomendaciones finales y checklist de migración
credentials y autenticación¶
Legacy (anterior):
get_credentials()— interacción con el usuario (input + getpass).read_credentials(file)— lee dos primeras líneas (user, pass) de un archivo.
Problemas del enfoque legacy:
- Mezcla de I/O con librería; las librerías no deben pedir input al usuario.
- Dificulta testing.
Nueva aproximación (src/bcch_sdk/types/auth.py + bcch_sdk/mappers/credentials.py):
InternalCredentialses unTypedDictexplícito.CredentialsMapper.to_query_credentialsconvierteInternalCredentialsa{"user": ..., "pass": ...}.
Consejos de migración:
- Evita cambiar código que lee credenciales (scripts CLI). Reemplaza su salida por un
InternalCredentials. - Para tests, crea fixtures
{"username": "u", "password": "p"}y pruebaCredentialsMapper.
Código relacionado:
src/bcch_sdk/types/auth.pybcch_sdk/mappers/credentials.py
Manejo de parámetros y nombres (timeseries vs time_series)¶
Observación práctica:
- Legacy usaba la clave HTTP
timeseries. - La API Python en
src/expone argumentos idiomáticostime_seriesy usaParameterBuilderpara producirtimeseriesen la query.
Ventajas de esta separación:
- API Python más clara (
time_serieses más legible). - Centralización del mapeo en
ParameterBuilderevita fugas de nombres en todo el código.
Archivo clave: src/bcch_sdk/builders/parameters.py
Ejemplo de uso:
params = ParameterBuilder.build_get_series_params(creds, "SF43718")
# params["timeseries"] == "SF43718"
Recomendación: no cambiar la clave timeseries en las peticiones HTTP salvo que la API cambie; solo normaliza la interfaz Python.
Peticiones HTTP y reintentos¶
Legacy:
- Usaba
requests.getsin reintentos niTimeoutconfigurable.
Nueva implementación:
httpx.Client/httpx.AsyncClientconTimeoutyRetryTransport.- Reintentos por defecto: 3, backoff 0.5 (configurable en
BaseClient.retry_policy).
Impacto:
- Resiliencia frente a fallos transitorios de red.
- Mayor control del comportamiento en producción.
Recomendación operacional:
- Exponer
timeoutyretry_policya usuarios avanzados a través de la configuración del cliente.
Validación y parseo de respuestas¶
Legacy:
- Parseo directo
r.json()y mapeo aWSResponse.
Nueva:
_validate_responsecentraliza:raise_for_status()con mapeo aWebServiceResponseException.json()parse con captura deValueError→ResponseParseException.- Validación a Pydantic
WebServiceResponse.model_validate(payload).
Beneficios:
- Errores más claros y fáciles de capturar en el cliente que consume el SDK.
Modelado de datos¶
Legacy: estructuras simples y pandas helpers dentro de WSResponse.
Nuevo: Pydantic models con nombres descriptivos y tipos precisos:
Series→id,spanish_description,english_description,observations.ObservationSeries→index_date(date),value(float),status_code.
Consecuencia: los consumidores pueden trabajar con objetos tipados y convertir a DataFrame sólo cuando lo necesiten, evitando la dependencia inmediata a pandas.
Errores y jerarquía de excepciones¶
Legacy: excepciones planas (InvalidSeries, InvalidCredentials, ...).
Nuevo: jerarquía que distingue:
- Errores de transporte (
TransportException). - Errores de parseo (
ResponseParseException). - Errores de negocio (
InvalidCredentialsException,InvalidSeriesException, ...).
Recomendación de manejo en aplicaciones:
try:
resp = client.get_series(...)
except InvalidCredentialsException:
# pedir login o abortar
except TransportException:
# volver a intentar o avisar al usuario
except ResponseParseException:
# aviso y reporte
Concurrencia y SDK¶
La nueva estructura facilita:
- Ejecución paralela segura de consultas con helpers
run_in_threadsygather_async_tasks. - SDK
sync_sdkyasync_sdkexponen funciones convenientes para usuarios que sólo quieren obtener series sin manejar clientes directamente.
Ejemplo conceptual (paralelizar 10 series):
from bcch_sdk.sdk.concurrency import run_in_threads
from bcch_sdk.sdk.sync_sdk import BCChSDK
sdk = BCChSDK.from_credentials(creds)
series = ["SF1","SF2",...]
results = run_in_threads(lambda s: sdk.get_series(s), series)
Tests y cómo cubrir cambios¶
Recomendación de librerías:
pytestpara tests generales.httpx.MockTransportpara simularhttpxen tests sync/async.
Casos de prueba esenciales:
ParameterBuilder.build_get_series_paramscon combinaciones defirst_date/last_datey tipos.TimeSeriesBuilder.to_listcon strings, listas, dicts y errores.- Clientes
get_series/search_seriessimulando códigos backend (p.ej.-50,-1,-5).
Recomendaciones finales y checklist para migración¶
- Reemplazar
SessionporBCChSyncClientoBCChAsyncClient. - Pasar credenciales como
InternalCredentials(evitar I/O en librería). - Actualizar excepciones capturadas en el código consumidor.
- Añadir tests que cubran mapeos de parámetros y respuesta.
- Revisar puntos de integración que dependan de
pandassi ahora se usan modelos Pydantic.
Si quieres, puedo generar ejemplos de migración automáticos (scripts) que tomen fragmentos del código legacy y produzcan el equivalente usando src/.