datadis_python.utils package
Submodules
Module contents
Módulo de utilidades y constantes para el SDK de Datadis.
Este módulo proporciona funciones y constantes comunes utilizadas en el SDK de Datadis.
- author:
TacoronteRiveroCristian
- datadis_python.utils.validate_date_range(date_from, date_to, format_type='monthly')[fuente]
Valida un rango de fechas según las restricciones específicas de Datadis.
Esta función implementa todas las reglas de validación temporal específicas de la API de Datadis, incluyendo formatos aceptados, rangos permitidos y limitaciones de acceso a datos históricos.
- Restricciones de Datadis implementadas:
Rango temporal: Solo últimos 2 años desde la fecha actual
No fechas futuras: Las fechas no pueden ser posteriores al día actual
Orden lógico:
date_fromdebe ser anterior o igual adate_toFormatos específicos: YYYY/MM para mensual, YYYY/MM/DD para diario
- Formatos soportados:
Mensual: «YYYY/MM» (ej: «2024/01») - Recomendado para Datadis
Diario: «YYYY/MM/DD» (ej: «2024/01/15») - Limitado en algunos endpoints
- Validaciones aplicadas:
Formato de entrada: Verificación contra patrones regex específicos
Parseabilidad: Verificación de fechas válidas (no 30 de febrero)
Orden lógico: date_from ≤ date_to
Límite histórico: No más de 2 años hacia atrás
Límite futuro: No fechas posteriores a hoy
- Parámetros:
- Devuelve:
Tupla con las fechas validadas
(date_from, date_to)- Tipo del valor devuelto:
- Muestra:
ValidationError – Si cualquier validación falla
Ejemplo
Validaciones exitosas:
# Rango mensual válido validate_date_range("2024/01", "2024/12", "monthly") # → ("2024/01", "2024/12") # Rango diario válido validate_date_range("2024/01/01", "2024/01/31", "daily") # → ("2024/01/01", "2024/01/31") # Rango de un mes validate_date_range("2024/06", "2024/06", "monthly") # → ("2024/06", "2024/06")
Casos que fallan (errores esperados):
# ❌ Formato incorrecto validate_date_range("2024-01", "2024-12", "monthly") # → ValidationError: "Formato de fecha_desde inválido: 2024-01. Use 2024/01" # ❌ Rango invertido validate_date_range("2024/12", "2024/01", "monthly") # → ValidationError: "fecha_desde no puede ser posterior a fecha_hasta" # ❌ Demasiado antigua (más de 2 años) validate_date_range("2020/01", "2020/12", "monthly") # → ValidationError: "fecha_desde no puede ser anterior a hace 2 años" # ❌ Fecha futura validate_date_range("2030/01", "2030/12", "monthly") # → ValidationError: "fecha_hasta no puede ser futura" # ❌ Fecha inválida validate_date_range("2024/02/30", "2024/02/30", "daily") # → ValidationError: "Fecha inválida: day is out of range for month"
Uso típico en métodos del SDK:
def get_consumption(self, date_from, date_to): # Validación robusta antes de petición API validated_from, validated_to = validate_date_range( date_from, date_to, "monthly" ) # Las fechas están garantizadas como válidas params = {"dateFrom": validated_from, "dateTo": validated_to}
Nota
El límite de 2 años se basa en las limitaciones actuales de Datadis para acceso a datos históricos. Este límite puede cambiar en el futuro según las políticas de la plataforma.
- Performance:
La validación incluye cálculos de fecha para verificar límites temporales. Para uso intensivo, considere cachear los límites calculados.
- Technical Details:
Regex patterns: Específicos para cada formato (daily/monthly)
Parsing: Usa
datetime.strptime()para validación completaLímites dinámicos: Calculados en tiempo real basados en
datetime.now()Timezone: Usa timezone local del sistema
Ver también
convert_date_range_to_api_format()para conversión + validaciónconvert_date_to_api_format()para fechas individualesDocumentación de Datadis sobre disponibilidad de datos históricos
Added in version 1.0: Validación básica de rangos de fechas
Distinto en la versión 2.0: Añadidas validaciones específicas para limitaciones de Datadis
- datadis_python.utils.validate_distributor_code(distributor_code)[fuente]
Valida códigos de distribuidor eléctrico españoles oficiales.
- Parámetros:
distributor_code (str) – Código de distribuidor a validar
- Devuelve:
Código de distribuidor validado
- Tipo del valor devuelto:
- Muestra:
ValidationError – Si el código no corresponde a un distribuidor válido
Ejemplo
Códigos válidos:
# Distribuidores nacionales principales validate_distributor_code("2") # → "2" (E-distribución/Endesa) validate_distributor_code("5") # → "5" (UFD/Naturgy) # Distribuidores regionales validate_distributor_code("1") # → "1" (Viesgo - Norte) validate_distributor_code("3") # → "3" (E-redes - Galicia) validate_distributor_code("6") # → "6" (EOSA - Aragón) # Distribuidores insulares/locales validate_distributor_code("8") # → "8" (IDE - Baleares) validate_distributor_code("4") # → "4" (ASEME - Melilla) validate_distributor_code("7") # → "7" (CIDE - Ceuta)
Casos que fallan (errores esperados):
# ❌ Código inexistente validate_distributor_code("9") # → ValidationError: "Código de distribuidor inválido: 9. Válidos: 1, 2, 3, 4, 5, 6, 7, 8" # ❌ Código múltiple validate_distributor_code("12") # → ValidationError: "Código de distribuidor inválido: 12..." # ❌ Código negativo validate_distributor_code("-1") # → ValidationError: "Código de distribuidor inválido: -1..."
Uso con constantes descriptivas:
from datadis_python.utils.constants import DISTRIBUTOR_CODES # Usar nombres descriptivos en lugar de números endesa_code = DISTRIBUTOR_CODES["E_DISTRIBUCION"] # "2" validated = validate_distributor_code(endesa_code) # "2" # Iterar sobre todos los distribuidores válidos for name, code in DISTRIBUTOR_CODES.items(): validated_code = validate_distributor_code(code) print(f"{name}: {validated_code}")
Nota
Los códigos de distribuidor son siempre strings en la API de Datadis, aunque representen números. Use
convert_distributor_code_parameter()si necesita conversión automática desde enteros.- Technical Details:
Lista estática: Los 8 códigos están hardcodeados (no cambian frecuentemente)
Validación rápida: Lookup en lista pequeña, muy eficiente
Case sensitive: Los códigos deben ser exactamente como se especifican
No conversión: Esta función no convierte tipos, solo valida
Referencias
CNE: Comisión Nacional de Energía - Listado oficial de distribuidores
CNMC: Comisión Nacional de los Mercados y la Competencia
Datadis: Documentación oficial de códigos soportados
Ver también
convert_distributor_code_parameter()para conversión automática int→strdatadis_python.utils.constants.DISTRIBUTOR_CODESpara mapeo de nombresDocumentación oficial de distribuidores eléctricos en España
Added in version 1.0: Validación de códigos de distribuidor
Distinto en la versión 2.0: Actualizada lista con información geográfica detallada
- datadis_python.utils.convert_cups_parameter(cups)[fuente]
Procesa y valida un código CUPS para la API de Datadis.
Los códigos CUPS (Código Universal del Punto de Suministro) son identificadores únicos para puntos de suministro eléctrico en España. Esta función valida que el código tenga el formato correcto antes de enviarlo a la API.
- Formato CUPS español:
Prefijo: Siempre «ES» (código país)
Longitud: 20-22 caracteres alfanuméricos después del prefijo
Caracteres: Solo letras mayúsculas y números
Ejemplo:
"ES0031607515707001RC0F"
- Validaciones aplicadas:
Tipo correcto: Debe ser string
Formato válido: Cumplir patrón regex de CUPS españoles
Longitud correcta: Entre 22-24 caracteres totales (ES + 20-22)
- Parámetros:
cups (str) – Código CUPS a validar. Debe ser un string con formato válido
- Devuelve:
Código CUPS validado y limpio (sin espacios extra)
- Tipo del valor devuelto:
- Muestra:
ValidationError – Si el CUPS no cumple con el formato esperado o no es string
Ejemplo
Códigos CUPS válidos:
# Formato típico (20 caracteres después de ES) convert_cups_parameter("ES0031607515707001RC0F") # → "ES0031607515707001RC0F" # Formato largo (22 caracteres después de ES) convert_cups_parameter("ES1234567890123456789012") # → "ES1234567890123456789012" # Con espacios (se limpian automáticamente) convert_cups_parameter(" ES0031607515707001RC0F ") # → "ES0031607515707001RC0F"
Casos que fallan (errores esperados):
# ❌ Tipo incorrecto convert_cups_parameter(123456) # → ValidationError: "CUPS debe ser string, recibido: <class 'int'>" # ❌ Formato inválido (sin prefijo ES) convert_cups_parameter("0031607515707001RC0F") # → ValidationError: "Formato CUPS inválido. Debe ser: ES + 20-22 caracteres alfanuméricos" # ❌ Demasiado corto convert_cups_parameter("ES12345") # → ValidationError: "Formato CUPS inválido..." # ❌ Caracteres inválidos convert_cups_parameter("ES003160751570700@RC0F") # → ValidationError: "Formato CUPS inválido..."
Uso típico en consultas:
def get_consumption(self, cups, ...): # Validar CUPS antes de enviar a API validated_cups = convert_cups_parameter(cups) # validated_cups está garantizado como válido params = {"cups": validated_cups}
Nota
Esta función realiza validación del formato pero no verifica que el CUPS exista realmente o esté asociado al usuario. Esa validación la realiza la API de Datadis en el servidor.
- Technical Details:
Regex pattern:
^ES[A-Z0-9]{20,22}$Case sensitivity: Solo acepta mayúsculas (conversión automática)
Limpieza: Elimina espacios en blanco automáticamente
Delegación: Usa
datadis_python.utils.validators.validate_cups()internamente
Ver también
datadis_python.utils.validators.validate_cups()para validación detalladaDocumentación oficial sobre formato de códigos CUPS
CNE (Comisión Nacional de Energía) para especificaciones oficiales
Added in version 1.0: Validación de formato CUPS integrada en el SDK
- datadis_python.utils.convert_date_range_to_api_format(date_from, date_to, format_type='daily')[fuente]
Convierte y valida un rango de fechas para la API de Datadis.
Esta función es un wrapper de alto nivel que combina conversión de tipos y validación de rangos para asegurar que tanto las fechas individuales como el rango completo cumplan con los requisitos de la API de Datadis.
- Proceso de validación en dos etapas:
Conversión individual: Cada fecha se convierte usando
convert_date_to_api_format()Validación de rango: El rango se valida usando
validate_date_range
- Validaciones aplicadas:
Formato individual: Cada fecha debe tener formato válido
Consistencia de rango:
date_fromno puede ser posterior adate_toLímites temporales: Cumplir restricciones de Datadis (últimos 2 años)
Restricciones de modo: Solo formatos mensuales si
format_type="monthly"
- Parámetros:
date_from (Union[str, datetime, date]) – Fecha de inicio del rango. Acepta múltiples formatos
date_to (Union[str, datetime, date]) – Fecha de fin del rango. Acepta múltiples formatos
format_type (str) –
Tipo de formato de salida:
»monthly»: YYYY/MM (recomendado para Datadis)
»daily»: YYYY/MM/DD (limitado en Datadis)
- Devuelve:
Tupla con fechas convertidas y validadas
(date_from_str, date_to_str)- Tipo del valor devuelto:
- Muestra:
ValidationError – Si cualquier fecha es inválida o el rango no cumple restricciones
Ejemplo
Rangos típicos para consultas mensuales:
from datetime import date # Objetos date → strings de API start = date(2024, 1, 1) end = date(2024, 12, 31) converted = convert_date_range_to_api_format(start, end, "monthly") # Resultado: ("2024/01", "2024/12") # Strings en formatos mixtos converted = convert_date_range_to_api_format( "2024-01-01", # Formato ISO "2024/12", # Formato API "monthly" ) # Resultado: ("2024/01", "2024/12")
Rangos para consultas diarias (limitado):
# Solo algunos endpoints aceptan fechas específicas converted = convert_date_range_to_api_format( "2024/01/01", "2024/01/31", "daily" ) # Resultado: ("2024/01/01", "2024/01/31")
Casos que fallan (errores esperados):
# ❌ Rango invertido convert_date_range_to_api_format("2024/12", "2024/01", "monthly") # → ValidationError: "date_from no puede ser posterior a date_to" # ❌ Fechas específicas en modo mensual convert_date_range_to_api_format("2024/01/15", "2024/01/20", "monthly") # → ValidationError: "API solo acepta fechas mensuales"
Uso típico en métodos del SDK:
def get_consumption(self, date_from, date_to): # Conversión flexible + validación automática api_from, api_to = convert_date_range_to_api_format( date_from, date_to, "monthly" ) # api_from y api_to están garantizados como válidos params = {"dateFrom": api_from, "dateTo": api_to}
Nota
Esta función es la forma recomendada de procesar todos los rangos de fechas en el SDK, ya que combina flexibilidad de entrada con validación robusta.
- Performance:
La función realiza validación completa en cada llamada. Para uso intensivo con fechas ya validadas, considere llamar directamente las funciones de conversión individual.
Ver también
convert_date_to_api_format()para conversión de fechas individualesdatadis_python.utils.validators.validate_date_range()para validaciones de rangoDocumentación de Datadis sobre limitaciones temporales
Distinto en la versión 2.0: Añadida validación estricta para prevenir fechas específicas en modo mensual
- datadis_python.utils.convert_date_to_api_format(date_value, format_type='daily')[fuente]
Convierte fechas de múltiples formatos al formato requerido por la API de Datadis.
Esta función es el núcleo del sistema de conversión de fechas del SDK. Acepta fechas en múltiples formatos naturales de Python y las convierte al formato específico requerido por la API de Datadis, aplicando validaciones estrictas para prevenir errores comunes.
- Limitaciones específicas de Datadis:
Solo fechas mensuales: Para la mayoría de endpoints, solo se acepta YYYY/MM
No fechas específicas: Fechas como YYYY/MM/DD se rechazan en modo mensual
Rango temporal limitado: Solo últimos 2 años (validado por otros componentes)
- Formatos de entrada soportados:
Strings: «2024/01», «2024-01-15», «20240115», «15/01/2024»
datetime objects:
datetime(2024, 1, 15)→ «2024/01» (modo mensual)date objects:
date(2024, 1, 15)→ «2024/01» (modo mensual)
- Validaciones aplicadas:
Detección de días específicos: Rechaza YYYY/MM/DD en modo mensual
Parseo de múltiples formatos: Intenta varios formatos comunes automáticamente
Consistencia de modo: Asegura que el output coincida con el format_type
- Parámetros:
date_value (Union[str, datetime, date]) – Fecha a convertir. Acepta strings en múltiples formatos, objetos datetime, o objetos date de Python
format_type (str) –
Tipo de formato de salida requerido:
»monthly»: Formato YYYY/MM (recomendado para Datadis)
»daily»: Formato YYYY/MM/DD (limitado en Datadis)
- Devuelve:
Fecha formateada según el format_type especificado y validada para cumplir con las restricciones de la API de Datadis
- Tipo del valor devuelto:
- Muestra:
En los siguientes casos:
Fecha contiene día específico en modo mensual
Formato de fecha no reconocible
Tipo de entrada no soportado
format_type no válido
Ejemplo
Conversiones típicas en modo mensual (recomendado):
# Strings en formato correcto (pasan sin cambios) convert_date_to_api_format("2024/01", "monthly") # → "2024/01" # Objetos datetime (día se ignora en modo mensual) from datetime import datetime dt = datetime(2024, 1, 15) convert_date_to_api_format(dt, "monthly") # → "2024/01" # Strings en formatos alternativos (se convierten) convert_date_to_api_format("2024-01-15", "monthly") # → "2024/01" convert_date_to_api_format("15/01/2024", "monthly") # → "2024/01"
Validaciones que fallan (errores esperados):
# ❌ Fecha específica en modo mensual convert_date_to_api_format("2024/01/15", "monthly") # → ValidationError: "API solo acepta fechas mensuales" # ❌ datetime con día específico dt = datetime(2024, 1, 15) # día 15, no día 1 convert_date_to_api_format(dt, "monthly") # → ValidationError: "Fecha contiene día específico"
Conversiones en modo daily:
# Para endpoints que sí aceptan fechas específicas convert_date_to_api_format("2024/01/15", "daily") # → "2024/01/15" dt = datetime(2024, 1, 15) convert_date_to_api_format(dt, "daily") # → "2024/01/15"
Nota
La mayoría de endpoints de Datadis solo aceptan fechas mensuales (YYYY/MM). Use
format_type="monthly"a menos que esté seguro de que el endpoint específico acepta fechas diarias.- Technical Details:
Detección inteligente: Analiza el formato de entrada automáticamente
Múltiples intentos: Prueba varios formatos comunes antes de fallar
Validación estricta: Previene errores sutiles por formato incorrecto
Retrocompatibilidad: Strings correctos pasan sin modificación
Ver también
convert_date_range_to_api_format()para rangos de fechasdatadis_python.utils.validators.validate_date_range()para validaciones adicionalesDocumentación de Datadis sobre formatos de fecha aceptados
Distinto en la versión 2.0: Añadida validación estricta para fechas específicas en modo mensual
- datadis_python.utils.convert_distributor_code_parameter(distributor_code)[fuente]
Convierte y valida códigos de distribuidor para la API de Datadis.
Los códigos de distribuidor identifican las diferentes compañías distribuidoras eléctricas en España. Esta función acepta tanto enteros como strings para flexibilidad del usuario, y valida que el código sea uno de los oficialmente reconocidos por Datadis.
- Distribuidores válidos (códigos oficiales):
«1»: Viesgo (Cantabria, Asturias)
«2»: E-distribución/Endesa (Nacional)
«3»: E-redes (Galicia)
«4»: ASEME (Melilla)
«5»: UFD/Naturgy (Nacional)
«6»: EOSA (Aragón)
«7»: CIDE (Ceuta)
«8»: IDE (Baleares)
- Conversión automática:
Enteros: Se convierten a string (
2→"2")Strings: Se validan y retornan si son correctos
Otros tipos: Se rechazan con error claro
- Parámetros:
distributor_code (Union[str, int]) – Código del distribuidor. Acepta entero (ej:
2) o string (ej:"2") con código válido- Devuelve:
Código de distribuidor como string validado
- Tipo del valor devuelto:
- Muestra:
ValidationError – Si el código no es válido o es de tipo no soportado
Ejemplo
Conversiones exitosas:
# Enteros (forma natural para usuarios) convert_distributor_code_parameter(2) # → "2" (Endesa) convert_distributor_code_parameter(5) # → "5" (Naturgy) convert_distributor_code_parameter(1) # → "1" (Viesgo) # Strings válidos (pasan sin cambios) convert_distributor_code_parameter("2") # → "2" convert_distributor_code_parameter("8") # → "8" (IDE Baleares)
Casos que fallan (errores esperados):
# ❌ Código inválido (no existe distribuidor 9) convert_distributor_code_parameter(9) # → ValidationError: "Código de distribuidor inválido: 9. Válidos: 1, 2, 3, 4, 5, 6, 7, 8" # ❌ Código inválido como string convert_distributor_code_parameter("99") # → ValidationError: "Código de distribuidor inválido: 99..." # ❌ Tipo no soportado convert_distributor_code_parameter([1, 2]) # → ValidationError: "Código de distribuidor debe ser string o int, recibido: <class 'list'>"
Uso típico con constantes:
from datadis_python.utils.constants import DISTRIBUTOR_CODES # Usuario puede usar nombres descriptivos endesa_code = DISTRIBUTOR_CODES["E_DISTRIBUCION"] # "2" validated = convert_distributor_code_parameter(endesa_code) # "2" # O directamente números naturales validated = convert_distributor_code_parameter(2) # "2"
En métodos del SDK:
def get_supplies(self, distributor_code=None): if distributor_code is not None: # Conversión flexible + validación api_code = convert_distributor_code_parameter(distributor_code) params["distributorCode"] = api_code
Nota
Aunque la función acepta enteros para comodidad, la API de Datadis internamente espera todos los códigos como strings, por eso se hace la conversión automática.
- Technical Details:
Validación: Usa
datadis_python.utils.validators.validate_distributor_code()Conversión de tipos:
int→strautomáticamenteCódigos válidos: Solo 1-8 según distribuidores oficiales españoles
Case insensitive: Los strings se procesan exactamente como se reciben
Ver también
datadis_python.utils.validators.validate_distributor_code()para validación detalladadatadis_python.utils.constants.DISTRIBUTOR_CODESpara mapeo de nombresDocumentación oficial de Datadis sobre códigos de distribuidor
Added in version 1.0: Soporte para conversión automática int → string
- datadis_python.utils.convert_number_to_string(value)[fuente]
Convierte números de múltiples tipos a strings validados para la API de Datadis.
La API de Datadis espera parámetros numéricos como strings, pero los usuarios naturalmente quieren pasar enteros o floats. Esta función acepta cualquier tipo numérico y lo convierte a string después de validar que sea un número válido.
- Validaciones aplicadas:
Strings: Verifica que representen números válidos antes de retornarlos
Enteros: Convierte directamente a string
Floats: Convierte a string con representación completa
Tipos inválidos: Rechaza con mensaje de error claro
- Casos de uso típicos:
Códigos de distribuidor:
2→"2"Tipos de medida:
0→"0"(consumo vs generación)Tipos de punto:
1→"1"(frontera, consumo, etc.)IDs numéricos: Para cualquier identificador numérico de la API
- Parámetros:
value (Union[str, int, float]) – Valor numérico a convertir. Acepta enteros, floats, o strings que representen números válidos
- Devuelve:
Representación string del número, validada para ser numérica
- Tipo del valor devuelto:
- Muestra:
ValidationError – Si el valor no es numérico válido o es de tipo no soportado
Ejemplo
Conversiones exitosas:
# Enteros (caso más común) convert_number_to_string(2) # → "2" convert_number_to_string(0) # → "0" convert_number_to_string(-1) # → "-1" # Floats convert_number_to_string(2.5) # → "2.5" convert_number_to_string(0.0) # → "0.0" # Strings numéricos válidos (pasan sin cambios) convert_number_to_string("2") # → "2" convert_number_to_string("2.5") # → "2.5"
Casos que fallan (errores esperados):
# ❌ String no numérico convert_number_to_string("abc") # → ValidationError: "String no numérico: abc" # ❌ Tipos no soportados convert_number_to_string(None) # → ValidationError: "Tipo numérico no soportado: <class 'NoneType'>" convert_number_to_string([1, 2, 3]) # → ValidationError: "Tipo numérico no soportado: <class 'list'>"
Uso en contexto de Datadis:
# Flexibilidad para el usuario distributor_code = 2 # int natural api_param = convert_number_to_string(distributor_code) # "2" para API # Validación de entrada user_input = "2.5" # string del usuario validated = convert_number_to_string(user_input) # validado
Nota
La función preserva la precisión completa de los floats. Para casos donde necesite controlar el número de decimales, aplique redondeo antes de llamar esta función.
- Technical Details:
Validación de strings: Usa
float()para verificar que sean numéricosPreservación de formato: Strings válidos se retornan sin modificación
Conversión directa: Enteros y floats se convierten con
str()Mensajes específicos: Errores incluyen el valor problemático para debugging
Ver también
convert_optional_number_to_string()para valores que pueden ser Noneconvert_distributor_code_parameter()para códigos específicos de distribuidor
- datadis_python.utils.convert_optional_number_to_string(value)[fuente]
Convierte números opcionales a strings para la API de Datadis.
Esta función extiende
convert_number_to_string()para manejar valores que pueden serNone, lo que es común en parámetros opcionales de la API. Mantiene la semántica deNone(parámetro no especificado) mientras valida valores no-None.- Comportamiento:
None: Se retorna como
None(parámetro opcional no especificado)Valores válidos: Se procesan con
convert_number_to_string()Valores inválidos: Se rechazan con
ValidationError
- Casos de uso típicos:
point_type: Parámetro opcional en consultas de consumo
measurement_type: Parámetro opcional con valor por defecto
Filtros numéricos: Cualquier filtro numérico opcional
- Parámetros:
value (Optional[Union[str, int, float]]) – Valor numérico opcional a convertir. Puede ser None, entero, float, o string que represente un número
- Devuelve:
String representando el número si no es None, o None si es None
- Tipo del valor devuelto:
Optional[str]
- Muestra:
ValidationError – Si el valor no es None y no es numérico válido
Ejemplo
Manejo de parámetros opcionales:
# Valor None (parámetro no especificado) convert_optional_number_to_string(None) # → None # Valores numéricos válidos convert_optional_number_to_string(2) # → "2" convert_optional_number_to_string(2.5) # → "2.5" convert_optional_number_to_string("3") # → "3" # Valores inválidos (solo si no son None) convert_optional_number_to_string("abc") # → ValidationError
Uso en consultas de API:
# point_type es opcional point_type = None # Usuario no especifica api_point_type = convert_optional_number_to_string(point_type) # → None # measurement_type especificado por usuario measurement_type = 1 # Usuario especifica generación api_measurement = convert_optional_number_to_string(measurement_type) # → "1"
En métodos del cliente:
def get_consumption(self, point_type=None, measurement_type=0): # Convertir parámetros opcionales api_point_type = convert_optional_number_to_string(point_type) api_measurement = convert_optional_number_to_string(measurement_type) # Solo añadir a params si no son None params = {} if api_point_type is not None: params["pointType"] = api_point_type if api_measurement is not None: params["measurementType"] = api_measurement
Nota
Esta función es la forma recomendada de manejar todos los parámetros numéricos opcionales en el SDK, ya que mantiene la semántica clara entre «no especificado» (None) y «especificado con valor» (string).
Ver también
convert_number_to_string()para valores numéricos obligatoriosDocumentación de la API de Datadis sobre parámetros opcionales
- class datadis_python.utils.HTTPClient(timeout=60, retries=3)[fuente]
Bases:
objectCliente HTTP robusto especializado para la API de Datadis.
Esta clase proporciona una interfaz de alto nivel para realizar peticiones HTTP con características específicamente optimizadas para interactuar con la API de Datadis. Incluye manejo automático de reintentos, timeouts largos, gestión de autenticación y procesamiento especializado de respuestas.
- Optimizaciones para Datadis:
Timeouts largos: Por defecto 60s, recomendado 90-120s para Datadis
Reintentos robustos: Backoff exponencial con hasta 5 reintentos
Rate limiting: Delays automáticos para evitar sobrecarga del servidor
Manejo de encoding: Desactiva compresión gzip para evitar problemas
Procesamiento de texto: Normalización automática de caracteres especiales
- Estrategia de reintentos:
Errores de red y timeouts: Se reintentan automáticamente
Errores HTTP 4xx/5xx: Se propagan inmediatamente (no reintentos)
Backoff exponencial: 2s → 4s → 8s → 16s → 32s (máximo 10s para timeouts)
Error 401: Se propaga para permitir renovación de token
Ejemplo
Configuración típica para Datadis:
# Configuración robusta para API lenta de Datadis client = HTTPClient(timeout=120, retries=5) # Autenticación Bearer Token client.set_auth_header("jwt_token_from_datadis") # Petición con gestión automática de errores response = client.make_request( method="GET", url="https://datadis.es/api-private/api/get-supplies", params={"distributor_code": "2"} )
Diferentes tipos de contenido:
# Para autenticación (form-data) auth_response = client.make_request( method="POST", url="https://datadis.es/nikola-auth/tokens/login", data={"username": "12345678A", "password": "password"}, use_form_data=True ) # Para endpoints de datos (JSON, por defecto) data_response = client.make_request( method="GET", url="https://datadis.es/api-private/api/get-consumption-data", params={"cups": "ES001234567890123456AB"} )
- Parámetros:
Nota
La API de Datadis puede ser muy lenta (60-90 segundos) al procesar consultas complejas que requieren agregar datos de múltiples distribuidoras eléctricas.
Ver también
SimpleDatadisClientV1ySimpleDatadisClientV2para uso de alto nivelDocumentación oficial de Datadis para límites de rate limiting
- __enter__()[fuente]
Método de entrada para context manager.
Permite usar el HTTPClient con la declaración
withde Python para gestión automática de recursos. Al entrar en el bloquewith, retorna la instancia del cliente lista para usar.- Devuelve:
La instancia del cliente HTTP configurada
- Tipo del valor devuelto:
Ejemplo
Uso como context manager:
with HTTPClient(timeout=120, retries=5) as client: # Configurar autenticación token = client.make_request( "POST", "/auth", data={"user": "12345678A", "pass": "password"}, use_form_data=True ) client.set_auth_header(token) # Realizar peticiones data = client.make_request("GET", "/api/data") # client.close() se llama automáticamente aquí
Nota
El uso como context manager es la forma recomendada de usar HTTPClient ya que garantiza la liberación adecuada de recursos de red.
- __exit__(exc_type, exc_val, exc_tb)[fuente]
Método de salida para context manager.
Se llama automáticamente al salir del bloque
with, garantizando que los recursos del cliente HTTP se liberen adecuadamente, independientemente de si el bloque se completó exitosamente o se produjo una excepción.- Parámetros:
exc_type – Tipo de excepción si ocurrió una excepción, None en caso contrario
exc_val – Valor de la excepción si ocurrió una excepción, None en caso contrario
exc_tb – Traceback de la excepción si ocurrió una excepción, None en caso contrario
Nota
Este método siempre retorna None, lo que significa que no suprime ninguna excepción que pueda haber ocurrido dentro del bloque
with. Las excepciones se propagan normalmente después de la limpieza de recursos.
- __init__(timeout=60, retries=3)[fuente]
Inicializa el cliente HTTP con configuración optimizada para Datadis.
Configura una sesión HTTP persistente con headers optimizados y timeouts apropiados para la API de Datadis. La configuración por defecto está pensada para un uso general, pero se recomienda ajustar los valores para Datadis.
- Configuración recomendada para Datadis:
timeout: 90-120 segundos (la API puede ser muy lenta)
retries: 3-5 reintentos (para manejar inestabilidad ocasional)
- Parámetros:
Ejemplo
Configuraciones típicas:
# Configuración conservadora (rápida, pocos reintentos) client = HTTPClient(timeout=60, retries=2) # Configuración robusta para Datadis (recomendada) client = HTTPClient(timeout=120, retries=5) # Configuración para desarrollo/testing (muy paciente) client = HTTPClient(timeout=180, retries=3)
- close()[fuente]
Cierra la sesión HTTP y libera recursos asociados.
Cierra explícitamente la sesión HTTP subyacente, liberando conexiones de red y otros recursos. Es una buena práctica llamar este método cuando se termina de usar el cliente, especialmente en aplicaciones de larga duración.
Este método es seguro de llamar múltiples veces y no genera errores si la sesión ya está cerrada.
Ejemplo
Uso manual de cierre:
client = HTTPClient(timeout=120, retries=5) try: # Usar cliente para peticiones... response = client.make_request("GET", "https://example.com") finally: # Asegurar limpieza de recursos client.close()
Uso como context manager (recomendado):
with HTTPClient(timeout=120, retries=5) as client: # Usar cliente... response = client.make_request("GET", "https://example.com") # client.close() se llama automáticamente
Nota
Cuando se usa el cliente como context manager (
withstatement), este método se llama automáticamente al salir del bloque, por lo que no es necesario llamarlo manualmente.- Tipo del valor devuelto:
None
- make_request(method, url, data=None, params=None, headers=None, use_form_data=False)[fuente]
Realiza una petición HTTP robusta con reintentos automáticos y manejo de errores.
Este método es el núcleo del cliente HTTP y maneja toda la lógica de peticiones incluyendo reintentos con backoff exponencial, manejo de diferentes tipos de contenido, rate limiting automático y procesamiento especializado de respuestas.
- Flujo de operación:
Rate limiting: Delay automático de 0.1s (excepto para autenticación)
Configuración de headers: Combina headers por defecto con personalizados
Selección de formato: JSON o form-data según
use_form_dataEjecución con reintentos: Hasta
self.retriesintentos con backoff exponencialProcesamiento de respuesta: Manejo especializado según tipo de contenido
- Estrategia de reintentos:
Errores de red/timeout: Reintentos con backoff: 2s → 4s → 8s → 16s…
Errores HTTP: Propagación inmediata sin reintentos
Máximo wait: 10 segundos entre reintentos para evitar timeouts excesivos
- Tipos de contenido soportados:
JSON (por defecto): Para la mayoría de endpoints de datos
Form-data: Para autenticación y algunos endpoints legacy
Detección automática: Basada en el parámetro
use_form_data
- Parámetros:
method (str) – Método HTTP a usar (GET, POST, PUT, DELETE, etc.)
url (str) – URL completa del endpoint a consultar
data (Optional[Dict[str, Any]]) – Datos a enviar en el cuerpo de la petición. Para GET se ignora, para POST se usa según
use_form_dataparams (Optional[Dict[str, Any]]) – Parámetros de query string a añadir a la URL
headers (Optional[Dict[str, str]]) – Headers HTTP adicionales a combinar con los por defecto. Los headers personalizados tienen prioridad sobre los por defecto
use_form_data (bool) – Si
True, envía datos como application/x-www-form-urlencoded. SiFalse(por defecto), envía como application/json
- Devuelve:
Respuesta procesada del servidor. El tipo depende del endpoint:
JWT tokens:
str(para endpoints de autenticación)Datos JSON:
Dict[str, Any]oList[Any](para endpoints de datos)Respuestas de texto:
str(para endpoints que no devuelven JSON)
- Tipo del valor devuelto:
- Muestra:
DatadisError – Si se agotan todos los reintentos por errores de red/timeouts
AuthenticationError – Si hay errores de autenticación (401)
APIError – Si la API devuelve errores HTTP (400, 403, 404, 500, etc.)
Ejemplo
Diferentes tipos de peticiones:
# GET con parámetros de query response = client.make_request( method="GET", url="https://datadis.es/api-private/api/get-supplies", params={"distributor_code": "2", "authorized_nif": "12345678A"} ) # POST con autenticación (form-data) token = client.make_request( method="POST", url="https://datadis.es/nikola-auth/tokens/login", data={"username": "12345678A", "password": "mi_password"}, use_form_data=True ) # GET con headers personalizados response = client.make_request( method="GET", url="https://datadis.es/api-private/api/get-consumption-data", params={"cups": "ES001234567890123456AB"}, headers={"Authorization": f"Bearer {token}"} )
Nota
El rate limiting automático (delay de 0.1s) se aplica a todas las peticiones excepto las de autenticación para evitar sobrecargar los servidores de Datadis que pueden tener límites de rate restrictivos.
Ver también
_handle_response()para detalles del procesamiento de respuestasLa normalización de texto se realiza automáticamente en respuestas JSON
- remove_auth_header()[fuente]
Elimina el header de autorización de todas las peticiones futuras.
Remueve el token de autenticación de los headers de la sesión, haciendo que las peticiones subsecuentes se realicen sin autenticación. Esto es útil para limpiar credenciales cuando se cambia de usuario o cuando se quiere realizar peticiones no autenticadas.
Esta operación es segura y no genera errores si no existe un header de autorización configurado.
Ejemplo
Limpiar autenticación para cambio de usuario:
# Usuario 1 autenticado client.set_auth_header(token_user1) data_user1 = client.make_request("GET", "/get-supplies") # Cambiar a usuario 2 client.remove_auth_header() # Limpiar credenciales anteriores token_user2 = client.make_request( "POST", "/nikola-auth/tokens/login", data={"username": "87654321B", "password": "other_password"}, use_form_data=True ) client.set_auth_header(token_user2) data_user2 = client.make_request("GET", "/get-supplies")
Peticiones sin autenticación:
client.remove_auth_header() # Ahora las peticiones no incluirán Authorization header public_data = client.make_request("GET", "/public-endpoint")
Nota
Después de llamar este método, las peticiones a endpoints que requieren autenticación fallarán con error 401 hasta que se establezca un nuevo token con
set_auth_header().Ver también
set_auth_header()para establecer nuevo token de autenticación
- Tipo del valor devuelto:
None
- set_auth_header(token)[fuente]
Establece el header de autorización Bearer Token para todas las peticiones futuras.
Configura el token de autenticación que se añadirá automáticamente a todas las peticiones HTTP subsecuentes. Este método es típicamente llamado después de una autenticación exitosa para configurar el cliente para peticiones autenticadas.
El token se almacena en los headers de la sesión persistent, por lo que se aplicará automáticamente a todas las peticiones realizadas con este cliente hasta que se reemplace con un nuevo token o se elimine.
- Parámetros:
token (str) – Token JWT obtenido del endpoint de autenticación de Datadis. Debe ser un token válido sin el prefijo «Bearer « (se añade automáticamente)
- Tipo del valor devuelto:
None
Ejemplo
Configurar autenticación después del login:
client = HTTPClient(timeout=120, retries=5) # Autenticar y obtener token token = client.make_request( method="POST", url="https://datadis.es/nikola-auth/tokens/login", data={"username": "12345678A", "password": "mi_password"}, use_form_data=True ) # Configurar token para peticiones futuras client.set_auth_header(token) # Ahora todas las peticiones incluirán el header Authorization response = client.make_request( method="GET", url="https://datadis.es/api-private/api/get-supplies" )
Nota
El token se prefija automáticamente con «Bearer « según el estándar RFC 6750. No incluya este prefijo en el parámetro
token.Ver también
remove_auth_header()para eliminar la autenticaciónRFC 6750 para especificación completa de Bearer Token
- datadis_python.utils.normalize_text(text)[fuente]
Normaliza texto removiendo tildes, caracteres especiales y corrigiendo problemas de encoding.
Esta función es el núcleo del sistema de normalización de texto del SDK. Aplica múltiples estrategias para corregir problemas comunes de encoding que aparecen frecuentemente en las respuestas de la API de Datadis, especialmente con caracteres españoles.
- Proceso de normalización:
Detección de doble codificación: Identifica secuencias como «Ãx93» (debe ser «Ó»)
Corrección de encoding: Recodifica usando latin-1 → UTF-8 cuando es necesario
Normalización Unicode: Aplica descomposición NFD para separar caracteres base de acentos
Eliminación de acentos: Convierte caracteres acentuados a su equivalente ASCII
Reemplazos específicos: Maneja caracteres especiales españoles (ñ, ç, etc.)
- Casos de uso típicos:
Nombres de distribuidores: «EDISTRIBUCIÃx93N» → «EDISTRIBUCION»
Direcciones: «CALLE JOSÃπ MARTÃxadNEZ» → «CALLE JOSE MARTINEZ»
Nombres de municipios: «Málaga», «Cádiz» → «Malaga», «Cadiz»
Códigos postales: Normalmente no necesitan normalización pero se procesan igual
- Parámetros:
text (str) – Texto a normalizar. Puede contener caracteres especiales, acentos, o problemas de doble codificación típicos de Datadis
- Devuelve:
Texto normalizado sin tildes, acentos ni caracteres especiales. Convertido completamente a caracteres ASCII seguros
- Tipo del valor devuelto:
Ejemplo
Problemas típicos de encoding de Datadis:
# Doble codificación UTF-8 normalize_text("EDISTRIBUCIÃ\x93N") # → "EDISTRIBUCION" normalize_text("Málaga") # → "Malaga" # Caracteres españoles normales normalize_text("Málaga") # → "Malaga" normalize_text("Coruña") # → "Coruna" normalize_text("Cáceres") # → "Caceres" # Caracteres especiales normalize_text("Peñíscola") # → "Peniscola" normalize_text("François") # → "Francois"
Casos extremos manejados:
# Texto ya normalizado - sin cambios normalize_text("MADRID") # → "MADRID" # Mezcla de problemas normalize_text("Cádiz - AndalucÃ\xada") # → "Cadiz - Andalucia"
Nota
La función es segura con datos de entrada inválidos - si recibe algo que no es string, retorna el valor original sin modificar. Esto evita errores en cadenas de procesamiento de datos.
Advertencia
La normalización es irreversible. Si necesita preservar el texto original con acentos, haga una copia antes de llamar esta función.
- Technical details:
Usa
unicodedata.normalize('NFD', text)para descomposición UnicodeAplica
encode('ascii', 'ignore')para eliminar caracteres no-ASCIIManeja específicamente problemas de doble codificación latin-1/UTF-8
Incluye tabla de reemplazos para caracteres que
unicodedatano maneja
Ver también
normalize_dict_strings()para normalizar diccionarios completosnormalize_api_response()para procesar respuestas completas de APIDocumentación de
unicodedatapara detalles sobre normalización Unicode
- datadis_python.utils.normalize_api_response(response)[fuente]
Función principal para normalizar respuestas completas de la API de Datadis.
Esta es la función de entrada principal del sistema de normalización del SDK. Detecta automáticamente el tipo de respuesta (diccionario o lista) y aplica la estrategia de normalización correspondiente para limpiar todos los strings de problemas de encoding y caracteres especiales.
- Función de router inteligente:
Dict response: Usa
normalize_dict_strings()para procesamiento recursivoList response: Usa
normalize_list_strings()para procesamiento recursivoOtros tipos: Retorna sin modificar (para compatibilidad futura)
Esta función es llamada automáticamente por el
HTTPClientdel SDK, por lo que los usuarios normalmente no necesitan llamarla manualmente. Sin embargo, puede ser útil para procesar datos cacheados o respuestas guardadas localmente.- Casos de uso típicos:
Auto-procesamiento: Llamada automática por HTTPClient en todas las respuestas JSON
Procesamiento manual: Para limpiar datos guardados localmente o cacheados
Testing: Para normalizar respuestas mock en tests unitarios
Debugging: Para limpiar respuestas antes de análisis manual
- Parámetros:
response (Union[Dict[str, Any], List[Any]]) – Respuesta completa de la API de Datadis en formato JSON deserializado. Puede ser un diccionario (respuesta de objeto) o lista (respuesta de array)
- Devuelve:
Respuesta normalizada con la misma estructura pero con todos los strings limpios de problemas de encoding y caracteres especiales
- Tipo del valor devuelto:
Union[Dict[str, Any], List[Any]]
Ejemplo
Respuestas típicas de diferentes endpoints:
# Respuesta de get_supplies (lista de objetos) supplies_response = [ {"cups": "ES001...", "distributor": "EDISTRIBUCIÃ\x93N"}, {"cups": "ES002...", "distributor": "Málaga Eléctrica"} ] clean_supplies = normalize_api_response(supplies_response) # Resultado: [{"cups": "ES001...", "distributor": "EDISTRIBUCION"}, ...] # Respuesta de get_consumption (objeto con arrays) consumption_response = { "consumption": [ {"date": "2024/01/01", "distributor": "EDISTRIBUCIÃ\x93N"} ], "distributor_error": [] } clean_consumption = normalize_api_response(consumption_response) # Resultado: {"consumption": [{"date": "2024/01/01", "distributor": "EDISTRIBUCION"}], ...}
Procesamiento manual de datos guardados:
# Datos cacheados que pueden tener problemas de encoding cached_data = load_from_cache("datadis_supplies.json") clean_data = normalize_api_response(cached_data) # Ahora clean_data está libre de problemas de encoding
Uso en testing:
# Mock response con problemas simulados de Datadis mock_response = {"distributor": "EDISTRIBUCIÃ\x93N"} normalized_mock = normalize_api_response(mock_response) # Para tests con datos normalizados
Nota
Esta función es completamente segura con cualquier tipo de entrada. Si recibe datos que no puede procesar, los retorna sin modificar, garantizando que nunca cause errores en el pipeline de datos.
- Performance:
La función crea nuevas estructuras de datos en lugar de modificar las originales, lo que la hace segura para uso concurrente pero puede consumir más memoria con respuestas muy grandes (miles de registros).
- Integration:
Esta función está integrada automáticamente en la cadena de procesamiento de respuestas del
HTTPClient, por lo que todos los datos que llegan a los usuarios finales ya están normalizados.
Ver también
normalize_text()para normalización básica de stringsnormalize_dict_strings()para objetos JSONnormalize_list_strings()para arrays JSONdatadis_python.utils.http.HTTPClientdonde se integra automáticamente
Added in version 1.0: Normalización automática integrada en todo el SDK
Distinto en la versión 2.0: Mejorada detección de problemas de doble codificación UTF-8