synapse-sdk 1.0.0a77__py3-none-any.whl → 1.0.0a79__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 synapse-sdk might be problematic. Click here for more details.

@@ -82,4 +82,5 @@ class IntegrationClientMixin(BaseClient):
82
82
  def get_storage(self, pk):
83
83
  """Get specific storage data from synapse backend."""
84
84
  path = f'storages/{pk}/'
85
- return self._get(path, response_model=Storage)
85
+ params = {'with_configuration': True}
86
+ return self._get(path, params=params, response_model=Storage)
@@ -2,16 +2,25 @@ import json
2
2
  import os
3
3
  import shutil
4
4
  import uuid
5
+ from typing import IO
5
6
 
6
7
 
7
8
  class BaseConverter:
8
9
  """Base class for shared logic between converters."""
9
10
 
10
- def __init__(self, root_dir: str, is_categorized_dataset: bool = False) -> None:
11
+ def __init__(
12
+ self, root_dir: str = None, is_categorized_dataset: bool = False, is_single_conversion: bool = False
13
+ ) -> None:
11
14
  self.root_dir: str = root_dir
12
15
  self.is_categorized_dataset: bool = is_categorized_dataset
16
+ self.is_single_conversion: bool = is_single_conversion
13
17
  self.converted_data = None
14
18
 
19
+ # Set directories if single_conversion is False.
20
+ if not is_single_conversion:
21
+ if not root_dir:
22
+ raise ValueError('root_dir must be specified for conversion')
23
+
15
24
  @staticmethod
16
25
  def ensure_dir(path: str) -> None:
17
26
  """Ensure that the directory exists, creating it if necessary."""
@@ -55,6 +64,24 @@ class BaseConverter:
55
64
 
56
65
  return splits
57
66
 
67
+ def convert_single_file(self, data, original_file: IO, **kwargs):
68
+ """Convert a single data object and corresponding original file.
69
+
70
+ This method should be implemented by subclasses for single file conversion.
71
+ Only available when is_single_conversion=True.
72
+
73
+ Args:
74
+ data: The data object to convert (dict for JSON data, etc.)
75
+ original_file_path: File object for the corresponding original file
76
+ **kwargs: Additional parameters specific to each converter
77
+
78
+ Returns:
79
+ Converted data in the target format
80
+ """
81
+ if not self.is_single_conversion:
82
+ raise RuntimeError('convert_single_file is only available when is_single_conversion=True')
83
+ raise NotImplementedError('Subclasses must implement convert_single_file method')
84
+
58
85
  def _set_directories(self, split=None):
59
86
  """Set `self.json_dir` and `self.original_file_dir` based on the dataset split."""
60
87
  if split:
@@ -106,8 +133,10 @@ class FromDMConverter(BaseConverter):
106
133
  converter.save_to_folder('/my/target/output') # Writes files/folders to output location
