synapse-sdk 1.0.0a71__py3-none-any.whl → 1.0.0a72__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.

@@ -67,9 +67,11 @@ class ToTaskParams(BaseModel):
67
67
  name (str): The name of the action.
68
68
  description (str | None): The description of the action.
69
69
  project (int): The project ID.
70
+ agent (int): The agent ID.
70
71
  task_filters (dict): The filters of tasks.
71
72
  method (AnnotationMethod): The method of annotation.
72
73
  target_specification_name (str | None): The name of the target specification.
74
+ model (int): The model ID.
73
75
  pre_processor (int | None): The pre processor ID.
74
76
  pre_processor_params (dict): The params of the pre processor.
75
77
  """
@@ -77,9 +79,11 @@ class ToTaskParams(BaseModel):
77
79
  name: Annotated[str, AfterValidator(non_blank)]
78
80
  description: Optional[str] = None
79
81
  project: int
82
+ agent: int
80
83
  task_filters: Dict[str, Any]
81
84
  method: Optional[AnnotationMethod] = None
82
85
  target_specification_name: Optional[str] = None
86
+ model: Optional[int] = None
83
87
  pre_processor: Optional[int] = None
84
88
  pre_processor_params: Dict[str, Any]
85
89
 
@@ -48,7 +48,7 @@ class BaseConverter:
48
48
  else:
49
49
  required_dirs = {
50
50
  'json': os.path.join(self.root_dir, 'json'),
51
- 'original_file': os.path.join(self.root_dir, 'original_file'),
51
+ 'original_files': os.path.join(self.root_dir, 'original_files'),
52
52
  }
53
53
  self._validate_required_dirs(required_dirs)
54
54
  splits['root'] = self.root_dir
@@ -60,10 +60,10 @@ class BaseConverter:
60
60
  if split:
61
61
  split_dir = os.path.join(self.root_dir, split)
62
62
  self.json_dir = os.path.join(split_dir, 'json')
63
- self.original_file_dir = os.path.join(split_dir, 'original_file')
63
+ self.original_file_dir = os.path.join(split_dir, 'original_files')
64
64
  else:
65
65
  self.json_dir = os.path.join(self.root_dir, 'json')
66
- self.original_file_dir = os.path.join(self.root_dir, 'original_file')
66
+ self.original_file_dir = os.path.join(self.root_dir, 'original_files')
67
67
 
68
68
 
69
69
  class FromDMConverter(BaseConverter):
@@ -185,7 +185,7 @@ class ToDMConverter(BaseConverter):
185
185
  for split, img_dict in self.converted_data.items():
186
186
  split_dir = os.path.join(output_dir, split)
187
187
  json_dir = os.path.join(split_dir, 'json')
188
- original_file_dir = os.path.join(split_dir, 'original_file')
188
+ original_file_dir = os.path.join(split_dir, 'original_files')
189
189
  self.ensure_dir(json_dir)
190
190
  self.ensure_dir(original_file_dir)
191
191
  for img_filename, (dm_json, img_src_path) in img_dict.items():
@@ -196,7 +196,7 @@ class ToDMConverter(BaseConverter):
196
196
  shutil.copy(img_src_path, os.path.join(original_file_dir, img_filename))
197
197
  else:
198
198
  json_dir = os.path.join(output_dir, 'json')
199
- original_file_dir = os.path.join(output_dir, 'original_file')
199
+ original_file_dir = os.path.join(output_dir, 'original_files')
200
200
  self.ensure_dir(json_dir)
201
201
  self.ensure_dir(original_file_dir)
202
202
  for img_filename, (dm_json, img_src_path) in self.converted_data.items():
@@ -205,4 +205,5 @@ class ToDMConverter(BaseConverter):
205
205
  json.dump(dm_json, jf, indent=2, ensure_ascii=False)
206
206
  if img_src_path and os.path.exists(img_src_path):
207
207
  shutil.copy(img_src_path, os.path.join(original_file_dir, img_filename))
208
+
208
209
  print(f'[DM] Data exported to {output_dir}')
@@ -11,7 +11,7 @@ from tqdm import tqdm
11
11
  from synapse_sdk.utils.converters import FromDMConverter
12
12
 
13
13
 
14
- class DMToCOCOConverter(FromDMConverter):
14
+ class FromDMToCOCOConverter(FromDMConverter):
15
15
  """Convert DM (Data Manager) format annotations to COCO format.
