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.
- label_studio_sdk/__init__.py +37 -8
- label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +16 -4
- label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +5 -0
- label_studio_sdk/_extensions/pager_ext.py +8 -0
- label_studio_sdk/actions/client.py +91 -40
- label_studio_sdk/actions/types/actions_create_request_filters.py +14 -24
- label_studio_sdk/actions/types/actions_create_request_filters_items_item.py +16 -26
- label_studio_sdk/actions/types/actions_create_request_filters_items_item_value.py +3 -1
- label_studio_sdk/actions/types/actions_create_request_selected_items.py +1 -2
- label_studio_sdk/actions/types/actions_create_request_selected_items_excluded.py +15 -25
- label_studio_sdk/actions/types/actions_create_request_selected_items_included.py +15 -25
- label_studio_sdk/annotations/__init__.py +2 -2
- label_studio_sdk/annotations/client.py +278 -104
- label_studio_sdk/annotations/types/__init__.py +2 -1
- label_studio_sdk/annotations/types/annotations_create_bulk_request_selected_items.py +34 -0
- label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +11 -21
- label_studio_sdk/base_client.py +54 -27
- label_studio_sdk/client.py +1 -0
- label_studio_sdk/comments/client.py +190 -44
- label_studio_sdk/converter/converter.py +56 -13
- label_studio_sdk/converter/imports/yolo.py +1 -1
- label_studio_sdk/converter/utils.py +3 -2
- label_studio_sdk/core/__init__.py +21 -4
- label_studio_sdk/core/client_wrapper.py +37 -19
- label_studio_sdk/core/file.py +37 -8
- label_studio_sdk/core/http_client.py +52 -28
- label_studio_sdk/core/jsonable_encoder.py +33 -31
- label_studio_sdk/core/pagination.py +5 -4
- label_studio_sdk/core/pydantic_utilities.py +272 -4
- label_studio_sdk/core/query_encoder.py +38 -13
- label_studio_sdk/core/request_options.py +3 -0
- label_studio_sdk/core/serialization.py +272 -0
- label_studio_sdk/errors/__init__.py +3 -1
- label_studio_sdk/errors/bad_request_error.py +2 -3
- label_studio_sdk/errors/not_found_error.py +9 -0
- label_studio_sdk/errors/unauthorized_error.py +9 -0
- label_studio_sdk/export_storage/azure/client.py +228 -58
- label_studio_sdk/export_storage/azure/types/azure_create_response.py +19 -29
- label_studio_sdk/export_storage/azure/types/azure_update_response.py +19 -29
- label_studio_sdk/export_storage/client.py +48 -18
- label_studio_sdk/export_storage/gcs/client.py +228 -58
- label_studio_sdk/export_storage/gcs/types/gcs_create_response.py +19 -29
- label_studio_sdk/export_storage/gcs/types/gcs_update_response.py +19 -29
- label_studio_sdk/export_storage/local/client.py +222 -56
- label_studio_sdk/export_storage/local/types/local_create_response.py +17 -27
- label_studio_sdk/export_storage/local/types/local_update_response.py +17 -27
- label_studio_sdk/export_storage/redis/client.py +228 -58
- label_studio_sdk/export_storage/redis/types/redis_create_response.py +20 -30
- label_studio_sdk/export_storage/redis/types/redis_update_response.py +20 -30
- label_studio_sdk/export_storage/s3/client.py +228 -58
- label_studio_sdk/export_storage/s3/types/s3create_response.py +27 -35
- label_studio_sdk/export_storage/s3/types/s3update_response.py +27 -35
- label_studio_sdk/export_storage/s3s/client.py +187 -43
- label_studio_sdk/export_storage/types/export_storage_list_types_response_item.py +11 -21
- label_studio_sdk/files/client.py +172 -56
- label_studio_sdk/import_storage/azure/client.py +223 -53
- label_studio_sdk/import_storage/azure/types/azure_create_response.py +22 -32
- label_studio_sdk/import_storage/azure/types/azure_update_response.py +22 -32
- label_studio_sdk/import_storage/client.py +48 -18
- label_studio_sdk/import_storage/gcs/client.py +223 -53
- label_studio_sdk/import_storage/gcs/types/gcs_create_response.py +22 -32
- label_studio_sdk/import_storage/gcs/types/gcs_update_response.py +22 -32
- label_studio_sdk/import_storage/local/client.py +223 -53
- label_studio_sdk/import_storage/local/types/local_create_response.py +17 -27
- label_studio_sdk/import_storage/local/types/local_update_response.py +17 -27
- label_studio_sdk/import_storage/redis/client.py +223 -53
- label_studio_sdk/import_storage/redis/types/redis_create_response.py +20 -30
- label_studio_sdk/import_storage/redis/types/redis_update_response.py +20 -30
- label_studio_sdk/import_storage/s3/client.py +223 -53
- label_studio_sdk/import_storage/s3/types/s3create_response.py +31 -39
- label_studio_sdk/import_storage/s3/types/s3update_response.py +31 -39
- label_studio_sdk/import_storage/s3s/client.py +222 -52
- label_studio_sdk/import_storage/types/import_storage_list_types_response_item.py +11 -21
- label_studio_sdk/jwt_settings/__init__.py +2 -0
- label_studio_sdk/jwt_settings/client.py +259 -0
- label_studio_sdk/label_interface/control_tags.py +16 -3
- label_studio_sdk/label_interface/interface.py +80 -1
- label_studio_sdk/label_interface/object_tags.py +2 -2
- label_studio_sdk/ml/client.py +280 -78
- label_studio_sdk/ml/types/ml_create_response.py +21 -31
- label_studio_sdk/ml/types/ml_update_response.py +21 -31
- label_studio_sdk/model_providers/client.py +173 -56
- label_studio_sdk/predictions/client.py +247 -101
- label_studio_sdk/projects/__init__.py +5 -1
- label_studio_sdk/projects/client.py +313 -115
- label_studio_sdk/projects/client_ext.py +16 -0
- label_studio_sdk/projects/exports/__init__.py +3 -0
- label_studio_sdk/projects/exports/client.py +447 -296
- label_studio_sdk/projects/exports/client_ext.py +200 -0
- label_studio_sdk/projects/exports/types/__init__.py +6 -0
- label_studio_sdk/projects/exports/types/exports_convert_response.py +24 -0
- label_studio_sdk/projects/exports/types/exports_list_formats_response_item.py +44 -0
- label_studio_sdk/projects/pauses/__init__.py +2 -0
- label_studio_sdk/projects/pauses/client.py +704 -0
- label_studio_sdk/projects/types/projects_create_response.py +29 -34
- label_studio_sdk/projects/types/projects_import_tasks_response.py +19 -29
- label_studio_sdk/projects/types/projects_list_response.py +11 -21
- label_studio_sdk/projects/types/projects_update_response.py +34 -34
- label_studio_sdk/prompts/client.py +309 -92
- label_studio_sdk/prompts/indicators/client.py +67 -23
- label_studio_sdk/prompts/runs/client.py +95 -40
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +14 -24
- label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +11 -21
- label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +26 -29
- label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +11 -21
- label_studio_sdk/prompts/versions/client.py +277 -88
- label_studio_sdk/tasks/client.py +263 -90
- label_studio_sdk/tasks/types/tasks_list_response.py +15 -25
- label_studio_sdk/tokens/__init__.py +2 -0
- label_studio_sdk/tokens/client.py +470 -0
- label_studio_sdk/tokens/client_ext.py +94 -0
- label_studio_sdk/types/__init__.py +20 -6
- label_studio_sdk/types/access_token_response.py +22 -0
- label_studio_sdk/types/annotation.py +29 -38
- label_studio_sdk/types/annotation_filter_options.py +14 -24
- label_studio_sdk/types/annotations_dm_field.py +30 -39
- label_studio_sdk/types/api_token_response.py +32 -0
- label_studio_sdk/types/azure_blob_export_storage.py +28 -37
- label_studio_sdk/types/azure_blob_import_storage.py +28 -37
- label_studio_sdk/types/base_task.py +30 -39
- label_studio_sdk/types/base_task_updated_by.py +3 -1
- label_studio_sdk/types/base_user.py +14 -21
- label_studio_sdk/types/comment.py +12 -21
- label_studio_sdk/types/comment_created_by.py +1 -1
- label_studio_sdk/types/converted_format.py +12 -22
- label_studio_sdk/types/data_manager_task_serializer.py +31 -40
- label_studio_sdk/types/data_manager_task_serializer_annotators_item.py +1 -1
- label_studio_sdk/types/data_manager_task_serializer_drafts_item.py +13 -22
- label_studio_sdk/types/data_manager_task_serializer_predictions_item.py +15 -24
- label_studio_sdk/types/export.py +17 -26
- label_studio_sdk/types/export_format.py +25 -0
- label_studio_sdk/types/export_snapshot.py +45 -0
- label_studio_sdk/types/export_snapshot_status.py +5 -0
- label_studio_sdk/types/file_upload.py +11 -21
- label_studio_sdk/types/filter.py +16 -26
- label_studio_sdk/types/filter_group.py +12 -22
- label_studio_sdk/types/gcs_export_storage.py +28 -37
- label_studio_sdk/types/gcs_import_storage.py +28 -37
- label_studio_sdk/types/inference_run.py +14 -23
- label_studio_sdk/types/inference_run_cost_estimate.py +17 -27
- label_studio_sdk/types/inference_run_created_by.py +1 -1
- label_studio_sdk/types/inference_run_organization.py +1 -1
- label_studio_sdk/types/jwt_settings_response.py +32 -0
- label_studio_sdk/types/key_indicator_value.py +12 -22
- label_studio_sdk/types/key_indicators.py +0 -1
- label_studio_sdk/types/key_indicators_item.py +15 -25
- label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +13 -23
- label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +13 -23
- label_studio_sdk/types/local_files_export_storage.py +25 -34
- label_studio_sdk/types/local_files_import_storage.py +24 -33
- label_studio_sdk/types/ml_backend.py +23 -32
- label_studio_sdk/types/model_provider_connection.py +22 -31
- label_studio_sdk/types/model_provider_connection_created_by.py +1 -1
- label_studio_sdk/types/model_provider_connection_organization.py +1 -1
- label_studio_sdk/types/model_provider_connection_provider.py +3 -1
- label_studio_sdk/types/pause.py +34 -0
- label_studio_sdk/types/pause_paused_by.py +5 -0
- label_studio_sdk/types/prediction.py +21 -30
- label_studio_sdk/types/project.py +58 -55
- label_studio_sdk/types/project_import.py +21 -30
- label_studio_sdk/types/project_label_config.py +12 -22
- label_studio_sdk/types/prompt.py +24 -32
- label_studio_sdk/types/prompt_associated_projects_item.py +6 -0
- label_studio_sdk/types/prompt_associated_projects_item_id.py +20 -0
- label_studio_sdk/types/prompt_created_by.py +1 -1
- label_studio_sdk/types/prompt_organization.py +1 -1
- label_studio_sdk/types/prompt_version.py +13 -22
- label_studio_sdk/types/prompt_version_created_by.py +1 -1
- label_studio_sdk/types/prompt_version_organization.py +1 -1
- label_studio_sdk/types/prompt_version_provider.py +3 -1
- label_studio_sdk/types/redis_export_storage.py +29 -38
- label_studio_sdk/types/redis_import_storage.py +28 -37
- label_studio_sdk/types/refined_prompt_response.py +19 -29
- label_studio_sdk/types/s3export_storage.py +36 -43
- label_studio_sdk/types/s3import_storage.py +37 -44
- label_studio_sdk/types/s3s_export_storage.py +26 -33
- label_studio_sdk/types/s3s_import_storage.py +35 -42
- label_studio_sdk/types/serialization_option.py +12 -22
- label_studio_sdk/types/serialization_options.py +18 -28
- label_studio_sdk/types/task.py +44 -47
- label_studio_sdk/types/task_annotators_item.py +1 -1
- label_studio_sdk/types/task_comment_authors_item.py +1 -1
- label_studio_sdk/types/task_filter_options.py +15 -25
- label_studio_sdk/types/user_simple.py +11 -21
- label_studio_sdk/types/view.py +16 -26
- label_studio_sdk/types/webhook.py +19 -28
- label_studio_sdk/types/webhook_serializer_for_update.py +19 -28
- label_studio_sdk/types/workspace.py +22 -31
- label_studio_sdk/users/client.py +257 -63
- label_studio_sdk/users/types/users_get_token_response.py +12 -22
- label_studio_sdk/users/types/users_reset_token_response.py +12 -22
- label_studio_sdk/version.py +0 -1
- label_studio_sdk/versions/__init__.py +5 -0
- label_studio_sdk/versions/client.py +112 -0
- label_studio_sdk/versions/types/__init__.py +6 -0
- label_studio_sdk/versions/types/versions_get_response.py +73 -0
- label_studio_sdk/versions/types/versions_get_response_edition.py +5 -0
- label_studio_sdk/views/client.py +219 -52
- label_studio_sdk/views/types/views_create_request_data.py +13 -23
- label_studio_sdk/views/types/views_create_request_data_filters.py +14 -24
- label_studio_sdk/views/types/views_create_request_data_filters_items_item.py +16 -26
- label_studio_sdk/views/types/views_create_request_data_filters_items_item_value.py +3 -1
- label_studio_sdk/views/types/views_update_request_data.py +13 -23
- label_studio_sdk/views/types/views_update_request_data_filters.py +14 -24
- label_studio_sdk/views/types/views_update_request_data_filters_items_item.py +16 -26
- label_studio_sdk/views/types/views_update_request_data_filters_items_item_value.py +3 -1
- label_studio_sdk/webhooks/client.py +191 -61
- label_studio_sdk/workspaces/client.py +164 -41
- label_studio_sdk/workspaces/members/client.py +109 -31
- label_studio_sdk/workspaces/members/types/members_create_response.py +12 -22
- label_studio_sdk/workspaces/members/types/members_list_response_item.py +12 -22
- {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/METADATA +8 -5
- {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/RECORD +215 -188
- {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/WHEEL +1 -1
- label_studio_sdk/types/export_convert.py +0 -32
- label_studio_sdk/types/export_create.py +0 -54
- label_studio_sdk/types/export_create_status.py +0 -5
- {label_studio_sdk-1.0.8.dist-info → label_studio_sdk-1.0.11.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
import asyncio
|
|
4
|
+
import typing
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from .client import ExportsClient, AsyncExportsClient
|
|
7
|
+
from io import BytesIO
|
|
8
|
+
from label_studio_sdk.versions.client import VersionsClient, AsyncVersionsClient
|
|
9
|
+
from label_studio_sdk.core.api_error import ApiError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ExportTimeoutError(ApiError):
|
|
13
|
+
|
|
14
|
+
def __init__(self, export_snapshot):
|
|
15
|
+
super().__init__(
|
|
16
|
+
status_code=500,
|
|
17
|
+
body=(
|
|
18
|
+
f"Export job timed out after {timeout} seconds: "
|
|
19
|
+
f"unable to retrieve export job {export_snapshot.id}. "
|
|
20
|
+
f"Current status: {export_snapshot.status}. "
|
|
21
|
+
f"Try manually checking the running job with "
|
|
22
|
+
f"`ls.projects.exports.get(project_id={project_id}, export_pk={export_snapshot.id})`."
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
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
|
+
|
|
34
|
+
|
|
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
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ExportsClientExt(ExportsClient):
|
|
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
|
+
|
|
80
|
+
def _get_bytestream(
|
|
81
|
+
self,
|
|
82
|
+
project_id: int,
|
|
83
|
+
export_type: str,
|
|
84
|
+
timeout: int = 60,
|
|
85
|
+
create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
86
|
+
convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
87
|
+
download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
88
|
+
):
|
|
89
|
+
version = VersionsClient(client_wrapper=self._client_wrapper).get()
|
|
90
|
+
|
|
91
|
+
if version.edition == "Enterprise":
|
|
92
|
+
# Enterprise edition exports are async, so we need to wait for the export job to complete
|
|
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
|
|
97
|
+
if export_type != "JSON":
|
|
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
|
+
|
|
101
|
+
bytestream = self.download(project_id, export_pk=export_snapshot.id, export_type=export_type, request_options={'chunk_size': 1024}, **(download_kwargs or {}))
|
|
102
|
+
else:
|
|
103
|
+
# Community edition exports are sync, so we can download the file immediately
|
|
104
|
+
bytestream = self.download_sync(project_id, export_type=export_type, download_all_tasks=True, download_resources=True)
|
|
105
|
+
return bytestream
|
|
106
|
+
|
|
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):
|
|
108
|
+
bytestream = self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
109
|
+
return self._bytestream_to_fileobj(bytestream)
|
|
110
|
+
|
|
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):
|
|
112
|
+
bytestream = self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
113
|
+
return self._bytestream_to_binary(bytestream)
|
|
114
|
+
|
|
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):
|
|
116
|
+
bytestream = self._get_bytestream(project_id, "JSON", timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
117
|
+
return self._bytestream_to_json(bytestream)
|
|
118
|
+
|
|
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):
|
|
120
|
+
bytestream = self._get_bytestream(project_id, "CSV", timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
121
|
+
return self._bytestream_to_pandas(bytestream)
|
|
122
|
+
|
|
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)
|
|
160
|
+
|
|
161
|
+
async def _get_bytestream(
|
|
162
|
+
self,
|
|
163
|
+
project_id: int,
|
|
164
|
+
export_type: str,
|
|
165
|
+
timeout: int = 60,
|
|
166
|
+
create_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
167
|
+
convert_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
168
|
+
download_kwargs: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
169
|
+
):
|
|
170
|
+
version = await AsyncVersionsClient(client_wrapper=self._client_wrapper).get()
|
|
171
|
+
if version.edition == "Enterprise":
|
|
172
|
+
# Enterprise edition exports are async, so we need to wait for the export job to complete
|
|
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
|
|
177
|
+
if export_type != "JSON":
|
|
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 {}))
|
|
182
|
+
else:
|
|
183
|
+
bytestream = self.download_sync(project_id, export_type=export_type, download_all_tasks=True, download_resources=True)
|
|
184
|
+
return bytestream
|
|
185
|
+
|
|
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):
|
|
187
|
+
bytestream = await self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
188
|
+
return await self._bytestream_to_fileobj(bytestream)
|
|
189
|
+
|
|
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):
|
|
191
|
+
bytestream = await self._get_bytestream(project_id, export_type, timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
192
|
+
return await self._bytestream_to_binary(bytestream)
|
|
193
|
+
|
|
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):
|
|
195
|
+
bytestream = await self._get_bytestream(project_id, "JSON", timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
196
|
+
return await self._bytestream_to_json(bytestream)
|
|
197
|
+
|
|
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):
|
|
199
|
+
bytestream = await self._get_bytestream(project_id, "CSV", timeout, create_kwargs, convert_kwargs, download_kwargs)
|
|
200
|
+
return await self._bytestream_to_pandas(bytestream)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from .exports_convert_response import ExportsConvertResponse
|
|
4
|
+
from .exports_list_formats_response_item import ExportsListFormatsResponseItem
|
|
5
|
+
|
|
6
|
+
__all__ = ["ExportsConvertResponse", "ExportsListFormatsResponseItem"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from ....core.pydantic_utilities import UniversalBaseModel
|
|
4
|
+
import typing
|
|
5
|
+
from ....types.export_format import ExportFormat
|
|
6
|
+
import pydantic
|
|
7
|
+
from ....core.pydantic_utilities import IS_PYDANTIC_V2
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ExportsConvertResponse(UniversalBaseModel):
|
|
11
|
+
export_type: typing.Optional[ExportFormat] = None
|
|
12
|
+
converted_format: typing.Optional[int] = pydantic.Field(default=None)
|
|
13
|
+
"""
|
|
14
|
+
ID of the converted format
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
if IS_PYDANTIC_V2:
|
|
18
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
|
19
|
+
else:
|
|
20
|
+
|
|
21
|
+
class Config:
|
|
22
|
+
frozen = True
|
|
23
|
+
smart_union = True
|
|
24
|
+
extra = pydantic.Extra.allow
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from ....core.pydantic_utilities import UniversalBaseModel
|
|
4
|
+
import typing
|
|
5
|
+
from ....types.export_format import ExportFormat
|
|
6
|
+
import pydantic
|
|
7
|
+
from ....core.pydantic_utilities import IS_PYDANTIC_V2
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ExportsListFormatsResponseItem(UniversalBaseModel):
|
|
11
|
+
name: typing.Optional[ExportFormat] = None
|
|
12
|
+
title: typing.Optional[str] = pydantic.Field(default=None)
|
|
13
|
+
"""
|
|
14
|
+
Export format title
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
description: typing.Optional[str] = pydantic.Field(default=None)
|
|
18
|
+
"""
|
|
19
|
+
Export format description
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
link: typing.Optional[str] = pydantic.Field(default=None)
|
|
23
|
+
"""
|
|
24
|
+
Export format documentation link
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None)
|
|
28
|
+
"""
|
|
29
|
+
Export format tags
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
disabled: typing.Optional[bool] = pydantic.Field(default=None)
|
|
33
|
+
"""
|
|
34
|
+
If true, the export format is not supported by the project.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
if IS_PYDANTIC_V2:
|
|
38
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
|
39
|
+
else:
|
|
40
|
+
|
|
41
|
+
class Config:
|
|
42
|
+
frozen = True
|
|
43
|
+
smart_union = True
|
|
44
|
+
extra = pydantic.Extra.allow
|