python-esios 2.0.0__tar.gz → 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_esios-2.0.0 → python_esios-2.0.1}/.github/workflows/publish.yml +2 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/.gitignore +1 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/PKG-INFO +1 -1
- {python_esios-2.0.0 → python_esios-2.0.1}/pyproject.toml +1 -1
- python_esios-2.0.1/src/esios/data/catalogs/__init__.py +0 -0
- python_esios-2.0.1/src/esios/data/catalogs/archives/__init__.py +5 -0
- python_esios-2.0.1/src/esios/data/catalogs/archives/catalog.py +163 -0
- python_esios-2.0.1/src/esios/data/catalogs/archives/refresh.py +95 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/managers/archives.py +28 -15
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/processing/i90.py +63 -20
- python_esios-2.0.1/tests/__init__.py +0 -0
- python_esios-2.0.0/.claude-plugin/marketplace.json +0 -15
- python_esios-2.0.0/.claude-plugin/plugin.json +0 -12
- {python_esios-2.0.0 → python_esios-2.0.1}/CHANGELOG.md +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/LICENSE +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/README.md +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/.gitignore +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/01_Quickstart/01_Setup and First Query.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/01_Search Indicators.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/02_Historical Data.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/03_Multi-Geography Indicators.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/04_Compare Indicators.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/05_Market Prices.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/06_Generation and Demand.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/03_Archives/01_Download Archives.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/03_Archives/02_I90 Settlement Files.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/04_Caching/01_Cache Management.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/05_Advanced/01_Ad-hoc Pandas Expressions.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/05_Advanced/02_Async Client.ipynb +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/01_Quickstart/01_Setup and First Query.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/01_Search Indicators.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/02_Historical Data.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/03_Multi-Geography Indicators.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/04_Compare Indicators.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/05_Market Prices.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/06_Generation and Demand.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/03_Archives/01_Download Archives.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/03_Archives/02_I90 Settlement Files.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/04_Caching/01_Cache Management.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/05_Advanced/01_Ad-hoc Pandas Expressions.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/05_Advanced/02_Async Client.yaml +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/examples/generate.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1/src/esios/.agents}/skills/esios/SKILL.md +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/__init__.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/async_client.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cache.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/__init__.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/app.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/archives.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/cache_cmd.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/config.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/config_cmd.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/exec_cmd.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/cli/indicators.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/client.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/constants.py +0 -0
- {python_esios-2.0.0/tests → python_esios-2.0.1/src/esios/data}/__init__.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/exceptions.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/managers/__init__.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/managers/base.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/managers/indicators.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/managers/offer_indicators.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/models/__init__.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/models/archive.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/models/indicator.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/models/offer_indicator.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/processing/__init__.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/processing/dataframes.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/src/esios/processing/zip.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/conftest.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/test_cache.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/test_client.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/test_dataframes.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/test_exceptions.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/test_managers.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/test_models.py +0 -0
- {python_esios-2.0.0 → python_esios-2.0.1}/tests/test_zip.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-esios
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: A Python wrapper for the ESIOS API (Spanish electricity market)
|
|
5
5
|
Project-URL: Homepage, https://github.com/datons/python-esios
|
|
6
6
|
Project-URL: Repository, https://github.com/datons/python-esios
|
|
File without changes
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Static catalog of ESIOS archives.
|
|
2
|
+
|
|
3
|
+
Auto-generated by refresh.py — do not edit manually.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
ARCHIVES_CATALOG: dict[int, dict[str, str]] = {
|
|
9
|
+
2: {"name": "A1_liquicomun", "description": "Avance de liquidación A1", "horizon": "M", "archive_type": "zip"},
|
|
10
|
+
3: {"name": "A2_liquicomun", "description": "Avance de liquidación A2", "horizon": "M", "archive_type": "zip"},
|
|
11
|
+
8: {"name": "C2_liquicomun", "description": "Cierre de liquidación C2", "horizon": "M", "archive_type": "zip"},
|
|
12
|
+
9: {"name": "C3_liquicomun", "description": "Cierre de liquidación C3", "horizon": "M", "archive_type": "zip"},
|
|
13
|
+
10: {"name": "C4_liquicomun", "description": "Cierre de liquidación C4", "horizon": "M", "archive_type": "zip"},
|
|
14
|
+
11: {"name": "C5_liquicomun", "description": "Cierre de liquidación C5", "horizon": "M", "archive_type": "zip"},
|
|
15
|
+
12: {"name": "C6_liquicomun", "description": "Cierre de liquidación C6", "horizon": "M", "archive_type": "zip"},
|
|
16
|
+
13: {"name": "C7_liquicomun", "description": "Cierre de liquidación C7", "horizon": "M", "archive_type": "zip"},
|
|
17
|
+
14: {"name": "C8_liquicomun", "description": "Cierre de liquidación C8", "horizon": "M", "archive_type": "zip"},
|
|
18
|
+
15: {"name": "hemeroteca_DD_ent", "description": "Fichero de hemeroteca de entrada.", "horizon": "D", "archive_type": "zip"},
|
|
19
|
+
16: {"name": "hemeroteca_DD_sal", "description": "Fichero de hemeroteca de salida", "horizon": "D", "archive_type": "zip"},
|
|
20
|
+
17: {"name": "liquicierre", "description": "Resultados de la Regulación Secundaria exigidos para la Liquidación", "horizon": "D", "archive_type": "xml"},
|
|
21
|
+
18: {"name": "totalpdbf", "description": "Programa agregado resultante del PBF", "horizon": "D", "archive_type": "xml"},
|
|
22
|
+
19: {"name": "totalrpdvpprec", "description": "Solución de Restricciones Técnicas", "horizon": "D", "archive_type": "xml"},
|
|
23
|
+
20: {"name": "totalpdvp", "description": "PVP Agregado Horizonte Diario", "horizon": "D", "archive_type": "xml"},
|
|
24
|
+
21: {"name": "totalasigsec", "description": "Asignación Regulación Secundaria", "horizon": "D", "archive_type": "xml"},
|
|
25
|
+
22: {"name": "totalrpibcirest", "description": "Solución de Restricciones Técnicas MI", "horizon": "H", "archive_type": "xml"},
|
|
26
|
+
23: {"name": "totalasigdesv", "description": "Mercado de Gestión de Desvíos", "horizon": "H", "archive_type": "xml"},
|
|
27
|
+
24: {"name": "totalasigter", "description": "Mercado de Regulación Terciaria", "horizon": "D", "archive_type": "xml"},
|
|
28
|
+
25: {"name": "totalenersec", "description": "Energía Secundaria utilizada", "horizon": "D", "archive_type": "xml"},
|
|
29
|
+
26: {"name": "totalliquicierre", "description": "Cálculo Variación Coste Fijo", "horizon": "D", "archive_type": "xml"},
|
|
30
|
+
27: {"name": "totalrp48prec", "description": "Redespachos Seguridad Tiempo Real (Horario)", "horizon": "H", "archive_type": "xml"},
|
|
31
|
+
28: {"name": "totalrp48preccierre", "description": "Redespachos Seguridad Tiempo Real (Cierre)", "horizon": "D", "archive_type": "xml"},
|
|
32
|
+
29: {"name": "totalp48", "description": "Programa Agregado P48 (Horario)", "horizon": "H", "archive_type": "xml"},
|
|
33
|
+
30: {"name": "totalp48cierre", "description": "Programa Agregado P48 (Cierre)", "horizon": "D", "archive_type": "xml"},
|
|
34
|
+
32: {"name": "I3DIA", "description": "Información agregada diaria por tecnología (I3DIA)", "horizon": "D", "archive_type": "zip"},
|
|
35
|
+
33: {"name": "IMES", "description": "Cuotas mensuales por Sujetos de Liquidación (IMES)", "horizon": "M", "archive_type": "zip"},
|
|
36
|
+
34: {"name": "I90DIA", "description": "Información de detalle por Unidad de Programación (I90DIA)", "horizon": "D", "archive_type": "zip"},
|
|
37
|
+
35: {"name": "COEF_PERD_PEN_MM", "description": "Coeficientes horarios de pérdidas en el sistema peninsular", "horizon": "M", "archive_type": "xls"},
|
|
38
|
+
36: {"name": "COEF_PERD_MEL_MM", "description": "Coeficientes horarios de pérdidas en el sistema de Melilla", "horizon": "M", "archive_type": "xls"},
|
|
39
|
+
37: {"name": "COEF_PERD_CEU_MM", "description": "Coeficientes horarios de pérdidas en el sistema de Ceuta", "horizon": "M", "archive_type": "xls"},
|
|
40
|
+
38: {"name": "COEF_PERD_CAN_MM", "description": "Coeficientes horarios de pérdidas en el sistema de Canarias", "horizon": "M", "archive_type": "xls"},
|
|
41
|
+
39: {"name": "COEF_PERD_BAL_MM", "description": "Coeficientes horarios de pérdidas en el sistema de Baleares", "horizon": "M", "archive_type": "xls"},
|
|
42
|
+
40: {"name": "COEF_KEST_MM", "description": "Coeficiente de ajuste horario estimado en el sistema peninsular y no peninsular", "horizon": "M", "archive_type": "xls"},
|
|
43
|
+
42: {"name": "Espec_Subasta_Diaria_EF", "description": "Especificación de subastas explícitas Diarias de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
44
|
+
43: {"name": "Espec_Subasta_Diaria_FE", "description": "Especificación de subastas explícitas Diarias de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
45
|
+
44: {"name": "Espec_Subasta_Intra1_EF", "description": "Especificación de subastas explícitas Intradiarias 1 de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
46
|
+
45: {"name": "Espec_Subasta_Intra1_FE", "description": "Especificación de subastas explícitas Intradiarias 1 de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
47
|
+
46: {"name": "Espec_Subasta_Intra2_EF", "description": "Especificación de subastas explícitas Intradiarias 2 de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
48
|
+
47: {"name": "Espec_Subasta_Intra2_FE", "description": "Especificación de subastas explícitas Intradiarias 2 de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
49
|
+
48: {"name": "Espec_Subasta_Mensual_EF", "description": "Especificación de subastas explícitas Mensuales de capacidad en la interconexión con Francia", "horizon": "M", "archive_type": "pdf"},
|
|
50
|
+
49: {"name": "Espec_Subasta_Mensual_FE", "description": "Especificación de subastas explícitas Mensuales de capacidad en la interconexión con Francia", "horizon": "M", "archive_type": "pdf"},
|
|
51
|
+
50: {"name": "Espec_Subasta_Anual_EF", "description": "Especificación de subastas explícitas Anuales de capacidad en la interconexión con Francia", "horizon": "A", "archive_type": "pdf"},
|
|
52
|
+
51: {"name": "Espec_Subasta_Anual_FE", "description": "Especificación de subastas explícitas Anuales de capacidad en la interconexión con Francia", "horizon": "A", "archive_type": "pdf"},
|
|
53
|
+
56: {"name": "Espec_Subasta_Intra2_EF_Cancel", "description": "Especificación de subastas explícitas Intradiarias 2 de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
54
|
+
57: {"name": "Espec_Subasta_Intra2_FE_Cancel", "description": "Especificación de subastas explícitas Intradiarias 2 de capacidad en la interconexión con Francia", "horizon": "D", "archive_type": "pdf"},
|
|
55
|
+
58: {"name": "Espec_Subasta_Mensual_EF_Cancel", "description": "Especificación de subastas explícitas Mensuales de capacidad en la interconexión con Francia", "horizon": "M", "archive_type": "pdf"},
|
|
56
|
+
59: {"name": "Espec_Subasta_Mensual_FE_Cancel", "description": "Especificación de subastas explícitas Mensuales de capacidad en la interconexión con Francia", "horizon": "M", "archive_type": "pdf"},
|
|
57
|
+
62: {"name": "IND_DemandaInterrumpible", "description": "IND_DemandaInterrumpible", "horizon": "D", "archive_type": "json"},
|
|
58
|
+
63: {"name": "IND_Interconexiones", "description": "IND_Interconexiones", "horizon": "D", "archive_type": "json"},
|
|
59
|
+
64: {"name": "IND_PotenciaInstalada", "description": "IND_PotenciaInstalada", "horizon": "M", "archive_type": "json"},
|
|
60
|
+
65: {"name": "IND_PrecioDesvios", "description": "IND_PrecioDesvios", "horizon": "D", "archive_type": "json"},
|
|
61
|
+
66: {"name": "IND_PrecioFinal", "description": "IND_PrecioFinal", "horizon": "D", "archive_type": "json"},
|
|
62
|
+
67: {"name": "IND_Umbrales", "description": "IND_Umbrales", "horizon": "D", "archive_type": "json"},
|
|
63
|
+
68: {"name": "INF_SUBASTA_AA", "description": "Informe anual de subastas de capacidad con Francia", "horizon": "A", "archive_type": "pdf"},
|
|
64
|
+
69: {"name": "INF_SUBASTA_MM", "description": "Informe mensual de subastas de capacidad con Francia", "horizon": "M", "archive_type": "pdf"},
|
|
65
|
+
70: {"name": "PVPC_CURV_DD", "description": "Datos origen de curva PVPC", "horizon": "D", "archive_type": "json"},
|
|
66
|
+
71: {"name": "PVPC_DETALLE_DD", "description": "PVPC Término de facturación energía activa – Desglose", "horizon": "D", "archive_type": "xls"},
|
|
67
|
+
72: {"name": "PVPC_GEN_P1_DD", "description": "Datos origen de tarifa general P1", "horizon": "D", "archive_type": "json"},
|
|
68
|
+
73: {"name": "PVPC_NOC_P1_DD", "description": "Datos origen de tarifa nocturna P1", "horizon": "D", "archive_type": "json"},
|
|
69
|
+
74: {"name": "PVPC_NOC_P2_DD", "description": "Datos origen de tarifa nocturna P2", "horizon": "D", "archive_type": "json"},
|
|
70
|
+
75: {"name": "PVPC_VHC_P1_DD", "description": "Datos origen de tarifa vehículo eléctrico P1", "horizon": "D", "archive_type": "json"},
|
|
71
|
+
76: {"name": "PVPC_VHC_P2_DD", "description": "Datos origen de tarifa vehículo eléctrico P2", "horizon": "D", "archive_type": "json"},
|
|
72
|
+
77: {"name": "PVPC_VHC_P3_DD", "description": "Datos origen de tarifa vehículo eléctrico P3", "horizon": "D", "archive_type": "json"},
|
|
73
|
+
78: {"name": "perfilconsumo", "description": "PVPC Coeficientes de perfilado", "horizon": "S", "archive_type": "xml"},
|
|
74
|
+
79: {"name": "preciovoluntariopconsumidor", "description": "PVPC por ciclo de lectura", "horizon": "D", "archive_type": "xml"},
|
|
75
|
+
80: {"name": "pvpcdesglosehorario", "description": "PVPC Término de facturación energía activa", "horizon": "D", "archive_type": "xml"},
|
|
76
|
+
81: {"name": "UnidadesFisicas", "description": "Datos Estructurales de unidades físicas", "horizon": "NA", "archive_type": "json"},
|
|
77
|
+
82: {"name": "UnidadesProgramacion", "description": "Datos estructurales de unidades de programación", "horizon": "NA", "archive_type": "json"},
|
|
78
|
+
83: {"name": "SujetosMercado", "description": "Datos estructurales de sujetos de mercado", "horizon": "NA", "archive_type": "json"},
|
|
79
|
+
84: {"name": "ParticipantesSubasta", "description": "Datos estructurales de participantes de subasta", "horizon": "NA", "archive_type": "json"},
|
|
80
|
+
87: {"name": "Resultado_Subasta_Mensual_FRA", "description": "Subastas mensuales del calendariode subastas de Francia", "horizon": "M", "archive_type": "xls"},
|
|
81
|
+
88: {"name": "Resultado_Subasta_Anual_FRA", "description": "Subastas anuales del calendariode subastas de Francia", "horizon": "A", "archive_type": "xls"},
|
|
82
|
+
89: {"name": "Descargos_AND_Planificados", "description": "Descargos Andorra", "horizon": "O", "archive_type": "xml"},
|
|
83
|
+
91: {"name": "Descargos_MAR_Planificados", "description": "Descargos Marruecos", "horizon": "O", "archive_type": "xml"},
|
|
84
|
+
93: {"name": "Descargos_POR_Planificados", "description": "Descargos Portugal", "horizon": "O", "archive_type": "xml"},
|
|
85
|
+
95: {"name": "Descargos_FRA_Planificados", "description": "Descargos Francia", "horizon": "O", "archive_type": "xml"},
|
|
86
|
+
101: {"name": "REE_InterChangeAvailab_FRA", "description": "Cambios en disponibilidad real de capacidad en interconexión con Francia", "horizon": "O", "archive_type": "xml"},
|
|
87
|
+
102: {"name": "REE_InterChangeAvailab_POR", "description": "Cambios en disponibilidad real de capacidad en interconexión con Portugal", "horizon": "O", "archive_type": "xml"},
|
|
88
|
+
105: {"name": "Indisponibilidades", "description": "Indisponibilidades de las unidades de generación y consumo", "horizon": "D", "archive_type": "xls"},
|
|
89
|
+
106: {"name": "PlanesMantenimiento", "description": "Plan de mantenimiento", "horizon": "M", "archive_type": "xls"},
|
|
90
|
+
107: {"name": "p48cierre", "description": "Cierre de programa Desagregado P48", "horizon": "D", "archive_type": "xml"},
|
|
91
|
+
108: {"name": "REE_AggGenOutput", "description": "Generación real por tipo de producción", "horizon": "QM", "archive_type": "xml"},
|
|
92
|
+
109: {"name": "REE_ActualGenOutput", "description": "Generación real por unidad física", "horizon": "D", "archive_type": "xml"},
|
|
93
|
+
110: {"name": "GenerationUnits", "description": "Generation Units Structural Data", "horizon": "NA", "archive_type": "json"},
|
|
94
|
+
111: {"name": "ProgrammingUnits", "description": "Programming Units Structural Data", "horizon": "NA", "archive_type": "json"},
|
|
95
|
+
112: {"name": "BalanceResponsibleParties", "description": "Balance Responsible Parties Structural Data", "horizon": "NA", "archive_type": "json"},
|
|
96
|
+
113: {"name": "EntitledParticipants", "description": "Entitled Participants Structural Data", "horizon": "NA", "archive_type": "json"},
|
|
97
|
+
114: {"name": "IND_DemandaPrevProg", "description": "IND_DemandaPrevProg", "horizon": "D", "archive_type": "json"},
|
|
98
|
+
115: {"name": "IND_DemandaRealGen", "description": "IND_DemandaRealGen", "horizon": "D", "archive_type": "json"},
|
|
99
|
+
116: {"name": "IND_MaxMin", "description": "IND_MaxMin", "horizon": "D", "archive_type": "json"},
|
|
100
|
+
117: {"name": "IND_MaxMinRenovEol", "description": "IND_MaxMinRenovEol", "horizon": "D", "archive_type": "json"},
|
|
101
|
+
118: {"name": "ActividadesSubactividades", "description": "Informe de actividades y subactividades", "horizon": "NA", "archive_type": "pdf"},
|
|
102
|
+
119: {"name": "AgregacionesValidas", "description": "Informe de agregaciones válidas", "horizon": "NA", "archive_type": "pdf"},
|
|
103
|
+
120: {"name": "CNAEValidos", "description": "Informe de códigos CNAE válidos", "horizon": "NA", "archive_type": "pdf"},
|
|
104
|
+
121: {"name": "Comercializadores", "description": "Informe de comercializadores", "horizon": "NA", "archive_type": "pdf"},
|
|
105
|
+
122: {"name": "Concentradores", "description": "Informe de concentradores", "horizon": "NA", "archive_type": "pdf"},
|
|
106
|
+
123: {"name": "DiscriminacionHoraria", "description": "Informe de discriminaciones horarias", "horizon": "NA", "archive_type": "pdf"},
|
|
107
|
+
124: {"name": "Distribuidores", "description": "Informe de distribuidores", "horizon": "NA", "archive_type": "pdf"},
|
|
108
|
+
125: {"name": "Fabricantes", "description": "Informe de fabricantes", "horizon": "NA", "archive_type": "pdf"},
|
|
109
|
+
126: {"name": "Magnitudes", "description": "Informe de magnitudes", "horizon": "NA", "archive_type": "pdf"},
|
|
110
|
+
127: {"name": "ModeloContadores", "description": "Informe de modelo de contadores", "horizon": "NA", "archive_type": "pdf"},
|
|
111
|
+
128: {"name": "ModeloRegistradores", "description": "Informe de modelos de registradores", "horizon": "NA", "archive_type": "pdf"},
|
|
112
|
+
129: {"name": "ModeloTransformadores", "description": "Informe de modelo de transformadores", "horizon": "NA", "archive_type": "pdf"},
|
|
113
|
+
130: {"name": "NivelesTension", "description": "Informe de niveles de tensión", "horizon": "NA", "archive_type": "pdf"},
|
|
114
|
+
131: {"name": "Provincias", "description": "Informe de provincias", "horizon": "NA", "archive_type": "pdf"},
|
|
115
|
+
132: {"name": "Representantes", "description": "Informe de representantes", "horizon": "NA", "archive_type": "pdf"},
|
|
116
|
+
133: {"name": "Subsistemas", "description": "Informe de subsistemas", "horizon": "NA", "archive_type": "pdf"},
|
|
117
|
+
134: {"name": "ZonasGeograficas", "description": "Informe de zonas geográficas", "horizon": "NA", "archive_type": "pdf"},
|
|
118
|
+
135: {"name": "TarifaAcceso", "description": "Informe de tarifas de acceso", "horizon": "NA", "archive_type": "pdf"},
|
|
119
|
+
136: {"name": "A6_liquicomun", "description": "Avance de liquidación A6", "horizon": "M", "archive_type": "zip"},
|
|
120
|
+
137: {"name": "A7_liquicomun", "description": "Avance de liquidación A7", "horizon": "M", "archive_type": "zip"},
|
|
121
|
+
139: {"name": "IND_EnergiaMensual", "description": "IND_EnergiaMensual", "horizon": "M", "archive_type": "json"},
|
|
122
|
+
140: {"name": "IND_EnergiaAnual", "description": "IND_EnergiaAnual", "horizon": "A", "archive_type": "json"},
|
|
123
|
+
142: {"name": "ConsumidoresDirectos", "description": "Informe de Consumidores Directos", "horizon": "NA", "archive_type": "pdf"},
|
|
124
|
+
143: {"name": "MotivosObjecionEdLD", "description": "Informe de Motivos Objeción EdLD", "horizon": "NA", "archive_type": "pdf"},
|
|
125
|
+
144: {"name": "MotivosObjecionEdLOS", "description": "Informe de Motivos Objeción EdLOS", "horizon": "NA", "archive_type": "pdf"},
|
|
126
|
+
145: {"name": "TiposMedidaPuntoMedida", "description": "Informe de tipos de medida de punto medida", "horizon": "NA", "archive_type": "pdf"},
|
|
127
|
+
146: {"name": "TiposMedidaPuntoFrontera", "description": "Informe de tipos de medida de punto frontera", "horizon": "NA", "archive_type": "pdf"},
|
|
128
|
+
147: {"name": "Espec_Subasta_Mensual_EP", "description": "Especificación de subastas explícitas Mensuales de capacidad en la interconexión con Portugal", "horizon": "M", "archive_type": "pdf"},
|
|
129
|
+
148: {"name": "Espec_Subasta_Mensual_PE", "description": "Especificación de subastas explícitas Mensuales de capacidad en la interconexión con Portugal", "horizon": "M", "archive_type": "pdf"},
|
|
130
|
+
149: {"name": "Espec_Subasta_Trimestral_EP", "description": "Especificación de subastas explícitas Trimestrales de capacidad en la interconexión con Portugal", "horizon": "T", "archive_type": "pdf"},
|
|
131
|
+
150: {"name": "Espec_Subasta_Trimestral_PE", "description": "Especificación de subastas explícitas Trimestrales de capacidad en la interconexión con Portugal", "horizon": "T", "archive_type": "pdf"},
|
|
132
|
+
151: {"name": "Espec_Subasta_Anual_EP", "description": "Especificación de subastas explícitas Trimestrales de capacidad en la interconexión con Portugal", "horizon": "A", "archive_type": "pdf"},
|
|
133
|
+
152: {"name": "Espec_Subasta_Anual_PE", "description": "Especificación de subastas explícitas Trimestrales de capacidad en la interconexión con Portugal", "horizon": "A", "archive_type": "pdf"},
|
|
134
|
+
159: {"name": "Resultado_Subasta_Mensual_POR", "description": "Subastas mensuales del calendario de subastas de Portugal", "horizon": "M", "archive_type": "xls"},
|
|
135
|
+
160: {"name": "Resultado_Subasta_Anual_POR", "description": "Subastas anuales del calendario de subastas de Portugal", "horizon": "A", "archive_type": "xls"},
|
|
136
|
+
161: {"name": "Resultado_Subasta_Trimestral_POR", "description": "Subastas trimestrales del calendario de subastas de Portugal", "horizon": "T", "archive_type": "xls"},
|
|
137
|
+
164: {"name": "CodigosTensiones", "description": "Informe de códigos de tensiones de suministro", "horizon": "NA", "archive_type": "pdf"},
|
|
138
|
+
165: {"name": "UnidadesConsumoGeneracion", "description": "Informe de unidades de consumo de generación", "horizon": "NA", "archive_type": "pdf"},
|
|
139
|
+
166: {"name": "CodigosAutoconsumo", "description": "Informe de códigos de autoconsumo", "horizon": "NA", "archive_type": "pdf"},
|
|
140
|
+
167: {"name": "IND_PotenciaInstaladaNacional", "description": "IND_PotenciaInstaladaNacional", "horizon": "M", "archive_type": "json"},
|
|
141
|
+
168: {"name": "IND_EnergiaMensualNacional", "description": "IND_EnergiaMensualNacional", "horizon": "M", "archive_type": "json"},
|
|
142
|
+
169: {"name": "IND_EnergiaAnualNacional", "description": "IND_EnergiaAnualNacional", "horizon": "A", "archive_type": "json"},
|
|
143
|
+
170: {"name": "IND_CoeficientesCO2", "description": "IND_CoeficientesCO2", "horizon": "NA", "archive_type": "json"},
|
|
144
|
+
171: {"name": "IND_InformacionApp", "description": "IND_InformacionApp", "horizon": "NA", "archive_type": "json"},
|
|
145
|
+
172: {"name": "IND_PreguntasApp", "description": "IND_PreguntasApp", "horizon": "NA", "archive_type": "json"},
|
|
146
|
+
173: {"name": "IND_VersionApp", "description": "IND_VersionApp", "horizon": "NA", "archive_type": "json"},
|
|
147
|
+
174: {"name": "IND_PrecioMinorista", "description": "IND_PrecioMinorista", "horizon": "D", "archive_type": "json"},
|
|
148
|
+
181: {"name": "REE_BalancingEnerBids", "description": "Mercado de Regulación Terciaria", "horizon": "QM", "archive_type": "csv"},
|
|
149
|
+
183: {"name": "IND_EnergiaAnualAutoconsumoNacional", "description": "IND_EnergiaAnualAutoconsumoNacional", "horizon": "A", "archive_type": "json"},
|
|
150
|
+
184: {"name": "IND_EnergiaMensualAutoconsumoNacional", "description": "IND_EnergiaMensualAutoconsumoNacional", "horizon": "M", "archive_type": "json"},
|
|
151
|
+
185: {"name": "ActivacionesDelServicio", "description": "Activaciones del Servicio", "horizon": "NA", "archive_type": "json"},
|
|
152
|
+
186: {"name": "ServiceActivation", "description": "Service Activation", "horizon": "NA", "archive_type": "json"},
|
|
153
|
+
187: {"name": "C2_PrecioFinal", "description": "Precio final de la energÃa C2", "horizon": "M", "archive_type": "zip"},
|
|
154
|
+
188: {"name": "C5_PrecioFinal", "description": "Precio final de la energÃa C5", "horizon": "M", "archive_type": "zip"},
|
|
155
|
+
193: {"name": "IND_Novedades", "description": "IND_Novedades", "horizon": "NA", "archive_type": "json"},
|
|
156
|
+
194: {"name": "IND_Novedades_Paso1", "description": "Json lottie Paso1", "horizon": "NA", "archive_type": "json"},
|
|
157
|
+
195: {"name": "IND_Novedades_Paso2", "description": "Json lottie Paso2", "horizon": "NA", "archive_type": "json"},
|
|
158
|
+
196: {"name": "IND_Novedades_Paso3", "description": "Json lottie Paso3", "horizon": "NA", "archive_type": "json"},
|
|
159
|
+
197: {"name": "IND_Novedades_Paso4", "description": "Json lottie Paso3", "horizon": "NA", "archive_type": "json"},
|
|
160
|
+
198: {"name": "IND_Novedades_Step1", "description": "Json lottie Step1", "horizon": "NA", "archive_type": "json"},
|
|
161
|
+
199: {"name": "IND_Novedades_Step2", "description": "Json lottie Step2", "horizon": "NA", "archive_type": "json"},
|
|
162
|
+
}
|
|
163
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Refresh the static archives catalog by scanning the ESIOS API.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
uv run python -m esios.data.catalogs.archives.refresh
|
|
5
|
+
|
|
6
|
+
Scans archive IDs 1-200 against the live API and regenerates catalog.py.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def scan_archives(max_id: int = 200) -> dict[int, dict[str, str]]:
|
|
16
|
+
"""Scan ESIOS API for all accessible archives."""
|
|
17
|
+
from esios import ESIOSClient
|
|
18
|
+
|
|
19
|
+
client = ESIOSClient()
|
|
20
|
+
catalog: dict[int, dict[str, str]] = {}
|
|
21
|
+
|
|
22
|
+
for i in range(1, max_id + 1):
|
|
23
|
+
try:
|
|
24
|
+
data = client.get(f"archives/{i}")
|
|
25
|
+
a = data.get("archive", {})
|
|
26
|
+
catalog[i] = {
|
|
27
|
+
"name": a.get("name", ""),
|
|
28
|
+
"description": a.get("description", ""),
|
|
29
|
+
"horizon": a.get("horizon", ""),
|
|
30
|
+
"archive_type": a.get("archive_type", ""),
|
|
31
|
+
}
|
|
32
|
+
except Exception:
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
return catalog
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def generate_catalog_py(catalog: dict[int, dict[str, str]]) -> str:
|
|
39
|
+
"""Generate the catalog.py source code."""
|
|
40
|
+
lines = [
|
|
41
|
+
'"""Static catalog of ESIOS archives.',
|
|
42
|
+
"",
|
|
43
|
+
"Auto-generated by refresh.py — do not edit manually.",
|
|
44
|
+
'"""',
|
|
45
|
+
"",
|
|
46
|
+
"from __future__ import annotations",
|
|
47
|
+
"",
|
|
48
|
+
"ARCHIVES_CATALOG: dict[int, dict[str, str]] = {",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
for id_ in sorted(catalog):
|
|
52
|
+
entry = catalog[id_]
|
|
53
|
+
name = entry["name"]
|
|
54
|
+
desc = entry["description"].replace('"', '\\"')
|
|
55
|
+
horizon = entry["horizon"]
|
|
56
|
+
atype = entry["archive_type"]
|
|
57
|
+
lines.append(
|
|
58
|
+
f' {id_}: {{"name": "{name}", "description": "{desc}", '
|
|
59
|
+
f'"horizon": "{horizon}", "archive_type": "{atype}"}},'
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
lines.append("}")
|
|
63
|
+
lines.append("")
|
|
64
|
+
return "\n".join(lines)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def main() -> None:
|
|
68
|
+
from esios.data.catalogs.archives.catalog import ARCHIVES_CATALOG
|
|
69
|
+
|
|
70
|
+
old_ids = set(ARCHIVES_CATALOG.keys())
|
|
71
|
+
|
|
72
|
+
print(f"Scanning ESIOS API for archives (IDs 1-200)...")
|
|
73
|
+
catalog = scan_archives()
|
|
74
|
+
new_ids = set(catalog.keys())
|
|
75
|
+
|
|
76
|
+
# Diff summary
|
|
77
|
+
added = new_ids - old_ids
|
|
78
|
+
removed = old_ids - new_ids
|
|
79
|
+
|
|
80
|
+
print(f"\nFound {len(catalog)} archives (was {len(old_ids)})")
|
|
81
|
+
if added:
|
|
82
|
+
print(f" Added: {sorted(added)}")
|
|
83
|
+
if removed:
|
|
84
|
+
print(f" Removed: {sorted(removed)}")
|
|
85
|
+
if not added and not removed:
|
|
86
|
+
print(" No changes in archive IDs.")
|
|
87
|
+
|
|
88
|
+
# Write catalog.py
|
|
89
|
+
catalog_path = Path(__file__).parent / "catalog.py"
|
|
90
|
+
catalog_path.write_text(generate_catalog_py(catalog))
|
|
91
|
+
print(f"\nWrote {catalog_path}")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
main()
|
|
@@ -76,20 +76,20 @@ class ArchiveHandle:
|
|
|
76
76
|
date: str | None = None,
|
|
77
77
|
output_dir: str | Path | None = None,
|
|
78
78
|
date_type: str = "datos",
|
|
79
|
-
) -> Path:
|
|
79
|
+
) -> list[Path]:
|
|
80
80
|
"""Download archive files for a single date or date range.
|
|
81
81
|
|
|
82
82
|
Files are always stored in the cache directory. If ``output_dir`` is
|
|
83
83
|
provided, a copy is placed there as well.
|
|
84
84
|
|
|
85
|
-
Returns
|
|
85
|
+
Returns a sorted list of downloaded/cached file paths.
|
|
86
86
|
"""
|
|
87
87
|
if date and not (start and end):
|
|
88
88
|
self.configure(date=date, date_type=date_type)
|
|
89
89
|
cache_folder = self._download_single()
|
|
90
90
|
if output_dir:
|
|
91
91
|
self._copy_to_output(cache_folder, Path(output_dir))
|
|
92
|
-
return cache_folder
|
|
92
|
+
return sorted(f for f in cache_folder.iterdir() if f.is_file())
|
|
93
93
|
|
|
94
94
|
if not (start and end):
|
|
95
95
|
raise ValueError("Provide 'date' or both 'start' and 'end'.")
|
|
@@ -101,7 +101,7 @@ class ArchiveHandle:
|
|
|
101
101
|
horizon = self.metadata.get("archive", {}).get("horizon", "D")
|
|
102
102
|
archive_type = self.metadata.get("archive", {}).get("archive_type", "zip")
|
|
103
103
|
current = start_date
|
|
104
|
-
|
|
104
|
+
files: list[Path] = []
|
|
105
105
|
|
|
106
106
|
while current <= end_date:
|
|
107
107
|
if horizon == "M":
|
|
@@ -118,7 +118,7 @@ class ArchiveHandle:
|
|
|
118
118
|
logger.info("Cache hit: %s", cache_folder)
|
|
119
119
|
if output_dir:
|
|
120
120
|
self._copy_to_output(cache_folder, Path(output_dir))
|
|
121
|
-
|
|
121
|
+
files.extend(f for f in cache_folder.iterdir() if f.is_file())
|
|
122
122
|
current = chunk_end + timedelta(days=1)
|
|
123
123
|
continue
|
|
124
124
|
|
|
@@ -136,7 +136,7 @@ class ArchiveHandle:
|
|
|
136
136
|
# Write to cache
|
|
137
137
|
cache_folder = self._cache.archive_dir(self.id, self.name, key)
|
|
138
138
|
self._write_content(content, cache_folder, key, archive_type)
|
|
139
|
-
|
|
139
|
+
files.extend(f for f in cache_folder.iterdir() if f.is_file())
|
|
140
140
|
|
|
141
141
|
# Copy to output if requested
|
|
142
142
|
if output_dir:
|
|
@@ -144,7 +144,7 @@ class ArchiveHandle:
|
|
|
144
144
|
|
|
145
145
|
current = chunk_end + timedelta(days=1)
|
|
146
146
|
|
|
147
|
-
return
|
|
147
|
+
return sorted(files)
|
|
148
148
|
|
|
149
149
|
# -- Internal helpers ------------------------------------------------------
|
|
150
150
|
|
|
@@ -199,12 +199,25 @@ class ArchiveHandle:
|
|
|
199
199
|
class ArchivesManager(BaseManager):
|
|
200
200
|
"""Manager for ``/archives`` endpoints."""
|
|
201
201
|
|
|
202
|
-
def list(self) -> pd.DataFrame:
|
|
203
|
-
"""List all available archives as a DataFrame.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
202
|
+
def list(self, *, source: str = "local") -> pd.DataFrame:
|
|
203
|
+
"""List all available archives as a DataFrame.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
source: ``"local"`` (default) returns the full static catalog
|
|
207
|
+
(153 archives including I90, settlements, etc.).
|
|
208
|
+
``"api"`` queries the ESIOS API which only returns ~24 archives.
|
|
209
|
+
"""
|
|
210
|
+
if source == "api":
|
|
211
|
+
data = self._get("archives", params={"date_type": "publicacion"})
|
|
212
|
+
df = pd.DataFrame(data.get("archives", []))
|
|
213
|
+
if "id" in df.columns:
|
|
214
|
+
df = df.set_index("id")
|
|
215
|
+
return df
|
|
216
|
+
|
|
217
|
+
from esios.data.catalogs.archives import ARCHIVES_CATALOG
|
|
218
|
+
|
|
219
|
+
df = pd.DataFrame.from_dict(ARCHIVES_CATALOG, orient="index")
|
|
220
|
+
df.index.name = "id"
|
|
208
221
|
return df
|
|
209
222
|
|
|
210
223
|
def get(self, archive_id: int) -> ArchiveHandle:
|
|
@@ -225,10 +238,10 @@ class ArchivesManager(BaseManager):
|
|
|
225
238
|
date: str | None = None,
|
|
226
239
|
output_dir: str | Path | None = None,
|
|
227
240
|
date_type: str = "datos",
|
|
228
|
-
) -> Path:
|
|
241
|
+
) -> list[Path]:
|
|
229
242
|
"""Convenience method: get + download in one call.
|
|
230
243
|
|
|
231
|
-
Returns
|
|
244
|
+
Returns a sorted list of downloaded/cached file paths.
|
|
232
245
|
"""
|
|
233
246
|
handle = self.get(archive_id)
|
|
234
247
|
return handle.download(
|
|
@@ -8,11 +8,15 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
10
|
from pathlib import Path
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
11
12
|
|
|
12
13
|
import numpy as np
|
|
13
14
|
import pandas as pd
|
|
14
15
|
import python_calamine
|
|
15
16
|
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from esios.managers.archives import ArchiveHandle
|
|
19
|
+
|
|
16
20
|
logger = logging.getLogger("esios")
|
|
17
21
|
|
|
18
22
|
|
|
@@ -43,26 +47,34 @@ class I90Book:
|
|
|
43
47
|
self.path = Path(path)
|
|
44
48
|
self.metadata: dict = {}
|
|
45
49
|
self.table_of_contents: dict[str, str] = {}
|
|
46
|
-
self.
|
|
50
|
+
self._sheets: dict[str, I90Sheet] = {}
|
|
51
|
+
self._workbook: python_calamine.CalamineWorkbook | None = None
|
|
52
|
+
self._sheet_names: list[str] = []
|
|
47
53
|
self._extract_metadata_and_toc()
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
self.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
@property
|
|
56
|
+
def sheets(self) -> dict[str, I90Sheet]:
|
|
57
|
+
"""Access already-loaded sheets."""
|
|
58
|
+
return self._sheets
|
|
59
|
+
|
|
60
|
+
def _open_workbook(self) -> python_calamine.CalamineWorkbook:
|
|
61
|
+
"""Open the workbook (cached after first call)."""
|
|
62
|
+
if self._workbook is None:
|
|
63
|
+
with open(self.path, "rb") as f:
|
|
64
|
+
self._workbook = python_calamine.CalamineWorkbook.from_filelike(f)
|
|
65
|
+
self._sheet_names = self._workbook.sheet_names
|
|
66
|
+
return self._workbook
|
|
56
67
|
|
|
57
68
|
def _extract_metadata_and_toc(self) -> None:
|
|
58
69
|
"""Extract dates and table of contents from the first sheet."""
|
|
59
|
-
self.
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
wb = self._open_workbook()
|
|
71
|
+
first_name = self._sheet_names[0]
|
|
72
|
+
first_sheet = I90Sheet(first_name, wb, self.path, self.metadata)
|
|
73
|
+
self._sheets[first_name] = first_sheet
|
|
62
74
|
|
|
63
75
|
# Dates from row 4
|
|
64
|
-
self.metadata["date_data"] = pd.to_datetime(rows[3][0])
|
|
65
|
-
self.metadata["date_publication"] = pd.to_datetime(rows[3][2])
|
|
76
|
+
self.metadata["date_data"] = pd.to_datetime(first_sheet.rows[3][0])
|
|
77
|
+
self.metadata["date_publication"] = pd.to_datetime(first_sheet.rows[3][2])
|
|
66
78
|
|
|
67
79
|
# Table of contents from row 10 onwards
|
|
68
80
|
df = pd.read_excel(self.path, sheet_name=0, header=None, skiprows=9, usecols="A,B", engine="calamine")
|
|
@@ -70,12 +82,13 @@ class I90Book:
|
|
|
70
82
|
self.table_of_contents = df.set_index("sheet_name")["description"].to_dict()
|
|
71
83
|
|
|
72
84
|
def get_sheet(self, sheet_name: str) -> I90Sheet:
|
|
73
|
-
"""Get and preprocess a specific sheet by name."""
|
|
74
|
-
if sheet_name not in self.
|
|
75
|
-
self.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
"""Get and preprocess a specific sheet by name (lazy — only reads on demand)."""
|
|
86
|
+
if sheet_name not in self._sheets:
|
|
87
|
+
wb = self._open_workbook()
|
|
88
|
+
if sheet_name not in self._sheet_names:
|
|
89
|
+
raise KeyError(f"Sheet '{sheet_name}' not found in {self.path.name}")
|
|
90
|
+
self._sheets[sheet_name] = I90Sheet(sheet_name, wb, self.path, self.metadata)
|
|
91
|
+
sheet = self._sheets[sheet_name]
|
|
79
92
|
if sheet.df is None:
|
|
80
93
|
sheet.df = sheet._preprocess()
|
|
81
94
|
return sheet
|
|
@@ -83,6 +96,36 @@ class I90Book:
|
|
|
83
96
|
def __getitem__(self, sheet_name: str) -> I90Sheet:
|
|
84
97
|
return self.get_sheet(sheet_name)
|
|
85
98
|
|
|
99
|
+
@classmethod
|
|
100
|
+
def from_archive(
|
|
101
|
+
cls,
|
|
102
|
+
archive: ArchiveHandle,
|
|
103
|
+
*,
|
|
104
|
+
start: str,
|
|
105
|
+
end: str,
|
|
106
|
+
) -> list[I90Book]:
|
|
107
|
+
"""Download I90 files and parse them into I90Book objects.
|
|
108
|
+
|
|
109
|
+
Calls ``archive.download()`` (cache-aware), then parses each file.
|
|
110
|
+
Files that fail to parse are logged and skipped.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
archive: An :class:`ArchiveHandle` from ``client.archives.get(34)``.
|
|
114
|
+
start: Start date (``"YYYY-MM-DD"``).
|
|
115
|
+
end: End date (``"YYYY-MM-DD"``).
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
A list of successfully parsed :class:`I90Book` objects, sorted by date.
|
|
119
|
+
"""
|
|
120
|
+
files = archive.download(start=start, end=end)
|
|
121
|
+
books: list[I90Book] = []
|
|
122
|
+
for f in files:
|
|
123
|
+
try:
|
|
124
|
+
books.append(cls(f))
|
|
125
|
+
except Exception as e:
|
|
126
|
+
logger.warning("Failed to parse %s: %s", f.name, e)
|
|
127
|
+
return books
|
|
128
|
+
|
|
86
129
|
def __repr__(self) -> str:
|
|
87
130
|
return f"<I90Book {self.path.name} sheets={len(self.sheets)}>"
|
|
88
131
|
|
|
@@ -192,7 +235,7 @@ class I90Sheet:
|
|
|
192
235
|
columns_datetime = base_date + pd.to_timedelta(time_deltas, unit="m")
|
|
193
236
|
columns_datetime = pd.DatetimeIndex(columns_datetime).tz_localize(
|
|
194
237
|
"Europe/Madrid", ambiguous="infer"
|
|
195
|
-
)
|
|
238
|
+
)
|
|
196
239
|
|
|
197
240
|
data = pd.DataFrame(self.rows[idx + 1 :], columns=columns)
|
|
198
241
|
|
|
File without changes
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "python-esios",
|
|
3
|
-
"owner": {
|
|
4
|
-
"name": "Datons AI",
|
|
5
|
-
"email": "jesus.lopez@datons.ai"
|
|
6
|
-
},
|
|
7
|
-
"plugins": [
|
|
8
|
-
{
|
|
9
|
-
"name": "esios",
|
|
10
|
-
"source": ".",
|
|
11
|
-
"description": "Query Spanish electricity market data (ESIOS/REE) — prices, generation, demand, I90 files, and any ESIOS indicator.",
|
|
12
|
-
"version": "2.0.0"
|
|
13
|
-
}
|
|
14
|
-
]
|
|
15
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "esios",
|
|
3
|
-
"description": "Query Spanish electricity market data (ESIOS/REE) — prices, generation, demand, I90 files, and any ESIOS indicator.",
|
|
4
|
-
"version": "2.0.0",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Jesús López",
|
|
7
|
-
"email": "jesus.lopez@datons.ai"
|
|
8
|
-
},
|
|
9
|
-
"repository": "https://github.com/datons/python-esios",
|
|
10
|
-
"license": "GPL-3.0-only",
|
|
11
|
-
"keywords": ["esios", "ree", "electricity", "energy", "spain", "omie"]
|
|
12
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/01_Quickstart/01_Setup and First Query.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/03_Multi-Geography Indicators.ipynb
RENAMED
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/04_Compare Indicators.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/02_Indicators/06_Generation and Demand.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/03_Archives/02_I90 Settlement Files.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/05_Advanced/01_Ad-hoc Pandas Expressions.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/01_Search Indicators.yaml
RENAMED
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/02_Historical Data.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/04_Compare Indicators.yaml
RENAMED
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/02_Indicators/05_Market Prices.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/03_Archives/01_Download Archives.yaml
RENAMED
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/03_Archives/02_I90 Settlement Files.yaml
RENAMED
|
File without changes
|
{python_esios-2.0.0 → python_esios-2.0.1}/examples/_specs/04_Caching/01_Cache Management.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|