datamint 1.7.3__py3-none-any.whl → 1.7.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.

@@ -138,7 +138,7 @@ class BaseAPIHandler:
138
138
  if isinstance(data, aiohttp.FormData): # Check if it's aiohttp.FormData
139
139
  # Handle FormData by extracting fields
140
140
  form_parts = []
141
- for options,headers,value in data._fields:
141
+ for options, headers, value in data._fields:
142
142
  # get the name from options
143
143
  name = options.get('name', 'file')
144
144
  if hasattr(value, 'read'): # File-like object
@@ -161,7 +161,7 @@ class BaseAPIHandler:
161
161
  if session is None:
162
162
  async with aiohttp.ClientSession() as s:
163
163
  return await self._run_request_async(request_args, s, data_to_get)
164
-
164
+
165
165
  async with self.semaphore:
166
166
  try:
167
167
  _LOGGER.debug(f"Running request to {request_args['url']}")
@@ -222,7 +222,7 @@ class BaseAPIHandler:
222
222
 
223
223
  def _run_request(self,
224
224
  request_args: dict,
225
- session: Session = None):
225
+ session: Session | None = None):
226
226
  if session is None:
227
227
  with Session() as s:
228
228
  return self._run_request(request_args, s)
@@ -281,24 +281,25 @@ class BaseAPIHandler:
281
281
  @staticmethod
282
282
  def convert_format(bytes_array: bytes,
283
283
  mimetype: str,
284
- file_path: str = None
284
+ file_path: str | None = None
285
285
  ) -> pydicom.dataset.Dataset | Image.Image | cv2.VideoCapture | bytes | nib_FileBasedImage:
286
+ """ Convert the bytes array to the appropriate format based on the mimetype."""
286
287
  content_io = BytesIO(bytes_array)
287
- if mimetype == 'application/dicom':
288
+ if mimetype.endswith('/dicom'):
288
289
  return pydicom.dcmread(content_io)
289
- elif mimetype in ('image/jpeg', 'image/png', 'image/tiff'):
290
+ elif mimetype.startswith('image/'):
290
291
  return Image.open(content_io)
291
- elif mimetype == 'video/mp4':
292
+ elif mimetype.startswith('video/'):
292
293
  if file_path is None:
293
- raise NotImplementedError("file_path=None is not implemented yet for video/mp4.")
294
+ raise NotImplementedError("file_path=None is not implemented yet for video/* mimetypes.")
294
295
  return cv2.VideoCapture(file_path)
295
296
  elif mimetype == 'application/json':
296
297
  return json.loads(bytes_array)
297
298
  elif mimetype == 'application/octet-stream':
298
299
  return bytes_array
299
- elif mimetype == 'application/nifti':
300
+ elif mimetype.endswith('nifti'):
300
301
  if file_path is None:
301
- raise NotImplementedError("file_path=None is not implemented yet for application/nifti.")
302
+ raise NotImplementedError(f"file_path=None is not implemented yet for {mimetype}.")
302
303
  return nib.load(file_path)
303
304
 
304
305
  raise ValueError(f"Unsupported mimetype: {mimetype}")
@@ -8,10 +8,11 @@ import asyncio
8
8
  import aiohttp
9
9
  from medimgkit.dicom_utils import anonymize_dicom, to_bytesio, is_dicom
10
10
  from medimgkit import dicom_utils
11
+ from medimgkit.io_utils import is_io_object
12
+ from medimgkit.format_detection import guess_type, guess_extension
11
13
  import pydicom
12
14
  from pathlib import Path
13
15
  from datetime import date
14
- import mimetypes
15
16
  from PIL import Image
16
17
  import cv2
17
18
  from nibabel.filebasedimages import FileBasedImage as nib_FileBasedImage
@@ -26,13 +27,6 @@ _LOGGER = logging.getLogger(__name__)
26
27
  _USER_LOGGER = logging.getLogger('user_logger')
27
28
 
28
29
 
29
- def _is_io_object(obj):
30
- """
31
- Check if an object is a file-like object.
32
- """
33
- return callable(getattr(obj, "read", None))
34
-
35
-
36
30
  def _infinite_gen(x):
37
31
  while True:
38
32
  yield x
@@ -65,7 +59,7 @@ class RootAPIHandler(BaseAPIHandler):
65
59
  publish: bool = False,
66
60
  metadata_file: Optional[str | dict] = None,
67
61
  ) -> str:
68
- if _is_io_object(file_path):
62
+ if is_io_object(file_path):
69
63
  name = file_path.name
