balancing-services 1.0.0__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.
Files changed (68) hide show
  1. balancing_services-1.0.0/.gitignore +74 -0
  2. balancing_services-1.0.0/LICENSE +21 -0
  3. balancing_services-1.0.0/PKG-INFO +364 -0
  4. balancing_services-1.0.0/PUBLISHING.md +56 -0
  5. balancing_services-1.0.0/README.md +331 -0
  6. balancing_services-1.0.0/RELEASE_CHECKLIST.md +25 -0
  7. balancing_services-1.0.0/balancing_services/__init__.py +8 -0
  8. balancing_services-1.0.0/balancing_services/api/__init__.py +1 -0
  9. balancing_services-1.0.0/balancing_services/api/default/__init__.py +1 -0
  10. balancing_services-1.0.0/balancing_services/api/default/get_balancing_capacity_bids.py +289 -0
  11. balancing_services-1.0.0/balancing_services/api/default/get_balancing_capacity_prices.py +259 -0
  12. balancing_services-1.0.0/balancing_services/api/default/get_balancing_capacity_procured_volumes.py +261 -0
  13. balancing_services-1.0.0/balancing_services/api/default/get_balancing_energy_activated_volumes.py +259 -0
  14. balancing_services-1.0.0/balancing_services/api/default/get_balancing_energy_bids.py +289 -0
  15. balancing_services-1.0.0/balancing_services/api/default/get_balancing_energy_prices.py +255 -0
  16. balancing_services-1.0.0/balancing_services/api/default/get_imbalance_prices.py +238 -0
  17. balancing_services-1.0.0/balancing_services/api/default/get_imbalance_total_volumes.py +242 -0
  18. balancing_services-1.0.0/balancing_services/client.py +286 -0
  19. balancing_services-1.0.0/balancing_services/errors.py +16 -0
  20. balancing_services-1.0.0/balancing_services/models/__init__.py +77 -0
  21. balancing_services-1.0.0/balancing_services/models/activation_type.py +10 -0
  22. balancing_services-1.0.0/balancing_services/models/area.py +50 -0
  23. balancing_services-1.0.0/balancing_services/models/balancing_capacity_bids.py +123 -0
  24. balancing_services-1.0.0/balancing_services/models/balancing_capacity_bids_response.py +120 -0
  25. balancing_services-1.0.0/balancing_services/models/balancing_capacity_price.py +77 -0
  26. balancing_services-1.0.0/balancing_services/models/balancing_capacity_prices.py +123 -0
  27. balancing_services-1.0.0/balancing_services/models/balancing_capacity_prices_response.py +120 -0
  28. balancing_services-1.0.0/balancing_services/models/balancing_capacity_volume.py +77 -0
  29. balancing_services-1.0.0/balancing_services/models/balancing_capacity_volumes.py +114 -0
  30. balancing_services-1.0.0/balancing_services/models/balancing_capacity_volumes_response.py +120 -0
  31. balancing_services-1.0.0/balancing_services/models/balancing_energy_bids.py +131 -0
  32. balancing_services-1.0.0/balancing_services/models/balancing_energy_bids_response.py +120 -0
  33. balancing_services-1.0.0/balancing_services/models/balancing_energy_price.py +77 -0
  34. balancing_services-1.0.0/balancing_services/models/balancing_energy_prices.py +140 -0
  35. balancing_services-1.0.0/balancing_services/models/balancing_energy_prices_response.py +120 -0
  36. balancing_services-1.0.0/balancing_services/models/balancing_energy_volume.py +77 -0
  37. balancing_services-1.0.0/balancing_services/models/balancing_energy_volumes.py +131 -0
  38. balancing_services-1.0.0/balancing_services/models/balancing_energy_volumes_response.py +120 -0
  39. balancing_services-1.0.0/balancing_services/models/bid_status.py +9 -0
  40. balancing_services-1.0.0/balancing_services/models/capacity_bid.py +97 -0
  41. balancing_services-1.0.0/balancing_services/models/currency.py +9 -0
  42. balancing_services-1.0.0/balancing_services/models/direction.py +9 -0
  43. balancing_services-1.0.0/balancing_services/models/eic_code.py +50 -0
  44. balancing_services-1.0.0/balancing_services/models/energy_bid.py +85 -0
  45. balancing_services-1.0.0/balancing_services/models/imbalance_direction.py +10 -0
  46. balancing_services-1.0.0/balancing_services/models/imbalance_price.py +77 -0
  47. balancing_services-1.0.0/balancing_services/models/imbalance_prices.py +114 -0
  48. balancing_services-1.0.0/balancing_services/models/imbalance_prices_response.py +120 -0
  49. balancing_services-1.0.0/balancing_services/models/imbalance_total_volumes.py +97 -0
  50. balancing_services-1.0.0/balancing_services/models/imbalance_total_volumes_response.py +120 -0
  51. balancing_services-1.0.0/balancing_services/models/period.py +72 -0
  52. balancing_services-1.0.0/balancing_services/models/problem.py +91 -0
  53. balancing_services-1.0.0/balancing_services/models/problem_type.py +14 -0
  54. balancing_services-1.0.0/balancing_services/models/reserve_type.py +11 -0
  55. balancing_services-1.0.0/balancing_services/models/total_imbalance_direction.py +10 -0
  56. balancing_services-1.0.0/balancing_services/models/total_imbalance_volume.py +90 -0
  57. balancing_services-1.0.0/balancing_services/py.typed +0 -0
  58. balancing_services-1.0.0/balancing_services/types.py +54 -0
  59. balancing_services-1.0.0/config.yaml +2 -0
  60. balancing_services-1.0.0/examples/basic_usage.py +78 -0
  61. balancing_services-1.0.0/examples/error_handling.py +164 -0
  62. balancing_services-1.0.0/examples/pagination_example.py +112 -0
  63. balancing_services-1.0.0/generate.sh +51 -0
  64. balancing_services-1.0.0/pyproject.toml +73 -0
  65. balancing_services-1.0.0/tests/conftest.py +59 -0
  66. balancing_services-1.0.0/tests/test_async.py +74 -0
  67. balancing_services-1.0.0/tests/test_basic.py +160 -0
  68. balancing_services-1.0.0/tests/test_integration.py +221 -0
