datamint 2.17.2__tar.gz → 2.17.4__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.
- {datamint-2.17.2 → datamint-2.17.4}/PKG-INFO +15 -2
- {datamint-2.17.2 → datamint-2.17.4}/README.md +9 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/__init__.py +4 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/base_api.py +33 -19
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/client.py +4 -4
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/annotations_api.py +11 -11
- datamint-2.17.4/datamint/api/endpoints/annotationsets_api.py +588 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/deploy_model_api.py +2 -2
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/inference_api.py +2 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/projects_api.py +1 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/resources_api.py +10 -9
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/entity_base_api.py +2 -2
- datamint-2.17.4/datamint/client_cmd_tools/datamint_init.py +1522 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/__init__.py +8 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/base.py +264 -35
- datamint-2.17.4/datamint/dataset/factory.py +99 -0
- datamint-2.17.4/datamint/dataset/image_dataset.py +145 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/multiframe_dataset.py +11 -9
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/sliced_dataset.py +14 -14
- datamint-2.17.4/datamint/dataset/split_result.py +57 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotation_worklist.py +2 -2
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resource.py +6 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/sliced_resource.py +10 -28
- datamint-2.17.4/datamint/entities/sliced_resource_base.py +54 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/sliced_video_resource.py +12 -24
- datamint-2.17.4/datamint/exceptions.py +107 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/__init__.py +12 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/datamodule.py +7 -5
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/__init__.py +10 -2
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/base_trainer.py +26 -13
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/classification_trainer.py +24 -4
- datamint-2.17.4/datamint/lightning/trainers/detection_trainer.py +74 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/__init__.py +3 -2
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/classification_module.py +5 -5
- datamint-2.17.4/datamint/lightning/trainers/lightning_modules/detection_modules/__init__.py +3 -0
- datamint-2.17.4/datamint/lightning/trainers/lightning_modules/detection_modules/yolox_module.py +251 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_module.py +2 -2
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/__init__.py +3 -1
- datamint-2.17.4/datamint/lightning/trainers/lightning_modules/segmentation_modules/transunet.py +219 -0
- datamint-2.17.4/datamint/lightning/trainers/lightning_modules/segmentation_modules/unetrpp.py +630 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/segmentation_trainer.py +8 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/__init__.py +18 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/specialized/deeplabv3plus.py +3 -3
- datamint-2.17.4/datamint/lightning/trainers/specialized/efficientnetv2.py +53 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/__init__.py +0 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/_nnunet_trainer_bridge.py +153 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/data_export.py +307 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/data_import.py +139 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/inference_model.py +169 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/trainer.py +551 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/transunet.py +183 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/specialized/unetpp.py +3 -3
- datamint-2.17.4/datamint/lightning/trainers/specialized/unetrpp.py +137 -0
- datamint-2.17.4/datamint/lightning/trainers/specialized/yolox.py +173 -0
- datamint-2.17.4/datamint/lightning/trainers/vol_seg_trainer.py +168 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/__init__.py +5 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/datamint_flavor.py +154 -18
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/model.py +11 -0
- datamint-2.17.4/datamint/mlflow/flavors/validation.py +228 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/lightning/callbacks/modelcheckpoint.py +23 -12
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/tracking/datamint_store.py +9 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/tracking/fluent.py +3 -3
- {datamint-2.17.2 → datamint-2.17.4}/pyproject.toml +7 -1
- datamint-2.17.2/datamint/api/endpoints/annotationsets_api.py +0 -144
- datamint-2.17.2/datamint/dataset/image_dataset.py +0 -106
- datamint-2.17.2/datamint/exceptions.py +0 -63
- datamint-2.17.2/datamint/lightning/trainers/specialized/__init__.py +0 -1
- {datamint-2.17.2 → datamint-2.17.4}/datamint/__main__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/dto/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/dto/annotation_dto.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/channels_api.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/datasetsinfo_api.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/models_api.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/users_api.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/client_cmd_tools/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/client_cmd_tools/datamint_config.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/client_cmd_tools/datamint_upload.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/configs.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/annotation.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/annotation_processor.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/base_dataset.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/dataset.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/sliced_video_dataset.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/video_dataset.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/volume_dataset.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/annotation.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/annotation_spec.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/base_geometry.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/base_segmentation.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/box_annotation.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/geometry.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/image_classification.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/image_segmentation.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/line_annotation.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/types.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/volume_segmentation.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/base_entity.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/cache_manager.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/channel.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/datasetinfo.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/deployjob.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/inferencejob.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/project.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/project_resource_split.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/dicom_resource.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/image_resource.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/nifti_resource.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/video_resource.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/volume_resource.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/user.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/examples/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/examples/example_projects.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/base.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/deeplabv3plus.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/smp_module.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/unetpp.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/seg2d_trainer.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/seg3d_trainer.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/logging.yaml +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/artifact/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/artifact/datamint_artifacts_repo.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/data/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/data/datamint_dataset.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/env_utils.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/env_vars.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/model_loader.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/prediction_modes.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/prediction_router.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/task_type.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/lightning/callbacks/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/models/__init__.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/tracking/default_experiment.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/types.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/collection_utils.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/env.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/logging_utils.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/nifti_utils.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/torchmetrics.py +0 -0
- {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/visualization.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datamint
|
|
3
|
-
Version: 2.17.
|
|
3
|
+
Version: 2.17.4
|
|
4
4
|
Summary: A library for interacting with the Datamint API, designed for efficient data management, processing and Deep Learning workflows.
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -9,8 +9,10 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.12
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.13
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Provides-Extra: detection
|
|
12
13
|
Provides-Extra: dev
|
|
13
14
|
Provides-Extra: docs
|
|
15
|
+
Provides-Extra: nnunet
|
|
14
16
|
Requires-Dist: Deprecated (>=1.2.0)
|
|
15
17
|
Requires-Dist: Flask (<4)
|
|
16
18
|
Requires-Dist: Flask-Cors (<7)
|
|
@@ -20,6 +22,7 @@ Requires-Dist: albumentations (>=2.0.0)
|
|
|
20
22
|
Requires-Dist: backports-strenum ; python_version < "3.11"
|
|
21
23
|
Requires-Dist: cachetools (>=6.0.0)
|
|
22
24
|
Requires-Dist: certifi (>=2025.0.0)
|
|
25
|
+
Requires-Dist: filelock (>=3.0) ; extra == "nnunet"
|
|
23
26
|
Requires-Dist: httpx
|
|
24
27
|
Requires-Dist: humanize (>=4.0.0,<5.0.0)
|
|
25
28
|
Requires-Dist: lazy-loader (>=0.3.0)
|
|
@@ -29,6 +32,7 @@ Requires-Dist: medimgkit (>=0.17.0)
|
|
|
29
32
|
Requires-Dist: mlflow-skinny (==3.8.1)
|
|
30
33
|
Requires-Dist: nest-asyncio (>=1.0.0,<2.0.0)
|
|
31
34
|
Requires-Dist: nibabel (>=4.0.0)
|
|
35
|
+
Requires-Dist: nnunetv2 (>=2.4,<3.0) ; extra == "nnunet"
|
|
32
36
|
Requires-Dist: numpy
|
|
33
37
|
Requires-Dist: opencv-python (>=4.0.0)
|
|
34
38
|
Requires-Dist: pandas (>=2.0.0)
|
|
@@ -53,6 +57,7 @@ Requires-Dist: torch (>=1.2.0,!=2.3.0)
|
|
|
53
57
|
Requires-Dist: torchvision (>=0.18.0)
|
|
54
58
|
Requires-Dist: tqdm (>=4.0.0,<5.0.0)
|
|
55
59
|
Requires-Dist: typing_extensions (>=4.0.0)
|
|
60
|
+
Requires-Dist: yolox-datamint (>=0.3.1) ; extra == "detection"
|
|
56
61
|
Description-Content-Type: text/markdown
|
|
57
62
|
|
|
58
63
|
# Datamint Python API
|
|
@@ -176,6 +181,14 @@ datamint-upload /path/to/dicoms \
|
|
|
176
181
|
```
|
|
177
182
|
Use `--ai-model` when uploaded segmentation files should be linked to an existing deployed model by name. `--segmentation_names` accepts YAML mappings and ITK-SNAP label export CSV/TXT files.
|
|
178
183
|
|
|
184
|
+
### Scaffold a New Project
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
datamint-init
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Generates a numbered set of scripts (`01_upload_data.py` through `06_deploy.py`) for your task (detection, segmentation, or classification). Run it once in a new directory and follow the scripts in order.
|
|
191
|
+
|
|
179
192
|
### Configuration Management
|
|
180
193
|
|
|
181
194
|
```bash
|
|
@@ -230,7 +243,7 @@ api = Api(verify_ssl=False)
|
|
|
230
243
|
|
|
231
244
|
## 🆘 Support
|
|
232
245
|
|
|
233
|
-
[Full Documentation](https://datamint-python-api
|
|
246
|
+
[Full Documentation](https://sonanceai.github.io/datamint-python-api)
|
|
234
247
|
[GitHub Issues](https://github.com/SonanceAI/datamint-python-api/issues)
|
|
235
248
|
|
|
236
249
|
|
|
@@ -119,6 +119,14 @@ datamint-upload /path/to/dicoms \
|
|
|
119
119
|
```
|
|
120
120
|
Use `--ai-model` when uploaded segmentation files should be linked to an existing deployed model by name. `--segmentation_names` accepts YAML mappings and ITK-SNAP label export CSV/TXT files.
|
|
121
121
|
|
|
122
|
+
### Scaffold a New Project
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
datamint-init
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Generates a numbered set of scripts (`01_upload_data.py` through `06_deploy.py`) for your task (detection, segmentation, or classification). Run it once in a new directory and follow the scripts in order.
|
|
129
|
+
|
|
122
130
|
### Configuration Management
|
|
123
131
|
|
|
124
132
|
```bash
|
|
@@ -173,6 +181,6 @@ api = Api(verify_ssl=False)
|
|
|
173
181
|
|
|
174
182
|
## 🆘 Support
|
|
175
183
|
|
|
176
|
-
[Full Documentation](https://datamint-python-api
|
|
184
|
+
[Full Documentation](https://sonanceai.github.io/datamint-python-api)
|
|
177
185
|
[GitHub Issues](https://github.com/SonanceAI/datamint-python-api/issues)
|
|
178
186
|
|
|
@@ -9,7 +9,8 @@ if TYPE_CHECKING:
|
|
|
9
9
|
# New modular datasets
|
|
10
10
|
from .dataset.image_dataset import ImageDataset
|
|
11
11
|
from .dataset.volume_dataset import VolumeDataset
|
|
12
|
-
|
|
12
|
+
from .mlflow.flavors.validation import validate_model, ValidationReport, ValidationIssue, ModelValidationError
|
|
13
|
+
|
|
13
14
|
else:
|
|
14
15
|
import lazy_loader as lazy
|
|
15
16
|
|
|
@@ -21,6 +22,8 @@ else:
|
|
|
21
22
|
# New modular dataset classes
|
|
22
23
|
"dataset.image_dataset": ["ImageDataset"],
|
|
23
24
|
"dataset.volume_dataset": ["VolumeDataset"],
|
|
25
|
+
"mlflow.flavors.validation": ["validate_model", "ValidationReport",
|
|
26
|
+
"ValidationIssue", "ModelValidationError"],
|
|
24
27
|
},
|
|
25
28
|
)
|
|
26
29
|
|
|
@@ -3,7 +3,14 @@ from typing import TYPE_CHECKING
|
|
|
3
3
|
from collections.abc import Generator, AsyncGenerator
|
|
4
4
|
import httpx
|
|
5
5
|
from dataclasses import dataclass
|
|
6
|
-
from datamint.exceptions import
|
|
6
|
+
from datamint.exceptions import (
|
|
7
|
+
ItemNotFoundError,
|
|
8
|
+
AuthenticationError,
|
|
9
|
+
PermissionDeniedError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
NetworkError,
|
|
12
|
+
ServerError,
|
|
13
|
+
)
|
|
7
14
|
import aiohttp
|
|
8
15
|
import json
|
|
9
16
|
from PIL import Image
|
|
@@ -126,7 +133,7 @@ class BaseApi:
|
|
|
126
133
|
original_error: The original SSL-related exception
|
|
127
134
|
|
|
128
135
|
Raises:
|
|
129
|
-
|
|
136
|
+
NetworkError: With helpful troubleshooting information
|
|
130
137
|
"""
|
|
131
138
|
error_msg = (
|
|
132
139
|
f"SSL Certificate verification failed: {original_error}\n\n"
|
|
@@ -141,7 +148,7 @@ class BaseApi:
|
|
|
141
148
|
" api = Api(verify_ssl=False)\n\n"
|
|
142
149
|
"For more help, see: https://github.com/SonanceAI/datamint-python-api#-ssl-certificate-troubleshooting"
|
|
143
150
|
)
|
|
144
|
-
raise
|
|
151
|
+
raise NetworkError(error_msg) from original_error
|
|
145
152
|
|
|
146
153
|
def _create_aiohttp_connector(self, force_close: bool = False) -> aiohttp.TCPConnector:
|
|
147
154
|
"""Create aiohttp connector with SSL configuration.
|
|
@@ -417,7 +424,7 @@ class BaseApi:
|
|
|
417
424
|
except httpx.ConnectError as e:
|
|
418
425
|
if "CERTIFICATE_VERIFY_FAILED" in str(e) or "certificate verify failed" in str(e).lower():
|
|
419
426
|
self._raise_ssl_error(e)
|
|
420
|
-
raise
|
|
427
|
+
raise NetworkError(str(e)) from e
|
|
421
428
|
except httpx.HTTPError as e:
|
|
422
429
|
try:
|
|
423
430
|
response_json = response.json()
|
|
@@ -426,18 +433,21 @@ class BaseApi:
|
|
|
426
433
|
error_msg = f"{getattr(e, 'message', str(e))} | {getattr(response, 'text', '')}"
|
|
427
434
|
if response_json:
|
|
428
435
|
error_msg = f"{error_msg} | {response_json}"
|
|
429
|
-
try:
|
|
430
|
-
e.message = error_msg
|
|
431
|
-
except Exception:
|
|
432
|
-
logger.debug("Unable to set message attribute on exception")
|
|
433
|
-
pass
|
|
434
436
|
|
|
435
437
|
status_code = response.status_code
|
|
436
|
-
if status_code
|
|
438
|
+
if status_code == 401:
|
|
439
|
+
raise AuthenticationError(error_msg) from e
|
|
440
|
+
if status_code == 403:
|
|
441
|
+
raise PermissionDeniedError(error_msg) from e
|
|
442
|
+
if status_code in (400, 422):
|
|
443
|
+
raise ValidationError(error_msg) from e
|
|
444
|
+
if status_code == 404:
|
|
437
445
|
new_error_msg = error_msg.replace('404 Not Found', '')
|
|
438
446
|
if ' not found' in new_error_msg.lower() or 'Not Found' in new_error_msg:
|
|
439
|
-
# Will be caught by the caller and properly initialized:
|
|
440
447
|
raise ItemNotFoundError('unknown', {})
|
|
448
|
+
raise ValidationError(error_msg) from e
|
|
449
|
+
if status_code >= 500:
|
|
450
|
+
raise ServerError(error_msg, status_code=status_code) from e
|
|
441
451
|
raise
|
|
442
452
|
return response_json
|
|
443
453
|
|
|
@@ -447,9 +457,10 @@ class BaseApi:
|
|
|
447
457
|
response_json = None
|
|
448
458
|
try:
|
|
449
459
|
response.raise_for_status()
|
|
460
|
+
except aiohttp.ClientConnectionError as e:
|
|
461
|
+
raise NetworkError(str(e)) from e
|
|
450
462
|
except aiohttp.ClientError as e:
|
|
451
463
|
error_msg = str(getattr(e, 'message', e))
|
|
452
|
-
# log the raw response for debugging
|
|
453
464
|
status_code = BaseApi.get_status_code(e)
|
|
454
465
|
# Only read the body on error to get detailed message; do NOT read on success
|
|
455
466
|
# as that would exhaust the stream before callers can iterate over it.
|
|
@@ -461,15 +472,18 @@ class BaseApi:
|
|
|
461
472
|
error_msg = f"{error_msg} | {response_json}"
|
|
462
473
|
|
|
463
474
|
logger.error(f"HTTP error {status_code} for {url}: {error_msg}")
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
475
|
+
if status_code == 401:
|
|
476
|
+
raise AuthenticationError(error_msg) from e
|
|
477
|
+
if status_code == 403:
|
|
478
|
+
raise PermissionDeniedError(error_msg) from e
|
|
479
|
+
if status_code in (400, 422):
|
|
480
|
+
raise ValidationError(error_msg) from e
|
|
481
|
+
if status_code == 404:
|
|
470
482
|
if ' not found' in error_msg.lower() or 'Not Found' in error_msg:
|
|
471
|
-
# Will be caught by the caller and properly initialized:
|
|
472
483
|
raise ItemNotFoundError('unknown', {})
|
|
484
|
+
raise ValidationError(error_msg) from e
|
|
485
|
+
if status_code >= 500:
|
|
486
|
+
raise ServerError(error_msg, status_code=status_code) from e
|
|
473
487
|
raise
|
|
474
488
|
return response_json
|
|
475
489
|
|
|
@@ -6,7 +6,7 @@ from .endpoints import (ProjectsApi, ResourcesApi, AnnotationsApi,
|
|
|
6
6
|
)
|
|
7
7
|
from .endpoints.models_api import ModelsApi
|
|
8
8
|
import datamint.configs
|
|
9
|
-
from datamint.exceptions import
|
|
9
|
+
from datamint.exceptions import AuthenticationError, NetworkError
|
|
10
10
|
import logging
|
|
11
11
|
|
|
12
12
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -58,7 +58,7 @@ class Api:
|
|
|
58
58
|
if api_key is None:
|
|
59
59
|
msg = f"API key not provided! Use the environment variable " + \
|
|
60
60
|
f"{Api.DATAMINT_API_VENV_NAME} or pass it as an argument."
|
|
61
|
-
raise
|
|
61
|
+
raise AuthenticationError(msg)
|
|
62
62
|
self.config = ApiConfig(
|
|
63
63
|
server_url=server_url,
|
|
64
64
|
api_key=api_key,
|
|
@@ -94,8 +94,8 @@ class Api:
|
|
|
94
94
|
try:
|
|
95
95
|
self.projects.get_list(limit=1)
|
|
96
96
|
except Exception as e:
|
|
97
|
-
raise
|
|
98
|
-
|
|
97
|
+
raise NetworkError("Error connecting to the Datamint API."
|
|
98
|
+
" Please check your api_key and/or other configurations.") from e
|
|
99
99
|
|
|
100
100
|
def close(self) -> None:
|
|
101
101
|
"""Close underlying HTTP clients and any shared aiohttp sessions.
|
|
@@ -31,7 +31,7 @@ from datamint.entities.annotations import (
|
|
|
31
31
|
LineAnnotation,
|
|
32
32
|
annotation_from_dict,
|
|
33
33
|
)
|
|
34
|
-
from datamint.exceptions import
|
|
34
|
+
from datamint.exceptions import ItemNotFoundError, ServerError
|
|
35
35
|
from datamint.utils.nifti_utils import metadata_to_nifti_obj
|
|
36
36
|
|
|
37
37
|
from ..entity_base_api import ApiConfig, CreatableEntityApi, DeletableEntityApi
|
|
@@ -453,7 +453,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
453
453
|
the basename of the path will be used.
|
|
454
454
|
|
|
455
455
|
Raises:
|
|
456
|
-
|
|
456
|
+
ServerError: If the upload fails.
|
|
457
457
|
|
|
458
458
|
"""
|
|
459
459
|
f, filename, close_file, content_type = self._prepare_upload_file(file,
|
|
@@ -470,7 +470,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
470
470
|
session=session,
|
|
471
471
|
data=form)
|
|
472
472
|
if isinstance(respdata, dict) and 'error' in respdata:
|
|
473
|
-
raise
|
|
473
|
+
raise ServerError(respdata['error'])
|
|
474
474
|
finally:
|
|
475
475
|
if close_file:
|
|
476
476
|
f.close()
|
|
@@ -494,7 +494,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
494
494
|
the basename of the path will be used.
|
|
495
495
|
|
|
496
496
|
Raises:
|
|
497
|
-
|
|
497
|
+
ServerError: If the upload fails.
|
|
498
498
|
"""
|
|
499
499
|
f, filename, close_file, content_type = self._prepare_upload_file(file,
|
|
500
500
|
filename,
|
|
@@ -509,7 +509,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
509
509
|
files=files)
|
|
510
510
|
respdata = resp.json()
|
|
511
511
|
if isinstance(respdata, dict) and 'error' in respdata:
|
|
512
|
-
raise
|
|
512
|
+
raise ServerError(respdata['error'])
|
|
513
513
|
finally:
|
|
514
514
|
if close_file:
|
|
515
515
|
f.close()
|
|
@@ -550,7 +550,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
550
550
|
json=annotations_payload).json()
|
|
551
551
|
for r in respdata:
|
|
552
552
|
if isinstance(r, dict) and 'error' in r:
|
|
553
|
-
raise
|
|
553
|
+
raise ServerError(r['error'])
|
|
554
554
|
if is_single_annotation:
|
|
555
555
|
return respdata[0]
|
|
556
556
|
return respdata
|
|
@@ -788,7 +788,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
788
788
|
json=annotations)
|
|
789
789
|
for r in respdata:
|
|
790
790
|
if isinstance(r, dict) and 'error' in r:
|
|
791
|
-
raise
|
|
791
|
+
raise ServerError(r['error'])
|
|
792
792
|
return respdata
|
|
793
793
|
|
|
794
794
|
@staticmethod
|
|
@@ -917,7 +917,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
917
917
|
raise
|
|
918
918
|
|
|
919
919
|
if 'error' in respdata:
|
|
920
|
-
raise
|
|
920
|
+
raise ServerError(respdata['error'])
|
|
921
921
|
return respdata
|
|
922
922
|
else:
|
|
923
923
|
raise ValueError(f"Volume upload not supported for file format: {file_path}")
|
|
@@ -951,7 +951,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
951
951
|
raise
|
|
952
952
|
|
|
953
953
|
if 'error' in respdata:
|
|
954
|
-
raise
|
|
954
|
+
raise ServerError(respdata['error'])
|
|
955
955
|
return respdata
|
|
956
956
|
else:
|
|
957
957
|
raise ValueError(f"Unsupported file_path type for volume upload: {type(file_path)}")
|
|
@@ -1460,7 +1460,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
1460
1460
|
project_id: Optional project ID to associate with the annotation.
|
|
1461
1461
|
|
|
1462
1462
|
Raises:
|
|
1463
|
-
|
|
1463
|
+
ServerError: If the update fails.
|
|
1464
1464
|
"""
|
|
1465
1465
|
annotation_id = self._entid(annotation)
|
|
1466
1466
|
|
|
@@ -1477,7 +1477,7 @@ class AnnotationsApi(CreatableEntityApi[Annotation], DeletableEntityApi[Annotati
|
|
|
1477
1477
|
|
|
1478
1478
|
respdata = resp.json()
|
|
1479
1479
|
if isinstance(respdata, dict) and 'error' in respdata:
|
|
1480
|
-
raise
|
|
1480
|
+
raise ServerError(respdata['error'])
|
|
1481
1481
|
|
|
1482
1482
|
def approve(self, annotation: str | Annotation) -> None:
|
|
1483
1483
|
"""Approve an annotation.
|