datamint 2.3.2__py3-none-any.whl → 2.3.4__py3-none-any.whl

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.

Potentially problematic release.


This version of datamint might be problematic. Click here for more details.

@@ -1,19 +1,33 @@
1
1
  """Resource entity module for DataMint API."""
2
2
 
3
3
  from datetime import datetime
4
- from typing import Optional, Any
4
+ from typing import TYPE_CHECKING, Optional, Any, Sequence
5
5
  import logging
6
+
6
7
  from .base_entity import BaseEntity, MISSING_FIELD
7
- from pydantic import Field
8
+ from .cache_manager import CacheManager
9
+ from pydantic import PrivateAttr
10
+ from datamint.api.dto import AnnotationType
11
+ import webbrowser
12
+ from datamint.types import ImagingData
13
+
14
+ if TYPE_CHECKING:
15
+ from datamint.api.endpoints.resources_api import ResourcesApi
16
+ from .project import Project
17
+ from .annotation import Annotation
8
18
 
9
19
  logger = logging.getLogger(__name__)
10
20
 
21
+
22
+ _IMAGE_CACHEKEY = "image_data"
23
+
24
+
11
25
  class Resource(BaseEntity):
12
26
  """Represents a DataMint resource with all its properties and metadata.
13
-
27
+
14
28
  This class models a resource entity from the DataMint API, containing
15
29
  information about uploaded files, their metadata, and associated projects.
16
-
30
+
17
31
  Attributes:
18
32
  id: Unique identifier for the resource
19
33
  resource_uri: URI path to access the resource file
@@ -84,42 +98,145 @@ class Resource(BaseEntity):
84
98
  categories: Optional[Any] = None # TODO: Define proper type when spec available
85
99
  user_info: Optional[dict] = None
86
100
 
101
+ _api: 'ResourcesApi' = PrivateAttr()
102
+
103
+ def __init__(self, **data):
104
+ """Initialize the resource entity."""
105
+ super().__init__(**data)
106
+ self._cache: CacheManager[bytes] = CacheManager[bytes]('resources')
107
+
108
+ def fetch_file_data(
109
+ self,
110
+ auto_convert: bool = True,
111
+ save_path: str | None = None,
112
+ use_cache: bool = False,
113
+ ) -> bytes | ImagingData:
114
+ """Get the file data for this resource.
115
+
116
+ This method automatically caches the file data locally. On subsequent
117
+ calls, it checks the server for changes and uses cached data if unchanged.
118
+
119
+ Args:
120
+ use_cache: If True, uses cached data when available and valid
121
+ auto_convert: If True, automatically converts to appropriate format (pydicom.Dataset, PIL Image, etc.)
122
+ save_path: Optional path to save the file locally
123
+
124
+ Returns:
125
+ File data (format depends on auto_convert and file type)
126
+ """
127
+ # Version info for cache validation
128
+ version_info = self._generate_version_info()
129
+
130
+ # Try to get from cache
131
+ img_data = None
132
+ if use_cache:
133
+ img_data = self._cache.get(self.id, _IMAGE_CACHEKEY, version_info)
134
+ if img_data is not None:
135
+ logger.debug(f"Using cached image data for resource {self.id}")
136
+
137
+ if img_data is None:
138
+ # Fetch from server using download_resource_file
139
+ logger.debug(f"Fetching image data from server for resource {self.id}")
140
+ img_data = self._api.download_resource_file(
141
+ self,
142
+ save_path=save_path,
143
+ auto_convert=False
144
+ )
145
+ # Cache the data
146
+ if use_cache:
147
+ self._cache.set(self.id, _IMAGE_CACHEKEY, img_data, version_info)
148
+
149
+ if auto_convert:
150
+ try:
151
+ mimetype, ext = self._api._determine_mimetype(img_data, self)
152
+ img_data = self._api.convert_format(img_data,
153
+ mimetype=mimetype,
154
+ file_path=save_path)
155
+ except Exception as e:
156
+ logger.error(f"Failed to auto-convert resource {self.id}: {e}")
157
+
158
+ return img_data
159
+
160
+ def _generate_version_info(self) -> dict:
161
+ """Helper to generate version info for caching."""
162
+ return {
163
+ 'created_at': self.created_at,
164
+ 'deleted_at': self.deleted_at,
165
+ 'size': self.size,
166
+ }
167
+
168
+ def _save_into_cache(self, data: bytes) -> None:
169
+ """Helper to save raw data into cache."""
170
+ version_info = self._generate_version_info()
171
+ self._cache.set(self.id, _IMAGE_CACHEKEY, data, version_info)
172
+
173
+ def fetch_annotations(
174
+ self,
175
+ annotation_type: AnnotationType | str | None = None
176
+ ) -> Sequence['Annotation']:
177
+ """Get annotations associated with this resource."""
178
+
179
+ annotations = self._api.get_annotations(self)
180
+
181
+ if annotation_type:
182
+ annotation_type = AnnotationType(annotation_type)
183
+ annotations = [a for a in annotations if a.annotation_type == annotation_type]
184
+ return annotations
185
+
186
+ # def get_projects(
187
+ # self,
188
+ # ) -> Sequence['Project']:
189
+ # """Get all projects this resource belongs to.
190
+
191
+ # Returns:
192
+ # List of Project instances
193
+ # """
194
+ # return self._api.get_projects(self)
195
+
196
+
197
+ def invalidate_cache(self) -> None:
198
+ """Invalidate cached data for this resource.
199
+ """
200
+ # Invalidate all
201
+ self._cache.invalidate(self.id)
202
+ logger.debug(f"Invalidated all cache for resource {self.id}")
203
+
87
204
  @property
