python-entsoe 0.5.0__py3-none-any.whl → 0.6.1__py3-none-any.whl

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.
@@ -1,105 +1,61 @@
1
1
  ---
2
2
  name: entsoe
3
3
  description: Query European electricity market data (ENTSO-E Transparency Platform). Use when the user asks about electricity prices, load, generation, transmission, or balancing data for European countries.
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  ---
6
6
 
7
7
  # ENTSO-E Data Assistant
8
8
 
9
- You have access to the `python-entsoe` CLI and library for querying the ENTSO-E Transparency Platform (European electricity market data).
9
+ You have access to the `python-entsoe` library and CLI for querying the ENTSO-E Transparency Platform (European electricity market data).
10
10
 
11
- ## CLI Reference
11
+ ## When to use what
12
12
 
13
- ### Prices
13
+ - **Python scripts** (default): reproducible, composable, saveable. Use for any data work the user will want to keep or iterate on.
14
+ - **CLI**: quick one-shot lookups, exploration, sanity checks. Use when the user wants a fast answer they won't need again.
15
+ - **If unsure**: ask the user whether they want a script or a quick CLI check.
14
16
 
15
- ```bash
16
- # Day-ahead prices for one country
17
- entsoe prices day-ahead -s 2024-06-01 -e 2024-06-08 --country FR
18
-
19
- # Multi-country
20
- entsoe prices day-ahead -s 2024-06-01 -e 2024-06-08 --country FR --country ES
21
- ```
22
-
23
- ### Load
24
-
25
- ```bash
26
- # Actual total system load
27
- entsoe load actual -s 2024-06-01 -e 2024-06-08 --country FR
28
-
29
- # Day-ahead load forecast
30
- entsoe load forecast -s 2024-06-01 -e 2024-06-08 --country FR
31
- ```
32
-
33
- ### Generation
34
-
35
- ```bash
36
- # Actual generation per type (all types)
37
- entsoe generation actual -s 2024-06-01 -e 2024-06-08 --country FR
38
-
39
- # Filter by PSR type
40
- entsoe generation actual -s 2024-06-01 -e 2024-06-08 --country FR --psr solar --psr wind_onshore
41
-
42
- # Generation forecast (wind/solar)
43
- entsoe generation forecast -s 2024-06-01 -e 2024-06-08 --country FR
44
-
45
- # Installed capacity
46
- entsoe generation capacity -s 2024-06-01 -e 2024-06-08 --country FR
47
-
48
- # Per production unit
49
- entsoe generation per-plant -s 2024-06-01 -e 2024-06-08 --country FR
50
- ```
51
-
52
- ### Transmission
53
-
54
- ```bash
55
- # Physical cross-border flows
56
- entsoe transmission flows -s 2024-06-01 -e 2024-06-08 --from FR --to ES
57
-
58
- # Scheduled commercial exchanges
59
- entsoe transmission exchanges -s 2024-06-01 -e 2024-06-08 --from FR --to ES
60
-
61
- # Net transfer capacity
62
- entsoe transmission capacity -s 2024-06-01 -e 2024-06-08 --from FR --to ES
63
- ```
64
-
65
- ### Balancing
17
+ ## Python Library (default)
66
18
 
67
- ```bash
68
- # Imbalance prices
69
- entsoe balancing prices -s 2024-06-01 -e 2024-06-08 --country FR
70
-
71
- # Imbalance volumes
72
- entsoe balancing volumes -s 2024-06-01 -e 2024-06-08 --country FR
73
- ```
19
+ ```python
20
+ from entsoe import Client
74
21
 
75
- ### Exec (ad-hoc pandas expressions)
22
+ client = Client() # reads config file, then ENTSOE_API_KEY env var
76
23
 
77
- Run any pandas expression against fetched data:
24
+ # --- Prices ---
25
+ df = client.prices.day_ahead("2024-06-01", "2024-06-08", country="FR")
26
+ df = client.prices.day_ahead("2024-06-01", "2024-06-08", country=["FR", "ES"])
78
27
 
79
- ```bash
80
- # Descriptive statistics on prices
81
- entsoe exec prices day-ahead -s 2024-06-01 -e 2024-06-08 -c FR -x "df.describe()"
28
+ # --- Load ---
29
+ df = client.load.actual("2024-06-01", "2024-06-08", country="FR")
30
+ df = client.load.forecast("2024-06-01", "2024-06-08", country="FR")
82
31
 
