label-studio-sdk 1.0.8__py3-none-any.whl → 1.0.11__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 label-studio-sdk might be problematic. Click here for more details.

Files changed (218) hide show
  1. label_studio_sdk/__init__.py +37 -8
  2. label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +16 -4
  3. label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +5 -0
  4. label_studio_sdk/_extensions/pager_ext.py +8 -0
  5. label_studio_sdk/actions/client.py +91 -40
  6. label_studio_sdk/actions/types/actions_create_request_filters.py +14 -24
  7. label_studio_sdk/actions/types/actions_create_request_filters_items_item.py +16 -26
  8. label_studio_sdk/actions/types/actions_create_request_filters_items_item_value.py +3 -1
  9. label_studio_sdk/actions/types/actions_create_request_selected_items.py +1 -2
  10. label_studio_sdk/actions/types/actions_create_request_selected_items_excluded.py +15 -25
  11. label_studio_sdk/actions/types/actions_create_request_selected_items_included.py +15 -25
  12. label_studio_sdk/annotations/__init__.py +2 -2
  13. label_studio_sdk/annotations/client.py +278 -104
  14. label_studio_sdk/annotations/types/__init__.py +2 -1
  15. label_studio_sdk/annotations/types/annotations_create_bulk_request_selected_items.py +34 -0
  16. label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +11 -21
  17. label_studio_sdk/base_client.py +54 -27
  18. label_studio_sdk/client.py +1 -0
  19. label_studio_sdk/comments/client.py +190 -44
  20. label_studio_sdk/converter/converter.py +56 -13
  21. label_studio_sdk/converter/imports/yolo.py +1 -1
  22. label_studio_sdk/converter/utils.py +3 -2
  23. label_studio_sdk/core/__init__.py +21 -4
  24. label_studio_sdk/core/client_wrapper.py +37 -19
  25. label_studio_sdk/core/file.py +37 -8
  26. label_studio_sdk/core/http_client.py +52 -28
  27. label_studio_sdk/core/jsonable_encoder.py +33 -31
  28. label_studio_sdk/core/pagination.py +5 -4
  29. label_studio_sdk/core/pydantic_utilities.py +272 -4
  30. label_studio_sdk/core/query_encoder.py +38 -13
  31. label_studio_sdk/core/request_options.py +3 -0
  32. label_studio_sdk/core/serialization.py +272 -0
  33. label_studio_sdk/errors/__init__.py +3 -1
  34. label_studio_sdk/errors/bad_request_error.py +2 -3
  35. label_studio_sdk/errors/not_found_error.py +9 -0
  36. label_studio_sdk/errors/unauthorized_error.py +9 -0
  37. label_studio_sdk/export_storage/azure/client.py +228 -58
  38. label_studio_sdk/export_storage/azure/types/azure_create_response.py +19 -29
  39. label_studio_sdk/export_storage/azure/types/azure_update_response.py +19 -29
  40. label_studio_sdk/export_storage/client.py +48 -18
  41. label_studio_sdk/export_storage/gcs/client.py +228 -58
  42. label_studio_sdk/export_storage/gcs/types/gcs_create_response.py +19 -29
  43. label_studio_sdk/export_storage/gcs/types/gcs_update_response.py +19 -29
  44. label_studio_sdk/export_storage/local/client.py +222 -56
  45. label_studio_sdk/export_storage/local/types/local_create_response.py +17 -27
  46. label_studio_sdk/export_storage/local/types/local_update_response.py +17 -27
  47. label_studio_sdk/export_storage/redis/client.py +228 -58
  48. label_studio_sdk/export_storage/redis/types/redis_create_response.py +20 -30
  49. label_studio_sdk/export_storage/redis/types/redis_update_response.py +20 -30
  50. label_studio_sdk/export_storage/s3/client.py +228 -58
  51. label_studio_sdk/export_storage/s3/types/s3create_response.py +27 -35
  52. label_studio_sdk/export_storage/s3/types/s3update_response.py +27 -35
  53. label_studio_sdk/export_storage/s3s/client.py +187 -43
  54. label_studio_sdk/export_storage/types/export_storage_list_types_response_item.py +11 -21
  55. label_studio_sdk/files/client.py +172 -56
  56. label_studio_sdk/import_storage/azure/client.py +223 -53
  57. label_studio_sdk/import_storage/azure/types/azure_create_response.py +22 -32
  58. label_studio_sdk/import_storage/azure/types/azure_update_response.py +22 -32
  59. label_studio_sdk/import_storage/client.py +48 -18
  60. label_studio_sdk/import_storage/gcs/client.py +223 -53
  61. label_studio_sdk/import_storage/gcs/types/gcs_create_response.py +22 -32
  62. label_studio_sdk/import_storage/gcs/types/gcs_update_response.py +22 -32
  63. label_studio_sdk/import_storage/local/client.py +223 -53
  64. label_studio_sdk/import_storage/local/types/local_create_response.py +17 -27
  65. label_studio_sdk/import_storage/local/types/local_update_response.py +17 -27
  66. label_studio_sdk/import_storage/redis/client.py +223 -53
  67. label_studio_sdk/import_storage/redis/types/redis_create_response.py +20 -30
  68. label_studio_sdk/import_storage/redis/types/redis_update_response.py +20 -30
  69. label_studio_sdk/import_storage/s3/client.py +223 -53
  70. label_studio_sdk/import_storage/s3/types/s3create_response.py +31 -39
  71. label_studio_sdk/import_storage/s3/types/s3update_response.py +31 -39
  72. label_studio_sdk/import_storage/s3s/client.py +222 -52
  73. label_studio_sdk/import_storage/types/import_storage_list_types_response_item.py +11 -21
  74. label_studio_sdk/jwt_settings/__init__.py +2 -0
  75. label_studio_sdk/jwt_settings/client.py +259 -0
  76. label_studio_sdk/label_interface/control_tags.py +16 -3
  77. label_studio_sdk/label_interface/interface.py +80 -1
  78. label_studio_sdk/label_interface/object_tags.py +2 -2
  79. label_studio_sdk/ml/client.py +280 -78
  80. label_studio_sdk/ml/types/ml_create_response.py +21 -31
  81. label_studio_sdk/ml/types/ml_update_response.py +21 -31
  82. label_studio_sdk/model_providers/client.py +173 -56
  83. label_studio_sdk/predictions/client.py +247 -101
  84. label_studio_sdk/projects/__init__.py +5 -1
  85. label_studio_sdk/projects/client.py +313 -115
  86. label_studio_sdk/projects/client_ext.py +16 -0
  87. label_studio_sdk/projects/exports/__init__.py +3 -0
  88. label_studio_sdk/projects/exports/client.py +447 -296
  89. label_studio_sdk/projects/exports/client_ext.py +200 -0
  90. label_studio_sdk/projects/exports/types/__init__.py +6 -0
  91. label_studio_sdk/projects/exports/types/exports_convert_response.py +24 -0
  92. label_studio_sdk/projects/exports/types/exports_list_formats_response_item.py +44 -0
  93. label_studio_sdk/projects/pauses/__init__.py +2 -0
  94. label_studio_sdk/projects/pauses/client.py +704 -0
  95. label_studio_sdk/projects/types/projects_create_response.py +29 -34
  96. label_studio_sdk/projects/types/projects_import_tasks_response.py +19 -29
  97. label_studio_sdk/projects/types/projects_list_response.py +11 -21
  98. label_studio_sdk/projects/types/projects_update_response.py +34 -34
  99. label_studio_sdk/prompts/client.py +309 -92
  100. label_studio_sdk/prompts/indicators/client.py +67 -23
  101. label_studio_sdk/prompts/runs/client.py +95 -40
  102. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +14 -24
  103. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +11 -21
  104. label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +26 -29
  105. label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +11 -21
  106. label_studio_sdk/prompts/versions/client.py +277 -88
  107. label_studio_sdk/tasks/client.py +263 -90
  108. label_studio_sdk/tasks/types/tasks_list_response.py +15 -25
  109. label_studio_sdk/tokens/__init__.py +2 -0
  110. label_studio_sdk/tokens/client.py +470 -0
  111. label_studio_sdk/tokens/client_ext.py +94 -0
  112. label_studio_sdk/types/__init__.py +20 -6
  113. label_studio_sdk/types/access_token_response.py +22 -0
  114. label_studio_sdk/types/annotation.py +29 -38
  115. label_studio_sdk/types/annotation_filter_options.py +14 -24
  116. label_studio_sdk/types/annotations_dm_field.py +30 -39
  117. label_studio_sdk/types/api_token_response.py +32 -0
  118. label_studio_sdk/types/azure_blob_export_storage.py +28 -37
  119. label_studio_sdk/types/azure_blob_import_storage.py +28 -37
  120. label_studio_sdk/types/base_task.py +30 -39
  121. label_studio_sdk/types/base_task_updated_by.py +3 -1
  122. label_studio_sdk/types/base_user.py +14 -21
  123. label_studio_sdk/types/comment.py +12 -21
  124. label_studio_sdk/types/comment_created_by.py +1 -1
  125. label_studio_sdk/types/converted_format.py +12 -22
  126. label_studio_sdk/types/data_manager_task_serializer.py +31 -40
  127. label_studio_sdk/types/data_manager_task_serializer_annotators_item.py +1 -1
  128. label_studio_sdk/types/data_manager_task_serializer_drafts_item.py +13 -22
  129. label_studio_sdk/types/data_manager_task_serializer_predictions_item.py +15 -24
  130. label_studio_sdk/types/export.py +17 -26
  131. label_studio_sdk/types/export_format.py +25 -0
  132. label_studio_sdk/types/export_snapshot.py +45 -0
  133. label_studio_sdk/types/export_snapshot_status.py +5 -0
  134. label_studio_sdk/types/file_upload.py +11 -21
  135. label_studio_sdk/types/filter.py +16 -26
  136. label_studio_sdk/types/filter_group.py +12 -22
  137. label_studio_sdk/types/gcs_export_storage.py +28 -37
  138. label_studio_sdk/types/gcs_import_storage.py +28 -37
  139. label_studio_sdk/types/inference_run.py +14 -23
  140. label_studio_sdk/types/inference_run_cost_estimate.py +17 -27
  141. label_studio_sdk/types/inference_run_created_by.py +1 -1
  142. label_studio_sdk/types/inference_run_organization.py +1 -1
  143. label_studio_sdk/types/jwt_settings_response.py +32 -0
  144. label_studio_sdk/types/key_indicator_value.py +12 -22
  145. label_studio_sdk/types/key_indicators.py +0 -1
  146. label_studio_sdk/types/key_indicators_item.py +15 -25
  147. label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +13 -23
  148. label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +13 -23
  149. label_studio_sdk/types/local_files_export_storage.py +25 -34
  150. label_studio_sdk/types/local_files_import_storage.py +24 -33
  151. label_studio_sdk/types/ml_backend.py +23 -32
  152. label_studio_sdk/types/model_provider_connection.py +22 -31
  153. label_studio_sdk/types/model_provider_connection_created_by.py +1 -1
  154. label_studio_sdk/types/model_provider_connection_organization.py +1 -1
  155. label_studio_sdk/types/model_provider_connection_provider.py +3 -1
  156. label_studio_sdk/types/pause.py +34 -0
  157. label_studio_sdk/types/pause_paused_by.py +5 -0
  158. label_studio_sdk/types/prediction.py +21 -30
  159. label_studio_sdk/types/project.py +58 -55
  160. label_studio_sdk/types/project_import.py +21 -30
  161. label_studio_sdk/types/project_label_config.py +12 -22
  162. label_studio_sdk/types/prompt.py +24 -32
  163. label_studio_sdk/types/prompt_associated_projects_item.py +6 -0
  164. label_studio_sdk/types/prompt_associated_projects_item_id.py +20 -0
  165. label_studio_sdk/types/prompt_created_by.py +1 -1
  166. label_studio_sdk/types/prompt_organization.py +1 -1
  167. label_studio_sdk/types/prompt_version.py +13 -22
  168. label_studio_sdk/types/prompt_version_created_by.py +1 -1
  169. label_studio_sdk/types/prompt_version_organization.py +1 -1
  170. label_studio_sdk/types/prompt_version_provider.py +3 -1
  171. label_studio_sdk/types/redis_export_storage.py +29 -38
  172. label_studio_sdk/types/redis_import_storage.py +28 -37
  173. label_studio_sdk/types/refined_prompt_response.py +19 -29
  174. label_studio_sdk/types/s3export_storage.py +36 -43
  175. label_studio_sdk/types/s3import_storage.py +37 -44
  176. label_studio_sdk/types/s3s_export_storage.py +26 -33
  177. label_studio_sdk/types/s3s_import_storage.py +35 -42
  178. label_studio_sdk/types/serialization_option.py +12 -22
  179. label_studio_sdk/types/serialization_options.py +18 -28
  180. label_studio_sdk/types/task.py +44 -47
  181. label_studio_sdk/types/task_annotators_item.py +1 -1
  182. label_studio_sdk/types/task_comment_authors_item.py +1 -1
  183. label_studio_sdk/types/task_filter_options.py +15 -25
  184. label_studio_sdk/types/user_simple.py +11 -21
  185. label_studio_sdk/types/view.py +16 -26
  186. label_studio_sdk/types/webhook.py +19 -28
  187. label_studio_sdk/types/webhook_serializer_for_update.py +19 -28
  188. label_studio_sdk/types/workspace.py +22 -31
  189. label_studio_sdk/users/client.py +257 -63
  190. label_studio_sdk/users/types/users_get_token_response.py +12 -22
  191. label_studio_sdk/users/types/users_reset_token_response.py +12 -22
  192. label_studio_sdk/version.py +0 -1
  193. label_studio_sdk/versions/__init__.py +5 -0
  194. label_studio_sdk/versions/client.py +112 -0
  195. label_studio_sdk/versions/types/__init__.py +6 -0
  196. label_studio_sdk/versions/types/versions_get_response.py +73 -0
  197. label_studio_sdk/versions/types/versions_get_response_edition.py +5 -0
  198. label_studio_sdk/views/client.py +219 -52
  199. label_studio_sdk/views/types/views_create_request_data.py +13 -23
  200. label_studio_sdk/views/types/views_create_request_data_filters.py +14 -24
  201. label_studio_sdk/views/types/views_create_request_data_filters_items_item.py +16 -26
  202. label_studio_sdk/views/types/views_create_request_data_filters_items_item_value.py +3 -1
  203. label_studio_sdk/views/types/views_update_request_data.py +13 -23
  204. label_studio_sdk/views/types/views_update_request_data_filters.py +14 -24
  205. label_studio_sdk/views/types/views_update_request_data_filters_items_item.py +16 -26
  206. label_studio_sdk/views/types/views_update_request_data_filters_items_item_value.py +3 -1
  207. label_studio_sdk/webhooks/client.py +191 -61
  208. label_studio_sdk/workspaces/client.py +164 -41
  209. label_studio_sdk/workspaces/members/client.py +109 -31
  210. label_studio_sdk/workspaces/members/types/members_create_response.py +12 -22
  211. label_studio_sdk/workspaces/members/types/members_list_response_item.py +12 -22
  212. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/METADATA +8 -5
  213. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/RECORD +215 -188
  214. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/WHEEL +1 -1
  215. label_studio_sdk/types/export_convert.py +0 -32
  216. label_studio_sdk/types/export_create.py +0 -54
  217. label_studio_sdk/types/export_create_status.py +0 -5
  218. {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/LICENSE +0 -0
@@ -1,14 +1,14 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
3
  import typing
4
+ from ..core.client_wrapper import SyncClientWrapper
5
+ from ..core.request_options import RequestOptions
6
+ from ..types.comment import Comment
7
+ from ..core.pydantic_utilities import parse_obj_as
4
8
  from json.decoder import JSONDecodeError
5
-
6
9
  from ..core.api_error import ApiError
7
- from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
8
10
  from ..core.jsonable_encoder import jsonable_encoder
9
- from ..core.pydantic_utilities import pydantic_v1
10
- from ..core.request_options import RequestOptions
11
- from ..types.comment import Comment
11
+ from ..core.client_wrapper import AsyncClientWrapper
12
12
 
13
13
  # this is used as the default value for optional parameters
14
14
  OMIT = typing.cast(typing.Any, ...)
@@ -27,6 +27,7 @@ class CommentsClient:
27
27
  request_options: typing.Optional[RequestOptions] = None,
28
28
  ) -> typing.List[Comment]:
