label-studio-sdk 1.0.10__py3-none-any.whl → 1.0.12__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 (40) hide show
  1. label_studio_sdk/__init__.py +21 -1
  2. label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +5 -0
  3. label_studio_sdk/base_client.py +8 -0
  4. label_studio_sdk/converter/converter.py +22 -0
  5. label_studio_sdk/converter/exports/brush_to_coco.py +332 -0
  6. label_studio_sdk/converter/main.py +14 -0
  7. label_studio_sdk/core/client_wrapper.py +34 -15
  8. label_studio_sdk/errors/__init__.py +3 -1
  9. label_studio_sdk/errors/not_found_error.py +9 -0
  10. label_studio_sdk/errors/unauthorized_error.py +9 -0
  11. label_studio_sdk/jwt_settings/__init__.py +2 -0
  12. label_studio_sdk/jwt_settings/client.py +259 -0
  13. label_studio_sdk/label_interface/control_tags.py +15 -2
  14. label_studio_sdk/label_interface/interface.py +80 -1
  15. label_studio_sdk/label_interface/object_tags.py +2 -2
  16. label_studio_sdk/projects/__init__.py +2 -1
  17. label_studio_sdk/projects/client.py +4 -0
  18. label_studio_sdk/projects/exports/client_ext.py +106 -40
  19. label_studio_sdk/projects/pauses/__init__.py +2 -0
  20. label_studio_sdk/projects/pauses/client.py +704 -0
  21. label_studio_sdk/projects/types/projects_update_response.py +10 -0
  22. label_studio_sdk/tokens/__init__.py +2 -0
  23. label_studio_sdk/tokens/client.py +610 -0
  24. label_studio_sdk/tokens/client_ext.py +94 -0
  25. label_studio_sdk/types/__init__.py +14 -0
  26. label_studio_sdk/types/access_token_response.py +22 -0
  27. label_studio_sdk/types/annotation.py +2 -1
  28. label_studio_sdk/types/annotation_completed_by.py +6 -0
  29. label_studio_sdk/types/api_token_response.py +32 -0
  30. label_studio_sdk/types/jwt_settings_response.py +32 -0
  31. label_studio_sdk/types/model_provider_connection_provider.py +1 -1
  32. label_studio_sdk/types/pause.py +34 -0
  33. label_studio_sdk/types/pause_paused_by.py +5 -0
  34. label_studio_sdk/types/project.py +10 -0
  35. label_studio_sdk/types/prompt_version_provider.py +1 -1
  36. label_studio_sdk/types/rotate_token_response.py +22 -0
  37. {label_studio_sdk-1.0.10.dist-info → label_studio_sdk-1.0.12.dist-info}/METADATA +3 -2
  38. {label_studio_sdk-1.0.10.dist-info → label_studio_sdk-1.0.12.dist-info}/RECORD +40 -23
  39. {label_studio_sdk-1.0.10.dist-info → label_studio_sdk-1.0.12.dist-info}/WHEEL +1 -1
  40. {label_studio_sdk-1.0.10.dist-info → label_studio_sdk-1.0.12.dist-info}/LICENSE +0 -0
@@ -23,28 +23,60 @@ class ExportTimeoutError(ApiError):
23
23
  )
24
24
  )
25
25
 
26
-
27
- def _bytestream_to_fileobj(bytestream: typing.Iterable[bytes]) -> typing.BinaryIO:
28
- buffer = BytesIO()
29
- for chunk in bytestream:
30
- buffer.write(chunk)
31
- buffer.seek(0)
32
- return buffer
26
+ class ExportFailedError(ApiError):
27
+
28
+ def __init__(self, export_snapshot):
29
+ super().__init__(
30
+ status_code=500,
31
+ body=f"Export failed: {export_snapshot}"
32
+ )
33
33
 
34
- def _bytestream_to_binary(bytestream: typing.Iterable[bytes]) -> bytes:
35
- fileobj = _bytestream_to_fileobj(bytestream)
36
- return fileobj.getvalue()
37
34
 
38
- def _bytestream_to_json(bytestream: typing.Iterable[bytes]) -> dict:
39
- fileobj = _bytestream_to_fileobj(bytestream)
40
- return json.load(fileobj)
35
+ def _check_status(export_snapshot, converted_format_id, status):
36
+ if converted_format_id:
37
+ converted_format = next((c for c in export_snapshot.converted_formats if c.id == converted_format_id), None)
38
+ if converted_format and converted_format.status == status:
39
+ return True
40
+ else:
41
+ if export_snapshot.status == status:
42
+ return True
43
+ return False
41
44
 
42
- def _bytestream_to_pandas(bytestream: typing.Iterable[bytes]) -> pd.DataFrame:
43
- fileobj = _bytestream_to_fileobj(bytestream)
44
- return pd.read_csv(fileobj)
45
45
 