83
- # Daily mean load
84
- entsoe exec load actual -s 2024-06-01 -e 2024-06-08 -c FR -x "df.resample('D').mean()"
32
+ # --- Generation ---
33
+ df = client.generation.actual("2024-06-01", "2024-06-08", country="FR")
34
+ df = client.generation.actual("2024-06-01", "2024-06-08", country="FR", psr_type="solar")
35
+ df = client.generation.actual("2024-06-01", "2024-06-08", country="FR", psr_type=["solar", "wind_onshore"])
36
+ df = client.generation.forecast("2024-06-01", "2024-06-08", country="FR")
37
+ df = client.generation.installed_capacity("2024-06-01", "2024-06-08", country="FR")
38
+ df = client.generation.per_plant("2024-06-01", "2024-06-08", country="FR")
85
39
 
86
- # Generation with PSR filter
87
- entsoe exec generation actual -s 2024-06-01 -e 2024-06-08 -c FR --psr solar -x "df.head(20)"
40
+ # --- Transmission ---
41
+ df = client.transmission.crossborder_flows("2024-06-01", "2024-06-08", country_from="FR", country_to="ES")
42
+ df = client.transmission.scheduled_exchanges("2024-06-01", "2024-06-08", country_from="FR", country_to="ES")
43
+ df = client.transmission.net_transfer_capacity("2024-06-01", "2024-06-08", country_from="FR", country_to="ES")
88
44
 
89
- # Transmission analysis
90
- entsoe exec transmission flows -s 2024-06-01 -e 2024-06-08 --from FR --to ES -x "df.describe()"
45
+ # --- Balancing ---
46
+ df = client.balancing.imbalance_prices("2024-06-01", "2024-06-08", country="FR")
47
+ df = client.balancing.imbalance_volumes("2024-06-01", "2024-06-08", country="FR")
91
48
  ```
92
49
 
93
- ### Output formats
50
+ ### Key conventions
94
51
 
95
- All commands support:
96
-
97
- ```bash
98
- --format table # Default: Rich table in terminal
99
- --format csv # CSV output
100
- --format json # JSON output
101
- --output file.csv # Write to file instead of stdout
102
- ```
52
+ - **Timezone**: All string dates are interpreted in Europe/Brussels (CET) by default
53
+ - **Auto year-splitting**: Date ranges > 1 year are automatically split into yearly API requests
54
+ - **Rate limiting**: ENTSO-E has a 400-request/minute limit; the library handles retries
55
+ - **Multi-value support**: Pass lists for `country` or `psr_type` to get combined results with label columns
56
+ - **Transmission**: Uses `country_from`/`country_to`; multi-value adds a `border` column
57
+ - **No caching**: Data is fetched fresh on each request
58
+ - **Custom exceptions**: `ENTSOEError`, `AuthenticationError`, `APIResponseError`, `InvalidParameterError`, `NetworkError`
103
59
 
104
60
  ## Country Codes
105
61
 
@@ -143,60 +99,78 @@ Bidding zones: `DK_1`, `DK_2`, `NO_1`–`NO_5`, `SE_1`–`SE_4`, `IT_NORTH`, `IT
143
99
  | waste | Waste | B17 |
144
100
  | other | Other | B20 |
145
101
 
146
- Use shorthands with `--psr` (e.g. `--psr solar --psr wind_onshore`), or ENTSO-E codes (e.g. `--psr B16`).
102
+ Use shorthands with `psr_type=` (Python) or `--psr` (CLI), e.g. `psr_type="solar"` or `--psr solar`.
147
103
 
148
- ## Python Library
104
+ ## CLI Reference (quick lookups)
149
105
 
150
- ```python
151
- from entsoe import ENTSOEClient
106
+ ### Catalog (offline)
152
107
 
153
- client = ENTSOEClient() # reads config file, then ENTSOE_API_KEY env var
108
+ ```bash
109
+ entsoe catalog list # All data categories and endpoints
110
+ entsoe catalog show prices # Detailed info for a category
111
+ entsoe catalog countries # Country/bidding zone codes
112
+ entsoe catalog psr # PSR (generation) types
113
+ entsoe catalog borders # Border groups and interconnections
114
+ ```
115
+
116
+ ### Fetch data
154
117
 
118
+ ```bash
155
119
  # Prices
156
- df = client.prices.day_ahead("2024-06-01", "2024-06-08", country="FR")
157
- df = client.prices.day_ahead("2024-06-01", "2024-06-08", country=["FR", "ES"])
120
+ entsoe prices day-ahead -s 2024-06-01 -e 2024-06-08 -c FR
121
+ entsoe prices day-ahead -P week -c FR,ES # Period shorthand
158
122
 
159
123
  # Load
160
- df = client.load.actual("2024-06-01", "2024-06-08", country="FR")
161
- df = client.load.forecast("2024-06-01", "2024-06-08", country="FR")
124
+ entsoe load actual -P month -c FR
125
+ entsoe load forecast -s 2024-06-01 -e 2024-06-08 -c FR
162
126
 
163
127
  # Generation
