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.
Files changed (145) hide show
  1. {datamint-2.17.2 → datamint-2.17.4}/PKG-INFO +15 -2
  2. {datamint-2.17.2 → datamint-2.17.4}/README.md +9 -1
  3. {datamint-2.17.2 → datamint-2.17.4}/datamint/__init__.py +4 -1
  4. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/base_api.py +33 -19
  5. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/client.py +4 -4
  6. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/annotations_api.py +11 -11
  7. datamint-2.17.4/datamint/api/endpoints/annotationsets_api.py +588 -0
  8. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/deploy_model_api.py +2 -2
  9. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/inference_api.py +2 -1
  10. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/projects_api.py +1 -1
  11. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/resources_api.py +10 -9
  12. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/entity_base_api.py +2 -2
  13. datamint-2.17.4/datamint/client_cmd_tools/datamint_init.py +1522 -0
  14. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/__init__.py +8 -1
  15. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/base.py +264 -35
  16. datamint-2.17.4/datamint/dataset/factory.py +99 -0
  17. datamint-2.17.4/datamint/dataset/image_dataset.py +145 -0
  18. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/multiframe_dataset.py +11 -9
  19. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/sliced_dataset.py +14 -14
  20. datamint-2.17.4/datamint/dataset/split_result.py +57 -0
  21. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotation_worklist.py +2 -2
  22. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resource.py +6 -1
  23. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/sliced_resource.py +10 -28
  24. datamint-2.17.4/datamint/entities/sliced_resource_base.py +54 -0
  25. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/sliced_video_resource.py +12 -24
  26. datamint-2.17.4/datamint/exceptions.py +107 -0
  27. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/__init__.py +12 -0
  28. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/datamodule.py +7 -5
  29. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/__init__.py +10 -2
  30. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/base_trainer.py +26 -13
  31. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/classification_trainer.py +24 -4
  32. datamint-2.17.4/datamint/lightning/trainers/detection_trainer.py +74 -0
  33. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/__init__.py +3 -2
  34. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/classification_module.py +5 -5
  35. datamint-2.17.4/datamint/lightning/trainers/lightning_modules/detection_modules/__init__.py +3 -0
  36. datamint-2.17.4/datamint/lightning/trainers/lightning_modules/detection_modules/yolox_module.py +251 -0
  37. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_module.py +2 -2
  38. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/__init__.py +3 -1
  39. datamint-2.17.4/datamint/lightning/trainers/lightning_modules/segmentation_modules/transunet.py +219 -0
  40. datamint-2.17.4/datamint/lightning/trainers/lightning_modules/segmentation_modules/unetrpp.py +630 -0
  41. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/segmentation_trainer.py +8 -0
  42. datamint-2.17.4/datamint/lightning/trainers/specialized/__init__.py +18 -0
  43. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/specialized/deeplabv3plus.py +3 -3
  44. datamint-2.17.4/datamint/lightning/trainers/specialized/efficientnetv2.py +53 -0
  45. datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/__init__.py +0 -0
  46. datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/_nnunet_trainer_bridge.py +153 -0
  47. datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/data_export.py +307 -0
  48. datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/data_import.py +139 -0
  49. datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/inference_model.py +169 -0
  50. datamint-2.17.4/datamint/lightning/trainers/specialized/nnunet/trainer.py +551 -0
  51. datamint-2.17.4/datamint/lightning/trainers/specialized/transunet.py +183 -0
  52. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/specialized/unetpp.py +3 -3
  53. datamint-2.17.4/datamint/lightning/trainers/specialized/unetrpp.py +137 -0
  54. datamint-2.17.4/datamint/lightning/trainers/specialized/yolox.py +173 -0
  55. datamint-2.17.4/datamint/lightning/trainers/vol_seg_trainer.py +168 -0
  56. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/__init__.py +5 -0
  57. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/datamint_flavor.py +154 -18
  58. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/model.py +11 -0
  59. datamint-2.17.4/datamint/mlflow/flavors/validation.py +228 -0
  60. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/lightning/callbacks/modelcheckpoint.py +23 -12
  61. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/tracking/datamint_store.py +9 -1
  62. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/tracking/fluent.py +3 -3
  63. {datamint-2.17.2 → datamint-2.17.4}/pyproject.toml +7 -1
  64. datamint-2.17.2/datamint/api/endpoints/annotationsets_api.py +0 -144
  65. datamint-2.17.2/datamint/dataset/image_dataset.py +0 -106
  66. datamint-2.17.2/datamint/exceptions.py +0 -63
  67. datamint-2.17.2/datamint/lightning/trainers/specialized/__init__.py +0 -1
  68. {datamint-2.17.2 → datamint-2.17.4}/datamint/__main__.py +0 -0
  69. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/__init__.py +0 -0
  70. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/dto/__init__.py +0 -0
  71. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/dto/annotation_dto.py +0 -0
  72. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/__init__.py +0 -0
  73. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/channels_api.py +0 -0
  74. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/datasetsinfo_api.py +0 -0
  75. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/models_api.py +0 -0
  76. {datamint-2.17.2 → datamint-2.17.4}/datamint/api/endpoints/users_api.py +0 -0
  77. {datamint-2.17.2 → datamint-2.17.4}/datamint/client_cmd_tools/__init__.py +0 -0
  78. {datamint-2.17.2 → datamint-2.17.4}/datamint/client_cmd_tools/datamint_config.py +0 -0
  79. {datamint-2.17.2 → datamint-2.17.4}/datamint/client_cmd_tools/datamint_upload.py +0 -0
  80. {datamint-2.17.2 → datamint-2.17.4}/datamint/configs.py +0 -0
  81. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/annotation.py +0 -0
  82. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/annotation_processor.py +0 -0
  83. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/base_dataset.py +0 -0
  84. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/dataset.py +0 -0
  85. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/sliced_video_dataset.py +0 -0
  86. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/video_dataset.py +0 -0
  87. {datamint-2.17.2 → datamint-2.17.4}/datamint/dataset/volume_dataset.py +0 -0
  88. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/__init__.py +0 -0
  89. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/__init__.py +0 -0
  90. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/annotation.py +0 -0
  91. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/annotation_spec.py +0 -0
  92. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/base_geometry.py +0 -0
  93. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/base_segmentation.py +0 -0
  94. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/box_annotation.py +0 -0
  95. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/geometry.py +0 -0
  96. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/image_classification.py +0 -0
  97. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/image_segmentation.py +0 -0
  98. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/line_annotation.py +0 -0
  99. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/types.py +0 -0
  100. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/annotations/volume_segmentation.py +0 -0
  101. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/base_entity.py +0 -0
  102. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/cache_manager.py +0 -0
  103. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/channel.py +0 -0
  104. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/datasetinfo.py +0 -0
  105. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/deployjob.py +0 -0
  106. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/inferencejob.py +0 -0
  107. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/project.py +0 -0
  108. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/project_resource_split.py +0 -0
  109. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/__init__.py +0 -0
  110. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/dicom_resource.py +0 -0
  111. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/image_resource.py +0 -0
  112. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/nifti_resource.py +0 -0
  113. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/video_resource.py +0 -0
  114. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/resources/volume_resource.py +0 -0
  115. {datamint-2.17.2 → datamint-2.17.4}/datamint/entities/user.py +0 -0
  116. {datamint-2.17.2 → datamint-2.17.4}/datamint/examples/__init__.py +0 -0
  117. {datamint-2.17.2 → datamint-2.17.4}/datamint/examples/example_projects.py +0 -0
  118. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/base.py +0 -0
  119. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/deeplabv3plus.py +0 -0
  120. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/smp_module.py +0 -0
  121. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/lightning_modules/segmentation_modules/unetpp.py +0 -0
  122. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/seg2d_trainer.py +0 -0
  123. {datamint-2.17.2 → datamint-2.17.4}/datamint/lightning/trainers/seg3d_trainer.py +0 -0
  124. {datamint-2.17.2 → datamint-2.17.4}/datamint/logging.yaml +0 -0
  125. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/__init__.py +0 -0
  126. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/artifact/__init__.py +0 -0
  127. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/artifact/datamint_artifacts_repo.py +0 -0
  128. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/data/__init__.py +0 -0
  129. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/data/datamint_dataset.py +0 -0
  130. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/env_utils.py +0 -0
  131. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/env_vars.py +0 -0
  132. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/model_loader.py +0 -0
  133. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/prediction_modes.py +0 -0
  134. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/prediction_router.py +0 -0
  135. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/flavors/task_type.py +0 -0
  136. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/lightning/callbacks/__init__.py +0 -0
  137. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/models/__init__.py +0 -0
  138. {datamint-2.17.2 → datamint-2.17.4}/datamint/mlflow/tracking/default_experiment.py +0 -0
  139. {datamint-2.17.2 → datamint-2.17.4}/datamint/types.py +0 -0
  140. {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/collection_utils.py +0 -0
  141. {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/env.py +0 -0
  142. {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/logging_utils.py +0 -0
  143. {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/nifti_utils.py +0 -0
  144. {datamint-2.17.2 → datamint-2.17.4}/datamint/utils/torchmetrics.py +0 -0
  145. {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.2
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.readthedocs.io/)
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.readthedocs.io/)
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 DatamintException, ItemNotFoundError
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
- DatamintException: With helpful troubleshooting information
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 DatamintException(error_msg) from original_error
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 in (400, 404):
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
- try:
465
- e.message = error_msg
466
- except Exception:
467
- logger.debug("Unable to set message attribute on exception")
468
- pass
469
- if status_code in (400, 404):
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 DatamintException
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 DatamintException(msg)
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 DatamintException("Error connecting to the Datamint API." +
98
- f" Please check your api_key and/or other configurations.") from e
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 DatamintException, ItemNotFoundError
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
- DatamintException: If the upload fails.
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 DatamintException(respdata['error'])
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
- DatamintException: If the upload fails.
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 DatamintException(respdata['error'])
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 DatamintException(r['error'])
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 DatamintException(r['error'])
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 DatamintException(respdata['error'])
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 DatamintException(respdata['error'])
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
- DatamintException: If the update fails.
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 DatamintException(respdata['error'])
1480
+ raise ServerError(respdata['error'])
1481
1481
 
1482
1482
  def approve(self, annotation: str | Annotation) -> None:
1483
1483
  """Approve an annotation.