ionworks-api 0.1.0__tar.gz → 0.1.2__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.
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/.gitignore +6 -0
- ionworks_api-0.1.2/LICENSE.md +21 -0
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/PKG-INFO +35 -16
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/README.md +29 -15
- ionworks_api-0.1.2/ionworks/__init__.py +28 -0
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/cell_instance.py +54 -48
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/cell_measurement.py +95 -58
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/cell_specification.py +106 -19
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/client.py +37 -8
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/errors.py +22 -5
- ionworks_api-0.1.2/ionworks/job.py +165 -0
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/models.py +29 -37
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/pipeline.py +113 -4
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/ionworks/simulation.py +123 -73
- ionworks_api-0.1.2/ionworks/validators.py +692 -0
- {ionworks_api-0.1.0 → ionworks_api-0.1.2}/pyproject.toml +6 -1
- ionworks_api-0.1.0/ionworks/__init__.py +0 -3
- ionworks_api-0.1.0/ionworks/job.py +0 -111
- ionworks_api-0.1.0/ionworks/validators.py +0 -171
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ionworks Technologies Inc
|
|
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.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ionworks-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python client for interacting with the Ionworks API
|
|
5
|
+
License-File: LICENSE.md
|
|
5
6
|
Requires-Python: >=3.10
|
|
6
7
|
Requires-Dist: black
|
|
7
8
|
Requires-Dist: iwutil
|
|
@@ -17,6 +18,10 @@ Requires-Dist: supabase
|
|
|
17
18
|
Requires-Dist: types-requests>=2.31.0
|
|
18
19
|
Provides-Extra: dev
|
|
19
20
|
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
21
|
+
Provides-Extra: docs
|
|
22
|
+
Requires-Dist: furo; extra == 'docs'
|
|
23
|
+
Requires-Dist: myst-nb>=1.0.0; extra == 'docs'
|
|
24
|
+
Requires-Dist: sphinx>=7.0.0; extra == 'docs'
|
|
20
25
|
Description-Content-Type: text/markdown
|
|
21
26
|
|
|
22
27
|
# Ionworks API Client
|
|
@@ -34,7 +39,13 @@ A Python client for interacting with the Ionworks API.
|
|
|
34
39
|
pip install -e .
|
|
35
40
|
```
|
|
36
41
|
|
|
37
|
-
3.
|
|
42
|
+
3. Copy the example environment file and fill in your credentials:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cp .env.example .env
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Get your API key from the [Ionworks account settings](https://app.ionworks.com/dashboard/account) and your project ID from your project settings page. See [Environment Setup](#environment-setup) for details.
|
|
38
49
|
|
|
39
50
|
## Usage
|
|
40
51
|
|
|
@@ -185,7 +196,6 @@ Available element types:
|
|
|
185
196
|
- `validation`: Validate model against data
|
|
186
197
|
|
|
187
198
|
```python
|
|
188
|
-
import time
|
|
189
199
|
from ionworks import Ionworks
|
|
190
200
|
|
|
191
201
|
client = Ionworks()
|
|
@@ -236,22 +246,15 @@ pipeline_config = {
|
|
|
236
246
|
},
|
|
237
247
|
}
|
|
238
248
|
|
|
239
|
-
# Submit pipeline
|
|
249
|
+
# Submit pipeline and wait for completion
|
|
240
250
|
pipeline = client.pipeline.create(pipeline_config)
|
|
241
251
|
print(f"Pipeline submitted: {pipeline.id}")
|
|
242
252
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
result = client.pipeline.result(pipeline.id)
|
|
249
|
-
print("Fitted parameters:", result.element_results["fit data"])
|
|
250
|
-
break
|
|
251
|
-
elif pipeline.status == "failed":
|
|
252
|
-
print("Pipeline failed:", pipeline.error)
|
|
253
|
-
break
|
|
254
|
-
time.sleep(2)
|
|
253
|
+
pipeline = client.pipeline.wait_for_completion(pipeline.id, timeout=600)
|
|
254
|
+
|
|
255
|
+
if pipeline.status == "completed":
|
|
256
|
+
result = client.pipeline.result(pipeline.id)
|
|
257
|
+
print("Fitted parameters:", result.element_results["fit data"])
|
|
255
258
|
```
|
|
256
259
|
|
|
257
260
|
### Running simulations
|
|
@@ -307,6 +310,22 @@ simulation_data = client.simulation.get_result(result.simulation_id)
|
|
|
307
310
|
time_series = simulation_data.get("time_series", {})
|
|
308
311
|
```
|
|
309
312
|
|
|
313
|
+
## Environment Setup
|
|
314
|
+
|
|
315
|
+
The client uses environment variables for configuration. Copy the example file and fill in your values:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
cp .env.example .env
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
| Variable | Required | Default | Description |
|
|
322
|
+
|---|---|---|---|
|
|
323
|
+
| `IONWORKS_API_KEY` | Yes | — | API key from [account settings](https://app.ionworks.com/dashboard/account) |
|
|
324
|
+
| `IONWORKS_API_URL` | No | `https://api.ionworks.com` | API base URL |
|
|
325
|
+
| `PROJECT_ID` | For pipelines | — | Project ID from your project settings page |
|
|
326
|
+
|
|
327
|
+
The client loads `.env` automatically via `python-dotenv`.
|
|
328
|
+
|
|
310
329
|
## Error Handling
|
|
311
330
|
|
|
312
331
|
The client will raise exceptions in the following cases:
|
|
@@ -13,7 +13,13 @@ A Python client for interacting with the Ionworks API.
|
|
|
13
13
|
pip install -e .
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
3.
|
|
16
|
+
3. Copy the example environment file and fill in your credentials:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cp .env.example .env
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Get your API key from the [Ionworks account settings](https://app.ionworks.com/dashboard/account) and your project ID from your project settings page. See [Environment Setup](#environment-setup) for details.
|
|
17
23
|
|
|
18
24
|
## Usage
|
|
19
25
|
|
|
@@ -164,7 +170,6 @@ Available element types:
|
|
|
164
170
|
- `validation`: Validate model against data
|
|
165
171
|
|
|
166
172
|
```python
|
|
167
|
-
import time
|
|
168
173
|
from ionworks import Ionworks
|
|
169
174
|
|
|
170
175
|
client = Ionworks()
|
|
@@ -215,22 +220,15 @@ pipeline_config = {
|
|
|
215
220
|
},
|
|
216
221
|
}
|
|
217
222
|
|
|
218
|
-
# Submit pipeline
|
|
223
|
+
# Submit pipeline and wait for completion
|
|
219
224
|
pipeline = client.pipeline.create(pipeline_config)
|
|
220
225
|
print(f"Pipeline submitted: {pipeline.id}")
|
|
221
226
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
result = client.pipeline.result(pipeline.id)
|
|
228
|
-
print("Fitted parameters:", result.element_results["fit data"])
|
|
229
|
-
break
|
|
230
|
-
elif pipeline.status == "failed":
|
|
231
|
-
print("Pipeline failed:", pipeline.error)
|
|
232
|
-
break
|
|
233
|
-
time.sleep(2)
|
|
227
|
+
pipeline = client.pipeline.wait_for_completion(pipeline.id, timeout=600)
|
|
228
|
+
|
|
229
|
+
if pipeline.status == "completed":
|
|
230
|
+
result = client.pipeline.result(pipeline.id)
|
|
231
|
+
print("Fitted parameters:", result.element_results["fit data"])
|
|
234
232
|
```
|
|
235
233
|
|
|
236
234
|
### Running simulations
|
|
@@ -286,6 +284,22 @@ simulation_data = client.simulation.get_result(result.simulation_id)
|
|
|
286
284
|
time_series = simulation_data.get("time_series", {})
|
|
287
285
|
```
|
|
288
286
|
|
|
287
|
+
## Environment Setup
|
|
288
|
+
|
|
289
|
+
The client uses environment variables for configuration. Copy the example file and fill in your values:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
cp .env.example .env
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
| Variable | Required | Default | Description |
|
|
296
|
+
|---|---|---|---|
|
|
297
|
+
| `IONWORKS_API_KEY` | Yes | — | API key from [account settings](https://app.ionworks.com/dashboard/account) |
|
|
298
|
+
| `IONWORKS_API_URL` | No | `https://api.ionworks.com` | API base URL |
|
|
299
|
+
| `PROJECT_ID` | For pipelines | — | Project ID from your project settings page |
|
|
300
|
+
|
|
301
|
+
The client loads `.env` automatically via `python-dotenv`.
|
|
302
|
+
|
|
289
303
|
## Error Handling
|
|
290
304
|
|
|
291
305
|
The client will raise exceptions in the following cases:
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ionworks API Client.
|
|
3
|
+
|
|
4
|
+
A Python client for interacting with the Ionworks platform for battery cell
|
|
5
|
+
testing, simulation, and modeling.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
-------
|
|
9
|
+
>>> from ionworks import Ionworks
|
|
10
|
+
>>> client = Ionworks()
|
|
11
|
+
>>> specs = client.cell_spec.list()
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .client import Ionworks
|
|
15
|
+
from .errors import IonworksError
|
|
16
|
+
from .validators import (
|
|
17
|
+
MeasurementValidationError,
|
|
18
|
+
get_dataframe_backend,
|
|
19
|
+
set_dataframe_backend,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"Ionworks",
|
|
24
|
+
"IonworksError",
|
|
25
|
+
"MeasurementValidationError",
|
|
26
|
+
"get_dataframe_backend",
|
|
27
|
+
"set_dataframe_backend",
|
|
28
|
+
]
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cell instance client for managing individual cell records.
|
|
3
|
+
|
|
4
|
+
This module provides the :class:`CellInstanceClient` for creating, reading,
|
|
5
|
+
updating, and deleting cell instances, which represent individual physical
|
|
6
|
+
battery cells linked to a cell specification.
|
|
7
|
+
"""
|
|
8
|
+
|
|
1
9
|
from typing import Any
|
|
2
10
|
|
|
3
11
|
from pydantic import ValidationError
|
|
@@ -12,13 +20,20 @@ from .models import (
|
|
|
12
20
|
|
|
13
21
|
|
|
14
22
|
class CellInstanceClient:
|
|
15
|
-
|
|
23
|
+
"""Client for managing cell instances."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, client: Any) -> None:
|
|
26
|
+
"""Initialize the CellInstanceClient.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
client : Any
|
|
31
|
+
The HTTP client instance used for API calls.
|
|
32
|
+
"""
|
|
16
33
|
self.client = client
|
|
17
34
|
|
|
18
35
|
def get(self, cell_instance_id: str) -> CellInstance:
|
|
19
|
-
"""
|
|
20
|
-
Get a specific cell instance by ID.
|
|
21
|
-
"""
|
|
36
|
+
"""Get a specific cell instance by ID."""
|
|
22
37
|
endpoint = f"/cell_instances/{cell_instance_id}"
|
|
23
38
|
try:
|
|
24
39
|
response_data = self.client.get(endpoint)
|
|
@@ -30,9 +45,7 @@ class CellInstanceClient:
|
|
|
30
45
|
raise RuntimeError(f"API call to {endpoint} failed: {e}") from e
|
|
31
46
|
|
|
32
47
|
def get_by_slug(self, cell_instance_slug: str) -> CellInstance:
|
|
33
|
-
"""
|
|
34
|
-
Get a specific cell instance by slug.
|
|
35
|
-
"""
|
|
48
|
+
"""Get a specific cell instance by slug."""
|
|
36
49
|
endpoint = f"/cell_instances/slug/{cell_instance_slug}"
|
|
37
50
|
try:
|
|
38
51
|
response_data = self.client.get(endpoint)
|
|
@@ -43,9 +56,7 @@ class CellInstanceClient:
|
|
|
43
56
|
raise RuntimeError(f"API call to {endpoint} failed: {e}") from e
|
|
44
57
|
|
|
45
58
|
def list(self, cell_spec_id: str) -> list[CellInstance]:
|
|
46
|
-
"""
|
|
47
|
-
List all cell instances for a cell specification by specification ID.
|
|
48
|
-
"""
|
|
59
|
+
"""List all cell instances for a cell specification by specification ID."""
|
|
49
60
|
endpoint = f"/cell_specifications/{cell_spec_id}/cell_instances"
|
|
50
61
|
try:
|
|
51
62
|
response_data = self.client.get(endpoint)
|
|
@@ -74,14 +85,13 @@ class CellInstanceClient:
|
|
|
74
85
|
# return [CellMeasurementDetailBase(**item) for item in response_data]
|
|
75
86
|
|
|
76
87
|
def update(self, cell_instance_id: str, data: dict[str, Any]) -> CellInstance:
|
|
77
|
-
"""
|
|
78
|
-
Update an existing cell instance.
|
|
88
|
+
"""Update an existing cell instance.
|
|
79
89
|
|
|
80
90
|
Parameters
|
|
81
91
|
----------
|
|
82
92
|
cell_instance_id : str
|
|
83
93
|
The ID of the cell instance to update.
|
|
84
|
-
data : dict
|
|
94
|
+
data : dict[str, Any]
|
|
85
95
|
Dictionary containing the fields to update.
|
|
86
96
|
|
|
87
97
|
Returns
|
|
@@ -94,30 +104,36 @@ class CellInstanceClient:
|
|
|
94
104
|
return CellInstance(**response_data)
|
|
95
105
|
|
|
96
106
|
def delete(self, cell_instance_id: str) -> None:
|
|
97
|
-
"""
|
|
98
|
-
Delete a cell instance by ID.
|
|
99
|
-
"""
|
|
107
|
+
"""Delete a cell instance by ID."""
|
|
100
108
|
endpoint = f"/cell_instances/{cell_instance_id}"
|
|
101
109
|
self.client.delete(endpoint)
|
|
102
110
|
|
|
103
111
|
# Renamed and moved method from Data class
|
|
104
112
|
def detail(self, cell_instance_id: str) -> CellInstanceDetail:
|
|
105
|
-
"""
|
|
106
|
-
Loads the full details for a cell instance from a single API endpoint,
|
|
107
|
-
including its spec, instance data, steps DataFrame, and time series DataFrame.
|
|
108
|
-
Uses the /detail endpoint.
|
|
113
|
+
"""Load the full details for a cell instance.
|
|
109
114
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
Loads the full details for a cell instance from a single API endpoint,
|
|
116
|
+
including its spec, instance data, steps DataFrame, and time series
|
|
117
|
+
DataFrame. Uses the /detail endpoint.
|
|
113
118
|
|
|
114
|
-
|
|
115
|
-
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
cell_instance_id : str
|
|
122
|
+
The cell instance ID.
|
|
116
123
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
CellInstanceDetail
|
|
127
|
+
Object containing validated cell instance data.
|
|
128
|
+
|
|
129
|
+
Raises
|
|
130
|
+
------
|
|
131
|
+
RuntimeError
|
|
132
|
+
If the API call fails.
|
|
133
|
+
ValueError
|
|
134
|
+
If the API response format is unexpected or parsing fails.
|
|
135
|
+
ValidationError
|
|
136
|
+
If the response data doesn't match expected models.
|
|
121
137
|
"""
|
|
122
138
|
endpoint = f"/cell_instances/{cell_instance_id}/detail"
|
|
123
139
|
try:
|
|
@@ -127,9 +143,9 @@ class CellInstanceClient:
|
|
|
127
143
|
except ValidationError as e:
|
|
128
144
|
# Pydantic validation error during parsing
|
|
129
145
|
raise ValueError(f"Response validation failed for {endpoint}: {e}") from e
|
|
130
|
-
except ValueError
|
|
146
|
+
except ValueError:
|
|
131
147
|
# Re-raise our explicit format validation errors
|
|
132
|
-
raise
|
|
148
|
+
raise
|
|
133
149
|
except Exception as e:
|
|
134
150
|
# Catch client errors or any other unexpected issues
|
|
135
151
|
raise RuntimeError(
|
|
@@ -137,19 +153,13 @@ class CellInstanceClient:
|
|
|
137
153
|
) from e
|
|
138
154
|
|
|
139
155
|
def create(self, cell_spec_id: str, data: dict[str, Any]) -> CellInstance:
|
|
140
|
-
"""
|
|
141
|
-
Create a new cell instance under a cell specification by
|
|
142
|
-
specification ID.
|
|
143
|
-
"""
|
|
156
|
+
"""Create a new cell instance under a cell specification by specification ID."""
|
|
144
157
|
endpoint = f"/cell_specifications/{cell_spec_id}/cell_instances"
|
|
145
158
|
response_data = self.client.post(endpoint, data)
|
|
146
159
|
return CellInstance(**response_data)
|
|
147
160
|
|
|
148
161
|
def create_or_get(self, cell_spec_id: str, data: dict[str, Any]) -> CellInstance:
|
|
149
|
-
"""
|
|
150
|
-
Create a new cell instance if it doesn't exist, otherwise get the
|
|
151
|
-
existing one.
|
|
152
|
-
"""
|
|
162
|
+
"""Create a new cell instance if it doesn't exist, otherwise get it."""
|
|
153
163
|
try:
|
|
154
164
|
return self.create(cell_spec_id, data)
|
|
155
165
|
except IonworksError as e:
|
|
@@ -157,11 +167,11 @@ class CellInstanceClient:
|
|
|
157
167
|
existing_id = e.data.get("existing_cell_instance_id")
|
|
158
168
|
if existing_id:
|
|
159
169
|
return self.get(existing_id)
|
|
160
|
-
raise
|
|
170
|
+
raise
|
|
161
171
|
|
|
162
172
|
def list_with_measurements(self, cell_spec_id: str) -> CellSpecificationInstances:
|
|
163
|
-
"""
|
|
164
|
-
|
|
173
|
+
"""List all instances and measurements for a cell specification.
|
|
174
|
+
|
|
165
175
|
Returns normalized data: separate lists for specification, instances, and
|
|
166
176
|
measurements.
|
|
167
177
|
"""
|
|
@@ -179,8 +189,8 @@ class CellInstanceClient:
|
|
|
179
189
|
def list_with_measurements_and_steps(
|
|
180
190
|
self, cell_spec_id: str
|
|
181
191
|
) -> CellSpecificationInstancesWithSteps:
|
|
182
|
-
"""
|
|
183
|
-
|
|
192
|
+
"""List all instances, measurements, and steps for a cell specification.
|
|
193
|
+
|
|
184
194
|
Returns normalized data: separate lists for specification, instances,
|
|
185
195
|
measurements, and steps.
|
|
186
196
|
"""
|
|
@@ -195,7 +205,3 @@ class CellInstanceClient:
|
|
|
195
205
|
raise ValueError(f"Response validation failed for {endpoint}: {e}") from e
|
|
196
206
|
except Exception as e:
|
|
197
207
|
raise RuntimeError(f"API call to {endpoint} failed: {e}") from e
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
class CellMeasurementClient:
|
|
201
|
-
pass
|