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.
- balancing_services-1.0.0/.gitignore +74 -0
- balancing_services-1.0.0/LICENSE +21 -0
- balancing_services-1.0.0/PKG-INFO +364 -0
- balancing_services-1.0.0/PUBLISHING.md +56 -0
- balancing_services-1.0.0/README.md +331 -0
- balancing_services-1.0.0/RELEASE_CHECKLIST.md +25 -0
- balancing_services-1.0.0/balancing_services/__init__.py +8 -0
- balancing_services-1.0.0/balancing_services/api/__init__.py +1 -0
- balancing_services-1.0.0/balancing_services/api/default/__init__.py +1 -0
- balancing_services-1.0.0/balancing_services/api/default/get_balancing_capacity_bids.py +289 -0
- balancing_services-1.0.0/balancing_services/api/default/get_balancing_capacity_prices.py +259 -0
- balancing_services-1.0.0/balancing_services/api/default/get_balancing_capacity_procured_volumes.py +261 -0
- balancing_services-1.0.0/balancing_services/api/default/get_balancing_energy_activated_volumes.py +259 -0
- balancing_services-1.0.0/balancing_services/api/default/get_balancing_energy_bids.py +289 -0
- balancing_services-1.0.0/balancing_services/api/default/get_balancing_energy_prices.py +255 -0
- balancing_services-1.0.0/balancing_services/api/default/get_imbalance_prices.py +238 -0
- balancing_services-1.0.0/balancing_services/api/default/get_imbalance_total_volumes.py +242 -0
- balancing_services-1.0.0/balancing_services/client.py +286 -0
- balancing_services-1.0.0/balancing_services/errors.py +16 -0
- balancing_services-1.0.0/balancing_services/models/__init__.py +77 -0
- balancing_services-1.0.0/balancing_services/models/activation_type.py +10 -0
- balancing_services-1.0.0/balancing_services/models/area.py +50 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_bids.py +123 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_bids_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_price.py +77 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_prices.py +123 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_prices_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_volume.py +77 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_volumes.py +114 -0
- balancing_services-1.0.0/balancing_services/models/balancing_capacity_volumes_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_bids.py +131 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_bids_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_price.py +77 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_prices.py +140 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_prices_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_volume.py +77 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_volumes.py +131 -0
- balancing_services-1.0.0/balancing_services/models/balancing_energy_volumes_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/bid_status.py +9 -0
- balancing_services-1.0.0/balancing_services/models/capacity_bid.py +97 -0
- balancing_services-1.0.0/balancing_services/models/currency.py +9 -0
- balancing_services-1.0.0/balancing_services/models/direction.py +9 -0
- balancing_services-1.0.0/balancing_services/models/eic_code.py +50 -0
- balancing_services-1.0.0/balancing_services/models/energy_bid.py +85 -0
- balancing_services-1.0.0/balancing_services/models/imbalance_direction.py +10 -0
- balancing_services-1.0.0/balancing_services/models/imbalance_price.py +77 -0
- balancing_services-1.0.0/balancing_services/models/imbalance_prices.py +114 -0
- balancing_services-1.0.0/balancing_services/models/imbalance_prices_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/imbalance_total_volumes.py +97 -0
- balancing_services-1.0.0/balancing_services/models/imbalance_total_volumes_response.py +120 -0
- balancing_services-1.0.0/balancing_services/models/period.py +72 -0
- balancing_services-1.0.0/balancing_services/models/problem.py +91 -0
- balancing_services-1.0.0/balancing_services/models/problem_type.py +14 -0
- balancing_services-1.0.0/balancing_services/models/reserve_type.py +11 -0
- balancing_services-1.0.0/balancing_services/models/total_imbalance_direction.py +10 -0
- balancing_services-1.0.0/balancing_services/models/total_imbalance_volume.py +90 -0
- balancing_services-1.0.0/balancing_services/py.typed +0 -0
- balancing_services-1.0.0/balancing_services/types.py +54 -0
- balancing_services-1.0.0/config.yaml +2 -0
- balancing_services-1.0.0/examples/basic_usage.py +78 -0
- balancing_services-1.0.0/examples/error_handling.py +164 -0
- balancing_services-1.0.0/examples/pagination_example.py +112 -0
- balancing_services-1.0.0/generate.sh +51 -0
- balancing_services-1.0.0/pyproject.toml +73 -0
- balancing_services-1.0.0/tests/conftest.py +59 -0
- balancing_services-1.0.0/tests/test_async.py +74 -0
- balancing_services-1.0.0/tests/test_basic.py +160 -0
- 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
|