entitysdk 0.6.1__tar.gz → 0.7.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.
- {entitysdk-0.6.1/src/entitysdk.egg-info → entitysdk-0.7.0}/PKG-INFO +1 -1
- {entitysdk-0.6.1 → entitysdk-0.7.0}/examples/02_morphology.ipynb +18 -2
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/client.py +35 -21
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/core.py +20 -7
- entitysdk-0.7.0/src/entitysdk/dependencies/__init__.py +1 -0
- entitysdk-0.7.0/src/entitysdk/dependencies/entity.py +18 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/downloaders/emodel.py +1 -1
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/downloaders/ion_channel_model.py +1 -1
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/downloaders/morphology.py +1 -1
- entitysdk-0.7.0/src/entitysdk/downloaders/simulation.py +78 -0
- entitysdk-0.7.0/src/entitysdk/downloaders/simulation_result.py +61 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/exception.py +8 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/asset.py +4 -0
- entitysdk-0.7.0/src/entitysdk/schemas/asset.py +20 -0
- entitysdk-0.7.0/src/entitysdk/staging/__init__.py +7 -0
- entitysdk-0.7.0/src/entitysdk/staging/circuit.py +43 -0
- entitysdk-0.7.0/src/entitysdk/staging/simulation.py +142 -0
- entitysdk-0.7.0/src/entitysdk/staging/simulation_result.py +72 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/types.py +6 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/util.py +3 -0
- entitysdk-0.7.0/src/entitysdk/utils/io.py +16 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0/src/entitysdk.egg-info}/PKG-INFO +1 -1
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk.egg-info/SOURCES.txt +24 -0
- entitysdk-0.7.0/tests/unit/dependencies/test_entity.py +27 -0
- entitysdk-0.7.0/tests/unit/models/data/.gitignore +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_asset.py +1 -0
- entitysdk-0.7.0/tests/unit/staging/__init__.py +0 -0
- entitysdk-0.7.0/tests/unit/staging/conftest.py +281 -0
- entitysdk-0.7.0/tests/unit/staging/data/SomaVoltRec 1.h5 +0 -0
- entitysdk-0.7.0/tests/unit/staging/data/SomaVoltRec 2.h5 +0 -0
- entitysdk-0.7.0/tests/unit/staging/data/circuit/circuit_config.json +36 -0
- entitysdk-0.7.0/tests/unit/staging/data/circuit/edges.h5 +0 -0
- entitysdk-0.7.0/tests/unit/staging/data/circuit/nodes.h5 +0 -0
- entitysdk-0.7.0/tests/unit/staging/data/node_sets.json +67 -0
- entitysdk-0.7.0/tests/unit/staging/data/simulation_config.json +128 -0
- entitysdk-0.7.0/tests/unit/staging/data/spike_replays.h5 +0 -0
- entitysdk-0.7.0/tests/unit/staging/data/spikes.h5 +0 -0
- entitysdk-0.7.0/tests/unit/staging/test_simulation.py +98 -0
- entitysdk-0.7.0/tests/unit/staging/test_simulation_result.py +106 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_client.py +106 -3
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/utils/test_asset.py +5 -0
- entitysdk-0.6.1/src/entitysdk/schemas/asset.py +0 -13
- {entitysdk-0.6.1 → entitysdk-0.7.0}/.github/workflows/sdist.yml +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/.github/workflows/tox.yml +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/.gitignore +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/CHANGELOG.rst +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/CONTRIBUTING.md +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/LICENSE.txt +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/README.md +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/examples/01_searching.ipynb +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/examples/03_circuit.ipynb +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/examples/04_simulation_campaign.ipynb +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/examples/utils.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/pyproject.toml +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/setup.cfg +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/common.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/config.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/downloaders/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/downloaders/memodel.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/mixin.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/activity.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/agent.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/base.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/brain_location.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/brain_region.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/brain_region_hierarchy.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/circuit.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/classification.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/contribution.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/core.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/electrical_cell_recording.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/emodel.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/entity.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/etype.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/ion_channel_model.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/license.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/memodel.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/memodelcalibrationresult.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/morphology.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/mtype.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/response.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/scientific_artifact.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/simulation.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/simulation_campaign.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/simulation_execution.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/simulation_generation.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/simulation_result.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/single_neuron_simulation.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/single_neuron_synaptome_simulation.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/subject.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/synaptome.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/taxonomy.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/models/validation_result.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/result.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/route.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/schemas/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/schemas/base.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/schemas/memodel.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/serdes.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/token_manager.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/utils/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/utils/asset.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk/utils/filesystem.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk.egg-info/dependency_links.txt +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk.egg-info/requires.txt +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/src/entitysdk.egg-info/top_level.txt +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/integration/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/integration/conftest.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/integration/test_searching.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/conftest.py +0 -0
- {entitysdk-0.6.1/tests/unit/models → entitysdk-0.7.0/tests/unit/dependencies}/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/downloaders/test_emodel.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/downloaders/test_ion_channel_model.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/downloaders/test_memodel.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/downloaders/test_morphology.py +0 -0
- /entitysdk-0.6.1/tests/unit/models/data/.gitignore → /entitysdk-0.7.0/tests/unit/models/__init__.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/data/circuit.json +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/data/electrical_cell_recording.json +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/data/ion_channel_model.json +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/data/memodel_calibration_result.json +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/data/reconstruction_morphology.json +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/data/simulation_campaign.json +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/data/validation_result.json +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_agent.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_brain_region.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_circuit.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_contribution.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_electrical_cell_recording.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_init.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_ion_channel_model.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_memodel_calibration_result.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_morphology.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_simulation_campaign.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/models/test_validation_result.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_base.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_common.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_config.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_result.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_route.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_serdes.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_token_manager.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/test_util.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/util.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tests/unit/utils/test_filesystem.py +0 -0
- {entitysdk-0.6.1 → entitysdk-0.7.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: entitysdk
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.0
|
4
4
|
Summary: Python library for interacting with the entitycore service
|
5
5
|
Author-email: Open Brain Institute <info@openbraininstitute.org>
|
6
6
|
Maintainer-email: Open Brain Institute <info@openbraininstitute.org>
|
@@ -276,7 +276,8 @@
|
|
276
276
|
" entity_id=registered.id,\n",
|
277
277
|
" entity_type=ReconstructionMorphology,\n",
|
278
278
|
" file_path=file1,\n",
|
279
|
-
" file_content_type=\"application/
|
279
|
+
" file_content_type=\"application/x-hdf5\",\n",
|
280
|
+
" asset_label=\"hdf5\",\n",
|
280
281
|
" )\n",
|
281
282
|
" rprint(asset1)\n",
|
282
283
|
"\n",
|
@@ -289,6 +290,7 @@
|
|
289
290
|
" file_content=buffer,\n",
|
290
291
|
" file_name=\"buffer.h5\",\n",
|
291
292
|
" file_content_type=\"application/swc\",\n",
|
293
|
+
" asset_label=\"swc\",\n",
|
292
294
|
" )\n",
|
293
295
|
" rprint(asset2)"
|
294
296
|
]
|
@@ -408,8 +410,22 @@
|
|
408
410
|
}
|
409
411
|
],
|
410
412
|
"metadata": {
|
413
|
+
"kernelspec": {
|
414
|
+
"display_name": "Python 3 (ipykernel)",
|
415
|
+
"language": "python",
|
416
|
+
"name": "python3"
|
417
|
+
},
|
411
418
|
"language_info": {
|
412
|
-
"
|
419
|
+
"codemirror_mode": {
|
420
|
+
"name": "ipython",
|
421
|
+
"version": 3
|
422
|
+
},
|
423
|
+
"file_extension": ".py",
|
424
|
+
"mimetype": "text/x-python",
|
425
|
+
"name": "python",
|
426
|
+
"nbconvert_exporter": "python",
|
427
|
+
"pygments_lexer": "ipython3",
|
428
|
+
"version": "3.12.10"
|
413
429
|
}
|
414
430
|
},
|
415
431
|
"nbformat": 4,
|
@@ -3,7 +3,7 @@
|
|
3
3
|
import io
|
4
4
|
import os
|
5
5
|
from pathlib import Path
|
6
|
-
from typing import Any, cast
|
6
|
+
from typing import Any, TypeVar, cast
|
7
7
|
|
8
8
|
import httpx
|
9
9
|
|
@@ -14,7 +14,7 @@ from entitysdk.models.asset import Asset, DetailedFileList, LocalAssetMetadata
|
|
14
14
|
from entitysdk.models.core import Identifiable
|
15
15
|
from entitysdk.models.entity import Entity
|
16
16
|
from entitysdk.result import IteratorResult
|
17
|
-
from entitysdk.schemas.asset import
|
17
|
+
from entitysdk.schemas.asset import DownloadedAssetFile
|
18
18
|
from entitysdk.token_manager import TokenFromValue, TokenManager
|
19
19
|
from entitysdk.types import ID, DeploymentEnvironment, Token
|
20
20
|
from entitysdk.util import (
|
@@ -24,6 +24,8 @@ from entitysdk.util import (
|
|
24
24
|
)
|
25
25
|
from entitysdk.utils.asset import filter_assets
|
26
26
|
|
27
|
+
TEntity = TypeVar("TEntity", bound=Entity)
|
28
|
+
|
27
29
|
|
28
30
|
class Client:
|
29
31
|
"""Client for entitysdk."""
|
@@ -94,9 +96,9 @@ class Client:
|
|
94
96
|
self,
|
95
97
|
entity_id: ID,
|
96
98
|
*,
|
97
|
-
entity_type: type[
|
99
|
+
entity_type: type[TEntity],
|
98
100
|
project_context: ProjectContext | None = None,
|
99
|
-
) ->
|
101
|
+
) -> TEntity:
|
100
102
|
"""Get entity from resource id.
|
101
103
|
|
102
104
|
Args:
|
@@ -214,6 +216,7 @@ class Client:
|
|
214
216
|
file_content_type: str,
|
215
217
|
file_name: str | None = None,
|
216
218
|
file_metadata: dict | None = None,
|
219
|
+
asset_label: str | None = None,
|
217
220
|
project_context: ProjectContext | None = None,
|
218
221
|
) -> Asset:
|
219
222
|
"""Upload asset to an existing entity's endpoint from a file path."""
|
@@ -229,6 +232,7 @@ class Client:
|
|
229
232
|
file_name=file_name or path.name,
|
230
233
|
content_type=file_content_type,
|
231
234
|
metadata=file_metadata,
|
235
|
+
label=asset_label,
|
232
236
|
)
|
233
237
|
return core.upload_asset_file(
|
234
238
|
url=url,
|
@@ -248,6 +252,7 @@ class Client:
|
|
248
252
|
file_name: str,
|
249
253
|
file_content_type: str,
|
250
254
|
file_metadata: dict | None = None,
|
255
|
+
asset_label: str | None = None,
|
251
256
|
project_context: ProjectContext | None = None,
|
252
257
|
) -> Asset:
|
253
258
|
"""Upload asset to an existing entity's endpoint from a file-like object."""
|
@@ -261,6 +266,7 @@ class Client:
|
|
261
266
|
file_name=file_name,
|
262
267
|
content_type=file_content_type,
|
263
268
|
metadata=file_metadata or {},
|
269
|
+
label=asset_label,
|
264
270
|
)
|
265
271
|
context = self._required_user_context(override_context=project_context)
|
266
272
|
return core.upload_asset_content(
|
@@ -353,28 +359,30 @@ class Client:
|
|
353
359
|
|
354
360
|
context = self._optional_user_context(override_context=project_context)
|
355
361
|
|
356
|
-
asset = None
|
362
|
+
asset = cast(Asset, asset_id) if isinstance(asset_id, Asset) else None
|
363
|
+
|
357
364
|
if not ignore_directory_name:
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
365
|
+
if asset is None:
|
366
|
+
asset_endpoint = route.get_assets_endpoint(
|
367
|
+
api_url=self.api_url,
|
368
|
+
entity_type=entity_type,
|
369
|
+
entity_id=cast(ID, entity_id),
|
370
|
+
asset_id=asset_id,
|
371
|
+
)
|
372
|
+
asset = core.get_entity(
|
373
|
+
asset_endpoint,
|
374
|
+
entity_type=Asset,
|
375
|
+
project_context=context,
|
376
|
+
http_client=self._http_client,
|
377
|
+
token=self._token_manager.get_token(),
|
378
|
+
)
|
371
379
|
|
372
380
|
output_path /= asset.path
|
373
381
|
|
374
382
|
contents = self.list_directory(
|
375
383
|
entity_id=entity_id,
|
376
384
|
entity_type=entity_type,
|
377
|
-
asset_id=asset_id,
|
385
|
+
asset_id=asset_id if isinstance(asset_id, ID) else asset.id,
|
378
386
|
project_context=project_context,
|
379
387
|
)
|
380
388
|
|
@@ -453,6 +461,7 @@ class Client:
|
|
453
461
|
Output file path.
|
454
462
|
"""
|
455
463
|
context = self._optional_user_context(override_context=project_context)
|
464
|
+
|
456
465
|
asset_endpoint = route.get_assets_endpoint(
|
457
466
|
api_url=self.api_url,
|
458
467
|
entity_type=entity_type,
|
@@ -494,6 +503,11 @@ class Client:
|
|
494
503
|
token=self._token_manager.get_token(),
|
495
504
|
)
|
496
505
|
|
506
|
+
@staticmethod
|
507
|
+
def select_assets(entity: Entity, selection: dict) -> IteratorResult:
|
508
|
+
"""Select assets from entity based on selection."""
|
509
|
+
return IteratorResult(filter_assets(entity.assets, selection))
|
510
|
+
|
497
511
|
def download_assets(
|
498
512
|
self,
|
499
513
|
entity_or_id: Entity | tuple[ID, type[Entity]],
|
@@ -516,9 +530,9 @@ class Client:
|
|
516
530
|
project_context=context,
|
517
531
|
)
|
518
532
|
|
519
|
-
return
|
533
|
+
return DownloadedAssetFile(
|
520
534
|
asset=asset,
|
521
|
-
|
535
|
+
path=path,
|
522
536
|
)
|
523
537
|
|
524
538
|
context = self._optional_user_context(override_context=project_context)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""Core SDK operations."""
|
2
2
|
|
3
3
|
import io
|
4
|
+
import logging
|
4
5
|
import os
|
5
6
|
from collections.abc import Iterator
|
6
7
|
from pathlib import Path
|
@@ -10,11 +11,13 @@ import httpx
|
|
10
11
|
|
11
12
|
from entitysdk import serdes
|
12
13
|
from entitysdk.common import ProjectContext
|
14
|
+
from entitysdk.exception import EntitySDKError
|
13
15
|
from entitysdk.models.asset import Asset, DetailedFileList, LocalAssetMetadata
|
14
16
|
from entitysdk.models.core import Identifiable
|
15
17
|
from entitysdk.result import IteratorResult
|
16
18
|
from entitysdk.util import make_db_api_request, stream_paginated_request
|
17
19
|
|
20
|
+
L = logging.getLogger(__name__)
|
18
21
|
TIdentifiable = TypeVar("TIdentifiable", bound=Identifiable)
|
19
22
|
|
20
23
|
|
@@ -170,6 +173,7 @@ def upload_asset_content(
|
|
170
173
|
url=url,
|
171
174
|
method="POST",
|
172
175
|
files=files,
|
176
|
+
data={"label": asset_metadata.label} if asset_metadata.label else None,
|
173
177
|
project_context=project_context,
|
174
178
|
token=token,
|
175
179
|
http_client=http_client,
|
@@ -192,7 +196,7 @@ def upload_asset_directory(
|
|
192
196
|
for concrete_path in paths.values():
|
193
197
|
if not concrete_path.exists():
|
194
198
|
msg = f"Path {concrete_path} does not exist"
|
195
|
-
raise
|
199
|
+
raise EntitySDKError(msg)
|
196
200
|
|
197
201
|
response = make_db_api_request(
|
198
202
|
url=url,
|
@@ -214,11 +218,20 @@ def upload_asset_directory(
|
|
214
218
|
failed = {}
|
215
219
|
for path, url in to_upload.items():
|
216
220
|
with open(paths[Path(path)], "rb") as fd:
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
221
|
+
try:
|
222
|
+
response = http_client.request(
|
223
|
+
method="PUT",
|
224
|
+
url=url,
|
225
|
+
content=fd,
|
226
|
+
follow_redirects=True,
|
227
|
+
timeout=20,
|
228
|
+
)
|
229
|
+
except httpx.HTTPError:
|
230
|
+
L.exception("Upload failed, will retry again")
|
231
|
+
failed[path] = url
|
232
|
+
else:
|
233
|
+
if response.status_code != 200:
|
234
|
+
failed[path] = url
|
222
235
|
return failed
|
223
236
|
|
224
237
|
to_upload = js["files"]
|
@@ -228,7 +241,7 @@ def upload_asset_directory(
|
|
228
241
|
break
|
229
242
|
|
230
243
|
if to_upload:
|
231
|
-
raise
|
244
|
+
raise EntitySDKError(f"Uploading these files failed: {to_upload}")
|
232
245
|
|
233
246
|
return serdes.deserialize_model(js["asset"], Asset)
|
234
247
|
|
@@ -0,0 +1 @@
|
|
1
|
+
"""Dependencies."""
|
@@ -0,0 +1,18 @@
|
|
1
|
+
"""Entity dependencies."""
|
2
|
+
|
3
|
+
from entitysdk.exception import DependencyError
|
4
|
+
from entitysdk.models.entity import Entity
|
5
|
+
|
6
|
+
|
7
|
+
def ensure_has_id(model: Entity) -> Entity:
|
8
|
+
"""Ensure entity has id."""
|
9
|
+
if model.id is None:
|
10
|
+
raise DependencyError(f"Model has no id: {repr(model)}")
|
11
|
+
return model
|
12
|
+
|
13
|
+
|
14
|
+
def ensure_has_assets(model: Entity) -> Entity:
|
15
|
+
"""Ensure entity has assets."""
|
16
|
+
if not model.assets:
|
17
|
+
raise DependencyError(f"Model has no assets: {repr(model)}")
|
18
|
+
return model
|
@@ -0,0 +1,78 @@
|
|
1
|
+
"""Downloading functions for Simulation."""
|
2
|
+
|
3
|
+
import json
|
4
|
+
import logging
|
5
|
+
from pathlib import Path
|
6
|
+
from typing import cast
|
7
|
+
|
8
|
+
from entitysdk.client import Client
|
9
|
+
from entitysdk.dependencies.entity import ensure_has_assets, ensure_has_id
|
10
|
+
from entitysdk.models import Simulation
|
11
|
+
from entitysdk.types import ID
|
12
|
+
|
13
|
+
L = logging.getLogger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
def download_simulation_config_content(client: Client, *, model: Simulation) -> dict:
|
17
|
+
"""Download the the simulation config json into a dictionary."""
|
18
|
+
ensure_has_id(model)
|
19
|
+
ensure_has_assets(model)
|
20
|
+
|
21
|
+
asset = client.select_assets(
|
22
|
+
model,
|
23
|
+
selection={"label": "sonata_simulation_config"},
|
24
|
+
).one()
|
25
|
+
|
26
|
+
json_content: bytes = client.download_content(
|
27
|
+
entity_id=cast(ID, model.id),
|
28
|
+
entity_type=Simulation,
|
29
|
+
asset_id=asset.id,
|
30
|
+
)
|
31
|
+
|
32
|
+
return json.loads(json_content)
|
33
|
+
|
34
|
+
|
35
|
+
def download_node_sets_file(client: Client, *, model: Simulation, output_path: Path) -> Path:
|
36
|
+
"""Download the node sets file from simulation's assets."""
|
37
|
+
ensure_has_id(model)
|
38
|
+
ensure_has_assets(model)
|
39
|
+
|
40
|
+
asset = client.select_assets(
|
41
|
+
model,
|
42
|
+
selection={"label": "custom_node_sets"},
|
43
|
+
).one()
|
44
|
+
|
45
|
+
path = client.download_file(
|
46
|
+
entity_id=cast(ID, model.id),
|
47
|
+
entity_type=Simulation,
|
48
|
+
asset_id=asset,
|
49
|
+
output_path=output_path,
|
50
|
+
)
|
51
|
+
|
52
|
+
L.info("Node sets file downloaded at %s", path)
|
53
|
+
|
54
|
+
return path
|
55
|
+
|
56
|
+
|
57
|
+
def download_spike_replay_files(
|
58
|
+
client: Client, *, model: Simulation, output_dir: Path
|
59
|
+
) -> list[Path]:
|
60
|
+
"""Download the spike replay files from simualtion's assets."""
|
61
|
+
ensure_has_id(model)
|
62
|
+
ensure_has_assets(model)
|
63
|
+
|
64
|
+
assets = client.select_assets(model, selection={"label": "replay_spikes"}).all()
|
65
|
+
|
66
|
+
spike_files: list[Path] = [
|
67
|
+
client.download_file(
|
68
|
+
entity_id=cast(ID, model.id),
|
69
|
+
entity_type=Simulation,
|
70
|
+
asset_id=asset,
|
71
|
+
output_path=output_dir / asset.path,
|
72
|
+
)
|
73
|
+
for asset in assets
|
74
|
+
]
|
75
|
+
|
76
|
+
L.info("Downloaded %d spike replay files: %s", len(spike_files), spike_files)
|
77
|
+
|
78
|
+
return spike_files
|
@@ -0,0 +1,61 @@
|
|
1
|
+
"""Downloading functions for SimulationResult."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import cast
|
6
|
+
|
7
|
+
from entitysdk.client import Client
|
8
|
+
from entitysdk.dependencies.entity import ensure_has_assets, ensure_has_id
|
9
|
+
from entitysdk.models import SimulationResult
|
10
|
+
from entitysdk.types import ID
|
11
|
+
|
12
|
+
L = logging.getLogger(__name__)
|
13
|
+
|
14
|
+
|
15
|
+
def download_spike_report_file(
|
16
|
+
client: Client, *, model: SimulationResult, output_path: Path
|
17
|
+
) -> Path:
|
18
|
+
"""Download spike report file from SimulationResult entity."""
|
19
|
+
ensure_has_id(model)
|
20
|
+
ensure_has_assets(model)
|
21
|
+
|
22
|
+
asset = client.select_assets(
|
23
|
+
model,
|
24
|
+
selection={"label": "spike_report"},
|
25
|
+
).one()
|
26
|
+
|
27
|
+
path = client.download_file(
|
28
|
+
entity_id=cast(ID, model.id),
|
29
|
+
entity_type=SimulationResult,
|
30
|
+
asset_id=asset,
|
31
|
+
output_path=output_path / asset.path if output_path.is_dir() else output_path,
|
32
|
+
)
|
33
|
+
L.info("Spike report file downloaded at %s", path)
|
34
|
+
return path
|
35
|
+
|
36
|
+
|
37
|
+
def download_voltage_report_files(
|
38
|
+
client: Client, *, model: SimulationResult, output_dir: Path
|
39
|
+
) -> list[Path]:
|
40
|
+
"""Download voltage report files from SimulationResult entity."""
|
41
|
+
ensure_has_id(model)
|
42
|
+
ensure_has_assets(model)
|
43
|
+
|
44
|
+
assets = client.select_assets(
|
45
|
+
model,
|
46
|
+
selection={"label": "voltage_report"},
|
47
|
+
).all()
|
48
|
+
|
49
|
+
files: list[Path] = [
|
50
|
+
client.download_file(
|
51
|
+
entity_id=cast(ID, model.id),
|
52
|
+
entity_type=SimulationResult,
|
53
|
+
asset_id=asset,
|
54
|
+
output_path=output_dir / asset.path,
|
55
|
+
)
|
56
|
+
for asset in assets
|
57
|
+
]
|
58
|
+
|
59
|
+
L.info("Downloaded voltage report files: %s", files)
|
60
|
+
|
61
|
+
return files
|
@@ -11,3 +11,11 @@ class RouteNotFoundError(EntitySDKError):
|
|
11
11
|
|
12
12
|
class IteratorResultError(EntitySDKError):
|
13
13
|
"""Raised when the result of an iterator is not as expected."""
|
14
|
+
|
15
|
+
|
16
|
+
class DependencyError(EntitySDKError):
|
17
|
+
"""Raised when a dependency check fails."""
|
18
|
+
|
19
|
+
|
20
|
+
class StagingError(EntitySDKError):
|
21
|
+
"""Raised when a staging operation has failed."""
|
@@ -8,11 +8,14 @@ from pydantic import ConfigDict, Field
|
|
8
8
|
|
9
9
|
from entitysdk.models.base import BaseModel
|
10
10
|
from entitysdk.models.core import Identifiable
|
11
|
+
from entitysdk.types import ID
|
11
12
|
|
12
13
|
|
13
14
|
class Asset(Identifiable):
|
14
15
|
"""Asset."""
|
15
16
|
|
17
|
+
id: ID
|
18
|
+
|
16
19
|
path: Annotated[
|
17
20
|
str,
|
18
21
|
Field(
|
@@ -93,6 +96,7 @@ class LocalAssetMetadata(BaseModel):
|
|
93
96
|
description="The metadata of the asset.",
|
94
97
|
),
|
95
98
|
] = None
|
99
|
+
label: Annotated[str | None, Field(description="Optional asset label.")] = None
|
96
100
|
|
97
101
|
|
98
102
|
class DetailedFile(BaseModel):
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"""Asset related schemas."""
|
2
|
+
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
from entitysdk.models.asset import Asset
|
6
|
+
from entitysdk.schemas.base import Schema
|
7
|
+
|
8
|
+
|
9
|
+
class DownloadedAssetFile(Schema):
|
10
|
+
"""Downloaded asset file."""
|
11
|
+
|
12
|
+
asset: Asset
|
13
|
+
path: Path
|
14
|
+
|
15
|
+
|
16
|
+
class DownloadedAssetContent(Schema):
|
17
|
+
"""Downloaded asset content."""
|
18
|
+
|
19
|
+
asset: Asset
|
20
|
+
content: bytes
|
@@ -0,0 +1,7 @@
|
|
1
|
+
"""Staging functions."""
|
2
|
+
|
3
|
+
from entitysdk.staging.circuit import stage_circuit
|
4
|
+
from entitysdk.staging.simulation import stage_simulation
|
5
|
+
from entitysdk.staging.simulation_result import stage_simulation_result
|
6
|
+
|
7
|
+
__all__ = ["stage_circuit", "stage_simulation", "stage_simulation_result"]
|
@@ -0,0 +1,43 @@
|
|
1
|
+
"""Staging functions for Circuit."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import cast
|
6
|
+
|
7
|
+
from entitysdk.client import Client
|
8
|
+
from entitysdk.dependencies.entity import ensure_has_assets, ensure_has_id
|
9
|
+
from entitysdk.models import Circuit
|
10
|
+
from entitysdk.types import ID
|
11
|
+
|
12
|
+
L = logging.getLogger(__name__)
|
13
|
+
|
14
|
+
|
15
|
+
def stage_circuit(client: Client, *, model: Circuit, output_dir: Path) -> Path:
|
16
|
+
"""Stage a Circuit directory into output_dir."""
|
17
|
+
ensure_has_id(model)
|
18
|
+
ensure_has_assets(model)
|
19
|
+
|
20
|
+
asset = client.select_assets(
|
21
|
+
model,
|
22
|
+
selection={
|
23
|
+
"content_type": "application/vnd.directory",
|
24
|
+
"is_directory": True,
|
25
|
+
},
|
26
|
+
).one()
|
27
|
+
|
28
|
+
paths = client.download_directory(
|
29
|
+
entity_id=cast(ID, model.id),
|
30
|
+
entity_type=Circuit,
|
31
|
+
asset_id=asset,
|
32
|
+
output_path=output_dir,
|
33
|
+
ignore_directory_name=True,
|
34
|
+
)
|
35
|
+
|
36
|
+
L.debug("Downloaded circuit %s paths: %s", model.id, paths)
|
37
|
+
|
38
|
+
circuit_config_path = output_dir / "circuit_config.json"
|
39
|
+
assert circuit_config_path in paths
|
40
|
+
|
41
|
+
L.info("Circuit %s staged at %s", model.id, circuit_config_path)
|
42
|
+
|
43
|
+
return circuit_config_path
|