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.

Files changed (78) hide show
  1. synapse_sdk/clients/base.py +129 -9
  2. synapse_sdk/devtools/docs/docs/api/clients/base.md +230 -8
  3. synapse_sdk/devtools/docs/docs/api/plugins/models.md +58 -3
  4. synapse_sdk/devtools/docs/docs/plugins/categories/neural-net-plugins/train-action-overview.md +663 -0
  5. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  6. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  7. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  8. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  9. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-action.md +934 -0
  10. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-overview.md +585 -0
  11. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-template.md +715 -0
  12. synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +39 -0
  13. synapse_sdk/devtools/docs/docs/plugins/plugins.md +12 -5
  14. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/base.md +230 -8
  15. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/plugins/models.md +114 -0
  16. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/neural-net-plugins/train-action-overview.md +621 -0
  17. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  18. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  19. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  20. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  21. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-action.md +934 -0
  22. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-overview.md +585 -0
  23. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-template.md +715 -0
  24. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +39 -0
  25. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current.json +16 -4
  26. synapse_sdk/devtools/docs/sidebars.ts +45 -1
  27. synapse_sdk/plugins/README.md +487 -80
  28. synapse_sdk/plugins/categories/base.py +1 -0
  29. synapse_sdk/plugins/categories/export/actions/export/action.py +8 -3
  30. synapse_sdk/plugins/categories/export/actions/export/utils.py +108 -8
  31. synapse_sdk/plugins/categories/export/templates/config.yaml +18 -0
  32. synapse_sdk/plugins/categories/export/templates/plugin/export.py +97 -0
  33. synapse_sdk/plugins/categories/neural_net/actions/train.py +592 -22
  34. synapse_sdk/plugins/categories/neural_net/actions/tune.py +150 -3
  35. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
  36. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
  37. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/action.py +10 -0
  38. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
  39. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +145 -0
  40. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
  41. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
  42. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
  43. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +97 -0
  44. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +250 -0
  45. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
  46. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
  47. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +284 -0
  48. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
  49. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
  50. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +87 -0
  51. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +127 -0
  52. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
  53. synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +2 -1
  54. synapse_sdk/plugins/categories/upload/actions/upload/action.py +8 -1
  55. synapse_sdk/plugins/categories/upload/actions/upload/context.py +0 -1
  56. synapse_sdk/plugins/categories/upload/actions/upload/models.py +134 -94
  57. synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +2 -2
  58. synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +6 -2
  59. synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +24 -9
  60. synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +130 -18
  61. synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +147 -37
  62. synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +10 -5
  63. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +31 -6
  64. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +65 -37
  65. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +17 -2
  66. synapse_sdk/plugins/categories/upload/templates/README.md +394 -0
  67. synapse_sdk/plugins/models.py +62 -0
  68. synapse_sdk/utils/file/download.py +261 -0
  69. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/METADATA +15 -2
  70. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/RECORD +74 -43
  71. synapse_sdk/devtools/docs/docs/plugins/developing-upload-template.md +0 -1463
  72. synapse_sdk/devtools/docs/docs/plugins/upload-plugins.md +0 -1964
  73. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/developing-upload-template.md +0 -1463
  74. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/upload-plugins.md +0 -2077
  75. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/WHEEL +0 -0
  76. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/entry_points.txt +0 -0
  77. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/licenses/LICENSE +0 -0
  78. {synapse_sdk-2025.9.5.dist-info → synapse_sdk-2025.10.6.dist-info}/top_level.txt +0 -0
@@ -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
- response = self._get(path, **kwargs)
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
- return self._list_all(path, url_conversion, **kwargs), response['count']
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={}, **kwargs):
261
- params['page_size'] = self.page_size
262
- response = self._get(path, url_conversion, params=params, **kwargs)
263
- yield from response['results']
264
- if response['next']:
265
- yield from self._list_all(response['next'], url_conversion, **kwargs)
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, and request management used by all other clients.
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
- - File upload/download capabilities
19
+ - Efficient pagination with generators
20
+ - File URL to local path conversion
20
21
  - Pydantic model validation
21
22
  - Connection pooling
22
23
 
23
- ## Usage
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
- from synapse_sdk.clients.base import BaseClient
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
- # BaseClient is typically not used directly
29
- # Use BackendClient or AgentClient instead
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