70
64
  else:
71
65
  name = file_path
@@ -91,15 +85,12 @@ class RootAPIHandler(BaseAPIHandler):
91
85
  name = new_file_path
92
86
  _LOGGER.debug(f"New file path: {name}")
93
87
 
94
- if mimetype is None:
95
- mimetype = mimetypes.guess_type(name)[0]
96
88
  is_a_dicom_file = None
97
89
  if mimetype is None:
98
- is_a_dicom_file = is_dicom(name) or is_dicom(file_path)
99
- if is_a_dicom_file:
100
- mimetype = 'application/dicom'
101
- elif name.endswith('.nii') or name.endswith('.nii.gz'):
102
- mimetype = 'application/x-nifti'
90
+ mimetype, _ = guess_type(file_path, use_magic=True)
91
+ if mimetype == 'application/gzip' and name.lower().endswith('nii.gz'):
92
+ # Special case for gzipped NIfTI files
93
+ mimetype = 'image/x.nifti'
103
94
 
104
95
  filename = os.path.basename(name)
105
96
  _LOGGER.debug(f"File name '{filename}' mimetype: {mimetype}")
@@ -451,7 +442,7 @@ class RootAPIHandler(BaseAPIHandler):
451
442
 
452
443
  files_path, is_multiple_resources = RootAPIHandler.__process_files_parameter(files_path)
453
444
 
454
- ### Discard DICOM reports
445
+ # Discard DICOM reports
455
446
  if discard_dicom_reports:
456
447
  files_path = [f for f in files_path if not RootAPIHandler._is_dicom_report(f)]
457
448
  old_size = len(files_path)
@@ -678,7 +669,7 @@ class RootAPIHandler(BaseAPIHandler):
678
669
  is_list = False
679
670
  new_file_path = [file_path]
680
671
  # Check if is an IO object
681
- elif _is_io_object(file_path):
672
+ elif is_io_object(file_path):
682
673
  is_list = False
683
674
  new_file_path = [file_path]
684
675
  elif not hasattr(file_path, '__len__'):
@@ -728,8 +719,8 @@ class RootAPIHandler(BaseAPIHandler):
728
719
 