107
134
  """
108
135
 
109
- def __init__(self, root_dir: str, is_categorized_dataset: bool = False) -> None:
110
- super().__init__(root_dir, is_categorized_dataset)
136
+ def __init__(
137
+ self, root_dir: str = None, is_categorized_dataset: bool = False, is_single_conversion: bool = False
138
+ ) -> None:
139
+ super().__init__(root_dir, is_categorized_dataset, is_single_conversion)
111
140
  self.version: str = '1.0'
112
141
 
113
142
  def convert(self):
@@ -2,7 +2,7 @@ import json
2
2
  import os
3
3
  import shutil
4
4
  from glob import glob
5
- from typing import Any, Dict, List, Optional, Union
5
+ from typing import IO, Any, Dict, List, Optional, Union
6
6
 
7
7
  from PIL import Image
8
8
 
@@ -14,8 +14,8 @@ class FromDMToYOLOConverter(FromDMConverter):
14
14
 
15
15
  IMG_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.bmp']
16
16
 
17
- def __init__(self, root_dir: str, is_categorized_dataset: bool = False):
18
- super().__init__(root_dir, is_categorized_dataset)
17
+ def __init__(self, root_dir: str = None, is_categorized_dataset: bool = False, is_single_conversion: bool = False):
18
+ super().__init__(root_dir, is_categorized_dataset, is_single_conversion)
19
19
  self.class_names: List[str] = []
20
20
  self.class_map: Dict[str, int] = {}
21
21
  self.dataset_yaml_content: str = ''
@@ -300,3 +300,85 @@ class FromDMToYOLOConverter(FromDMConverter):
300
300
  for c in self.class_names:
301
301
  f.write(f'{c}\n')
302
302
  print(f'YOLO data exported to {output_dir}')
303
+
304
+ def convert_single_file(
305
+ self, data: Dict[str, Any], original_file: IO, class_names: Optional[List[str]] = None
306
+ ) -> Dict[str, Any]:
307
+ """Convert a single DM data dict and corresponding image file object to YOLO format.
308
+
309
+ Args:
310
+ data: DM format data dictionary (JSON content)
311
+ original_file: File object for the corresponding original image
312
+ class_names: Optional list of class names. If not provided, classes will be extracted from data.
313
+
314
+ Returns:
315
+ Dictionary containing YOLO format data for the single file
316
+ """
317
+ if not self.is_single_conversion:
318
+ raise RuntimeError('convert_single_file is only available when is_single_conversion=True')
319
+
320
+ if class_names is None:
321
+ classes = set()
322
+ for img_ann in data['images']:
323
+ for k in ['bounding_box', 'polygon', 'keypoint']:
324
+ if k in img_ann:
325
+ for ann in img_ann[k]:
326
+ classes.add(ann['classification'])
327
+ class_names = sorted(list(classes))
328
+
329
+ class_map = {name: idx for idx, name in enumerate(class_names)}
330
+ # You need to update get_image_size to accept a file object
331
+ width, height = self.get_image_size(original_file)
332
+
333
+ img_ann = data['images'][0]
334
+ label_lines = []
335
+
336
+ # bbox
337
+ if 'bounding_box' in img_ann:
338
+ for box in img_ann['bounding_box']:
339
+ if box['classification'] not in class_map:
340
+ continue
341
+ cidx = class_map[box['classification']]
342
+ x, y, w, h = box['data']
343
+ cx = x + w / 2
344
+ cy = y + h / 2
345
+ cx /= width
346
+ cy /= height
347
+ w /= width
348
+ h /= height
349
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}')
350
+
351
+ # polygon
352
+ if 'polygon' in img_ann:
353
+ for poly in img_ann['polygon']:
354
+ if poly['classification'] not in class_map:
355
+ continue
356
+ cidx = class_map[poly['classification']]
357
+ poly_str = self.polygon_to_yolo_string(poly['data'], width, height)
358
+ if poly_str:
359
+ label_lines.append(f'{cidx} {poly_str}')
360
+
361
+ # keypoint
362
+ if 'keypoint' in img_ann:
363
+ for kp in img_ann['keypoint']:
364
+ if kp['classification'] not in class_map:
365
+ continue
366
+ cidx = class_map[kp['classification']]
367
+ if 'bounding_box' in kp:
368
+ x, y, w, h = kp['bounding_box']
369
+ cx = x + w / 2
370
+ cy = y + h / 2
371
+ cx /= width
372
+ cy /= height
373
+ w /= width
374
+ h /= height
375
+ else:
376
+ cx, cy, w, h = 0.5, 0.5, 1.0, 1.0
377
+ kp_str = self.keypoints_to_yolo_string(kp['data'], width, height)
378
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f} {kp_str}')
379
+
380
+ return {
381
+ 'label_lines': label_lines,
382
+ 'class_names': class_names,
383
+ 'class_map': class_map,
384
+ }
@@ -12,6 +12,9 @@ class YOLOToDMConverter(ToDMConverter):
12
12
 
13
13
  IMG_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.bmp']
14
14
 
15
+ def __init__(self, root_dir: str = None, is_categorized_dataset: bool = False, is_single_conversion: bool = False):
16
+ super().__init__(root_dir, is_categorized_dataset, is_single_conversion)
17
+
15
18
  def convert(self):
16
19
  """Convert YOLO dataset to DM format."""
17
20
  if self.is_categorized_dataset:
@@ -183,3 +186,69 @@ class YOLOToDMConverter(ToDMConverter):
183
186
  dm_json = {'images': [dm_img]}
184
187
  result[os.path.basename(img_path)] = (dm_json, img_path)
185
188
  return result
189
+
190
+ def convert_single_file(self, data: List[str], original_file_path: str, class_names: List[str]) -> Dict[str, Any]:
191
+ """Convert a single YOLO label data and corresponding image to DM format.
192
+
193
+ Args:
194
+ data: List of YOLO label lines (strings from .txt file content)
195
+ original_file_path: Path to the corresponding original file
196
+ class_names: List of class names corresponding to indices in the label data
197
+
198
+ Returns:
199
+ Dictionary containing DM format data for the single file
200
+ """
201
+ if not self.is_single_conversion:
202
+ raise RuntimeError('convert_single_file is only available when is_single_conversion=True')
203
+
204
+ if not os.path.exists(original_file_path):
205
+ raise FileNotFoundError(f'Original file not found: {original_file_path}')
206
+
207
+ img_size = self._get_image_size(original_file_path)
208
+
209
+ # data is already a list of label lines
210
+ label_lines = [line.strip() for line in data if line.strip()]
211
+
212
+ # Prepare DM annotation structure
213
+ dm_img = {
214
+ 'bounding_box': [],
215
+ 'polygon': [],
216
+ 'keypoint': [],
217
+ 'relation': [],
218
+ 'group': [],
219
+ }
220
+
221
+ for line in label_lines:
222
+ ann = self._parse_yolo_line(line, class_names, img_size)
223
+ if ann is None:
224
+ continue
225
+
226
+ if ann['type'] == 'bounding_box':
227
+ dm_img['bounding_box'].append({
228
+ 'id': self._generate_unique_id(),
229
+ 'classification': ann['classification'],
230
+ 'attrs': [],
231
+ 'data': ann['data'],
232
+ })
233
+ elif ann['type'] == 'polygon':
234
+ dm_img['polygon'].append({
235
+ 'id': self._generate_unique_id(),
236
+ 'classification': ann['classification'],
237
+ 'attrs': [],
238
+ 'data': ann['data'],
239
+ })
240
+ elif ann['type'] == 'keypoint':
241
+ dm_img['keypoint'].append({
242
+ 'id': self._generate_unique_id(),
243
+ 'classification': ann['classification'],
244
+ 'attrs': [],
245
+ 'data': ann['data'],
246
+ 'bounding_box': ann['bounding_box'],
247
+ })
248
+
249
+ dm_json = {'images': [dm_img]}
250
+ return {
251
+ 'dm_json': dm_json,
252
+ 'image_path': original_file_path,
253
+ 'image_name': os.path.basename(original_file_path),
254
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: synapse-sdk
3
- Version: 1.0.0a77
3
+ Version: 1.0.0a79
4
4
  Summary: synapse sdk
5
5
  Author-email: datamaker <developer@datamaker.io>
6
6
  License: MIT
@@ -35,7 +35,7 @@ synapse_sdk/clients/backend/annotation.py,sha256=4MfX_ubDw6UxU_TFEWLqjqOT1lS8RYD
35
35
  synapse_sdk/clients/backend/core.py,sha256=5XAOdo6JZ0drfk-FMPJ96SeTd9oja-VnTwzGXdvK7Bg,1027
36
36
  synapse_sdk/clients/backend/data_collection.py,sha256=uI-_ByLh-Xez4VIIVRBO8FCNUpDcxhBcLxCVFb_aG7o,4104
37
37
  synapse_sdk/clients/backend/hitl.py,sha256=na2mSXFud92p4zUEuagcDWk2klxO7xn-e86cm0VZEvs,709
38
- synapse_sdk/clients/backend/integration.py,sha256=9LjkYcBpi7aog-MODSDS4RlmYahypu65qxBj-AcY7xc,2683
38
+ synapse_sdk/clients/backend/integration.py,sha256=IdjPkllvHJ_vASHSmxsWO3CRlZz2L4eWkMOch7bHWok,2744
39
39
  synapse_sdk/clients/backend/ml.py,sha256=JoPH9Ly2E3HJ7S5mdGLtcGq7ruQVVrYfWArogwZLlms,1193
40
40
  synapse_sdk/clients/backend/models.py,sha256=Bd8UHPcn_AZWbhLkOKs93QljHBYtWV3g1EfLQfdpu7k,2058
41
41
  synapse_sdk/clients/ray/__init__.py,sha256=9ZSPXVVxlJ8Wp8ku7l021ENtPjVrGgQDgqifkkVAXgM,187
@@ -196,7 +196,7 @@ synapse_sdk/utils/http.py,sha256=yRxYfru8tMnBVeBK-7S0Ga13yOf8oRHquG5e8K_FWcI,475
196
196
  synapse_sdk/utils/module_loading.py,sha256=chHpU-BZjtYaTBD_q0T7LcKWtqKvYBS4L0lPlKkoMQ8,1020
197
197
  synapse_sdk/utils/network.py,sha256=WI8qn6KlKpHdMi45V57ofKJB8zusJrbQsxT74LwVfsY,1000
198
198
  synapse_sdk/utils/string.py,sha256=rEwuZ9SAaZLcQ8TYiwNKr1h2u4CfnrQx7SUL8NWmChg,216
199
- synapse_sdk/utils/converters/__init__.py,sha256=RysXR5z_hOZBSYuqV0w-MACMY2-HupTqAYdw1nuNW_Q,10053
199
+ synapse_sdk/utils/converters/__init__.py,sha256=xQi_n7xS9BNyDiolsxH2jw1CtD6avxMPj2cHnwvidi8,11311
200
200
  synapse_sdk/utils/converters/coco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
201
201
  synapse_sdk/utils/converters/coco/from_dm.py,sha256=78aJ_O2_hmkQQ96nrjHY38roETWfBZB8GRHDn7qKEls,9626
202
202
  synapse_sdk/utils/converters/coco/to_dm.py,sha256=Ve8LrcKVlzNysam3fidcgP5fdm0_UGbBgSPoj2dT_JA,4906
@@ -207,8 +207,8 @@ synapse_sdk/utils/converters/pascal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
207
207
  synapse_sdk/utils/converters/pascal/from_dm.py,sha256=PvP70jvzCbUKJg49BikgSpc5qb7nvVvfDDFmf1oPJWc,8497
208
208
  synapse_sdk/utils/converters/pascal/to_dm.py,sha256=RBMlVOdc7ev7jEWj7eyoNoO_1cpdhrJ7LhJqaboxBS4,5751
209
209
  synapse_sdk/utils/converters/yolo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
210
- synapse_sdk/utils/converters/yolo/from_dm.py,sha256=ppvIt4uceLlkBE7ybc0xhS_C6pK9knso-qWEjeqDMXM,12858
211
- synapse_sdk/utils/converters/yolo/to_dm.py,sha256=2llBYSEMwvvnECcb1nn7p_UXg6Krr3Za5RicVkYRlGI,7531
210
+ synapse_sdk/utils/converters/yolo/from_dm.py,sha256=-JDCQLk4g1_FIVoOwZ1Tcs2kWFkhXRCAPVLKLXz6sLU,16180
211
+ synapse_sdk/utils/converters/yolo/to_dm.py,sha256=yRCcgnLbejga1cyAVflY4SBXeYYcbK0b8DiNllPb0so,10275
212
212
  synapse_sdk/utils/pydantic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
213
213
  synapse_sdk/utils/pydantic/config.py,sha256=1vYOcUI35GslfD1rrqhFkNXXJOXt4IDqOPSx9VWGfNE,123
214
214
  synapse_sdk/utils/pydantic/errors.py,sha256=0v0T12eQBr1KrFiEOBu6KMaPK4aPEGEC6etPJGoR5b4,1061
@@ -220,9 +220,9 @@ synapse_sdk/utils/storage/providers/gcp.py,sha256=i2BQCu1Kej1If9SuNr2_lEyTcr5M_n
220
220
  synapse_sdk/utils/storage/providers/http.py,sha256=2DhIulND47JOnS5ZY7MZUex7Su3peAPksGo1Wwg07L4,5828
221
221
  synapse_sdk/utils/storage/providers/s3.py,sha256=ZmqekAvIgcQBdRU-QVJYv1Rlp6VHfXwtbtjTSphua94,2573
222
222
  synapse_sdk/utils/storage/providers/sftp.py,sha256=_8s9hf0JXIO21gvm-JVS00FbLsbtvly4c-ETLRax68A,1426
223
- synapse_sdk-1.0.0a77.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
224
- synapse_sdk-1.0.0a77.dist-info/METADATA,sha256=zNj-Z1w6d0xO7AcphTa0fU0zeN_9pTuKct48zs6m_kA,3805
225
- synapse_sdk-1.0.0a77.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
226
- synapse_sdk-1.0.0a77.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
227
- synapse_sdk-1.0.0a77.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
228
- synapse_sdk-1.0.0a77.dist-info/RECORD,,
223
+ synapse_sdk-1.0.0a79.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
224
+ synapse_sdk-1.0.0a79.dist-info/METADATA,sha256=ZpqySA8CqPd1Guvz_q0z8xqNrrrz1mKSVNukdAnNiwU,3805
225
+ synapse_sdk-1.0.0a79.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
226
+ synapse_sdk-1.0.0a79.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
227
+ synapse_sdk-1.0.0a79.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
228
+ synapse_sdk-1.0.0a79.dist-info/RECORD,,