synapse-sdk 2025.9.5__py3-none-any.whl → 2025.10.6__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.
- synapse_sdk/clients/base.py +129 -9
- synapse_sdk/devtools/docs/docs/api/clients/base.md +230 -8
- synapse_sdk/devtools/docs/docs/api/plugins/models.md +58 -3
- synapse_sdk/devtools/docs/docs/plugins/categories/neural-net-plugins/train-action-overview.md +663 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-action.md +934 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-overview.md +585 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-template.md +715 -0
- synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +39 -0
- synapse_sdk/devtools/docs/docs/plugins/plugins.md +12 -5
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/base.md +230 -8
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/plugins/models.md +114 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/neural-net-plugins/train-action-overview.md +621 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-action.md +934 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-overview.md +585 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-template.md +715 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +39 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current.json +16 -4
- synapse_sdk/devtools/docs/sidebars.ts +45 -1
- synapse_sdk/plugins/README.md +487 -80
- synapse_sdk/plugins/categories/base.py +1 -0
- synapse_sdk/plugins/categories/export/actions/export/action.py +8 -3
- synapse_sdk/plugins/categories/export/actions/export/utils.py +108 -8
- synapse_sdk/plugins/categories/export/templates/config.yaml +18 -0
- synapse_sdk/plugins/categories/export/templates/plugin/export.py +97 -0
- synapse_sdk/plugins/categories/neural_net/actions/train.py +592 -22
- synapse_sdk/plugins/categories/neural_net/actions/tune.py +150 -3
- synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/action.py +10 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +145 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +97 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +250 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +284 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +87 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +127 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
- synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +2 -1
- synapse_sdk/plugins/categories/upload/actions/upload/action.py +8 -1
- synapse_sdk/plugins/categories/upload/actions/upload/context.py +0 -1
- synapse_sdk/plugins/categories/upload/actions/upload/models.py +134 -94
- synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +2 -2
- synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +6 -2
- synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +24 -9
- synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +130 -18
- synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +147 -37
- synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +10 -5
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +31 -6
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +65 -37
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +17 -2
- synapse_sdk/plugins/categories/upload/templates/README.md +394 -0
- synapse_sdk/plugins/models.py +62 -0
- synapse_sdk/utils/file/download.py +261 -0
- {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/METADATA +15 -2
- {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/RECORD +74 -43
- synapse_sdk/devtools/docs/docs/plugins/developing-upload-template.md +0 -1463
- synapse_sdk/devtools/docs/docs/plugins/upload-plugins.md +0 -1964
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/developing-upload-template.md +0 -1463
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/upload-plugins.md +0 -2077
- {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/WHEEL +0 -0
- {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/top_level.txt +0 -0
synapse_sdk/clients/base.py
CHANGED
|
@@ -250,19 +250,139 @@ class BaseClient:
|
|
|
250
250
|
else:
|
|
251
251
|
return response
|
|
252
252
|
|
|
253
|
-
def _list(self, path, url_conversion=None, list_all=False, **kwargs):
|
|
254
|
-
|
|
253
|
+
def _list(self, path, url_conversion=None, list_all=False, params=None, **kwargs):
|
|
254
|
+
"""List resources from a paginated API endpoint.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
path (str): URL path to request.
|
|
258
|
+
url_conversion (dict, optional): Configuration for URL to path conversion.
|
|
259
|
+
Used to convert file URLs to local paths in the response.
|
|
260
|
+
Example: {'files_fields': ['files'], 'is_list': True}
|
|
261
|
+
This will convert file URLs in the 'files' field of each result.
|
|
262
|
+
list_all (bool): If True, returns a generator yielding all results across all pages.
|
|
263
|
+
Default is False, which returns only the first page.
|
|
264
|
+
params (dict, optional): Query parameters to pass to the request.
|
|
265
|
+
Example: {'status': 'active', 'project': 123}
|
|
266
|
+
**kwargs: Additional keyword arguments to pass to the request.
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
If list_all is False: dict response from the API containing:
|
|
270
|
+
- 'results': list of items on the current page
|
|
271
|
+
- 'count': total number of items
|
|
272
|
+
- 'next': URL to the next page (or None)
|
|
273
|
+
- 'previous': URL to the previous page (or None)
|
|
274
|
+
If list_all is True: tuple of (generator, count) where:
|
|
275
|
+
- generator: yields individual items from all pages
|
|
276
|
+
- count: total number of items across all pages
|
|
277
|
+
|
|
278
|
+
Examples:
|
|
279
|
+
Get first page only:
|
|
280
|
+
>>> response = client._list('api/tasks/')
|
|
281
|
+
>>> tasks = response['results'] # List of tasks on first page
|
|
282
|
+
>>> total_count = response['count'] # Total number of tasks
|
|
283
|
+
|
|
284
|
+
Get all results across all pages:
|
|
285
|
+
>>> generator, count = client._list('api/tasks/', list_all=True)
|
|
286
|
+
>>> all_tasks = list(generator) # Fetches all pages
|
|
287
|
+
|
|
288
|
+
With filters and url_conversion:
|
|
289
|
+
>>> url_conversion = {'files_fields': ['files'], 'is_list': True}
|
|
290
|
+
>>> params = {'status': 'active'}
|
|
291
|
+
>>> generator, count = client._list(
|
|
292
|
+
... 'api/data_units/',
|
|
293
|
+
... url_conversion=url_conversion,
|
|
294
|
+
... list_all=True,
|
|
295
|
+
... params=params
|
|
296
|
+
... )
|
|
297
|
+
>>> active_units = list(generator) # All active units with file URLs converted
|
|
298
|
+
"""
|
|
299
|
+
if params is None:
|
|
300
|
+
params = {}
|
|
301
|
+
|
|
255
302
|
if list_all:
|
|
256
|
-
|
|
303
|
+
response = self._get(path, params=params, **kwargs)
|
|
304
|
+
return self._list_all(path, url_conversion, params=params, **kwargs), response.get('count')
|
|
257
305
|
else:
|
|
306
|
+
response = self._get(path, params=params, **kwargs)
|
|
258
307
|
return response
|
|
259
308
|
|
|
260
|
-
def _list_all(self, path, url_conversion=None, params=
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
309
|
+
def _list_all(self, path, url_conversion=None, params=None, **kwargs):
|
|
310
|
+
"""Generator that yields all results from a paginated API endpoint.
|
|
311
|
+
|
|
312
|
+
This method handles pagination automatically by following the 'next' URLs
|
|
313
|
+
returned by the API until all pages have been fetched. It uses an iterative
|
|
314
|
+
approach (while loop) instead of recursion to avoid stack overflow with
|
|
315
|
+
deep pagination.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
path (str): Initial URL path to request.
|
|
319
|
+
url_conversion (dict, optional): Configuration for URL to path conversion.
|
|
320
|
+
Applied to all pages. Common structure:
|
|
321
|
+
- 'files_fields': List of field names containing file URLs
|
|
322
|
+
- 'is_list': Whether the response is a list (True for paginated results)
|
|
323
|
+
Example: {'files_fields': ['files', 'images'], 'is_list': True}
|
|
324
|
+
params (dict, optional): Query parameters for the first request only.
|
|
325
|
+
Subsequent requests use the 'next' URL which already includes
|
|
326
|
+
all necessary parameters. If 'page_size' is not specified,
|
|
327
|
+
it defaults to self.page_size (100).
|
|
328
|
+
Example: {'status': 'active', 'page_size': 50}
|
|
329
|
+
**kwargs: Additional keyword arguments to pass to requests.
|
|
330
|
+
Example: timeout, headers, etc.
|
|
331
|
+
|
|
332
|
+
Yields:
|
|
333
|
+
dict: Individual result items from all pages. Each item is yielded
|
|
334
|
+
as soon as it's fetched, allowing for memory-efficient processing
|
|
335
|
+
of large datasets.
|
|
336
|
+
|
|
337
|
+
Examples:
|
|
338
|
+
Basic usage - fetch all tasks:
|
|
339
|
+
>>> for task in client._list_all('api/tasks/'):
|
|
340
|
+
... process_task(task)
|
|
341
|
+
|
|
342
|
+
With filters:
|
|
343
|
+
>>> params = {'status': 'pending', 'priority': 'high'}
|
|
344
|
+
>>> for task in client._list_all('api/tasks/', params=params):
|
|
345
|
+
... print(task['id'])
|
|
346
|
+
|
|
347
|
+
With url_conversion for file fields:
|
|
348
|
+
>>> url_conversion = {'files_fields': ['files'], 'is_list': True}
|
|
349
|
+
>>> for data_unit in client._list_all('api/data_units/', url_conversion):
|
|
350
|
+
... # File URLs in 'files' field are converted to local paths
|
|
351
|
+
... print(data_unit['files'])
|
|
352
|
+
|
|
353
|
+
Collecting results into a list:
|
|
354
|
+
>>> all_tasks = list(client._list_all('api/tasks/'))
|
|
355
|
+
>>> print(f"Total tasks: {len(all_tasks)}")
|
|
356
|
+
|
|
357
|
+
Note:
|
|
358
|
+
- This is a generator function, so results are fetched lazily as you iterate
|
|
359
|
+
- The first page is fetched with the provided params
|
|
360
|
+
- Subsequent pages use the 'next' URL from the API response
|
|
361
|
+
- No duplicate page_size parameters are added to subsequent requests
|
|
362
|
+
- Memory efficient: processes one item at a time rather than loading all at once
|
|
363
|
+
"""
|
|
364
|
+
if params is None:
|
|
365
|
+
params = {}
|
|
366
|
+
|
|
367
|
+
# Set page_size only if not already specified by user
|
|
368
|
+
request_params = params.copy()
|
|
369
|
+
if 'page_size' not in request_params:
|
|
370
|
+
request_params['page_size'] = self.page_size
|
|
371
|
+
|
|
372
|
+
next_url = path
|
|
373
|
+
is_first_request = True
|
|
374
|
+
|
|
375
|
+
while next_url:
|
|
376
|
+
# First request uses params, subsequent requests use next URL directly
|
|
377
|
+
if is_first_request:
|
|
378
|
+
response = self._get(next_url, url_conversion, params=request_params, **kwargs)
|
|
379
|
+
is_first_request = False
|
|
380
|
+
else:
|
|
381
|
+
# next URL already contains all necessary query parameters
|
|
382
|
+
response = self._get(next_url, url_conversion, **kwargs)
|
|
383
|
+
|
|
384
|
+
yield from response['results']
|
|
385
|
+
next_url = response.get('next')
|
|
266
386
|
|
|
267
387
|
def exists(self, api, *args, **kwargs):
|
|
268
388
|
return getattr(self, api)(*args, **kwargs)['count'] > 0
|
|
@@ -6,30 +6,252 @@ sidebar_position: 3
|
|
|
6
6
|
|
|
7
7
|
# BaseClient
|
|
8
8
|
|
|
9
|
-
Base class for all Synapse SDK clients.
|
|
9
|
+
Base class for all Synapse SDK clients providing core HTTP operations and pagination.
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
|
-
The `BaseClient` provides common functionality for HTTP operations, error handling,
|
|
13
|
+
The `BaseClient` provides common functionality for HTTP operations, error handling, request management, and pagination used by all other clients. It implements efficient pagination handling with automatic file URL conversion capabilities.
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
17
|
- HTTP request handling with retry logic
|
|
18
18
|
- Automatic timeout management
|
|
19
|
-
-
|
|
19
|
+
- Efficient pagination with generators
|
|
20
|
+
- File URL to local path conversion
|
|
20
21
|
- Pydantic model validation
|
|
21
22
|
- Connection pooling
|
|
22
23
|
|
|
23
|
-
##
|
|
24
|
+
## Core HTTP Methods
|
|
25
|
+
|
|
26
|
+
The BaseClient provides low-level HTTP methods that are used internally by all client mixins:
|
|
27
|
+
|
|
28
|
+
- `_get()` - GET requests with optional response model validation
|
|
29
|
+
- `_post()` - POST requests with request/response validation
|
|
30
|
+
- `_put()` - PUT requests with model validation
|
|
31
|
+
- `_patch()` - PATCH requests with model validation
|
|
32
|
+
- `_delete()` - DELETE requests with model validation
|
|
33
|
+
|
|
34
|
+
These methods are typically not called directly. Instead, use the higher-level methods provided by client mixins.
|
|
35
|
+
|
|
36
|
+
## Pagination Methods
|
|
37
|
+
|
|
38
|
+
### `_list(path, url_conversion=None, list_all=False, params=None, **kwargs)`
|
|
39
|
+
|
|
40
|
+
List resources from a paginated API endpoint with optional automatic pagination and file URL conversion.
|
|
41
|
+
|
|
42
|
+
**Parameters:**
|
|
43
|
+
|
|
44
|
+
- `path` (str): URL path to request
|
|
45
|
+
- `url_conversion` (dict, optional): Configuration for converting file URLs to local paths
|
|
46
|
+
- Structure: `{'files_fields': ['field1', 'field2'], 'is_list': True}`
|
|
47
|
+
- Automatically downloads files and replaces URLs with local paths
|
|
48
|
+
- `list_all` (bool): If True, returns all results across all pages using a generator
|
|
49
|
+
- `params` (dict, optional): Query parameters (filters, sorting, etc.)
|
|
50
|
+
- `**kwargs`: Additional request arguments
|
|
51
|
+
|
|
52
|
+
**Returns:**
|
|
53
|
+
|
|
54
|
+
- If `list_all=False`: Dict with `results`, `count`, `next`, `previous`
|
|
55
|
+
- If `list_all=True`: Tuple of `(generator, total_count)`
|
|
56
|
+
|
|
57
|
+
**Examples:**
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
# Get first page only
|
|
61
|
+
response = client._list('api/tasks/')
|
|
62
|
+
tasks = response['results'] # First page of tasks
|
|
63
|
+
total = response['count'] # Total number of tasks
|
|
64
|
+
|
|
65
|
+
# Get all results using generator (memory efficient)
|
|
66
|
+
generator, total_count = client._list('api/tasks/', list_all=True)
|
|
67
|
+
all_tasks = list(generator) # Fetches all pages automatically
|
|
68
|
+
|
|
69
|
+
# With filters
|
|
70
|
+
params = {'status': 'pending', 'priority': 'high'}
|
|
71
|
+
response = client._list('api/tasks/', params=params)
|
|
72
|
+
|
|
73
|
+
# With url_conversion for file fields
|
|
74
|
+
url_conversion = {'files_fields': ['files'], 'is_list': True}
|
|
75
|
+
generator, count = client._list(
|
|
76
|
+
'api/data_units/',
|
|
77
|
+
url_conversion=url_conversion,
|
|
78
|
+
list_all=True,
|
|
79
|
+
params={'status': 'active'}
|
|
80
|
+
)
|
|
81
|
+
# File URLs in 'files' field are automatically downloaded and converted to local paths
|
|
82
|
+
for unit in generator:
|
|
83
|
+
print(unit['files']) # Local file paths, not URLs
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `_list_all(path, url_conversion=None, params=None, **kwargs)`
|
|
87
|
+
|
|
88
|
+
Generator that yields all results from a paginated API endpoint.
|
|
89
|
+
|
|
90
|
+
This method is called internally by `_list()` when `list_all=True`. It handles pagination automatically by following `next` URLs and uses an iterative approach (while loop) instead of recursion to avoid stack overflow with deep pagination.
|
|
91
|
+
|
|
92
|
+
**Key Improvements (SYN-5757):**
|
|
93
|
+
|
|
94
|
+
1. **No duplicate page_size**: The `page_size` parameter is only added to the first request. Subsequent requests use the `next` URL directly, which already contains all necessary parameters.
|
|
95
|
+
|
|
96
|
+
2. **Proper params handling**: User-specified query parameters are correctly passed to the first request and preserved through pagination via the `next` URL.
|
|
97
|
+
|
|
98
|
+
3. **url_conversion on all pages**: URL conversion is applied to every page, not just the first one.
|
|
99
|
+
|
|
100
|
+
4. **Iterative instead of recursive**: Uses a while loop instead of recursion for better memory efficiency and to prevent stack overflow on large datasets.
|
|
101
|
+
|
|
102
|
+
**Parameters:**
|
|
103
|
+
|
|
104
|
+
- `path` (str): Initial URL path
|
|
105
|
+
- `url_conversion` (dict, optional): Applied to all pages
|
|
106
|
+
- `params` (dict, optional): Query parameters for first request only
|
|
107
|
+
- `**kwargs`: Additional request arguments
|
|
108
|
+
|
|
109
|
+
**Yields:**
|
|
110
|
+
|
|
111
|
+
Individual result items from all pages, fetched lazily.
|
|
112
|
+
|
|
113
|
+
**Examples:**
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
# Basic: iterate through all tasks
|
|
117
|
+
for task in client._list_all('api/tasks/'):
|
|
118
|
+
process_task(task)
|
|
119
|
+
|
|
120
|
+
# With filters
|
|
121
|
+
params = {'status': 'pending'}
|
|
122
|
+
for task in client._list_all('api/tasks/', params=params):
|
|
123
|
+
print(task['id'])
|
|
124
|
+
|
|
125
|
+
# With url_conversion for nested file fields
|
|
126
|
+
url_conversion = {'files_fields': ['data.files', 'metadata.attachments'], 'is_list': True}
|
|
127
|
+
for item in client._list_all('api/items/', url_conversion=url_conversion):
|
|
128
|
+
print(item['data']['files']) # Local paths
|
|
129
|
+
|
|
130
|
+
# Collect all results (memory intensive for large datasets)
|
|
131
|
+
all_results = list(client._list_all('api/tasks/'))
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## URL Conversion for File Downloads
|
|
135
|
+
|
|
136
|
+
The `url_conversion` parameter enables automatic downloading of files referenced by URLs in API responses. This is particularly useful when working with data units, tasks, or any resources that include file references.
|
|
137
|
+
|
|
138
|
+
### URL Conversion Structure
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
url_conversion = {
|
|
142
|
+
'files_fields': ['files', 'images', 'data.attachments'], # Field paths
|
|
143
|
+
'is_list': True # Whether processing a list of items
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- `files_fields`: List of field paths (supports dot notation for nested fields)
|
|
148
|
+
- `is_list`: Set to `True` for paginated list responses
|
|
149
|
+
|
|
150
|
+
### How It Works
|
|
151
|
+
|
|
152
|
+
1. API returns responses with file URLs
|
|
153
|
+
2. `url_conversion` identifies fields containing URLs
|
|
154
|
+
3. Files are downloaded automatically to a temporary directory
|
|
155
|
+
4. URLs are replaced with local file paths
|
|
156
|
+
5. Your code receives responses with local paths instead of URLs
|
|
157
|
+
|
|
158
|
+
### Examples
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
# Simple file field
|
|
162
|
+
url_conversion = {'files_fields': ['image_url'], 'is_list': True}
|
|
163
|
+
generator, count = client._list(
|
|
164
|
+
'api/photos/',
|
|
165
|
+
url_conversion=url_conversion,
|
|
166
|
+
list_all=True
|
|
167
|
+
)
|
|
168
|
+
for photo in generator:
|
|
169
|
+
# photo['image_url'] is now a local Path object, not a URL
|
|
170
|
+
with open(photo['image_url'], 'rb') as f:
|
|
171
|
+
process_image(f)
|
|
172
|
+
|
|
173
|
+
# Multiple file fields
|
|
174
|
+
url_conversion = {
|
|
175
|
+
'files_fields': ['thumbnail', 'full_image', 'raw_data'],
|
|
176
|
+
'is_list': True
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Nested fields using dot notation
|
|
180
|
+
url_conversion = {
|
|
181
|
+
'files_fields': ['data.files', 'metadata.preview', 'annotations.image'],
|
|
182
|
+
'is_list': True
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# With async download for better performance
|
|
186
|
+
from synapse_sdk.utils.file import files_url_to_path_from_objs
|
|
187
|
+
|
|
188
|
+
results = client._list('api/data_units/')['results']
|
|
189
|
+
files_url_to_path_from_objs(
|
|
190
|
+
results,
|
|
191
|
+
files_fields=['files'],
|
|
192
|
+
is_list=True,
|
|
193
|
+
is_async=True # Download all files concurrently
|
|
194
|
+
)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Performance Considerations
|
|
198
|
+
|
|
199
|
+
### Memory Efficiency
|
|
200
|
+
|
|
201
|
+
When working with large datasets, use generators instead of loading all results into memory:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
# ❌ Memory intensive - loads all results
|
|
205
|
+
all_tasks = list(client._list('api/tasks/', list_all=True)[0])
|
|
206
|
+
|
|
207
|
+
# ✅ Memory efficient - processes one at a time
|
|
208
|
+
generator, _ = client._list('api/tasks/', list_all=True)
|
|
209
|
+
for task in generator:
|
|
210
|
+
process_task(task)
|
|
211
|
+
# Task is processed and can be garbage collected
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Pagination Best Practices
|
|
215
|
+
|
|
216
|
+
1. **Use list_all=True** for datasets larger than one page
|
|
217
|
+
2. **Set appropriate page_size** in params if default (100) isn't optimal
|
|
218
|
+
3. **Use url_conversion** only when you need to process files
|
|
219
|
+
4. **Consider async downloads** for multiple files per item
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
# Optimal pagination for large dataset
|
|
223
|
+
params = {'page_size': 50} # Smaller pages for faster first response
|
|
224
|
+
generator, total = client._list(
|
|
225
|
+
'api/large_dataset/',
|
|
226
|
+
list_all=True,
|
|
227
|
+
params=params
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Process with progress tracking
|
|
231
|
+
from tqdm import tqdm
|
|
232
|
+
for item in tqdm(generator, total=total):
|
|
233
|
+
process_item(item)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Usage in Client Mixins
|
|
237
|
+
|
|
238
|
+
The BaseClient pagination methods are used internally by all client mixins:
|
|
24
239
|
|
|
25
240
|
```python
|
|
26
|
-
|
|
241
|
+
# DataCollectionClientMixin
|
|
242
|
+
def list_data_units(self, params=None, url_conversion=None, list_all=False):
|
|
243
|
+
return self._list('data_units/', params=params,
|
|
244
|
+
url_conversion=url_conversion, list_all=list_all)
|
|
27
245
|
|
|
28
|
-
#
|
|
29
|
-
|
|
246
|
+
# AnnotationClientMixin
|
|
247
|
+
def list_tasks(self, params=None, url_conversion=None, list_all=False):
|
|
248
|
+
return self._list('sdk/tasks/', params=params,
|
|
249
|
+
url_conversion=url_conversion, list_all=list_all)
|
|
30
250
|
```
|
|
31
251
|
|
|
32
252
|
## See Also
|
|
33
253
|
|
|
34
254
|
- [BackendClient](./backend.md) - Main client implementation
|
|
35
|
-
- [AgentClient](./agent.md) - Agent-specific operations
|
|
255
|
+
- [AgentClient](./agent.md) - Agent-specific operations
|
|
256
|
+
- [DataCollectionClientMixin](./data-collection-mixin.md) - Data and file operations
|
|
257
|
+
- [AnnotationClientMixin](./annotation-mixin.md) - Task and annotation management
|
|
@@ -50,10 +50,65 @@ Execution context for plugin actions.
|
|
|
50
50
|
def start(self):
|
|
51
51
|
# Log messages
|
|
52
52
|
self.run.log("Processing started")
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
# Update progress
|
|
55
55
|
self.run.set_progress(0.5)
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
# Set metrics
|
|
58
58
|
self.run.set_metrics({"processed": 100})
|
|
59
|
-
```
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Development Logging
|
|
62
|
+
|
|
63
|
+
The `Run` class includes a specialized logging system for plugin developers with the `log_dev_event()` method and `DevLog` model.
|
|
64
|
+
|
|
65
|
+
#### DevLog Model
|
|
66
|
+
|
|
67
|
+
Structured model for development event logging:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from synapse_sdk.shared.enums import Context
|
|
71
|
+
|
|
72
|
+
class DevLog(BaseModel):
|
|
73
|
+
event_type: str # Event category (automatically generated as '{action_name}_dev_log')
|
|
74
|
+
message: str # Descriptive message
|
|
75
|
+
data: dict | None # Optional additional data
|
|
76
|
+
level: Context # Event severity level
|
|
77
|
+
created: str # ISO timestamp
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### log_dev_event Method
|
|
81
|
+
|
|
82
|
+
Log custom development events for debugging and monitoring:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
def start(self):
|
|
86
|
+
# Basic event logging (event_type automatically set to '{action_name}_dev_log')
|
|
87
|
+
self.run.log_dev_event('Data validation completed', {'records_count': 100})
|
|
88
|
+
|
|
89
|
+
# Performance tracking
|
|
90
|
+
self.run.log_dev_event('Processing time recorded', {'duration_ms': 1500})
|
|
91
|
+
|
|
92
|
+
# Debug with warning level
|
|
93
|
+
self.run.log_dev_event('Variable state checkpoint',
|
|
94
|
+
{'variable_x': 42}, level=Context.WARNING)
|
|
95
|
+
|
|
96
|
+
# Simple event without data
|
|
97
|
+
self.run.log_dev_event('Plugin initialization complete')
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Parameters:**
|
|
101
|
+
|
|
102
|
+
- `message` (str): Human-readable description
|
|
103
|
+
- `data` (dict, optional): Additional context data
|
|
104
|
+
- `level` (Context, optional): Event severity (default: Context.INFO)
|
|
105
|
+
|
|
106
|
+
**Note:** The `event_type` is automatically generated as `{action_name}_dev_log` and cannot be modified by plugin developers.
|
|
107
|
+
|
|
108
|
+
**Use Cases:**
|
|
109
|
+
|
|
110
|
+
- **Debugging**: Track variable states and execution flow
|
|
111
|
+
- **Performance**: Record processing times and resource usage
|
|
112
|
+
- **Validation**: Log data validation results
|
|
113
|
+
- **Error Tracking**: Capture detailed error information
|
|
114
|
+
- **Progress Monitoring**: Record intermediate states in long-running tasks
|