@@ -0,0 +1,74 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ *.manifest
32
+ *.spec
33
+
34
+ # Unit test / coverage reports
35
+ htmlcov/
36
+ .tox/
37
+ .nox/
38
+ .coverage
39
+ .coverage.*
40
+ .cache
41
+ nosetests.xml
42
+ coverage.xml
43
+ *.cover
44
+ *.py,cover
45
+ .hypothesis/
46
+ .pytest_cache/
47
+
48
+ # Virtual environments
49
+ venv/
50
+ env/
51
+ ENV/
52
+ env.bak/
53
+ venv.bak/
54
+ .venv/
55
+
56
+ # IDEs
57
+ .vscode/
58
+ .idea/
59
+ *.swp
60
+ *.swo
61
+ *~
62
+ .DS_Store
63
+
64
+ # mypy
65
+ .mypy_cache/
66
+ .dmypy.json
67
+ dmypy.json
68
+
69
+ # Pyre type checker
70
+ .pyre/
71
+
72
+ # uv
73
+ .uv/
74
+ uv.lock
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Balancing Services
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,364 @@
1
+ Metadata-Version: 2.4
2
+ Name: balancing-services
3
+ Version: 1.0.0
4
+ Summary: Official Python client for accessing European electricity balancing market data via the Balancing Services REST API
5
+ Project-URL: Homepage, https://balancing.services
6
+ Project-URL: Documentation, https://api.balancing.services/v1/documentation
7
+ Project-URL: Repository, https://github.com/balancing-services/rest-api
8
+ Project-URL: Changelog, https://github.com/balancing-services/rest-api/blob/main/CHANGELOG.md
9
+ Author: Balancing Services Team
10
+ License: MIT
11
+ Keywords: FCR,aFRR,api,balancing,electricity,energy,europe,grid,imbalance,mFRR,market,openapi,power,reserves
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: attrs>=23.0.0
23
+ Requires-Dist: httpx<1.0.0,>=0.28.0
24
+ Requires-Dist: python-dateutil<3.0.0,>=2.9.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=1.0.0; extra == 'dev'
28
+ Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
30
+ Requires-Dist: respx>=0.22.0; extra == 'dev'
31
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Balancing Services Python Client
35
+
36
+ Python client library for the [Balancing Services REST API](https://api.balancing.services). Access European electricity balancing market data with a modern, type-safe Python interface.
37
+
38
+ ## Features
39
+
40
+ - **Type-safe**: Full type hints for better IDE support and code quality
41
+ - **Modern Python**: Built with httpx and attrs for async support and clean data models
42
+ - **Auto-generated**: Generated from the official OpenAPI specification
43
+ - **Comprehensive**: Access to all API endpoints and data models
44
+ - **Well-documented**: Inline documentation and usage examples
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ uv pip install balancing-services
50
+ ```
51
+
52
+ Or with pip:
53
+
54
+ ```bash
55
+ pip install balancing-services
56
+ ```
57
+
58
+ For development, install from source:
59
+
60
+ ```bash
61
+ cd clients/python
62
+ uv pip install -e .
63
+ ```
64
+
65
+ ## Quick Start
66
+
67
+ ```python
68
+ from balancing_services import AuthenticatedClient
69
+ from balancing_services.api.default import (
70
+ get_imbalance_prices,
71
+ get_balancing_energy_bids,
72
+ )
73
+
74
+ # Create an authenticated client
75
+ client = AuthenticatedClient(
76
+ base_url="https://api.balancing.services/v1",
77
+ token="YOUR_API_TOKEN"
78
+ )
79
+
80
+ # Get imbalance prices for Estonia
81
+ response = get_imbalance_prices.sync_detailed(
82
+ client=client,
83
+ area="EE",
84
+ period_start_at="2025-01-01T00:00:00Z",
85
+ period_end_at="2025-01-02T00:00:00Z"
86
+ )
87
+
88
+ if response.status_code == 200:
89
+ data = response.parsed
90
+ print(f"Query period: {data.queried_period.start_at} to {data.queried_period.end_at}")
91
+ for imbalance_prices in data.data:
92
+ print(f"Area: {imbalance_prices.area}, Direction: {imbalance_prices.direction}")
93
+ for price in imbalance_prices.prices:
94
+ print(f" {price.period.start_at}: {price.price} {imbalance_prices.currency}")
95
+ ```
96
+
97
+ ## Authentication
98
+
99
+ To obtain an API token:
100
+ - **Email:** info@balancing.services
101
+ - **Website:** https://balancing.services
102
+
103
+ Include your token when creating the client:
104
+
105
+ ```python
106
+ from balancing_services import AuthenticatedClient
107
+
108
+ client = AuthenticatedClient(
109
+ base_url="https://api.balancing.services/v1",
110
+ token="YOUR_API_TOKEN"
111
+ )
112
+ ```
113
+
114
+ ## Available Endpoints
115
+
116
+ ### Imbalance Data
117
+ - `get_imbalance_prices` - Get imbalance prices for an area
118
+ - `get_imbalance_total_volumes` - Get total imbalance volumes
119
+
120
+ ### Balancing Energy
121
+ - `get_balancing_energy_activated_volumes` - Get activated balancing energy volumes
122
+ - `get_balancing_energy_prices` - Get balancing energy prices
123
+ - `get_balancing_energy_bids` - Get balancing energy bids (paginated)
124
+
125
+ ### Balancing Capacity
126
+ - `get_balancing_capacity_bids` - Get balancing capacity bids (paginated)
127
+ - `get_balancing_capacity_prices` - Get balancing capacity prices
128
+ - `get_balancing_capacity_procured_volumes` - Get procured balancing capacity volumes
129
+
130
+ ## Usage Examples
131
+
132
+ ### Get Balancing Energy Bids with Pagination
133
+
134
+ ```python
135
+ from balancing_services import AuthenticatedClient
136
+ from balancing_services.api.default import get_balancing_energy_bids
137
+
138
+ client = AuthenticatedClient(base_url="https://api.balancing.services/v1", token="YOUR_TOKEN")
139
+
140
+ # First page
141
+ response = get_balancing_energy_bids.sync_detailed(
142
+ client=client,
143
+ area="EE",
144
+ period_start_at="2025-01-01T00:00:00Z",
145
+ period_end_at="2025-01-02T00:00:00Z",
146
+ reserve_type="aFRR",
147
+ limit=100
148
+ )
149
+
150
+ if response.status_code == 200:
151
+ data = response.parsed
152
+ print(f"Has more: {data.has_more}")
153
+
154
+ # Process first page
155
+ for bid_group in data.data:
156
+ for bid in bid_group.bids:
157
+ print(f"Bid: {bid.volume} MW @ {bid.price} {bid_group.currency}")
158
+
159
+ # Get next page if available
160
+ if data.has_more and data.next_cursor:
161
+ next_response = get_balancing_energy_bids.sync_detailed(
162
+ client=client,
163
+ area="EE",
164
+ period_start_at="2025-01-01T00:00:00Z",
165
+ period_end_at="2025-01-02T00:00:00Z",
166
+ reserve_type="aFRR",
167
+ cursor=data.next_cursor,
168
+ limit=100
169
+ )
170
+ ```
171
+
172
+ ### Async Usage
173
+
174
+ ```python
175
+ import asyncio
176
+ from balancing_services import AuthenticatedClient
177
+ from balancing_services.api.default import get_imbalance_prices
178
+
179
+ async def fetch_prices():
180
+ client = AuthenticatedClient(
181
+ base_url="https://api.balancing.services/v1",
182
+ token="YOUR_TOKEN"
183
+ )
184
+
185
+ response = await get_imbalance_prices.asyncio_detailed(
186
+ client=client,
187
+ area="EE",
188
+ period_start_at="2025-01-01T00:00:00Z",
189
+ period_end_at="2025-01-02T00:00:00Z"
190
+ )
191
+
192
+ if response.status_code == 200:
193
+ return response.parsed
194
+ return None
195
+
196
+ # Run async function
197
+ prices = asyncio.run(fetch_prices())
198
+ ```
199
+
200
+ ### Error Handling
201
+
202
+ ```python
203
+ from balancing_services import AuthenticatedClient
204
+ from balancing_services.api.default import get_imbalance_prices
205
+ from balancing_services.models import Problem
206
+
207
+ client = AuthenticatedClient(base_url="https://api.balancing.services/v1", token="YOUR_TOKEN")
208
+
209
+ response = get_imbalance_prices.sync_detailed(
210
+ client=client,
211
+ area="EE",
212
+ period_start_at="2025-01-01T00:00:00Z",
213
+ period_end_at="2025-01-02T00:00:00Z"
214
+ )
215
+
216
+ if response.status_code == 200:
217
+ data = response.parsed
218
+ # Process successful response
219
+ elif response.status_code == 400:
220
+ error = response.parsed
221
+ print(f"Bad request: {error.detail}")
222
+ elif response.status_code == 401:
223
+ print("Authentication failed - check your API token")
224
+ elif response.status_code == 429:
225
+ print("Rate limited - please retry later")
226
+ else:
227
+ print(f"Error {response.status_code}: {response.content}")
228
+ ```
229
+
230
+ ## Data Models
231
+
232
+ All response and request models are fully typed using attrs. Key models include:
233
+
234
+ - `ImbalancePricesResponse`, `ImbalanceTotalVolumesResponse`
235
+ - `BalancingEnergyVolumesResponse`, `BalancingEnergyPricesResponse`, `BalancingEnergyBidsResponse`
236
+ - `BalancingCapacityBidsResponse`, `BalancingCapacityPricesResponse`, `BalancingCapacityVolumesResponse`
237
+ - Enums: `Area`, `ReserveType`, `Direction`, `Currency`, `ActivationType`, `BidStatus`
238
+
239
+ ## Development
240
+
241
+ ### Regenerating the Client
242
+
243
+ The client is generated from the OpenAPI specification. To regenerate:
244
+
245
+ ```bash
246
+ cd clients/python
247
+ ./generate.sh
248
+ ```
249
+
250
+ ### Running Tests
251
+
252
+ ```bash
253
+ # Install development dependencies
254
+ uv pip install -e ".[dev]"
255
+
256
+ # Run tests
257
+ pytest
258
+
259
+ # Run tests with coverage
260
+ pytest --cov=balancing_services --cov-report=html
261
+ ```
262
+
263
+ ### Code Quality
264
+
265
+ ```bash
266
+ # Format code
267
+ ruff format .
268
+
269
+ # Lint code
270
+ ruff check .
271
+
272
+ # Type checking
273
+ mypy balancing_services
274
+ ```
275
+
276
+ ## Troubleshooting
277
+
278
+ ### Authentication Errors (401)
279
+
280
+ **Problem:** Receiving 401 Unauthorized responses
281
+
282
+ **Solutions:**
283
+ - Verify your API token is correct
284
+ - Check that the token is being passed to `AuthenticatedClient`
285
+ - Ensure your token hasn't expired (contact support if needed)
286
+
287
+ ### Bad Request Errors (400)
288
+
289
+ **Problem:** Receiving 400 Bad Request responses
290
+
291
+ **Common causes:**
292
+ - Invalid date range (end date before start date)
293
+ - Date range too large
294
+ - Invalid area code or reserve type
295
+ - Malformed datetime strings
296
+
297
+ **Solution:** Check the error detail in the response for specific information:
298
+ ```python
299
+ if response.status_code == 400:
300
+ error = response.parsed
301
+ print(f"Error detail: {error.detail}")
302
+ ```
303
+
304
+ ### Empty Results
305
+
306
+ **Problem:** Receiving 200 OK but no data
307
+
308
+ **Possible reasons:**
309
+ - No data available for the requested period
310
+ - Data not yet published for recent periods
311
+ - Requesting data for a period before data collection started
312
+
313
+ **Solution:** Try a different time period or check if data exists for your area
314
+
315
+ ### Timeout Issues
316
+
317
+ **Problem:** Requests timing out
318
+
319
+ **Solutions:**
320
+ - Increase the client timeout:
321
+ ```python
322
+ client = AuthenticatedClient(
323
+ base_url="https://api.balancing.services/v1",
324
+ token="YOUR_TOKEN",
325
+ timeout=30.0 # Increase from default
326
+ )
327
+ ```
328
+ - Reduce the date range in your request
329
+ - Use pagination for large datasets
330
+
331
+ ### Type Errors with Enums
332
+
333
+ **Problem:** Type errors when passing area or reserve type
334
+
335
+ **Solution:** Use the provided enum classes:
336
+ ```python
337
+ from balancing_services.models import Area, ReserveType
338
+
339
+ # Correct
340
+ area=Area.EE
341
+
342
+ # Incorrect
343
+ area="EE" # String might work but not type-safe
344
+ ```
345
+
346
+ ## Documentation
347
+
348
+ - **API Documentation:** https://api.balancing.services/v1/documentation
349
+ - **OpenAPI Spec:** [openapi.yaml](../../openapi.yaml)
350
+ - **Main Repository:** https://github.com/balancing-services/rest-api
351
+
352
+ ## Support
353
+
354
+ - **Website:** https://balancing.services
355
+ - **Email:** info@balancing.services
356
+ - **Issues:** [GitHub Issues](https://github.com/balancing-services/rest-api/issues)
357
+
358
+ ## License
359
+
360
+ MIT License - see [LICENSE](../../LICENSE) for details.
361
+
362
+ ## Changelog
363
+
364
+ See [CHANGELOG.md](../../CHANGELOG.md) for version history and changes.
@@ -0,0 +1,56 @@
1
+ # Publishing to PyPI
2
+
3
+ ## Prerequisites
4
+
5
+ - PyPI and TestPyPI accounts with API tokens
6
+ - `uv` installed: `pip install uv`
7
+
8
+ ## Publishing Process
9
+
10
+ ### 1. Pre-release checks
11
+
12
+ ```bash
13
+ cd clients/python
14
+
15
+ # Update version in pyproject.toml
16
+ # Update CHANGELOG.md
17
+
18
+ # Run tests
19
+ uv run pytest
20
+
21
+ # Build
22
+ uv build
23
+ ```
24
+
25
+ ### 2. Publish to TestPyPI
26
+
27
+ ```bash
28
+ export UV_PUBLISH_TOKEN="your-testpypi-token"
29
+ uv publish --publish-url https://test.pypi.org/legacy/
30
+ ```
31
+
32
+ Test installation:
33
+ ```bash
34
+ uv pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ balancing-services
35
+ ```
36
+
37
+ ### 3. Publish to PyPI
38
+
39
+ ```bash
40
+ export UV_PUBLISH_TOKEN="your-pypi-token"
41
+ uv publish
42
+ ```
43
+
44
+ Test installation:
45
+ ```bash
46
+ uv pip install balancing-services
47
+ ```
48
+
49
+ ### 4. Post-release
50
+
51
+ ```bash
52
+ git tag -a v1.0.0 -m "Release v1.0.0"
53
+ git push origin v1.0.0
54
+ ```
55
+
56
+ Create GitHub release at https://github.com/balancing-services/rest-api/releases