164
- df = client.generation.actual("2024-06-01", "2024-06-08", country="FR")
165
- df = client.generation.actual("2024-06-01", "2024-06-08", country="FR", psr_type="solar")
166
- df = client.generation.actual("2024-06-01", "2024-06-08", country="FR", psr_type=["solar", "wind_onshore"])
167
- df = client.generation.forecast("2024-06-01", "2024-06-08", country="FR")
168
- df = client.generation.installed_capacity("2024-06-01", "2024-06-08", country="FR")
169
- df = client.generation.per_plant("2024-06-01", "2024-06-08", country="FR")
128
+ entsoe generation actual -P week -c FR --psr solar --psr wind_onshore
129
+ entsoe generation forecast -P week -c FR
130
+ entsoe generation capacity -s 2024-01-01 -e 2024-12-31 -c FR
131
+ entsoe generation per-plant -P week -c FR
170
132
 
171
133
  # Transmission
172
- df = client.transmission.crossborder_flows("2024-06-01", "2024-06-08", country_from="FR", country_to="ES")
173
- df = client.transmission.scheduled_exchanges("2024-06-01", "2024-06-08", country_from="FR", country_to="ES")
174
- df = client.transmission.net_transfer_capacity("2024-06-01", "2024-06-08", country_from="FR", country_to="ES")
134
+ entsoe transmission flows -P week --from FR --to ES
135
+ entsoe transmission exchanges -P week --border ES-*,FR-*
175
136
 
176
137
  # Balancing
177
- df = client.balancing.imbalance_prices("2024-06-01", "2024-06-08", country="FR")
178
- df = client.balancing.imbalance_volumes("2024-06-01", "2024-06-08", country="FR")
138
+ entsoe balancing prices -P week -c FR
139
+ entsoe balancing volumes -P week -c FR
179
140
  ```
180
141
 
181
- ## Configuration
142
+ ### Exec (ad-hoc pandas)
143
+
144
+ `exec` is a subcommand **within each namespace**:
182
145
 
183
146
  ```bash