88
205
  def size_mb(self) -> float:
89
206
  """Get file size in megabytes.
90
-
207
+
91
208
  Returns:
92
209
  File size in MB rounded to 2 decimal places
93
210
  """
94
211
  return round(self.size / (1024 * 1024), 2)
95
-
212
+
96
213
  def is_dicom(self) -> bool:
97
214
  """Check if the resource is a DICOM file.
98
-
215
+
99
216
  Returns:
100
217
  True if the resource is a DICOM file, False otherwise
101
218
  """
102
219
  return self.mimetype == 'application/dicom' or self.storage == 'DicomResource'
103
-
104
- def get_project_names(self) -> list[str]:
105
- """Get list of project names this resource belongs to.
106
-
107
- Returns:
108
- List of project names
109
- """
110
- return [proj['name'] for proj in self.projects]
111
-
220
+
221
+ # def get_project_names(self) -> list[str]:
222
+ # """Get list of project names this resource belongs to.
223
+
224
+ # Returns:
225
+ # List of project names
226
+ # """
227
+ # return [proj['name'] for proj in self.projects] if self.projects != MISSING_FIELD else []
228
+
112
229
  def __str__(self) -> str:
113
230
  """String representation of the resource.
114
-
231
+
115
232
  Returns:
116
233
  Human-readable string describing the resource
117
234
  """
118
235
  return f"Resource(id='{self.id}', filename='{self.filename}', size={self.size_mb}MB)"
119
-
236
+
120
237
  def __repr__(self) -> str:
121
238
  """Detailed string representation of the resource.
122
-
239
+
123
240
  Returns:
124
241
  Detailed string representation for debugging
125
242
  """
@@ -128,3 +245,13 @@ class Resource(BaseEntity):
128
245
  f"modality='{self.modality}', status='{self.status}', "
129
246
  f"published={self.published})"
130
247
  )