729
720
  def get_resources(self,
730
721
  status: Optional[ResourceStatus] = None,
731
- from_date: Optional[date] = None,
732
- to_date: Optional[date] = None,
722
+ from_date: date | str | None = None,
723
+ to_date: date | str | None = None,
733
724
  tags: Optional[Sequence[str]] = None,
734
725
  modality: Optional[str] = None,
735
726
  mimetype: Optional[str] = None,
@@ -747,8 +738,8 @@ class RootAPIHandler(BaseAPIHandler):
747
738
 
748
739
  Args:
749
740
  status (ResourceStatus): The resource status. Possible values: 'inbox', 'published', 'archived' or None. If None, it will return all resources.
750
- from_date (Optional[date]): The start date.
751
- to_date (Optional[date]): The end date.
741
+ from_date (date | str | None): The start date.
742
+ to_date (date | str | None): The end date.
752
743
  tags (Optional[list[str]]): The tags to filter the resources.
753
744
  modality (Optional[str]): The modality of the resources.
754
745
  mimetype (Optional[str]): The mimetype of the resources.
@@ -767,9 +758,15 @@ class RootAPIHandler(BaseAPIHandler):
767
758
  """
768
759
  # Convert datetime objects to ISO format
769
760
  if from_date:
770
- from_date = from_date.isoformat()
761
+ if isinstance(from_date, str):
762
+ date.fromisoformat(from_date)
763
+ else:
764
+ from_date = from_date.isoformat()
771
765
  if to_date:
772
- to_date = to_date.isoformat()
766
+ if isinstance(to_date, str):
767
+ date.fromisoformat(to_date)
768
+ else:
769
+ to_date = to_date.isoformat()
773
770
 
774
771
  # Prepare the payload
775
772
  payload = {
@@ -953,6 +950,9 @@ class RootAPIHandler(BaseAPIHandler):
953
950
  >>> api_handler.download_resource_file('resource_id', save_path='path/to/dicomfile.dcm')
954
951
  saves the file in the specified path.
955
952
  """
953
+ if save_path is None and add_extension:
954
+ raise ValueError("If add_extension is True, save_path must be provided.")
955
+
956
956
  url = f"{self._get_endpoint_url(RootAPIHandler.ENDPOINT_RESOURCES)}/{resource_id}/file"
957
957
  request_params = {'method': 'GET',
958
958
  'headers': {'accept': 'application/octet-stream'},
@@ -964,7 +964,8 @@ class RootAPIHandler(BaseAPIHandler):
964
964
  mimetype = None
965
965
  if auto_convert or add_extension:
966
966
  resource_info = self.get_resources_by_ids(resource_id)
967
- mimetype = resource_info['mimetype']
967
+ mimetype = resource_info.get('mimetype', guess_type(response.content)[0])
968
+
968
969
 
969
970
  if auto_convert:
970
971
  try:
@@ -985,15 +986,15 @@ class RootAPIHandler(BaseAPIHandler):
985
986
  raise e
986
987
 
987
988
  if save_path is not None:
988
- if add_extension:
989
- ext = mimetypes.guess_extension(mimetype)
989
+ if add_extension and mimetype is not None:
990
+ ext = guess_extension(mimetype)
990
991
  if ext is not None and not save_path.endswith(ext):
991
992
  save_path += ext
992
993
  with open(save_path, 'wb') as f:
993
994
  f.write(response.content)
994
995
 
995
- if add_extension:
996
- return resource_file, save_path
996
+ if add_extension:
997
+ return resource_file, save_path
997
998
  return resource_file
998
999
 
999
1000
  def download_resource_frame(self,
@@ -283,10 +283,12 @@ class DatamintBaseDataset:
283
283
  """Post-process data after loading metadata."""
284
284
  self._check_integrity()
285
285
  self._calculate_dataset_length()
286
- self._precompute_frame_data()
286
+ if self.return_frame_by_frame:
287
+ self._precompute_frame_data()
288
+ self.subset_indices = list(range(self.dataset_length))
287
289
  self._setup_labels()
288
290
 
289
- if self.discard_without_annotations and self.return_frame_by_frame:
291
+ if self.discard_without_annotations:
290
292
  self._filter_unannotated()
291
293
 
292
294
  def _calculate_dataset_length(self) -> None:
@@ -301,9 +303,8 @@ class DatamintBaseDataset:
301
303
 
302
304
  def _precompute_frame_data(self) -> None:
303
305
  """Precompute frame-related data for efficient indexing."""
304
- self.num_frames_per_resource = self.__compute_num_frames_per_resource()
305
- self._cumulative_frames = np.cumsum([0] + self.num_frames_per_resource)
306
- self.subset_indices = list(range(self.dataset_length))
306
+ num_frames_per_resource = self.__compute_num_frames_per_resource()
307
+ self._cumulative_frames = np.cumsum([0] + num_frames_per_resource)
307
308
 
308
309
  def _setup_labels(self) -> None:
309
310
  """Setup label sets and mappings."""
@@ -989,9 +990,11 @@ class DatamintBaseDataset:
989
990
  return Path(resource['file'])
990
991
  else:
991
992
  ext = guess_extension(resource['mimetype'], strict=False)
993
+ _LOGGER.debug(f"Guessed extension for resource {resource['id']}|{resource['mimetype']}: {ext}")
992
994
  if ext is None:
993
995
  _LOGGER.warning(f"Could not guess extension for resource {resource['id']}.")
994
996
  ext = ''
997
+ raise Exception
995
998
  return Path('images', f"{resource['id']}{ext}")
996
999
 
997
1000
  def _get_annotation_file_path(self, annotation: dict | Annotation) -> Path | None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: datamint
3
- Version: 1.7.3
3
+ Version: 1.7.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
@@ -19,7 +19,7 @@ Requires-Dist: humanize (>=4.0.0,<5.0.0)
19
19
  Requires-Dist: lazy-loader (>=0.3.0)
20
20
  Requires-Dist: lightning
21
21
  Requires-Dist: matplotlib
22
- Requires-Dist: medimgkit
22
+ Requires-Dist: medimgkit (>=0.2.0)
23
23
  Requires-Dist: nest-asyncio (>=1.0.0,<2.0.0)
24
24
  Requires-Dist: nibabel (>=4.0.0)
25
25
  Requires-Dist: numpy
@@ -1,17 +1,17 @@
1
1
  datamint/__init__.py,sha256=7rKCCsaa4RBRTIfuHB708rai1xwDHLtkFNFJGKYG5D4,757
2
2
  datamint/apihandler/annotation_api_handler.py,sha256=HnWiG2ebq08mdaazTXVbkuwvh6fmKIKt8uqAOf3Y1jU,57013
3
3
  datamint/apihandler/api_handler.py,sha256=cdVSddrFCKlF_BJ81LO1aJ0OP49rssjpNEFzJ6Q7YyY,384
4
- datamint/apihandler/base_api_handler.py,sha256=dWLiowyuP1XiGfNc-_D5oQSmJdfR0Quy0ToeJlkRA8s,11911
4
+ datamint/apihandler/base_api_handler.py,sha256=t2no7gTIdPFfR_TXlZmh3rsncaL9p1G8eIS2m9Q7ALE,11978
5
5
  datamint/apihandler/dto/annotation_dto.py,sha256=qId1RK1VO7dXrvGJ7dqJ31jBQB7Z8yy5x0tLSiMxTB4,7105
6
6
  datamint/apihandler/exp_api_handler.py,sha256=hFUgUgBc5rL7odK7gTW3MnrvMY1pVfJUpUdzRNobMQE,6226
7
- datamint/apihandler/root_api_handler.py,sha256=aPJSPYEedm3oBKyEMJAz5J2l3eh1iw_nDVloWgQoeR4,56857
7
+ datamint/apihandler/root_api_handler.py,sha256=IHpr2Bki1WPTKzM133U68c7p_50Fq5t-JEkqGFlSl8k,57152
8
8
  datamint/client_cmd_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  datamint/client_cmd_tools/datamint_config.py,sha256=md7dnWrbl10lPtXKbmD9yo6onLJsajeG8Vz0ZWH1v4M,8181
10
10
  datamint/client_cmd_tools/datamint_upload.py,sha256=890USkrtaH23mNjTRYVHWce2q9jSmkUNHIP_e8fnJRM,29502
11
11
  datamint/configs.py,sha256=Bdp6NydYwyCJ2dk19_gf_o3M2ZyQOmMHpLi8wEWNHUk,1426
12
12
  datamint/dataset/__init__.py,sha256=4PlUKSvVhdfQvvuq8jQXrkdqnot-iTTizM3aM1vgSwg,47
13
13
  datamint/dataset/annotation.py,sha256=qN1IMjdfLD2ceQ6va3l76jOXA8Vb_c-eBk1oWQu6hW0,7994
14
- datamint/dataset/base_dataset.py,sha256=9aMzfrBBw8_Atro4j325OgBPXSQtcbRwXrdIpS7bM3Q,49251
14
+ datamint/dataset/base_dataset.py,sha256=vYM1Q7uVdtF6DfkbJjTjdleF-kG612rSBa2c2ynohX4,49393
15
15
  datamint/dataset/dataset.py,sha256=fdcgxB9NKvPEdr9S6TOeAIqFW38PdhmCiYsit6u5Wxc,27314
16
16
  datamint/examples/__init__.py,sha256=zcYnd5nLVme9GCTPYH-1JpGo8xXK2WEYvhzcy_2alZc,39
17
17
  datamint/examples/example_projects.py,sha256=7Nb_EaIdzJTQa9zopqc-WhTBQWQJSoQZ_KjRS4PB4FI,2931
@@ -22,7 +22,7 @@ datamint/logging.yaml,sha256=a5dsATpul7QHeUHB2TjABFjWaPXBMbO--dgn8GlRqwk,483
22
22
  datamint/utils/logging_utils.py,sha256=DvoA35ATYG3JTwfXEXYawDyKRfHeCrH0a9czfkmz8kM,1851
23
23
  datamint/utils/torchmetrics.py,sha256=lwU0nOtsSWfebyp7dvjlAggaqXtj5ohSEUXOg3L0hJE,2837
24
24
  datamint/utils/visualization.py,sha256=yaUVAOHar59VrGUjpAWv5eVvQSfztFG0eP9p5Vt3l-M,4470
25
- datamint-1.7.3.dist-info/METADATA,sha256=YTALWrY1wwiyjk2a-4FOx_LBxTKxd__QrchCCukTcDA,4090
26
- datamint-1.7.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
- datamint-1.7.3.dist-info/entry_points.txt,sha256=mn5H6jPjO-rY0W0CAZ6Z_KKWhMLvyVaSpoqk77jlTI4,145
28
- datamint-1.7.3.dist-info/RECORD,,
25
+ datamint-1.7.4.dist-info/METADATA,sha256=Fej5PDwzs3NQPuPf9ijJt0x57sY5f4Y9JGx_IEAwkX4,4100
26
+ datamint-1.7.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
27
+ datamint-1.7.4.dist-info/entry_points.txt,sha256=mn5H6jPjO-rY0W0CAZ6Z_KKWhMLvyVaSpoqk77jlTI4,145
28
+ datamint-1.7.4.dist-info/RECORD,,