balancing-services 1.6.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 (78) hide show
  1. balancing_services-1.6.0/.env.sample +15 -0
  2. balancing_services-1.6.0/.gitignore +80 -0
  3. balancing_services-1.6.0/LICENSE +21 -0
  4. balancing_services-1.6.0/PKG-INFO +433 -0
  5. balancing_services-1.6.0/PUBLISHING.md +56 -0
  6. balancing_services-1.6.0/README.md +398 -0
  7. balancing_services-1.6.0/RELEASE_CHECKLIST.md +25 -0
  8. balancing_services-1.6.0/balancing_services/__init__.py +8 -0
  9. balancing_services-1.6.0/balancing_services/api/__init__.py +1 -0
  10. balancing_services-1.6.0/balancing_services/api/default/__init__.py +1 -0
  11. balancing_services-1.6.0/balancing_services/api/default/get_balancing_capacity_bids.py +289 -0
  12. balancing_services-1.6.0/balancing_services/api/default/get_balancing_capacity_prices.py +259 -0
  13. balancing_services-1.6.0/balancing_services/api/default/get_balancing_capacity_procured_volumes.py +259 -0
  14. balancing_services-1.6.0/balancing_services/api/default/get_balancing_energy_activated_volumes.py +259 -0
  15. balancing_services-1.6.0/balancing_services/api/default/get_balancing_energy_bids.py +289 -0
  16. balancing_services-1.6.0/balancing_services/api/default/get_balancing_energy_offered_volumes.py +271 -0
  17. balancing_services-1.6.0/balancing_services/api/default/get_balancing_energy_prices.py +255 -0
  18. balancing_services-1.6.0/balancing_services/api/default/get_cross_zonal_capacity_allocation.py +275 -0
  19. balancing_services-1.6.0/balancing_services/api/default/get_imbalance_prices.py +238 -0
  20. balancing_services-1.6.0/balancing_services/api/default/get_imbalance_total_volumes.py +242 -0
  21. balancing_services-1.6.0/balancing_services/client.py +268 -0
  22. balancing_services-1.6.0/balancing_services/errors.py +16 -0
  23. balancing_services-1.6.0/balancing_services/models/__init__.py +81 -0
  24. balancing_services-1.6.0/balancing_services/models/activation_type.py +10 -0
  25. balancing_services-1.6.0/balancing_services/models/area.py +51 -0
  26. balancing_services-1.6.0/balancing_services/models/balancing_capacity_bids.py +121 -0
  27. balancing_services-1.6.0/balancing_services/models/balancing_capacity_bids_response.py +116 -0
  28. balancing_services-1.6.0/balancing_services/models/balancing_capacity_price.py +75 -0
  29. balancing_services-1.6.0/balancing_services/models/balancing_capacity_prices.py +158 -0
  30. balancing_services-1.6.0/balancing_services/models/balancing_capacity_prices_response.py +116 -0
  31. balancing_services-1.6.0/balancing_services/models/balancing_capacity_volume.py +75 -0
  32. balancing_services-1.6.0/balancing_services/models/balancing_capacity_volumes.py +149 -0
  33. balancing_services-1.6.0/balancing_services/models/balancing_capacity_volumes_response.py +116 -0
  34. balancing_services-1.6.0/balancing_services/models/balancing_energy_bids.py +129 -0
  35. balancing_services-1.6.0/balancing_services/models/balancing_energy_bids_response.py +116 -0
  36. balancing_services-1.6.0/balancing_services/models/balancing_energy_price.py +75 -0
  37. balancing_services-1.6.0/balancing_services/models/balancing_energy_prices.py +138 -0
  38. balancing_services-1.6.0/balancing_services/models/balancing_energy_prices_response.py +116 -0
  39. balancing_services-1.6.0/balancing_services/models/balancing_energy_volume.py +75 -0
  40. balancing_services-1.6.0/balancing_services/models/balancing_energy_volumes.py +129 -0
  41. balancing_services-1.6.0/balancing_services/models/balancing_energy_volumes_response.py +116 -0
  42. balancing_services-1.6.0/balancing_services/models/bid_status.py +9 -0
  43. balancing_services-1.6.0/balancing_services/models/capacity_bid.py +95 -0
  44. balancing_services-1.6.0/balancing_services/models/cross_zonal_capacity_allocation_response.py +116 -0
  45. balancing_services-1.6.0/balancing_services/models/cross_zonal_volumes.py +119 -0
  46. balancing_services-1.6.0/balancing_services/models/currency.py +12 -0
  47. balancing_services-1.6.0/balancing_services/models/direction.py +10 -0
  48. balancing_services-1.6.0/balancing_services/models/eic_code.py +51 -0
  49. balancing_services-1.6.0/balancing_services/models/energy_bid.py +83 -0
  50. balancing_services-1.6.0/balancing_services/models/imbalance_direction.py +10 -0
  51. balancing_services-1.6.0/balancing_services/models/imbalance_price.py +75 -0
  52. balancing_services-1.6.0/balancing_services/models/imbalance_prices.py +112 -0
  53. balancing_services-1.6.0/balancing_services/models/imbalance_prices_response.py +116 -0
  54. balancing_services-1.6.0/balancing_services/models/imbalance_total_volumes.py +95 -0
  55. balancing_services-1.6.0/balancing_services/models/imbalance_total_volumes_response.py +116 -0
  56. balancing_services-1.6.0/balancing_services/models/period.py +71 -0
  57. balancing_services-1.6.0/balancing_services/models/problem.py +89 -0
  58. balancing_services-1.6.0/balancing_services/models/problem_type.py +14 -0
  59. balancing_services-1.6.0/balancing_services/models/reserve_type.py +11 -0
  60. balancing_services-1.6.0/balancing_services/models/total_imbalance_direction.py +10 -0
  61. balancing_services-1.6.0/balancing_services/models/total_imbalance_volume.py +88 -0
  62. balancing_services-1.6.0/balancing_services/types.py +54 -0
  63. balancing_services-1.6.0/check.sh +62 -0
  64. balancing_services-1.6.0/config.yaml +4 -0
  65. balancing_services-1.6.0/examples/basic_usage.py +82 -0
  66. balancing_services-1.6.0/examples/error_handling.py +167 -0
  67. balancing_services-1.6.0/examples/pagination_example.py +113 -0
  68. balancing_services-1.6.0/generate-pyproject.sh +42 -0
  69. balancing_services-1.6.0/generate.sh +54 -0
  70. balancing_services-1.6.0/pyproject.toml +75 -0
  71. balancing_services-1.6.0/pyproject.toml.draft +75 -0
  72. balancing_services-1.6.0/test-and-publish.sh +443 -0
  73. balancing_services-1.6.0/tests/conftest.py +60 -0
  74. balancing_services-1.6.0/tests/test_async.py +74 -0
  75. balancing_services-1.6.0/tests/test_basic.py +159 -0
  76. balancing_services-1.6.0/tests/test_integration.py +427 -0
  77. balancing_services-1.6.0/tests/test_procured_at_none_handling.py +112 -0
  78. balancing_services-1.6.0/tests/test_readme_execution.py +285 -0