46
46
  class ExportsClientExt(ExportsClient):
47
47
 
48
+ def _bytestream_to_fileobj(self, bytestream: typing.Iterable[bytes] | bytes) -> typing.BinaryIO:
49
+ buffer = BytesIO()
50
+ if isinstance(bytestream, typing.Iterable):
51
+ for chunk in bytestream:
52
+ buffer.write(chunk)
53
+ else:
54
+ buffer.write(bytestream)
55
+ buffer.seek(0)
56
+ return buffer
57
+
58
+ def _bytestream_to_binary(self, bytestream: typing.Iterable[bytes]) -> bytes:
59
+ fileobj = self._bytestream_to_fileobj(bytestream)
60
+ return fileobj.getvalue()
61
+
62
+ def _bytestream_to_json(self, bytestream: typing.Iterable[bytes]) -> dict:
63
+ fileobj = self._bytestream_to_fileobj(bytestream)
64
+ return json.load(fileobj)
65
+
66
+ def _bytestream_to_pandas(self, bytestream: typing.Iterable[bytes]) -> pd.DataFrame:
67
+ fileobj = self._bytestream_to_fileobj(bytestream)
68
+ return pd.read_csv(fileobj)
69
+
70
+ def _poll_export(self, project_id, export_snapshot, converted_format_id, timeout):
71
+ start_time = time.time()
72
+ while not _check_status(export_snapshot, None, 'completed'):
73
+ export_snapshot = self.get(project_id, export_pk=export_snapshot.id)
74
+ if _check_status(export_snapshot, None, 'failed'):
75
+ raise ExportFailedError(export_snapshot)
76
+ if time.time() - start_time > timeout:
77
+ raise ExportTimeoutError(export_snapshot)
78
+ time.sleep(1)
79
+
48
80
  def _get_bytestream(
49
81
  self,
50
82
  project_id: int,
@@ -59,14 +91,13 @@ class ExportsClientExt(ExportsClient):
59
91
  if version.edition == "Enterprise":
60
92
  # Enterprise edition exports are async, so we need to wait for the export job to complete
61
93
  export_snapshot = self.create(project_id, **(create_kwargs or {}))
94
+ # Poll for base (JSON) export to complete
95
+ self._poll_export(project_id, export_snapshot, None, timeout)
96
+ # Convert to requested format if not JSON
62
97
  if export_type != "JSON":
63
- self.convert(project_id, export_pk=export_snapshot.id, export_type=export_type, **(convert_kwargs or {}))
64
- start_time = time.time()
65
- while export_snapshot.status != "completed":
66
- export_snapshot = self.get(project_id, export_pk=export_snapshot.id)
67
- if time.time() - start_time > timeout:
68
- raise ExportTimeoutError(export_snapshot)
69
- time.sleep(1)
98
+ converted_proc = self.convert(project_id, export_pk=export_snapshot.id, export_type=export_type, **(convert_kwargs or {}))
99
+ self._poll_export(project_id, export_snapshot, converted_proc.converted_format, timeout)
100
+
70
101
  bytestream = self.download(project_id, export_pk=export_snapshot.id, export_type=export_type, request_options={'chunk_size': 1024}, **(download_kwargs or {}))
71
102
  else:
72
103
  # Community edition exports are sync, so we can download the file immediately
@@ -75,21 +106,57 @@ class ExportsClientExt(ExportsClient):
75
106
 
76
107
  def as_file(self, project_id: int, export_type: str = "JSON", timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
77
108
  bytestream = self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
78
- return _bytestream_to_fileobj(bytestream)
109
+ return self._bytestream_to_fileobj(bytestream)
79
110
 
80
111
  def as_binary(self, project_id: int, export_type: str = "JSON", timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
81
112
  bytestream = self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
82
- return _bytestream_to_binary(bytestream)
113
+ return self._bytestream_to_binary(bytestream)
83
114
 
84
115
  def as_json(self, project_id: int, timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
85
116
  bytestream = self._get_bytestream(project_id, "JSON", timeout, create_kwargs, convert_kwargs, download_kwargs)
86
- return _bytestream_to_json(bytestream)
117
+ return self._bytestream_to_json(bytestream)
87
118
 
88
119
  def as_pandas(self, project_id: int, timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
89
120
  bytestream = self._get_bytestream(project_id, "CSV", timeout, create_kwargs, convert_kwargs, download_kwargs)
90
- return _bytestream_to_pandas(bytestream)
121
+ return self._bytestream_to_pandas(bytestream)
91
122
 
92
123
  class AsyncExportsClientExt(AsyncExportsClient):
124
+
125
+ async def _bytestream_to_fileobj(self, bytestream: typing.AsyncGenerator[bytes, None] | bytes):
126
+ """Convert bytestream to file-like object"""
127
+ fileobj = BytesIO()
128
+ if isinstance(bytestream, typing.AsyncGenerator):
129
+ async for chunk in bytestream:
130
+ fileobj.write(chunk)
131
+ else:
132
+ fileobj.write(bytestream)
133
+ fileobj.seek(0)
134
+ return fileobj
135
+
136
+ async def _bytestream_to_binary(self, bytestream):
137
+ """Convert bytestream to binary data"""
138
+ fileobj = await self._bytestream_to_fileobj(bytestream)
139
+ return fileobj.getvalue()
140
+
141
+ async def _bytestream_to_json(self, bytestream):
142
+ """Convert bytestream to JSON object"""
143
+ fileobj = await self._bytestream_to_fileobj(bytestream)
144
+ return json.load(fileobj)
145
+
146
+ async def _bytestream_to_pandas(self, bytestream):
147
+ """Convert bytestream to pandas DataFrame"""
148
+ fileobj = await self._bytestream_to_fileobj(bytestream)
149
+ return pd.read_csv(fileobj)
150
+
151
+ async def _poll_export(self, project_id, export_snapshot, converted_format_id, timeout):
152
+ start_time = time.time()
153
+ while not _check_status(export_snapshot, None, 'completed'):
154
+ export_snapshot = await self.get(project_id, export_pk=export_snapshot.id)
155
+ if _check_status(export_snapshot, None, 'failed'):
156
+ raise ExportFailedError(export_snapshot)
157
+ if time.time() - start_time > timeout:
158
+ raise ExportTimeoutError(export_snapshot)
159
+ await asyncio.sleep(1)
93
160
 
94
161
  async def _get_bytestream(
95
162
  self,
@@ -104,31 +171,30 @@ class AsyncExportsClientExt(AsyncExportsClient):
104
171
  if version.edition == "Enterprise":
105
172
  # Enterprise edition exports are async, so we need to wait for the export job to complete
106
173
  export_snapshot = await self.create(project_id, **(create_kwargs or {}))
174
+ # Poll for base (JSON) export to complete
175
+ await self._poll_export(project_id, export_snapshot, None, timeout)
176
+ # Convert to requested format if not JSON
107
177
  if export_type != "JSON":
108
- await self.convert(project_id, export_pk=export_snapshot.id, export_type=export_type, **(convert_kwargs or {}))
109
- start_time = time.time()
110
- while export_snapshot.status != "completed":
111
- export_snapshot = await self.get(project_id, export_pk=export_snapshot.id)
112
- if time.time() - start_time > timeout:
113
- raise ExportTimeoutError(export_snapshot)
114
- await asyncio.sleep(1)
115
- bytestream = await self.download(project_id, export_pk=export_snapshot.id, export_type=export_type, request_options={'chunk_size': 1024}, **(download_kwargs or {}))
178
+ converted_proc = await self.convert(project_id, export_pk=export_snapshot.id, export_type=export_type, **(convert_kwargs or {}))
179
+ await self._poll_export(project_id, export_snapshot, converted_proc.converted_format, timeout)
180
+
181
+ bytestream = self.download(project_id, export_pk=export_snapshot.id, export_type=export_type, request_options={'chunk_size': 1024}, **(download_kwargs or {}))
116
182
  else:
117
- bytestream = await self.download_sync(project_id, export_type=export_type, download_all_tasks=True, download_resources=True)
183
+ bytestream = self.download_sync(project_id, export_type=export_type, download_all_tasks=True, download_resources=True)
118
184
  return bytestream
119
185
 
120
186
  async def as_file(self, project_id: int, export_type: str = "JSON", timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
121
187
  bytestream = await self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
122
- return _bytestream_to_fileobj(bytestream)
188
+ return await self._bytestream_to_fileobj(bytestream)
123
189
 
124
190
  async def as_binary(self, project_id: int, export_type: str = "JSON", timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
125
191
  bytestream = await self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
126
- return _bytestream_to_binary(bytestream)
192
+ return await self._bytestream_to_binary(bytestream)
127
193
 
128
194
  async def as_json(self, project_id: int, timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
129
195
  bytestream = await self._get_bytestream(project_id, "JSON", timeout, create_kwargs, convert_kwargs, download_kwargs)
130
- return _bytestream_to_json(bytestream)
196
+ return await self._bytestream_to_json(bytestream)
131
197
 
132
198
  async def as_pandas(self, project_id: int, timeout: int = 60, create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None, download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None):
133
199
  bytestream = await self._get_bytestream(project_id, "CSV", timeout, create_kwargs, convert_kwargs, download_kwargs)
134
- return _bytestream_to_pandas(bytestream)
200
+ return await self._bytestream_to_pandas(bytestream)
@@ -0,0 +1,2 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+