29
29
  """
30
+
30
31
  Get a list of comments for a specific project.
31
32
 
32
33
  Parameters
@@ -50,7 +51,7 @@ class CommentsClient:
50
51
 
51
52
  Examples
52
53
  --------
53
- from label_studio_sdk.client import LabelStudio
54
+ from label_studio_sdk import LabelStudio
54
55
 
55
56
  client = LabelStudio(
56
57
  api_key="YOUR_API_KEY",
@@ -60,12 +61,22 @@ class CommentsClient:
60
61
  _response = self._client_wrapper.httpx_client.request(
61
62
  "api/comments/",
62
63
  method="GET",
63
- params={"project": project, "expand_created_by": expand_created_by, "annotation": annotation},
64
+ params={
65
+ "project": project,
66
+ "expand_created_by": expand_created_by,
67
+ "annotation": annotation,
68
+ },
64
69
  request_options=request_options,
65
70
  )
66
71
  try:
67
72
  if 200 <= _response.status_code < 300:
68
- return pydantic_v1.parse_obj_as(typing.List[Comment], _response.json()) # type: ignore
73
+ return typing.cast(
74
+ typing.List[Comment],
75
+ parse_obj_as(
76
+ type_=typing.List[Comment], # type: ignore
77
+ object_=_response.json(),
78
+ ),
79
+ )
69
80
  _response_json = _response.json()
70
81
  except JSONDecodeError:
71
82
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -81,6 +92,7 @@ class CommentsClient:
81
92
  request_options: typing.Optional[RequestOptions] = None,
82
93
  ) -> Comment:
83
94
  """