@@ -0,0 +1,15 @@
1
+ # Environment variables for development and publishing
2
+ # Copy this file to .env and fill in your actual tokens
3
+ # Never commit .env to version control!
4
+
5
+ # API key for Balancing Services API (for running examples/tests)
6
+ # Get your API key from: https://balancing.services
7
+ BALANCING_SERVICES_API_KEY=
8
+
9
+ # TestPyPI token (for testing releases)
10
+ # Get your token from: https://test.pypi.org/manage/account/token/
11
+ UV_PUBLISH_TOKEN_TESTPYPI=
12
+
13
+ # Production PyPI token (for production releases)
14
+ # Get your token from: https://pypi.org/manage/account/token/
15
+ UV_PUBLISH_TOKEN_PYPI=
@@ -0,0 +1,80 @@
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
75
+
76
+ # Generated from pyproject.toml.draft
77
+ pyproject.toml
78
+
79
+ # Environment variables (contains secrets)
80
+ .env
@@ -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,433 @@
1
+ Metadata-Version: 2.4
2
+ Name: balancing-services
3
+ Version: 1.6.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: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: attrs>=23.0.0
24
+ Requires-Dist: httpx<1.0.0,>=0.28.0
25
+ Requires-Dist: python-dateutil<3.0.0,>=2.9.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
28
+ Requires-Dist: pytest-asyncio>=1.0.0; extra == 'dev'
29
+ Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
30
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
31
+ Requires-Dist: respx>=0.22.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
33
+ Requires-Dist: types-python-dateutil>=2.9.0; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Balancing Services Python Client
37
+
38
+ 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.
39
+
40
+ ## Features
41
+
42
+ - **Type-safe**: Full type hints for better IDE support and code quality
43
+ - **Modern Python**: Built with httpx and attrs for async support and clean data models
44
+ - **Auto-generated**: Generated from the official OpenAPI specification
45
+ - **Comprehensive**: Access to all API endpoints and data models
46
+ - **Well-documented**: Inline documentation and usage examples
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ uv pip install balancing-services
52
+ ```
53
+
54
+ Or with pip:
55
+
56
+ ```bash
57
+ pip install balancing-services
58
+ ```
59
+
60
+ For development, install from source:
61
+
62
+ ```bash
63
+ cd clients/python
64
+ uv pip install -e .
65
+ ```
66
+
67
+ ## Quick Start
68
+
69
+ ```python
70
+ from balancing_services import AuthenticatedClient
71
+ from balancing_services.api.default import get_imbalance_prices
72
+ from balancing_services.models import Area
73
+ from datetime import datetime
74
+
75
+ # Create an authenticated client
76
+ client = AuthenticatedClient(
77
+ base_url="https://api.balancing.services/v1",
78
+ token="YOUR_API_TOKEN"
79
+ )
80
+
81
+ # Get imbalance prices for Estonia
82
+ response = get_imbalance_prices.sync_detailed(
83
+ client=client,
84
+ area=Area.EE,
85
+ period_start_at=datetime.fromisoformat("2025-01-01T00:00:00Z"),
86
+ period_end_at=datetime.fromisoformat("2025-01-02T00:00:00Z")
87
+ )
88
+
89
+ if response.status_code == 200:
90
+ data = response.parsed
91
+ print(f"Query period: {data.queried_period.start_at} to {data.queried_period.end_at}")
92
+ for imbalance_prices in data.data:
93
+ print(f"Area: {imbalance_prices.area}, Direction: {imbalance_prices.direction}")
94
+ for price in imbalance_prices.prices:
95
+ print(f" {price.period.start_at}: {price.price} {imbalance_prices.currency}")
96
+ ```
97
+
98
+ ## Authentication
99
+
100
+ To obtain an API token:
101
+ - **Email:** info@balancing.services
102
+ - **Website:** https://balancing.services
103
+
104
+ Include your token when creating the client:
105
+
106
+ ```python
107
+ from balancing_services import AuthenticatedClient
108
+
109
+ client = AuthenticatedClient(
110
+ base_url="https://api.balancing.services/v1",
111
+ token="YOUR_API_TOKEN"
112
+ )
113
+ ```
114
+
115
+ ## Usage Examples
116
+
117
+ ### Get Balancing Energy Bids with Pagination
118
+
119
+ ```python
120
+ from balancing_services import AuthenticatedClient
121
+ from balancing_services.api.default import get_balancing_energy_bids
122
+ from balancing_services.models import Area, ReserveType
123
+ from datetime import datetime
124
+
125
+ client = AuthenticatedClient(base_url="https://api.balancing.services/v1", token="YOUR_TOKEN")
126
+
127
+ # First page
128
+ response = get_balancing_energy_bids.sync_detailed(
129
+ client=client,
130
+ area=Area.EE,
131
+ period_start_at=datetime.fromisoformat("2025-01-01T00:00:00Z"),
132
+ period_end_at=datetime.fromisoformat("2025-01-02T00:00:00Z"),
133
+ reserve_type=ReserveType.AFRR,
134
+ limit=100
135
+ )
136
+
137
+ if response.status_code == 200:
138
+ data = response.parsed
139
+ print(f"Has more: {data.has_more}")
140
+
141
+ # Process first page
142
+ for bid_group in data.data:
143
+ for bid in bid_group.bids:
144
+ print(f"Bid: {bid.volume} MW @ {bid.price} {bid_group.currency}")
145
+
146
+ # Get next page if available
147
+ if data.has_more and data.next_cursor:
148
+ next_response = get_balancing_energy_bids.sync_detailed(
149
+ client=client,
150
+ area=Area.EE,
151
+ period_start_at=datetime.fromisoformat("2025-01-01T00:00:00Z"),
152
+ period_end_at=datetime.fromisoformat("2025-01-02T00:00:00Z"),
153
+ reserve_type=ReserveType.AFRR,
154
+ cursor=data.next_cursor,
155
+ limit=100
156
+ )
157
+ ```
158
+
159
+ ### Async Usage
160
+
161
+ ```python
162
+ import asyncio
163
+ from balancing_services import AuthenticatedClient
164
+ from balancing_services.api.default import get_imbalance_prices
165
+ from balancing_services.models import Area
166
+ from datetime import datetime
167
+
168
+ async def fetch_prices():
169
+ client = AuthenticatedClient(
170
+ base_url="https://api.balancing.services/v1",
171
+ token="YOUR_TOKEN"
172
+ )
173
+
174
+ response = await get_imbalance_prices.asyncio_detailed(
175
+ client=client,
176
+ area=Area.EE,
177
+ period_start_at=datetime.fromisoformat("2025-01-01T00:00:00Z"),
178
+ period_end_at=datetime.fromisoformat("2025-01-02T00:00:00Z")
179
+ )
180
+
181
+ if response.status_code == 200:
182
+ return response.parsed
183
+ return None
184
+
185
+ # Run async function
186
+ prices = asyncio.run(fetch_prices())
187
+ ```
188
+
189
+ ### Error Handling
190
+
191
+ ```python
192
+ from balancing_services import AuthenticatedClient
193
+ from balancing_services.api.default import get_imbalance_prices
194
+ from balancing_services.models import Area
195
+ from datetime import datetime
196
+
197
+ client = AuthenticatedClient(base_url="https://api.balancing.services/v1", token="YOUR_TOKEN")
198
+
199
+ response = get_imbalance_prices.sync_detailed(
200
+ client=client,
201
+ area=Area.EE,
202
+ period_start_at=datetime.fromisoformat("2025-01-01T00:00:00Z"),
203
+ period_end_at=datetime.fromisoformat("2025-01-02T00:00:00Z")
204
+ )
205
+
206
+ if response.status_code == 200:
207
+ data = response.parsed
208
+ # Process successful response
209
+ elif response.status_code == 400:
210
+ error = response.parsed
211
+ print(f"Bad request: {error.detail}")
212
+ elif response.status_code == 401:
213
+ print("Authentication failed - check your API token")
214
+ elif response.status_code == 429:
215
+ print("Rate limited - please retry later")
216
+ else:
217
+ print(f"Error {response.status_code}: {response.content}")
218
+ ```
219
+
220
+ ## Data Models
221
+
222
+ All response and request models are fully typed using attrs. Key models include:
223
+
224
+ - `ImbalancePricesResponse`, `ImbalanceTotalVolumesResponse`
225
+ - `BalancingEnergyVolumesResponse`, `BalancingEnergyPricesResponse`, `BalancingEnergyBidsResponse`
226
+ - `BalancingCapacityBidsResponse`, `BalancingCapacityPricesResponse`, `BalancingCapacityVolumesResponse`
227
+ - Enums: `Area`, `ReserveType`, `Direction`, `Currency`, `ActivationType`, `BidStatus`
228
+
229
+ ## Development
230
+
231
+ ### Regenerating the Client
232
+
233
+ The client is generated from the OpenAPI specification. To regenerate:
234
+
235
+ ```bash
236
+ cd clients/python
237
+ ./generate.sh
238
+ ```
239
+
240
+ ### Running Tests
241
+
242
+ ```bash
243
+ # Install development dependencies
244
+ uv pip install -e ".[dev]"
245
+
246
+ # Run tests
247
+ pytest
248
+
249
+ # Run tests with coverage
250
+ pytest --cov=balancing_services --cov-report=html
251
+ ```
252
+
253
+ ### Code Quality
254
+
255
+ ```bash
256
+ # Format code
257
+ ruff format .
258
+
259
+ # Lint code
260
+ ruff check .
261
+
262
+ # Type checking
263
+ mypy balancing_services
264
+ ```
265
+
266
+ ### Automation Scripts
267
+
268
+ The Python client includes automation scripts for development and publishing:
269
+
270
+ #### `generate-pyproject.sh`
271
+ Generates `pyproject.toml` from the template with the current version from `openapi.yaml`.
272
+
273
+ **Note:** The version is stored in `openapi.yaml` (single source of truth). The `pyproject.toml.draft` template contains invalid TOML (`version = __VERSION__` without quotes) to prevent accidental use without proper generation.
274
+
275
+ ```bash
276
+ ./generate-pyproject.sh
277
+ ```
278
+
279
+ This script is automatically called by `check.sh` and `test-and-publish.sh`.
280
+
281
+ #### `check.sh`
282
+ Runs all quality checks in one command:
283
+
284
+ ```bash
285
+ ./check.sh
286
+ ```
287
+
288
+ Performs:
289
+ - Generates `pyproject.toml` from draft
290
+ - Runs tests with pytest
291
+ - Runs linting with ruff
292
+ - Runs type checking with mypy
293
+ - Verifies the package builds
294
+
295
+ #### `test-and-publish.sh`
296
+ Complete publishing workflow with TestPyPI validation:
297
+
298
+ **Setup:**
299
+ 1. Copy `.env.sample` to `.env` and fill in your credentials:
300
+ ```bash
301
+ cp .env.sample .env
302
+ # Edit .env and add:
303
+ # BALANCING_SERVICES_API_KEY (required - for testing against live API)
304
+ # UV_PUBLISH_TOKEN_TESTPYPI (required)
305
+ # UV_PUBLISH_TOKEN_PYPI (required)
306
+ ```
307
+
308
+ 2. Run the publish script:
309
+ ```bash
310
+ ./test-and-publish.sh
311
+ ```
312
+
313
+ **Emergency option** - skip API tests if the server is down:
314
+ ```bash
315
+ ./test-and-publish.sh --skip-api-tests
316
+ ```
317
+ ⚠️ This skips testing against the live API. Use only in emergencies!
318
+
319
+ Alternatively, export variables manually:
320
+ ```bash
321
+ export BALANCING_SERVICES_API_KEY="your-api-key"
322
+ export UV_PUBLISH_TOKEN_TESTPYPI="your-testpypi-token"
323
+ export UV_PUBLISH_TOKEN_PYPI="your-pypi-token"
324
+ ./test-and-publish.sh
325
+ ```
326
+
327
+ **What it does:**
328
+ 1. Loads credentials from `.env` (if present)
329
+ 2. Verifies all required environment variables are set
330
+ 3. Runs quality checks
331
+ 4. Publishes to TestPyPI using `UV_PUBLISH_TOKEN_TESTPYPI`
332
+ 5. Creates isolated test sandbox
333
+ 6. Installs package from TestPyPI
334
+ 7. Runs all example scripts against live API using `BALANCING_SERVICES_API_KEY`
335
+ 8. Prompts to publish to PyPI using `UV_PUBLISH_TOKEN_PYPI` if tests pass
336
+ 9. Verifies production PyPI package by installing and running examples again
337
+
338
+ **Get your credentials:**
339
+ - API Key: https://balancing.services
340
+ - TestPyPI: https://test.pypi.org/manage/account/token/
341
+ - PyPI: https://pypi.org/manage/account/token/
342
+
343
+ **For maintainers:** See `../../scripts/README.md` for the complete release workflow.
344
+
345
+ ## Troubleshooting
346
+
347
+ ### Authentication Errors (401)
348
+
349
+ **Problem:** Receiving 401 Unauthorized responses
350
+
351
+ **Solutions:**
352
+ - Verify your API token is correct
353
+ - Check that the token is being passed to `AuthenticatedClient`
354
+ - Ensure your token hasn't expired (contact support if needed)
355
+
356
+ ### Bad Request Errors (400)
357
+
358
+ **Problem:** Receiving 400 Bad Request responses
359
+
360
+ **Common causes:**
361
+ - Invalid date range (end date before start date)
362
+ - Date range too large
363
+ - Invalid area code or reserve type
364
+ - Malformed datetime strings
365
+
366
+ **Solution:** Check the error detail in the response for specific information:
367
+ ```python
368
+ if response.status_code == 400:
369
+ error = response.parsed
370
+ print(f"Error detail: {error.detail}")
371
+ ```
372
+
373
+ ### Empty Results
374
+
375
+ **Problem:** Receiving 200 OK but no data
376
+
377
+ **Possible reasons:**
378
+ - No data available for the requested period
379
+ - Data not yet published for recent periods
380
+ - Requesting data for a period before data collection started
381
+
382
+ **Solution:** Try a different time period or check if data exists for your area
383
+
384
+ ### Timeout Issues
385
+
386
+ **Problem:** Requests timing out
387
+
388
+ **Solutions:**
389
+ - Increase the client timeout:
390
+ ```python
391
+ client = AuthenticatedClient(
392
+ base_url="https://api.balancing.services/v1",
393
+ token="YOUR_TOKEN",
394
+ timeout=30.0 # Increase from default
395
+ )
396
+ ```
397
+ - Reduce the date range in your request
398
+ - Use pagination for large datasets
399
+
400
+ ### Type Errors with Enums
401
+
402
+ **Problem:** Type errors when passing area or reserve type
403
+
404
+ **Solution:** Use the provided enum classes:
405
+ ```python
406
+ from balancing_services.models import Area, ReserveType
407
+
408
+ # Correct
409
+ area=Area.EE
410
+
411
+ # Incorrect
412
+ area="EE" # String might work but not type-safe
413
+ ```
414
+
415
+ ## Documentation
416
+
417
+ - **API Documentation:** https://api.balancing.services/v1/documentation
418
+ - **OpenAPI Spec:** [openapi.yaml](https://github.com/Balancing-Services/rest-api/blob/main/openapi.yaml)
419
+ - **Main Repository:** https://github.com/balancing-services/rest-api
420
+
421
+ ## Support
422
+
423
+ - **Website:** https://balancing.services
424
+ - **Email:** info@balancing.services
425
+ - **Issues:** [GitHub Issues](https://github.com/balancing-services/rest-api/issues)
426
+
427
+ ## License
428
+
429
+ MIT License - see [LICENSE](https://github.com/Balancing-Services/rest-api/blob/main/LICENSE) for details.
430
+
431
+ ## Changelog
432
+
433
+ See [CHANGELOG.md](https://github.com/Balancing-Services/rest-api/blob/main/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