16
16
  Designed for easy future extensibility to handle various data types.
17
17
  """
@@ -242,11 +242,11 @@ class DMToCOCOConverter(FromDMConverter):
242
242
  for split, coco_data in self.converted_data.items():
243
243
  split_output_dir = os.path.join(output_dir, split)
244
244
  self._save_annotations_and_images(
245
- coco_data, split_output_dir, os.path.join(self.root_dir, split, 'original_file')
245
+ coco_data, split_output_dir, os.path.join(self.root_dir, split, 'original_files')
246
246
  )
247
247
  else:
248
248
  self._save_annotations_and_images(
249
- self.converted_data, output_dir, os.path.join(self.root_dir, 'original_file')
249
+ self.converted_data, output_dir, os.path.join(self.root_dir, 'original_files')
250
250
  )
251
251
 
252
252
  def _save_annotations_and_images(self, coco_data, output_dir, original_file_dir):
File without changes
@@ -0,0 +1,296 @@
1
+ import json
2
+ import os
3
+ import shutil
4
+ from glob import glob
5
+ from typing import Any, Dict, List, Optional, Union
6
+
7
+ from PIL import Image
8
+
9
+ from synapse_sdk.utils.converters import FromDMConverter
10
+
11
+
12
+ class FromDMToYOLOConverter(FromDMConverter):
13
+ """Convert DM dataset format to YOLO format."""
14
+
15
+ IMG_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.bmp']
16
+
17
+ def __init__(self, root_dir: str, is_categorized_dataset: bool = False):
18
+ super().__init__(root_dir, is_categorized_dataset)
19
+ self.class_names: List[str] = []
20
+ self.class_map: Dict[str, int] = {}
21
+ self.dataset_yaml_content: str = ''
22
+
23
+ @staticmethod
24
+ def get_all_classes(list_of_dirs: List[str]) -> List[str]:
25
+ """Collect all unique class names from all splits or the root."""
26
+ classes = set()
27
+ for d in list_of_dirs:
28
+ if not d or not os.path.isdir(d):
29
+ continue
30
+ json_dir = os.path.join(d, 'json') if os.path.isdir(os.path.join(d, 'json')) else d
31
+ for jfile in glob(os.path.join(json_dir, '*.json')):
32
+ with open(jfile, encoding='utf-8') as jf:
33
+ data = json.load(jf)
34
+ for img_ann in data['images']:
35
+ for k in ['bounding_box', 'polygon', 'keypoint']:
36
+ if k in img_ann:
37
+ for ann in img_ann[k]:
38
+ classes.add(ann['classification'])
39
+ return sorted(list(classes))
40
+
41
+ @staticmethod
42
+ def get_image_size(image_path: str):
43
+ with Image.open(image_path) as img:
44
+ return img.size
45
+
46
+ @staticmethod
47
+ def polygon_to_bbox(polygon: list):
48
+ """Convert polygon points to bounding box [cx, cy, w, h]."""
49
+ if not polygon or len(polygon) == 0:
50
+ return None
51
+ xs = [p[0] for p in polygon]
52
+ ys = [p[1] for p in polygon]
53
+ x_min, y_min = min(xs), min(ys)
54
+ x_max, y_max = max(xs), max(ys)
55
+ cx = (x_min + x_max) / 2
56
+ cy = (y_min + y_max) / 2
57
+ w = x_max - x_min
58
+ h = y_max - y_min
59
+ return [cx, cy, w, h]
60
+
61
+ @staticmethod
62
+ def keypoints_to_yolo_string(keypoints: list, width: int, height: int):
63
+ """Convert keypoints to normalized YOLO keypoint format string (x1 y1 v1 x2 y2 v2 ...)."""
64
+ kp_strs = []
65
+ for kp in keypoints:
66
+ # kp: [x, y, visible]
67
+ x, y, v = kp
68
+ x = x / width
69
+ y = y / height
70
+ kp_strs.extend([f'{x:.6f}', f'{y:.6f}', str(v)])
71
+ return ' '.join(kp_strs)
72
+
73
+ def _convert_split_dir(self, split_dir: str, split_name: str) -> List[Dict[str, Any]]:
74
+ """Convert one split folder to YOLO format."""
75
+ if not self.class_map:
76
+ raise ValueError('class_map is not initialized. Ensure get_all_classes() is called before this method.')
77
+
78
+ json_dir = os.path.join(split_dir, 'json')
79
+ img_dir = os.path.join(split_dir, 'original_files')
80
+ entries = []
81
+ for jfile in glob(os.path.join(json_dir, '*.json')):
82
+ base = os.path.splitext(os.path.basename(jfile))[0]
83
+ found_img = None
84
+ for ext in self.IMG_EXTENSIONS:
85
+ img_path = os.path.join(img_dir, base + ext)
86
+ if os.path.exists(img_path):
87
+ found_img = img_path
88
+ break
89
+ if not found_img:
90
+ print(f'[{split_name}] Image for {base} not found, skipping.')
91
+ continue
92
+ width, height = self.get_image_size(found_img)
93
+ with open(jfile, encoding='utf-8') as jf:
94
+ data = json.load(jf)
95
+ img_ann = data['images'][0]
96
+ label_lines = []
97
+
98
+ # bbox
99
+ if 'bounding_box' in img_ann:
100
+ for box in img_ann['bounding_box']:
101
+ cidx = self.class_map[box['classification']]
102
+ x, y, w, h = box['data']
103
+ cx = x + w / 2
104
+ cy = y + h / 2
105
+ cx /= width
106
+ cy /= height
107
+ w /= width
108
+ h /= height
109
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}')
110
+
111
+ # polygon
112
+ if 'polygon' in img_ann:
113
+ for poly in img_ann['polygon']:
114
+ cidx = self.class_map[poly['classification']]
115
+ bbox = self.polygon_to_bbox(poly['data'])
116
+ if bbox is None:
117
+ print(f'[{split_name}] Polygon for {base} is empty, skipping this polygon.')
118
+ continue
119
+ cx, cy, w, h = bbox
120
+ cx /= width
121
+ cy /= height
122
+ w /= width
123
+ h /= height
124
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}')
125
+
126
+ # keypoint
127
+ if 'keypoint' in img_ann:
128
+ for kp in img_ann['keypoint']:
129
+ cidx = self.class_map[kp['classification']]
130
+ # Assume bounding box exists for keypoint, or fallback to full image
131
+ if 'bounding_box' in kp:
132
+ x, y, w, h = kp['bounding_box']
133
+ cx = x + w / 2
134
+ cy = y + h / 2
135
+ cx /= width
136
+ cy /= height
137
+ w /= width
138
+ h /= height
139
+ else:
140
+ # fallback to the whole image
141
+ cx, cy, w, h = 0.5, 0.5, 1.0, 1.0
142
+ kp_str = self.keypoints_to_yolo_string(kp['data'], width, height)
143
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f} {kp_str}')
144
+
145
+ entries.append({
146
+ 'img_path': found_img,
147
+ 'img_name': os.path.basename(found_img),
148
+ 'label_name': base + '.txt',
149
+ 'label_lines': label_lines,
150
+ })
151
+ return entries
152
+
153
+ def _convert_root_dir(self) -> List[Dict[str, Any]]:
154
+ """Convert non-categorized dataset to YOLO format."""
155
+ json_dir = os.path.join(self.root_dir, 'json')
156
+ img_dir = os.path.join(self.root_dir, 'original_files')
157
+ entries = []
158
+ for jfile in glob(os.path.join(json_dir, '*.json')):
159
+ base = os.path.splitext(os.path.basename(jfile))[0]
160
+ found_img = None
161
+ for ext in self.IMG_EXTENSIONS:
162
+ img_path = os.path.join(img_dir, base + ext)
163
+ if os.path.exists(img_path):
164
+ found_img = img_path
165
+ break
166
+ if not found_img:
167
+ print(f'[single] Image for {base} not found, skipping.')
168
+ continue
169
+ width, height = self.get_image_size(found_img)
170
+ with open(jfile, encoding='utf-8') as jf:
171
+ data = json.load(jf)
172
+ img_ann = data['images'][0]
173
+ label_lines = []
174
+
175
+ # bbox
176
+ if 'bounding_box' in img_ann:
177
+ for box in img_ann['bounding_box']:
178
+ cidx = self.class_map[box['classification']]
179
+ x, y, w, h = box['data']
180
+ cx = x + w / 2
181
+ cy = y + h / 2
182
+ cx /= width
183
+ cy /= height
184
+ w /= width
185
+ h /= height
186
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}')
187
+
188
+ # polygon
189
+ if 'polygon' in img_ann:
190
+ for poly in img_ann['polygon']:
191
+ cidx = self.class_map[poly['classification']]
192
+ bbox = self.polygon_to_bbox(poly['data'])
193
+ if bbox is None:
194
+ print(f'[single] Polygon for {base} is empty, skipping this polygon.')
195
+ continue
196
+ cx, cy, w, h = bbox
197
+ cx /= width
198
+ cy /= height
199
+ w /= width
200
+ h /= height
201
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}')
202
+
203
+ # keypoint
204
+ if 'keypoint' in img_ann:
205
+ for kp in img_ann['keypoint']:
206
+ cidx = self.class_map[kp['classification']]
207
+ if 'bounding_box' in kp:
208
+ x, y, w, h = kp['bounding_box']
209
+ cx = x + w / 2
210
+ cy = y + h / 2
211
+ cx /= width
212
+ cy /= height
213
+ w /= width
214
+ h /= height
215
+ else:
216
+ cx, cy, w, h = 0.5, 0.5, 1.0, 1.0
217
+ kp_str = self.keypoints_to_yolo_string(kp['data'], width, height)
218
+ label_lines.append(f'{cidx} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f} {kp_str}')
219
+
220
+ entries.append({
221
+ 'img_path': found_img,
222
+ 'img_name': os.path.basename(found_img),
223
+ 'label_name': base + '.txt',
224
+ 'label_lines': label_lines,
225
+ })
226
+ return entries
227
+
228
+ def convert(self) -> Union[Dict[str, List[Dict[str, Any]]], List[Dict[str, Any]]]:
229
+ """Convert DM format to YOLO format (categorized split or not).
230
+
231
+ Returns:
232
+ - If categorized: dict {split: list of entries}
233
+ - If not: list of entries
234
+ """
235
+ # Prepare dataset.yaml content (for save_to_folder)
236
+ yaml_lines = [
237
+ 'path: ' + self.root_dir,
238
+ ]
239
+
240
+ if self.is_categorized_dataset:
241
+ splits = self._validate_splits(required_splits=['train', 'valid'], optional_splits=['test'])
242
+ self.class_names = self.get_all_classes(list(splits.values()))
243
+ self.class_map = {name: idx for idx, name in enumerate(self.class_names)}
244
+ result = {}
245
+ for split, split_dir in splits.items():
246
+ result[split] = self._convert_split_dir(split_dir, split)
247
+ self.converted_data = result
248
+
249
+ yaml_lines.append('train: train/images')
250
+ yaml_lines.append('val: valid/images')
251
+ if 'test' in splits:
252
+ yaml_lines.append('test: test/images')
253
+ else:
254
+ self._validate_splits(required_splits=[], optional_splits=[])
255
+ self.class_names = self.get_all_classes([self.root_dir])
256
+ self.class_map = {name: idx for idx, name in enumerate(self.class_names)}
257
+ result = self._convert_root_dir()
258
+ self.converted_data = result
259
+
260
+ yaml_lines += ['', f'nc: {len(self.class_names)}', f'names: {self.class_names}', '']
261
+ self.dataset_yaml_content = '\n'.join(yaml_lines)
262
+ return result
263
+
264
+ def save_to_folder(self, output_dir: Optional[str] = None) -> None:
265
+ """Save converted YOLO data to the specified folder."""
266
+ output_dir = output_dir or self.root_dir
267
+ self.ensure_dir(output_dir)
268
+ if self.converted_data is None:
269
+ self.converted_data = self.convert()
270
+
271
+ if self.is_categorized_dataset:
272
+ for split, entries in self.converted_data.items():
273
+ split_imgs = os.path.join(output_dir, split, 'images')
274
+ split_labels = os.path.join(output_dir, split, 'labels')
275
+ self.ensure_dir(split_imgs)
276
+ self.ensure_dir(split_labels)
277
+ for entry in entries:
278
+ shutil.copy(entry['img_path'], os.path.join(split_imgs, entry['img_name']))
279
+ with open(os.path.join(split_labels, entry['label_name']), 'w', encoding='utf-8') as f:
280
+ f.write('\n'.join(entry['label_lines']))
281
+ else:
282
+ imgs_dir = os.path.join(output_dir, 'images')
283
+ labels_dir = os.path.join(output_dir, 'labels')
284
+ self.ensure_dir(imgs_dir)
285
+ self.ensure_dir(labels_dir)
286
+ for entry in self.converted_data:
287
+ shutil.copy(entry['img_path'], os.path.join(imgs_dir, entry['img_name']))
288
+ with open(os.path.join(labels_dir, entry['label_name']), 'w', encoding='utf-8') as f:
289
+ f.write('\n'.join(entry['label_lines']))
290
+
291
+ with open(os.path.join(output_dir, 'dataset.yaml'), 'w', encoding='utf-8') as f:
292
+ f.write(self.dataset_yaml_content)
293
+ with open(os.path.join(output_dir, 'classes.txt'), 'w', encoding='utf-8') as f:
294
+ for c in self.class_names:
295
+ f.write(f'{c}\n')
296
+ print(f'YOLO data exported to {output_dir}')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: synapse-sdk
3
- Version: 1.0.0a71
3
+ Version: 1.0.0a72
4
4
  Summary: synapse sdk
5
5
  Author-email: datamaker <developer@datamaker.io>
6
6
  License: MIT
@@ -153,7 +153,7 @@ synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.
153
153
  synapse_sdk/plugins/categories/pre_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
154
  synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
155
155
  synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py,sha256=6ib3RmnGrjpsQ0e_G-mRH1lfFunQ3gh2M831vuDn7HU,344
156
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py,sha256=JlFO2vydZ_rgLq_6lZc7-TvmVHGGZLEXkTrVR_TfQXM,23214
156
+ synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py,sha256=7w7CLHrsOjVC_qBjaPA1Vz2L0jyRFNsg05pS72cAr7Y,23331
157
157
  synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml,sha256=4SKJe2gF8UCi3oD0kV8B4M2MkYcosz5GZzzAjAg3slc,508
158
158
  synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
159
  synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py,sha256=HBHxHuv2gMBzDB2alFfrzI_SZ1Ztk6mo7eFbR5GqHKw,106
@@ -192,10 +192,12 @@ synapse_sdk/utils/http.py,sha256=yRxYfru8tMnBVeBK-7S0Ga13yOf8oRHquG5e8K_FWcI,475
192
192
  synapse_sdk/utils/module_loading.py,sha256=chHpU-BZjtYaTBD_q0T7LcKWtqKvYBS4L0lPlKkoMQ8,1020
193
193
  synapse_sdk/utils/network.py,sha256=WI8qn6KlKpHdMi45V57ofKJB8zusJrbQsxT74LwVfsY,1000
194
194
  synapse_sdk/utils/string.py,sha256=rEwuZ9SAaZLcQ8TYiwNKr1h2u4CfnrQx7SUL8NWmChg,216
195
- synapse_sdk/utils/converters/__init__.py,sha256=7Lc8PeHGKKRlfhIyBbWXa258ha6qOcZCywGleFwD47E,9919
195
+ synapse_sdk/utils/converters/__init__.py,sha256=jy-BxGUe1NOxQ0g8s9HNoPSYM2Xeq4Rd0vk8HDvFOhs,9926
196
196
  synapse_sdk/utils/converters/coco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
- synapse_sdk/utils/converters/coco/from_dm.py,sha256=GH_y0zOYczbwByDusC4JiBl1M3utxpBYit7E_px7F-U,9620
197
+ synapse_sdk/utils/converters/coco/from_dm.py,sha256=78aJ_O2_hmkQQ96nrjHY38roETWfBZB8GRHDn7qKEls,9626
198
198
  synapse_sdk/utils/converters/coco/to_dm.py,sha256=Ve8LrcKVlzNysam3fidcgP5fdm0_UGbBgSPoj2dT_JA,4906
199
+ synapse_sdk/utils/converters/yolo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
200
+ synapse_sdk/utils/converters/yolo/from_dm.py,sha256=e9u4CM4gWnh9_EzYiA-EqL8RICZo5NafWXzaqnrIrdU,12600
199
201
  synapse_sdk/utils/pydantic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
200
202
  synapse_sdk/utils/pydantic/config.py,sha256=1vYOcUI35GslfD1rrqhFkNXXJOXt4IDqOPSx9VWGfNE,123
201
203
  synapse_sdk/utils/pydantic/errors.py,sha256=0v0T12eQBr1KrFiEOBu6KMaPK4aPEGEC6etPJGoR5b4,1061
@@ -207,9 +209,9 @@ synapse_sdk/utils/storage/providers/gcp.py,sha256=i2BQCu1Kej1If9SuNr2_lEyTcr5M_n
207
209
  synapse_sdk/utils/storage/providers/http.py,sha256=2DhIulND47JOnS5ZY7MZUex7Su3peAPksGo1Wwg07L4,5828
208
210
  synapse_sdk/utils/storage/providers/s3.py,sha256=ZmqekAvIgcQBdRU-QVJYv1Rlp6VHfXwtbtjTSphua94,2573
209
211
  synapse_sdk/utils/storage/providers/sftp.py,sha256=_8s9hf0JXIO21gvm-JVS00FbLsbtvly4c-ETLRax68A,1426
210
- synapse_sdk-1.0.0a71.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
211
- synapse_sdk-1.0.0a71.dist-info/METADATA,sha256=Evpxgx7r7pGE_VEOeBHGktT7mNqWbnj9kGuWgNVKilc,1130
212
- synapse_sdk-1.0.0a71.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
213
- synapse_sdk-1.0.0a71.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
214
- synapse_sdk-1.0.0a71.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
215
- synapse_sdk-1.0.0a71.dist-info/RECORD,,
212
+ synapse_sdk-1.0.0a72.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
213
+ synapse_sdk-1.0.0a72.dist-info/METADATA,sha256=1tbrM3SJ6aPgNShk_AEYZNYLZ2i8iencEXohtAvoVG0,1130
214
+ synapse_sdk-1.0.0a72.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
215
+ synapse_sdk-1.0.0a72.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
216
+ synapse_sdk-1.0.0a72.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
217
+ synapse_sdk-1.0.0a72.dist-info/RECORD,,