95
+
84
96
  Create a new comment.
85
97
 
86
98
  Parameters
@@ -103,7 +115,7 @@ class CommentsClient:
103
115
 
104
116
  Examples
105
117
  --------
106
- from label_studio_sdk.client import LabelStudio
118
+ from label_studio_sdk import LabelStudio
107
119
 
108
120
  client = LabelStudio(
109
121
  api_key="YOUR_API_KEY",
@@ -113,13 +125,27 @@ class CommentsClient:
113
125
  _response = self._client_wrapper.httpx_client.request(
114
126
  "api/comments/",
115
127
  method="POST",
116
- json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
128
+ json={
129
+ "annotation": annotation,
130
+ "project": project,
131
+ "text": text,
132
+ "is_resolved": is_resolved,
133
+ },
134
+ headers={
135
+ "content-type": "application/json",
136
+ },
117
137
  request_options=request_options,
118
138
  omit=OMIT,
119
139
  )
120
140
  try:
121
141
  if 200 <= _response.status_code < 300:
122
- return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
142
+ return typing.cast(
143
+ Comment,
144
+ parse_obj_as(
145
+ type_=Comment, # type: ignore
146
+ object_=_response.json(),
147
+ ),
148
+ )
123
149
  _response_json = _response.json()
124
150
  except JSONDecodeError:
125
151
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -127,6 +153,7 @@ class CommentsClient:
127
153
 
128
154
  def get(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> Comment:
129
155
  """
156
+
130
157
  Get a specific comment.
131
158
 
132
159
  Parameters
@@ -144,7 +171,7 @@ class CommentsClient:
144
171
 
145
172
  Examples
146
173
  --------
147
- from label_studio_sdk.client import LabelStudio
174
+ from label_studio_sdk import LabelStudio
148
175
 
149
176
  client = LabelStudio(
150
177
  api_key="YOUR_API_KEY",
@@ -154,11 +181,19 @@ class CommentsClient:
154
181
  )
155
182
  """
156
183
  _response = self._client_wrapper.httpx_client.request(
157
- f"api/comments/{jsonable_encoder(id)}", method="GET", request_options=request_options
184
+ f"api/comments/{jsonable_encoder(id)}",
185
+ method="GET",
186
+ request_options=request_options,
158
187
  )
159
188
  try:
160
189
  if 200 <= _response.status_code < 300:
161
- return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
190
+ return typing.cast(
191
+ Comment,
192
+ parse_obj_as(
193
+ type_=Comment, # type: ignore
194
+ object_=_response.json(),
195
+ ),
196
+ )
162
197
  _response_json = _response.json()
163
198
  except JSONDecodeError:
164
199
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -166,6 +201,7 @@ class CommentsClient:
166
201
 
167
202
  def delete(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
168
203
  """
204
+
169
205
  Delete a specific comment.
170
206
 
171
207
  Parameters
@@ -182,7 +218,7 @@ class CommentsClient:
182
218
 
183
219
  Examples
184
220
  --------
185
- from label_studio_sdk.client import LabelStudio
221
+ from label_studio_sdk import LabelStudio
186
222
 
187
223
  client = LabelStudio(
188
224
  api_key="YOUR_API_KEY",
@@ -192,7 +228,9 @@ class CommentsClient:
192
228
  )
193
229
  """
194
230
  _response = self._client_wrapper.httpx_client.request(
195
- f"api/comments/{jsonable_encoder(id)}", method="DELETE", request_options=request_options
231
+ f"api/comments/{jsonable_encoder(id)}",
232
+ method="DELETE",
233
+ request_options=request_options,
196
234
  )
197
235
  try:
198
236
  if 200 <= _response.status_code < 300:
@@ -213,6 +251,7 @@ class CommentsClient:
213
251
  request_options: typing.Optional[RequestOptions] = None,
214
252
  ) -> Comment:
215
253
  """
254
+
216
255
  Update a specific comment.
217
256
 
218
257
  Parameters
@@ -238,7 +277,7 @@ class CommentsClient:
238
277
 
239
278
  Examples
240
279
  --------
241
- from label_studio_sdk.client import LabelStudio
280
+ from label_studio_sdk import LabelStudio
242
281
 
243
282
  client = LabelStudio(
244
283
  api_key="YOUR_API_KEY",
@@ -250,13 +289,27 @@ class CommentsClient:
250
289
  _response = self._client_wrapper.httpx_client.request(
251
290
  f"api/comments/{jsonable_encoder(id)}",
252
291
  method="PATCH",
253
- json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
292
+ json={
293
+ "annotation": annotation,
294
+ "project": project,
295
+ "text": text,
296
+ "is_resolved": is_resolved,
297
+ },
298
+ headers={
299
+ "content-type": "application/json",
300
+ },
254
301
  request_options=request_options,
255
302
  omit=OMIT,
256
303
  )
257
304
  try:
258
305
  if 200 <= _response.status_code < 300:
259
- return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
306
+ return typing.cast(
307
+ Comment,
308
+ parse_obj_as(
309
+ type_=Comment, # type: ignore
310
+ object_=_response.json(),
311
+ ),
312
+ )
260
313
  _response_json = _response.json()
261
314
  except JSONDecodeError:
262
315
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -276,6 +329,7 @@ class AsyncCommentsClient:
276
329
  request_options: typing.Optional[RequestOptions] = None,
277
330
  ) -> typing.List[Comment]:
278
331
  """
332
+
279
333
  Get a list of comments for a specific project.
280
334
 
281
335
  Parameters
@@ -299,22 +353,40 @@ class AsyncCommentsClient:
299
353
 
300
354
  Examples
301
355
  --------
302
- from label_studio_sdk.client import AsyncLabelStudio
356
+ import asyncio
357
+
358
+ from label_studio_sdk import AsyncLabelStudio
303
359
 
304
360
  client = AsyncLabelStudio(
305
361
  api_key="YOUR_API_KEY",
306
362
  )
307
- await client.comments.list()
363
+
364
+
365
+ async def main() -> None:
366
+ await client.comments.list()
367
+
368
+
369
+ asyncio.run(main())
308
370
  """
309
371
  _response = await self._client_wrapper.httpx_client.request(
310
372
  "api/comments/",
311
373
  method="GET",
312
- params={"project": project, "expand_created_by": expand_created_by, "annotation": annotation},
374
+ params={
375
+ "project": project,
376
+ "expand_created_by": expand_created_by,
377
+ "annotation": annotation,
378
+ },
313
379
  request_options=request_options,
314
380
  )
315
381
  try:
316
382
  if 200 <= _response.status_code < 300:
317
- return pydantic_v1.parse_obj_as(typing.List[Comment], _response.json()) # type: ignore
383
+ return typing.cast(
384
+ typing.List[Comment],
385
+ parse_obj_as(
386
+ type_=typing.List[Comment], # type: ignore
387
+ object_=_response.json(),
388
+ ),
389
+ )
318
390
  _response_json = _response.json()
319
391
  except JSONDecodeError:
320
392
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -330,6 +402,7 @@ class AsyncCommentsClient:
330
402
  request_options: typing.Optional[RequestOptions] = None,
331
403
  ) -> Comment:
332
404
  """
405
+
333
406
  Create a new comment.
334
407
 
335
408
  Parameters
@@ -352,23 +425,45 @@ class AsyncCommentsClient:
352
425
 
353
426
  Examples
354
427
  --------
355
- from label_studio_sdk.client import AsyncLabelStudio
428
+ import asyncio
429
+
430
+ from label_studio_sdk import AsyncLabelStudio
356
431
 
357
432
  client = AsyncLabelStudio(
358
433
  api_key="YOUR_API_KEY",
359
434
  )
360
- await client.comments.create()
435
+
436
+
437
+ async def main() -> None:
438
+ await client.comments.create()
439
+
440
+
441
+ asyncio.run(main())
361
442
  """
362
443
  _response = await self._client_wrapper.httpx_client.request(
363
444
  "api/comments/",
364
445
  method="POST",
365
- json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
446
+ json={
447
+ "annotation": annotation,
448
+ "project": project,
449
+ "text": text,
450
+ "is_resolved": is_resolved,
451
+ },
452
+ headers={
453
+ "content-type": "application/json",
454
+ },
366
455
  request_options=request_options,
367
456
  omit=OMIT,
368
457
  )
369
458
  try:
370
459
  if 200 <= _response.status_code < 300:
371
- return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
460
+ return typing.cast(
461
+ Comment,
462
+ parse_obj_as(
463
+ type_=Comment, # type: ignore
464
+ object_=_response.json(),
465
+ ),
466
+ )
372
467
  _response_json = _response.json()
373
468
  except JSONDecodeError:
374
469
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -376,6 +471,7 @@ class AsyncCommentsClient:
376
471
 
377
472
  async def get(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> Comment:
378
473
  """
474
+
379
475
  Get a specific comment.
380
476
 
381
477
  Parameters
@@ -393,21 +489,37 @@ class AsyncCommentsClient:
393
489
 
394
490
  Examples
395
491
  --------
396
- from label_studio_sdk.client import AsyncLabelStudio
492
+ import asyncio
493
+
494
+ from label_studio_sdk import AsyncLabelStudio
397
495
 
398
496
  client = AsyncLabelStudio(
399
497
  api_key="YOUR_API_KEY",
400
498
  )
401
- await client.comments.get(
402
- id=1,
403
- )
499
+
500
+
501
+ async def main() -> None:
502
+ await client.comments.get(
503
+ id=1,
504
+ )
505
+
506
+
507
+ asyncio.run(main())
404
508
  """
405
509
  _response = await self._client_wrapper.httpx_client.request(
406
- f"api/comments/{jsonable_encoder(id)}", method="GET", request_options=request_options
510
+ f"api/comments/{jsonable_encoder(id)}",
511
+ method="GET",
512
+ request_options=request_options,
407
513
  )
408
514
  try:
409
515
  if 200 <= _response.status_code < 300:
410
- return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
516
+ return typing.cast(
517
+ Comment,
518
+ parse_obj_as(
519
+ type_=Comment, # type: ignore
520
+ object_=_response.json(),
521
+ ),
522
+ )
411
523
  _response_json = _response.json()
412
524
  except JSONDecodeError:
413
525
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -415,6 +527,7 @@ class AsyncCommentsClient:
415
527
 
416
528
  async def delete(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
417
529
  """
530
+
418
531
  Delete a specific comment.
419
532
 
420
533
  Parameters
@@ -431,17 +544,27 @@ class AsyncCommentsClient:
431
544
 
432
545
  Examples
433
546
  --------
434
- from label_studio_sdk.client import AsyncLabelStudio
547
+ import asyncio
548
+
549
+ from label_studio_sdk import AsyncLabelStudio
435
550
 
436
551
  client = AsyncLabelStudio(
437
552
  api_key="YOUR_API_KEY",
438
553
  )
439
- await client.comments.delete(
440
- id=1,
441
- )
554
+
555
+
556
+ async def main() -> None:
557
+ await client.comments.delete(
558
+ id=1,
559
+ )
560
+
561
+
562
+ asyncio.run(main())
442
563
  """
443
564
  _response = await self._client_wrapper.httpx_client.request(
444
- f"api/comments/{jsonable_encoder(id)}", method="DELETE", request_options=request_options
565
+ f"api/comments/{jsonable_encoder(id)}",
566
+ method="DELETE",
567
+ request_options=request_options,
445
568
  )
446
569
  try:
447
570
  if 200 <= _response.status_code < 300:
@@ -462,6 +585,7 @@ class AsyncCommentsClient:
462
585
  request_options: typing.Optional[RequestOptions] = None,
463
586
  ) -> Comment:
464
587
  """
588
+
465
589
  Update a specific comment.
466
590
 
467
591
  Parameters
@@ -487,25 +611,47 @@ class AsyncCommentsClient:
487
611
 
488
612
  Examples
489
613
  --------
490
- from label_studio_sdk.client import AsyncLabelStudio
614
+ import asyncio
615
+
616
+ from label_studio_sdk import AsyncLabelStudio
491
617
 
492
618
  client = AsyncLabelStudio(
493
619
  api_key="YOUR_API_KEY",
494
620
  )
495
- await client.comments.update(
496
- id=1,
497
- )
621
+
622
+
623
+ async def main() -> None:
624
+ await client.comments.update(
625
+ id=1,
626
+ )
627
+
628
+
629
+ asyncio.run(main())
498
630
  """
499
631
  _response = await self._client_wrapper.httpx_client.request(
500
632
  f"api/comments/{jsonable_encoder(id)}",
501
633
  method="PATCH",
502
- json={"annotation": annotation, "project": project, "text": text, "is_resolved": is_resolved},
634
+ json={
635
+ "annotation": annotation,
636
+ "project": project,
637
+ "text": text,
638
+ "is_resolved": is_resolved,
639
+ },
640
+ headers={
641
+ "content-type": "application/json",
642
+ },
503
643
  request_options=request_options,
504
644
  omit=OMIT,
505
645
  )
506
646
  try:
507
647
  if 200 <= _response.status_code < 300:
508
- return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore
648
+ return typing.cast(
649
+ Comment,
650
+ parse_obj_as(
651
+ type_=Comment, # type: ignore
652
+ object_=_response.json(),
653
+ ),
654
+ )
509
655
  _response_json = _response.json()
510
656
  except JSONDecodeError:
511
657
  raise ApiError(status_code=_response.status_code, body=_response.text)
@@ -33,6 +33,7 @@ from label_studio_sdk.converter.utils import (
33
33
  convert_annotation_to_yolo,
34
34
  convert_annotation_to_yolo_obb,
35
35
  )
36
+ from label_studio_sdk._extensions.label_studio_tools.core.utils.io import get_local_path
36
37
 
37
38
  logger = logging.getLogger(__name__)
38
39
 
@@ -55,6 +56,9 @@ class Format(Enum):
55
56
  YOLO = 11
56
57
  YOLO_OBB = 12
57
58
  CSV_OLD = 13
59
+ YOLO_WITH_IMAGES = 14
60
+ COCO_WITH_IMAGES = 15
61
+ YOLO_OBB_WITH_IMAGES = 16
58
62
 
59
63
  def __str__(self):
60
64
  return self.name
@@ -106,6 +110,12 @@ class Converter(object):
106
110
  "link": "https://labelstud.io/guide/export.html#COCO",
107
111
  "tags": ["image segmentation", "object detection"],
108
112
  },
113
+ Format.COCO_WITH_IMAGES: {
114
+ "title": "COCO with Images",
115
+ "description": "COCO format with images downloaded.",
116
+ "link": "https://labelstud.io/guide/export.html#COCO",
117
+ "tags": ["image segmentation", "object detection"],
118
+ },
109
119
  Format.VOC: {
110
120
  "title": "Pascal VOC XML",
111
121
  "description": "Popular XML format used for object detection and polygon image segmentation tasks.",
@@ -119,6 +129,12 @@ class Converter(object):
119
129
  "link": "https://labelstud.io/guide/export.html#YOLO",
120
130
  "tags": ["image segmentation", "object detection"],
121
131
  },
132
+ Format.YOLO_WITH_IMAGES: {
133
+ "title": "YOLO with Images",
134
+ "description": "YOLO format with images downloaded.",
135
+ "link": "https://labelstud.io/guide/export.html#YOLO",
136
+ "tags": ["image segmentation", "object detection"],
137
+ },
122
138
  Format.YOLO_OBB: {
123
139
  "title": "YOLOv8 OBB",
124
140
  "description": "Popular TXT format is created for each image file. Each txt file contains annotations for "
@@ -127,6 +143,12 @@ class Converter(object):
127
143
  "link": "https://labelstud.io/guide/export.html#YOLO",
128
144
  "tags": ["image segmentation", "object detection"],
129
145
  },
146
+ Format.YOLO_OBB_WITH_IMAGES: {
147
+ "title": "YOLOv8 OBB with Images",
148
+ "description": "YOLOv8 OBB format with images downloaded.",
149
+ "link": "https://labelstud.io/guide/export.html#YOLO",
150
+ "tags": ["image segmentation", "object detection"],
151
+ },
130
152
  Format.BRUSH_TO_NUMPY: {
131
153
  "title": "Brush labels to NumPy",
132
154
  "description": "Export your brush labels as NumPy 2d arrays. Each label outputs as one image.",
@@ -158,6 +180,8 @@ class Converter(object):
158
180
  output_tags=None,
159
181
  upload_dir=None,
160
182
  download_resources=True,
183
+ access_token=None,
184
+ hostname=None,
161
185
  ):
162
186
  """Initialize Label Studio Converter for Exports
163
187
 
@@ -171,6 +195,8 @@ class Converter(object):
171
195
  self.upload_dir = upload_dir
172
196
  self.download_resources = download_resources
173
197
  self._schema = None
198
+ self.access_token = access_token
199
+ self.hostname = hostname
174
200
 
175
201
  if isinstance(config, dict):
176
202
  self._schema = config
@@ -216,21 +242,23 @@ class Converter(object):
216
242
  )
217
243
  elif format == Format.CONLL2003:
218
244
  self.convert_to_conll2003(input_data, output_data, is_dir=is_dir)
219
- elif format == Format.COCO:
245
+ elif format in [Format.COCO, Format.COCO_WITH_IMAGES]:
220
246
  image_dir = kwargs.get("image_dir")
247
+ self.download_resources = format == Format.COCO_WITH_IMAGES
221
248
  self.convert_to_coco(
222
249
  input_data, output_data, output_image_dir=image_dir, is_dir=is_dir
223
250
  )
224
- elif format == Format.YOLO or format == Format.YOLO_OBB:
251
+ elif format in [Format.YOLO, Format.YOLO_OBB, Format.YOLO_OBB_WITH_IMAGES, Format.YOLO_WITH_IMAGES]:
225
252
  image_dir = kwargs.get("image_dir")
226
253
  label_dir = kwargs.get("label_dir")
254
+ self.download_resources = format in [Format.YOLO_WITH_IMAGES, Format.YOLO_OBB_WITH_IMAGES]
227
255
  self.convert_to_yolo(
228
256
  input_data,
229
257
  output_data,
230
258
  output_image_dir=image_dir,
231
259
  output_label_dir=label_dir,
232
260
  is_dir=is_dir,
233
- is_obb=(format == Format.YOLO_OBB),
261
+ is_obb=(format in [Format.YOLO_OBB, Format.YOLO_OBB_WITH_IMAGES]),
234
262
  )
235
263
  elif format == Format.VOC:
236
264
  image_dir = kwargs.get("image_dir")
@@ -334,7 +362,9 @@ class Converter(object):
334
362
  and "Labels" in output_tag_types
335
363
  ):