248
+
249
+ @property
250
+ def url(self) -> str:
251
+ """Get the URL to access this resource in the DataMint web application."""
252
+ base_url = self._api.config.web_app_url
253
+ return f'{base_url}/resource/{self.id}'
254
+
255
+ def show(self) -> None:
256
+ """Open the resource in the default web browser."""
257
+ webbrowser.open(self.url)
datamint/types.py ADDED
@@ -0,0 +1,17 @@
1
+ from typing import TypeAlias, TYPE_CHECKING, Union
2
+
3
+ if TYPE_CHECKING:
4
+ import pydicom.dataset
5
+ from PIL import Image
6
+ import cv2
7
+ from nibabel.filebasedimages import FileBasedImage as nib_FileBasedImage
8
+
9
+ # Type alias for imaging formats
10
+ ImagingData: TypeAlias = (
11
+ Union[
12
+ 'pydicom.dataset.Dataset',
13
+ 'Image.Image',
14
+ 'cv2.VideoCapture',
15
+ 'nib_FileBasedImage'
16
+ ]
17
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datamint
3
- Version: 2.3.2
3
+ Version: 2.3.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
@@ -15,6 +15,7 @@ Requires-Dist: Deprecated (>=1.2.0)
15
15
  Requires-Dist: aiohttp (>=3.0.0,<4.0.0)
16
16
  Requires-Dist: aioresponses (>=0.7.8,<0.8.0) ; extra == "dev"
17
17
  Requires-Dist: albumentations (>=2.0.0)
18
+ Requires-Dist: backports-strenum ; python_version < "3.11"
18
19
  Requires-Dist: datamintapi (==0.0.*)
19
20
  Requires-Dist: httpx
20
21
  Requires-Dist: humanize (>=4.0.0,<5.0.0)
@@ -1,40 +1,41 @@
1
1
  datamint/__init__.py,sha256=ucsnxrYClh6pdy7psRJXWam_9rjAQB4NXzvy7xLovmo,824
2
2
  datamint/api/__init__.py,sha256=7QYkmDBXbKh8-zchV7k6Lpolaw6h-IK6ezfXROIWh2A,43
3
- datamint/api/base_api.py,sha256=Iu9oJEZ8YlIF5xcbH_M0Lkb7t9ZDNFLzjJp9bPDHW1c,16628
4
- datamint/api/client.py,sha256=WfcCpvH3tl0nQ9SgRdQG0qy8A7tD_2dytRxQUln3G9Y,3724
5
- datamint/api/dto/__init__.py,sha256=KOSNl1axDDE5eBt68MmsgkyE0Ds_1DDzWUg73iyoWvc,281
3
+ datamint/api/base_api.py,sha256=RUtiTMy0h6LV-nXKfRdQ9FDJzwLf6k2RCCMytacB2AU,18881
4
+ datamint/api/client.py,sha256=ndKSj2QnveRNOtaQhE9qM4tCGtgrTxfInDy9FhdReCo,3922
5
+ datamint/api/dto/__init__.py,sha256=fUi901Zs-q5XHyWwZ4dMi2fEO8-CUEVEdYbpd17lahc,416
6
6
  datamint/api/endpoints/__init__.py,sha256=wi4liAb5-wOohwyzKUD6TxHGeZmUPaZerFUGa2IUju4,529
7
- datamint/api/endpoints/annotations_api.py,sha256=jhaWkLd01zKw-lVQYhBX288o9Ew2lQ-jmRP-0fz2fx0,48185
7
+ datamint/api/endpoints/annotations_api.py,sha256=B21oGgNXO7xoir3ynNvhnbo1JyRvWZ9sbsc7VVjghhM,49713
8
8
  datamint/api/endpoints/annotationsets_api.py,sha256=NIsPIjGGptiUBxHft-EhOMRG-DsQAthheVqd7ph0id4,409
9
9
  datamint/api/endpoints/channels_api.py,sha256=oQqxSw9DJzAqtVQI7-tc1llTdnsm-URx8jwtXNXnhio,867
10
10
  datamint/api/endpoints/datasetsinfo_api.py,sha256=WdzrUzK63w9gvAP6U--P65FbD-3X-jm9TPCcYnRNjas,597
11
11
  datamint/api/endpoints/models_api.py,sha256=tbVuajc-mCsIp5AKSCoq3uQRDWgKnJaIA6tf_ck8-XY,1502
12
- datamint/api/endpoints/projects_api.py,sha256=9tYIQsnMFOGTXrsoizweoWNqNue5907nbI6G9PAcYcA,7784
13
- datamint/api/endpoints/resources_api.py,sha256=Hd8sObIarvAdATS6qmAvT9EdXzPfruyMHnlGXcYkeMg,48320
12
+ datamint/api/endpoints/projects_api.py,sha256=Pfr3fEiMw_aRzoGtcVXHJQ68leVoPAghw23L4ZIglno,8237
13
+ datamint/api/endpoints/resources_api.py,sha256=nEPDT5EjSw7-vXahR2sfvMeQDClE4Q71qYFUCABqPq8,50372
14
14
  datamint/api/endpoints/users_api.py,sha256=pnkuTZ1B9Y0FtwwvXO8J64e02RSkRxnBmTl9UGSuC5I,1186
15
- datamint/api/entity_base_api.py,sha256=gPE28bwv7B6JngMk9szD2XwaVhB8OwB1HJjaMYD354k,12935
15
+ datamint/api/entity_base_api.py,sha256=-8SIt4M8P9G2b8SQznuWpFuFE8zEQjQxkRkw0s_w0Y4,11692
16
16
  datamint/apihandler/annotation_api_handler.py,sha256=W3vV4z3BqX1OQe1r7zr8dI-IVu4zUDxED4QttdiWV-E,57098
17
17
  datamint/apihandler/api_handler.py,sha256=mL0gMaWePYa7zwkw92E-VMK2WjpcPt7au0KqnmsWSYw,439
18
18
  datamint/apihandler/base_api_handler.py,sha256=Hqt3oUvXfEqF25DJkk0WOWAtNLnKaZRGtnCchKFA1ag,11669
19
19
  datamint/apihandler/dto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- datamint/apihandler/dto/annotation_dto.py,sha256=KUeHbxLYols16q-ANNxC48eH4EA8Tc-nKmW_8xrqhy4,7119
20
+ datamint/apihandler/dto/annotation_dto.py,sha256=8gcTFsvbXQQU4QjdW6lcUI_De1fyNyF49_a2uIyBOpg,7220
21
21
  datamint/apihandler/exp_api_handler.py,sha256=hFUgUgBc5rL7odK7gTW3MnrvMY1pVfJUpUdzRNobMQE,6226
22
22
  datamint/apihandler/root_api_handler.py,sha256=jBof_XPTeq4o41CW-l-I5GHQKVa76kaX75RovS_qAM4,63384
23
23
  datamint/client_cmd_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  datamint/client_cmd_tools/datamint_config.py,sha256=MpR5UHv_xpElOOYyEESBkDg2n3JjP_PNLI2jqmZgYQ8,16222
25
- datamint/client_cmd_tools/datamint_upload.py,sha256=rZEqBRZZDBFSlwMvIg_DbipqgBtQD31v7DC1C6tysqA,36058
26
- datamint/configs.py,sha256=Bdp6NydYwyCJ2dk19_gf_o3M2ZyQOmMHpLi8wEWNHUk,1426
25
+ datamint/client_cmd_tools/datamint_upload.py,sha256=zGNEylfS2P5XUyzBz44ruHjoyAoKZFwZbw4wRVANEL8,36279
26
+ datamint/configs.py,sha256=ArVD5QxuohLcM6NB0dMxcEfrD1-x5lPRDLcBdY8jhMU,1625
27
27
  datamint/dataset/__init__.py,sha256=4PlUKSvVhdfQvvuq8jQXrkdqnot-iTTizM3aM1vgSwg,47
28
28
  datamint/dataset/annotation.py,sha256=qN1IMjdfLD2ceQ6va3l76jOXA8Vb_c-eBk1oWQu6hW0,7994
29
- datamint/dataset/base_dataset.py,sha256=pJXU_nY9_D67E7G3cjnVnwdzjNNJgOhMt-i687oHgtw,49869
29
+ datamint/dataset/base_dataset.py,sha256=2m_5nBayFCzXSjuPLb6mM9NLQ43wIUqeFUfm-6WVg_U,49827
30
30
  datamint/dataset/dataset.py,sha256=c0887PcI6fEWG3FjM3gz_EYb9maH8v4ormZhm7vf4gE,28929
31
- datamint/entities/__init__.py,sha256=tbHE7rZb0R9Hm-Dc8VWEq3PlRl7BYOzffumrV0ZdsMs,444
32
- datamint/entities/annotation.py,sha256=ochAEh_JqxAe_FyYTNUfPT47KiIAG7CkBTim52bu7M8,6636
33
- datamint/entities/base_entity.py,sha256=DniakCgJ-gV7Hz8VKQA_dRYTp4DU5rcjLBVOuD1aZuA,1902
31
+ datamint/entities/__init__.py,sha256=ePkFeNATE5tJ9Lulsn2VTGWBJGwPtoRT1zsfbg1bkPw,504
32
+ datamint/entities/annotation.py,sha256=4qsm3yO8bTgu5SNxY91P0LGXx3d7mxF1OGWpMNir1CA,8956
33
+ datamint/entities/base_entity.py,sha256=QX381VdnrisQeQKg2kkHNDUvczYm03VsDHlHZQXr78U,3307
34
+ datamint/entities/cache_manager.py,sha256=ZN5_HeyM6c0ocWFsJuJEF4CkuOHr6RPErwhZNYYq7WU,10282
34
35
  datamint/entities/channel.py,sha256=9fl22eSx_ng98NosfQGs18cdaRdbeC3wXL61KhSg4Zo,1601
35
- datamint/entities/datasetinfo.py,sha256=O73Aq0tLflQomFzseful8a_cXqKdO9w2yP0p3zBcA-s,489
36
- datamint/entities/project.py,sha256=FNweb1Q0ZQkWfbyijoV-UyqUXthzookdcyO-ophAl0U,2676
37
- datamint/entities/resource.py,sha256=7YCVihswd-bH-2AH4aMPIddt5ejwRqRFQAszI_sTWaU,4882
36
+ datamint/entities/datasetinfo.py,sha256=yeGy5CVxqc7h0SFBJROr0UObeIMkOVZKwrOBsZ-iCEg,4151
37
+ datamint/entities/project.py,sha256=QQXBOe6FzupPrCunBcqOlY6d3uqxvnYvGeCq8hZy_U8,4192
38
+ datamint/entities/resource.py,sha256=Ai36-dJ9PhrRYho8QLRnySfsAPWPW8QpKMiVra_jCgA,9316
38
39
  datamint/entities/user.py,sha256=MREHDOsV9NOBEbXqiQ2ww6DmetN07CELId-ZQVpZCb8,620
39
40
  datamint/examples/__init__.py,sha256=zcYnd5nLVme9GCTPYH-1JpGo8xXK2WEYvhzcy_2alZc,39
40
41
  datamint/examples/example_projects.py,sha256=sU-Gxy7PPqA0WUfN-ZmXV-0YnwrnzpJ79lMXTJp2DzU,2804
@@ -43,10 +44,11 @@ datamint/experiment/__init__.py,sha256=5qQOMzoG17DEd1YnTF-vS0qiM-DGdbNh42EUo91CR
43
44
  datamint/experiment/_patcher.py,sha256=ZgbezoevAYhJsbiJTvWPALGTcUiMT371xddcTllt3H4,23296
44
45
  datamint/experiment/experiment.py,sha256=aHK9dRFdQTi569xgUg1KqlCZLHZpDmSH3g3ndPIZvXw,44546
45
46
  datamint/logging.yaml,sha256=tOMxtc2UmwlIMTK6ljtnBwTco1PNrPeq3mx2iMuSbiw,482
47
+ datamint/types.py,sha256=2OaY5QJvQIJKxyMNJYzxBksKCa9ZS2gb_ayJrByvu2Y,410
46
48
  datamint/utils/logging_utils.py,sha256=9pRoaPrWu2jOdDCiAoUsjEdP5ZwaealWL3hjUqFvx9g,4022
47
49
  datamint/utils/torchmetrics.py,sha256=lwU0nOtsSWfebyp7dvjlAggaqXtj5ohSEUXOg3L0hJE,2837
48
50
  datamint/utils/visualization.py,sha256=yaUVAOHar59VrGUjpAWv5eVvQSfztFG0eP9p5Vt3l-M,4470
49
- datamint-2.3.2.dist-info/METADATA,sha256=wybrUAOXVw_v1HzHAamP9uGMO7mAemu87lmDf7-0mbE,4203
50
- datamint-2.3.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
51
- datamint-2.3.2.dist-info/entry_points.txt,sha256=mn5H6jPjO-rY0W0CAZ6Z_KKWhMLvyVaSpoqk77jlTI4,145
52
- datamint-2.3.2.dist-info/RECORD,,
51
+ datamint-2.3.4.dist-info/METADATA,sha256=Kz2iS6lI3cmVlpCA-d4AMrTfr77CcuXpO7kt65LoZHk,4262
52
+ datamint-2.3.4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
53
+ datamint-2.3.4.dist-info/entry_points.txt,sha256=mn5H6jPjO-rY0W0CAZ6Z_KKWhMLvyVaSpoqk77jlTI4,145
54
+ datamint-2.3.4.dist-info/RECORD,,