184
- # Store your API key persistently (recommended)
185
- entsoe config set api-key YOUR_KEY
147
+ entsoe prices exec day-ahead -P week -c FR -x "df.describe()"
148
+ entsoe load exec actual -P 7d -c FR -x "df.resample('D').mean()"
149
+ entsoe generation exec actual -P month -c FR --psr solar -x "df.head(20)"
150
+ entsoe transmission exec flows -P week --from FR --to ES -x "df.describe()"
151
+ entsoe balancing exec prices -P week -c NL -x "df.describe()"
152
+ ```
186
153
 
187
- # Verify it's stored
188
- entsoe config get api-key
154
+ ### Period shorthand (`-P`)
155
+
156
+ All data commands support `-P` as an alternative to `--start`/`--end`:
157
+
158
+ ```
159
+ -P today, -P yesterday, -P week, -P month, -P ytd, -P 14d
160
+ ```
161
+
162
+ ### Output options
163
+
164
+ ```
165
+ --format table|csv|json (default: table)
166
+ --output file.csv (write to file instead of stdout)
189
167
  ```
190
168
 
191
- The config file is stored at `~/.config/entsoe/config.toml`.
169
+ ## Configuration
192
170
 
193
- ## Key Conventions
171
+ ```bash
172
+ entsoe config set api-key YOUR_KEY
173
+ entsoe config get api-key
174
+ ```
194
175
 
195
- - **Timezone**: All string dates are interpreted in Europe/Brussels (CET) by default
196
- - **Auto year-splitting**: Date ranges exceeding 1 year are automatically split into yearly API requests
197
- - **Rate limiting**: ENTSO-E has a 400-request/minute limit; the library handles retries
198
- - **Multi-value support**: Pass lists for country or psr_type to get combined results with label columns
199
- - **Transmission**: Uses `--from`/`--to` instead of `--country`; multi-value adds a `border` column
200
- - **API key resolution**: config file (`~/.config/entsoe/config.toml`) > `ENTSOE_API_KEY` env var
201
- - **No caching**: Data is fetched fresh on each request (unlike python-esios)
202
- - **Custom exceptions**: `ENTSOEError`, `AuthenticationError`, `APIResponseError`, `InvalidParameterError`, `NetworkError`
176
+ Config file: `~/.config/entsoe/config.toml`. API key resolution: config file > `ENTSOE_API_KEY` env var.
entsoe/__init__.py CHANGED
@@ -3,6 +3,7 @@
3
3
  from .client import Client, ENTSOEClient
4
4
  from .exceptions import ENTSOEError, InvalidParameterError, NoDataError, RateLimitError
5
5
  from ._mappings import COUNTRY_NAMES, PSR_CODES, country_name, psr_name
6
+ from . import catalog
6
7
 
7
8
  __version__ = "0.4.2"
8
9
  __all__ = [
@@ -14,6 +15,7 @@ __all__ = [
14
15
  "NoDataError",
15
16
  "PSR_CODES",
16
17
  "RateLimitError",
18
+ "catalog",
17
19
  "country_name",
18
20
  "psr_name",
19
21
  ]
entsoe/catalog.py ADDED
@@ -0,0 +1,228 @@
1
+ """Built-in data catalog for ENTSO-E Transparency Platform.
2
+
3
+ Provides structured metadata about available data categories, endpoints,
4
+ country codes, PSR types, and border groups — so users don't need to
5
+ consult external documentation every time.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class Endpoint:
15
+ """A queryable data endpoint."""
16
+
17
+ name: str
18
+ description: str
19
+ method: str # Python client method name
20
+ cli: str # CLI command
21
+ resolution: str # e.g. "15min", "hourly", "daily"
22
+ columns: tuple[str, ...] # key columns returned
23
+ units: str
24
+ notes: str = ""
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class Category:
29
+ """A top-level data category grouping related endpoints."""
30
+
31
+ name: str
32
+ description: str
33
+ namespace: str # Python client namespace (e.g. "prices")
34
+ endpoints: tuple[Endpoint, ...]
35
+
36
+
37
+ # ── Prices ──────────────────────────────────────────────────────────────
38
+
39
+ PRICES = Category(
40
+ name="Prices",
41
+ description="Day-ahead electricity market prices",
42
+ namespace="prices",
43
+ endpoints=(
44
+ Endpoint(
45
+ name="Day-Ahead Prices",
46
+ description="Hourly day-ahead market clearing prices per bidding zone",
47
+ method="client.prices.day_ahead(start, end, country='FR')",
48
+ cli="entsoe prices day-ahead -s 2024-06-01 -e 2024-06-08 -c FR",
49
+ resolution="hourly",
50
+ columns=("timestamp", "country", "value", "currency", "quantity_unit"),
51
+ units="EUR/MWh",
52
+ ),
53
+ ),
54
+ )
55
+
56
+ # ── Load ────────────────────────────────────────────────────────────────
57
+
58
+ LOAD = Category(
59
+ name="Load",
60
+ description="Actual system load and day-ahead load forecasts",
61
+ namespace="load",
62
+ endpoints=(
63
+ Endpoint(
64
+ name="Actual Total Load",
65
+ description="Actual total electricity consumption per control area",
66
+ method="client.load.actual(start, end, country='FR')",
67
+ cli="entsoe load actual -s 2024-06-01 -e 2024-06-08 -c FR",
68
+ resolution="15min or hourly (varies by country)",
69
+ columns=("timestamp", "country", "value", "quantity_unit"),
70
+ units="MW",
71
+ ),
72
+ Endpoint(
73
+ name="Day-Ahead Load Forecast",
74
+ description="Day-ahead forecast of total electricity consumption",
75
+ method="client.load.forecast(start, end, country='FR')",
76
+ cli="entsoe load forecast -s 2024-06-01 -e 2024-06-08 -c FR",
77
+ resolution="15min or hourly (varies by country)",
78
+ columns=("timestamp", "country", "value", "quantity_unit"),
79
+ units="MW",
80
+ ),
81
+ ),
82
+ )
83
+
84
+ # ── Generation ──────────────────────────────────────────────────────────
85
+
86
+ GENERATION = Category(
87
+ name="Generation",
88
+ description="Actual generation, forecasts, installed capacity, and per-plant output",
89
+ namespace="generation",
90
+ endpoints=(
91
+ Endpoint(
92
+ name="Actual Generation per Type",
93
+ description="Actual electricity generation broken down by fuel/technology type (PSR)",
94
+ method="client.generation.actual(start, end, country='FR')",
95
+ cli="entsoe generation actual -s 2024-06-01 -e 2024-06-08 -c FR",
96
+ resolution="15min or hourly",
97
+ columns=("timestamp", "country", "psr_type", "value", "quantity_unit"),
98
+ units="MW",
99
+ notes="Filter by PSR type: --psr solar --psr wind_onshore",
100
+ ),
101
+ Endpoint(
102
+ name="Generation Forecast (Wind/Solar)",
103
+ description="Day-ahead forecast for wind and solar generation",
104
+ method="client.generation.forecast(start, end, country='FR')",
105
+ cli="entsoe generation forecast -s 2024-06-01 -e 2024-06-08 -c FR",
106
+ resolution="15min or hourly",
107
+ columns=("timestamp", "country", "psr_type", "value", "quantity_unit"),
108
+ units="MW",
109
+ ),
110
+ Endpoint(
111
+ name="Installed Generation Capacity",
112
+ description="Installed generation capacity per type (updated annually or on change)",
113
+ method="client.generation.installed_capacity(start, end, country='FR')",
114
+ cli="entsoe generation capacity -s 2024-06-01 -e 2024-06-08 -c FR",
115
+ resolution="yearly (point-in-time)",
116
+ columns=("timestamp", "country", "psr_type", "value", "quantity_unit"),
117
+ units="MW",
118
+ ),
119
+ Endpoint(
120
+ name="Actual Generation per Plant",
121
+ description="Generation output per individual production unit (>= 100 MW)",
122
+ method="client.generation.per_plant(start, end, country='FR')",
123
+ cli="entsoe generation per-plant -s 2024-06-01 -e 2024-06-08 -c FR",
124
+ resolution="15min or hourly",
125
+ columns=("timestamp", "country", "unit_name", "psr_type", "value", "quantity_unit"),
126
+ units="MW",
127
+ ),
128
+ ),
129
+ )
130
+
131
+ # ── Transmission ────────────────────────────────────────────────────────
132
+
133
+ TRANSMISSION = Category(
134
+ name="Transmission",
135
+ description="Cross-border physical flows, scheduled exchanges, and transfer capacity",
136
+ namespace="transmission",
137
+ endpoints=(
138
+ Endpoint(
139
+ name="Physical Cross-Border Flows",
140
+ description="Actual measured electricity flows between bidding zones",
141
+ method="client.transmission.crossborder_flows(start, end, country_from='FR', country_to='DE_LU')",
142
+ cli="entsoe transmission flows -s 2024-06-01 -e 2024-06-08 --from FR --to DE_LU",
143
+ resolution="15min or hourly",
144
+ columns=("timestamp", "in_domain", "value", "quantity_unit"),
145
+ units="MW",
146
+ notes="Use --border for multi-border queries: --border FR-*, --border iberian",
147
+ ),
148
+ Endpoint(
149
+ name="Scheduled Commercial Exchanges",
150
+ description="Day-ahead scheduled commercial power exchanges between zones",
151
+ method="client.transmission.scheduled_exchanges(start, end, country_from='FR', country_to='ES')",
152
+ cli="entsoe transmission exchanges -s 2024-06-01 -e 2024-06-08 --from FR --to ES",
153
+ resolution="hourly",
154
+ columns=("timestamp", "in_domain", "value", "quantity_unit"),
155
+ units="MW",
156
+ ),
157
+ Endpoint(
158
+ name="Net Transfer Capacity",
159
+ description="Available transfer capacity (NTC) between bidding zones",
160
+ method="client.transmission.net_transfer_capacity(start, end, country_from='FR', country_to='ES')",
161
+ cli="entsoe transmission capacity -s 2024-06-01 -e 2024-06-08 --from FR --to ES",
162
+ resolution="hourly",
163
+ columns=("timestamp", "in_domain", "value", "quantity_unit"),
164
+ units="MW",
165
+ ),
166
+ ),
167
+ )
168
+
169
+ # ── Balancing ───────────────────────────────────────────────────────────
170
+
171
+ BALANCING = Category(
172
+ name="Balancing",
173
+ description="System imbalance prices and volumes",
174
+ namespace="balancing",
175
+ endpoints=(
176
+ Endpoint(
177
+ name="Imbalance Prices",
178
+ description="System imbalance settlement prices",
179
+ method="client.balancing.imbalance_prices(start, end, country='FR')",
180
+ cli="entsoe balancing prices -s 2024-06-01 -e 2024-06-08 -c FR",
181
+ resolution="15min or hourly (varies by country)",
182
+ columns=("timestamp", "country", "value", "quantity_unit"),
183
+ units="EUR/MWh",
184
+ ),
185
+ Endpoint(
186
+ name="Imbalance Volumes",
187
+ description="Net system imbalance volumes",
188
+ method="client.balancing.imbalance_volumes(start, end, country='FR')",
189
+ cli="entsoe balancing volumes -s 2024-06-01 -e 2024-06-08 -c FR",
190
+ resolution="15min or hourly (varies by country)",
191
+ columns=("timestamp", "country", "value", "quantity_unit"),
192
+ units="MW",
193
+ ),
194
+ ),
195
+ )
196
+
197
+ # ── Full catalog ────────────────────────────────────────────────────────
198
+
199
+ CATEGORIES: dict[str, Category] = {
200
+ "prices": PRICES,
201
+ "load": LOAD,
202
+ "generation": GENERATION,
203
+ "transmission": TRANSMISSION,
204
+ "balancing": BALANCING,
205
+ }
206
+
207
+
208
+ def get_category(name: str) -> Category:
209
+ """Look up a category by name (case-insensitive)."""
210
+ key = name.lower().strip()
211
+ if key not in CATEGORIES:
212
+ raise KeyError(
213
+ f"Unknown category '{name}'. Available: {', '.join(CATEGORIES.keys())}"
214
+ )
215
+ return CATEGORIES[key]
216
+
217
+
218
+ def summary() -> str:
219
+ """Return a human-readable summary of all available data."""
220
+ lines = ["ENTSO-E Data Catalog", "=" * 50, ""]
221
+ for key, cat in CATEGORIES.items():
222
+ lines.append(f"{cat.name} ({cat.namespace})")
223
+ lines.append(f" {cat.description}")
224
+ for ep in cat.endpoints:
225
+ lines.append(f" - {ep.name}: {ep.description}")
226
+ lines.append(f" Resolution: {ep.resolution} | Units: {ep.units}")
227
+ lines.append("")
228
+ return "\n".join(lines)
entsoe/cli/app.py CHANGED
@@ -38,6 +38,7 @@ from entsoe.cli.transmission import transmission_app # noqa: E402
38
38
  from entsoe.cli.balancing import balancing_app # noqa: E402
39
39
  from entsoe.cli.config_cmd import config_app # noqa: E402
40
40
  from entsoe.cli.cache_cmd import cache_app # noqa: E402
41
+ from entsoe.cli.catalog_cmd import catalog_app # noqa: E402
41
42
 
42
43
  app.add_typer(prices_app, name="prices", help="Day-ahead electricity prices")
43
44
  app.add_typer(load_app, name="load", help="Actual load and load forecasts")
@@ -46,6 +47,7 @@ app.add_typer(transmission_app, name="transmission", help="Cross-border flows an
46
47
  app.add_typer(balancing_app, name="balancing", help="Imbalance prices and volumes")
47
48
  app.add_typer(config_app, name="config", help="Configuration management")
48
49
  app.add_typer(cache_app, name="cache", help="Cache management (status, clear)")
50
+ app.add_typer(catalog_app, name="catalog", help="Browse available data, countries, PSR types, and borders")
49
51
 
50
52
 
51
53
  def main() -> None:
@@ -0,0 +1,148 @@
1
+ """CLI command: browse the built-in data catalog."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ import typer
8
+ from rich.console import Console
9
+ from rich.table import Table
10
+
11
+ from entsoe._mappings import AREA_CODES, COUNTRY_NAMES, PSR_CODES, PSR_TYPES, BORDER_GROUPS, NEIGHBOURS
12
+
13
+ catalog_app = typer.Typer(no_args_is_help=True)
14
+ console = Console()
15
+
16
+
17
+ @catalog_app.command("list")
18
+ def catalog_list():
19
+ """List all available data categories and endpoints."""
20
+ from entsoe.catalog import CATEGORIES
21
+
22
+ for key, cat in CATEGORIES.items():
23
+ console.print(f"\n[bold]{cat.name}[/bold] — {cat.description}")
24
+ console.print(f" Python: client.{cat.namespace}.*")
25
+ console.print(f" CLI: entsoe {key} <command>")
26
+
27
+ table = Table(show_header=True, padding=(0, 1))
28
+ table.add_column("Endpoint", style="cyan")
29
+ table.add_column("CLI Command", style="green")
30
+ table.add_column("Resolution")
31
+ table.add_column("Units")
32
+
33
+ for ep in cat.endpoints:
34
+ cli_short = ep.cli.split("entsoe ")[-1].split(" -")[0]
35
+ table.add_row(ep.name, cli_short, ep.resolution, ep.units)
36
+
37
+ console.print(table)
38
+
39
+
40
+ @catalog_app.command("countries")
41
+ def catalog_countries(
42
+ query: Optional[str] = typer.Argument(None, help="Filter by country name or code"),
43
+ ):
44
+ """List available country and bidding zone codes."""
45
+ table = Table(title="Country / Bidding Zone Codes", show_header=True, padding=(0, 1))
46
+ table.add_column("Code", style="cyan")
47
+ table.add_column("Name")
48
+ table.add_column("Neighbours", style="dim")
49
+
50
+ for code in sorted(AREA_CODES.keys()):
51
+ name = COUNTRY_NAMES.get(code, "")
52
+ if query:
53
+ q = query.lower()
54
+ if q not in code.lower() and q not in name.lower():
55
+ continue
56
+ neighbours = ", ".join(sorted(NEIGHBOURS.get(code, set())))
57
+ table.add_row(code, name, neighbours)
58
+
59
+ console.print(table)
60
+
61
+
62
+ @catalog_app.command("psr")
63
+ def catalog_psr():
64
+ """List available PSR (generation) types."""
65
+ table = Table(title="PSR Types (Generation)", show_header=True, padding=(0, 1))
66
+ table.add_column("Shorthand", style="cyan")
67
+ table.add_column("ENTSO-E Code", style="green")
68
+ table.add_column("Full Name")
69
+
70
+ for shorthand, code in sorted(PSR_CODES.items()):
71
+ full_name = PSR_TYPES.get(code, "")
72
+ table.add_row(shorthand, code, full_name)
73
+
74
+ console.print(table)
75
+
76
+
77
+ @catalog_app.command("borders")
78
+ def catalog_borders(
79
+ country: Optional[str] = typer.Argument(None, help="Show borders for a specific country (e.g. FR, DE_LU)"),
80
+ ):
81
+ """List border groups and interconnections."""
82
+ if country:
83
+ code = country.upper().strip()
84
+ if code not in NEIGHBOURS:
85
+ console.print(f"[red]Unknown country '{country}'[/red]. Use 'entsoe catalog countries' to list.")
86
+ raise typer.Exit(1)
87
+
88
+ name = COUNTRY_NAMES.get(code, code)
89
+ console.print(f"\n[bold]{name} ({code})[/bold] — {len(NEIGHBOURS[code])} interconnections:")
90
+
91
+ table = Table(show_header=True, padding=(0, 1))
92
+ table.add_column("Neighbour", style="cyan")
93
+ table.add_column("Name")
94
+ table.add_column("CLI (flows)")
95
+
96
+ for n in sorted(NEIGHBOURS[code]):
97
+ n_name = COUNTRY_NAMES.get(n, n)
98
+ table.add_row(n, n_name, f"entsoe transmission flows --from {code} --to {n}")
99
+
100
+ console.print(table)
101
+ console.print(f"\n[dim]Shortcut: entsoe transmission flows --border {code}-*[/dim]")
102
+ else:
103
+ # Show named border groups
104
+ console.print("\n[bold]Named Border Groups[/bold]")
105
+ table = Table(show_header=True, padding=(0, 1))
106
+ table.add_column("Group", style="cyan")
107
+ table.add_column("Borders")
108
+
109
+ for group_name, pairs in sorted(BORDER_GROUPS.items()):
110
+ unique = set()
111
+ for a, b in pairs:
112
+ key = tuple(sorted([a, b]))
113
+ unique.add(key)
114
+ border_strs = [f"{a}-{b}" for a, b in sorted(unique)]
115
+ table.add_row(group_name, ", ".join(border_strs[:8]) + ("..." if len(border_strs) > 8 else ""))
116
+
117
+ console.print(table)
118
+ console.print(f"\n[dim]Use 'entsoe catalog borders <COUNTRY>' for a specific country.[/dim]")
119
+
120
+
121
+ @catalog_app.command("show")
122
+ def catalog_show(
123
+ category: str = typer.Argument(..., help="Category name: prices, load, generation, transmission, balancing"),
124
+ ):
125
+ """Show detailed info for a specific data category."""
126
+ from entsoe.catalog import get_category
127
+
128
+ try:
129
+ cat = get_category(category)
130
+ except KeyError as e:
131
+ console.print(f"[red]{e}[/red]")
132
+ raise typer.Exit(1)
133
+
134
+ console.print(f"\n[bold]{cat.name}[/bold] — {cat.description}")
135
+ console.print(f" Python namespace: client.{cat.namespace}")
136
+ console.print()
137
+
138
+ for ep in cat.endpoints:
139
+ console.print(f" [cyan]{ep.name}[/cyan]")
140
+ console.print(f" {ep.description}")
141
+ console.print(f" Resolution: {ep.resolution}")
142
+ console.print(f" Units: {ep.units}")
143
+ console.print(f" Columns: {', '.join(ep.columns)}")
144
+ console.print(f" Python: {ep.method}")
145
+ console.print(f" CLI: {ep.cli}")
146
+ if ep.notes:
147
+ console.print(f" Notes: {ep.notes}")
148
+ console.print()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-entsoe
3
- Version: 0.5.0
3
+ Version: 0.6.1
4
4
  Summary: Python client for the ENTSO-E Transparency Platform API
5
5
  Project-URL: Homepage, https://github.com/datons/python-entsoe
6
6
  Project-URL: Repository, https://github.com/datons/python-entsoe
@@ -1,18 +1,20 @@
1
- entsoe/__init__.py,sha256=PlcCfCffCH2nWK7EctaFPdGo5dRbHig4zkfWa-KfBj4,492
1
+ entsoe/__init__.py,sha256=9qzvMUzoD-CRfX1vTzWIBfpXBMdJ2MgRwJEgQQsw1fA,529
2
2
  entsoe/_http.py,sha256=XhZZy059XHh8uAP2Vsm1e7BfRwQcmGLEYdREcgaF3Tk,6608
3
3
  entsoe/_mappings.py,sha256=6-IKLtwChvM7_YG90oSRDxo3IfQUuz3Gnv17TmQgPjM,15534
4
4
  entsoe/_xml.py,sha256=222kgi8lStU0qQIU-oxiciO2WtplqKySi6qBZXbyiEc,6393
5
5
  entsoe/cache.py,sha256=rRkuQPGYg05Uo3xFW7gVltNE56M-1_E5mdEvgLoWhpM,13356
6
+ entsoe/catalog.py,sha256=FUPg_WqLBkfl5sUgT9m8Bua7IP10NvBsakcndpUOBa0,9733
6
7
  entsoe/client.py,sha256=zHB9y2TbCRjSNe9d5c9XVt_BNZ7b8KsvJDORc5V-ypE,3542
7
8
  entsoe/exceptions.py,sha256=vqeu6_LxAtDvJziPnjbH52KV0fm63F8n2Y1lzSNp2Bs,1017
8
9
  entsoe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- entsoe/.agents/skills/entsoe/SKILL.md,sha256=rdLGQqjuLyD-BwjLFR33erG-iO4D4tM46JOZzSi8z2Y,6717
10
+ entsoe/.agents/skills/entsoe/SKILL.md,sha256=JsFECSkfnxyR6iFx55WBBcMJjAOaMu84vhcsPsTVWC0,6452
10
11
  entsoe/cli/__init__.py,sha256=qUGXx4zdi8dCQkq3PPPa1sgD3Q6KIhJwWeBfTub4suM,139
11
12
  entsoe/cli/_output.py,sha256=aV_3CLmOHSxTAVuYdccTWYahqTNPunCbSeoq3YZL-4A,2943
12
13
  entsoe/cli/_resolve.py,sha256=vqsJJSBCht06HlToKW47ATrQesCl2Uy851KRVjE1kFk,4737
13
- entsoe/cli/app.py,sha256=Hrlw97yveSJr52Z_hUZ0awMeOni95Vgefh4CtG6QJbM,1900
14
+ entsoe/cli/app.py,sha256=_dQsejLncSFJTgOy-26Bvl7pIMXve_YD3gxP-gRVsG4,2069
14
15
  entsoe/cli/balancing.py,sha256=ZXcjTEdbx00MUL4L6116G7MwBfpffB02DgazYexq-dc,2752
15
16
  entsoe/cli/cache_cmd.py,sha256=ozbQ5apxeLBIjbPsH-Cs5rDOVBVfrzJfDPKv1anLFgY,2255
17
+ entsoe/cli/catalog_cmd.py,sha256=TzkkecSlnlz-f2_BlRqidKN6uTJtSInR0np4BA1rQ5c,5361
16
18
  entsoe/cli/config.py,sha256=YB6IeOBGMKahcVJBGUaCN5r1vs6YILv_XbXlcKLxLiU,1663
17
19
  entsoe/cli/config_cmd.py,sha256=HfpMMv8S1kDUIid6kxX-cNirCvhDby2lSPNSD8o3qX8,923
18
20
  entsoe/cli/exec_cmd.py,sha256=KiGwOTIjYQQPEg7v51oRbpk3Cj9-7hDDCbEYXfZ_lfQ,11308
@@ -27,7 +29,7 @@ entsoe/namespaces/generation.py,sha256=V4DkvV5ai7aWYYSdZKwWyxTEv1ed4nCCq7DYyVwvc
27
29
  entsoe/namespaces/load.py,sha256=fbkwKWZifb8DOf5Rc_7c4_eFAXiqT_562r9WTMQwsuo,2160
28
30
  entsoe/namespaces/prices.py,sha256=5-hVmpxytyxPKx0eBRN7mjKDhfPUK0ZZi1nnF5zOE9A,1295
29
31
  entsoe/namespaces/transmission.py,sha256=V8zrs2CQXf1WPjJRqz7wc-ztnkfriIKXPLfYHBDJD9M,8067
30
- python_entsoe-0.5.0.dist-info/METADATA,sha256=wqm7PMTOHh-DdtMYKJYMF96eMS8jlrnC9E0krpECs4c,8612
31
- python_entsoe-0.5.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
32
- python_entsoe-0.5.0.dist-info/entry_points.txt,sha256=tYyCheggCsGRKOq2vIjpAxBksEM7K_iGI6vHkkQLmYg,42
33
- python_entsoe-0.5.0.dist-info/RECORD,,
32
+ python_entsoe-0.6.1.dist-info/METADATA,sha256=YTJB_o6J02O8cxj5izGnykIZ8uZk-SrXdkasOyze2Qo,8612
33
+ python_entsoe-0.6.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
34
+ python_entsoe-0.6.1.dist-info/entry_points.txt,sha256=tYyCheggCsGRKOq2vIjpAxBksEM7K_iGI6vHkkQLmYg,42
35
+ python_entsoe-0.6.1.dist-info/RECORD,,