336
364
  all_formats.remove(Format.COCO.name)
365
+ all_formats.remove(Format.COCO_WITH_IMAGES.name)
337
366
  all_formats.remove(Format.YOLO.name)
367
+ all_formats.remove(Format.YOLO_WITH_IMAGES.name)
338
368
  if not (
339
369
  "Image" in input_tag_types
340
370
  and (
@@ -353,6 +383,7 @@ class Converter(object):
353
383
  all_formats.remove(Format.ASR_MANIFEST.name)
354
384
  if is_mig or ('Video' in input_tag_types and 'TimelineLabels' in output_tag_types):
355
385
  all_formats.remove(Format.YOLO_OBB.name)
386
+ all_formats.remove(Format.YOLO_OBB_WITH_IMAGES.name)
356
387
 
357
388
  return all_formats
358
389
 
@@ -593,20 +624,25 @@ class Converter(object):
593
624
  )
594
625
  for item_idx, item in enumerate(item_iterator):
595
626
  image_path = item["input"][data_key]
627
+ task_id = item["id"]
596
628
  image_id = len(images)
597
629
  width = None
598
630
  height = None
599
631
  # download all images of the dataset, including the ones without annotations
600
632
  if not os.path.exists(image_path):
601
633
  try:
602
- image_path = download(
603
- image_path,
604
- output_image_dir,
634
+ image_path = get_local_path(
635
+ url=image_path,
636
+ hostname=self.hostname,
605
637
  project_dir=self.project_dir,
606
- return_relative_path=True,
607
- upload_dir=self.upload_dir,
638
+ image_dir=self.upload_dir,
639
+ cache_dir=output_image_dir,
608
640
  download_resources=self.download_resources,
641
+ access_token=self.access_token,
642
+ task_id=task_id,
609
643
  )
644
+ # make path relative to output_image_dir
645
+ image_path = os.path.relpath(image_path, output_dir)
610
646
  except:
611
647
  logger.info(
612
648
  "Unable to download {image_path}. The image of {item} will be skipped".format(
@@ -801,19 +837,24 @@ class Converter(object):
801
837
  image_paths = [image_paths] if isinstance(image_paths, str) else image_paths
802
838
  # download image(s)
803
839
  image_path = None
840
+ task_id = item["id"]
804
841
  # TODO: for multi-page annotation, this code won't produce correct relationships between page and annotated shapes
805
842
  # fixing the issue in RND-84
806
843
  for image_path in reversed(image_paths):
807
844
  if not os.path.exists(image_path):
808
845
  try:
809
- image_path = download(
810
- image_path,
811
- output_image_dir,
846
+ image_path = get_local_path(
847
+ url=image_path,
848
+ hostname=self.hostname,
812
849
  project_dir=self.project_dir,
813
- return_relative_path=True,
814
- upload_dir=self.upload_dir,
850
+ image_dir=self.upload_dir,
851
+ cache_dir=output_image_dir,
815
852
  download_resources=self.download_resources,
853
+ access_token=self.access_token,
854
+ task_id=task_id,
816
855
  )
856
+ # make path relative to output_image_dir
857
+ image_path = os.path.relpath(image_path, output_dir)
817
858
  except:
818
859
  logger.info(
819
860
  "Unable to download {image_path}. The item {item} will be skipped".format(
@@ -920,6 +961,8 @@ class Converter(object):
920
961
  annotations.append([category_id, x, y, w, h])
921
962
 
922
963
  elif "polygonlabels" in label or "polygon" in label:
964
+ if not ('points' in label):
965
+ continue
923
966
  points_abs = [(x / 100, y / 100) for x, y in label["points"]]
924
967
  annotations.append(
925
968
  [category_id]
@@ -218,7 +218,7 @@ def add_parser(subparsers):
218
218
  "--image-ext",
219
219
  dest="image_ext",
220
220
  help="image extension to search: .jpeg or .jpg, .png",
221
- default=".jpg",
221
+ default=".jpg,jpeg,.png",
222
222
  )
223
223
  yolo.add_argument(
224
224
  "--image-dims",