label-studio-sdk 0.0.32__py3-none-any.whl → 1.0.0__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.
- label_studio_sdk/__init__.py +206 -6
- label_studio_sdk/_extensions/label_studio_tools/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/core/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/core/label_config.py +163 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/exceptions.py +2 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +228 -0
- label_studio_sdk/_extensions/label_studio_tools/core/utils/params.py +45 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/__init__.py +1 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/beam.py +34 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/example.py +17 -0
- label_studio_sdk/_extensions/label_studio_tools/etl/registry.py +67 -0
- label_studio_sdk/_extensions/label_studio_tools/postprocessing/__init__.py +0 -0
- label_studio_sdk/_extensions/label_studio_tools/postprocessing/video.py +97 -0
- label_studio_sdk/_legacy/__init__.py +11 -0
- label_studio_sdk/_legacy/client.py +471 -0
- label_studio_sdk/_legacy/exceptions.py +10 -0
- label_studio_sdk/_legacy/label_interface/__init__.py +1 -0
- label_studio_sdk/_legacy/label_interface/base.py +77 -0
- label_studio_sdk/_legacy/label_interface/control_tags.py +756 -0
- label_studio_sdk/_legacy/label_interface/data_examples.json +96 -0
- label_studio_sdk/_legacy/label_interface/interface.py +925 -0
- label_studio_sdk/_legacy/label_interface/label_tags.py +72 -0
- label_studio_sdk/_legacy/label_interface/object_tags.py +292 -0
- label_studio_sdk/_legacy/label_interface/region.py +43 -0
- label_studio_sdk/_legacy/objects.py +35 -0
- label_studio_sdk/{project.py → _legacy/project.py} +711 -258
- label_studio_sdk/_legacy/schema/label_config_schema.json +226 -0
- label_studio_sdk/{users.py → _legacy/users.py} +15 -13
- label_studio_sdk/{utils.py → _legacy/utils.py} +31 -30
- label_studio_sdk/{workspaces.py → _legacy/workspaces.py} +13 -11
- label_studio_sdk/actions/__init__.py +2 -0
- label_studio_sdk/actions/client.py +150 -0
- label_studio_sdk/annotations/__init__.py +2 -0
- label_studio_sdk/annotations/client.py +750 -0
- label_studio_sdk/client.py +164 -436
- label_studio_sdk/converter/__init__.py +7 -0
- label_studio_sdk/converter/audio.py +56 -0
- label_studio_sdk/converter/brush.py +452 -0
- label_studio_sdk/converter/converter.py +1175 -0
- label_studio_sdk/converter/exports/__init__.py +0 -0
- label_studio_sdk/converter/exports/csv.py +82 -0
- label_studio_sdk/converter/exports/csv2.py +103 -0
- label_studio_sdk/converter/funsd.py +85 -0
- label_studio_sdk/converter/imports/__init__.py +0 -0
- label_studio_sdk/converter/imports/coco.py +314 -0
- label_studio_sdk/converter/imports/colors.py +198 -0
- label_studio_sdk/converter/imports/label_config.py +45 -0
- label_studio_sdk/converter/imports/pathtrack.py +269 -0
- label_studio_sdk/converter/imports/yolo.py +236 -0
- label_studio_sdk/converter/main.py +202 -0
- label_studio_sdk/converter/utils.py +473 -0
- label_studio_sdk/core/__init__.py +33 -0
- label_studio_sdk/core/api_error.py +15 -0
- label_studio_sdk/core/client_wrapper.py +55 -0
- label_studio_sdk/core/datetime_utils.py +28 -0
- label_studio_sdk/core/file.py +38 -0
- label_studio_sdk/core/http_client.py +443 -0
- label_studio_sdk/core/jsonable_encoder.py +99 -0
- label_studio_sdk/core/pagination.py +87 -0
- label_studio_sdk/core/pydantic_utilities.py +28 -0
- label_studio_sdk/core/query_encoder.py +33 -0
- label_studio_sdk/core/remove_none_from_dict.py +11 -0
- label_studio_sdk/core/request_options.py +32 -0
- label_studio_sdk/data_manager.py +32 -23
- label_studio_sdk/environment.py +7 -0
- label_studio_sdk/errors/__init__.py +6 -0
- label_studio_sdk/errors/bad_request_error.py +8 -0
- label_studio_sdk/errors/internal_server_error.py +8 -0
- label_studio_sdk/export_storage/__init__.py +28 -0
- label_studio_sdk/export_storage/azure/__init__.py +5 -0
- label_studio_sdk/export_storage/azure/client.py +722 -0
- label_studio_sdk/export_storage/azure/types/__init__.py +6 -0
- label_studio_sdk/export_storage/azure/types/azure_create_response.py +52 -0
- label_studio_sdk/export_storage/azure/types/azure_update_response.py +52 -0
- label_studio_sdk/export_storage/client.py +107 -0
- label_studio_sdk/export_storage/gcs/__init__.py +5 -0
- label_studio_sdk/export_storage/gcs/client.py +722 -0
- label_studio_sdk/export_storage/gcs/types/__init__.py +6 -0
- label_studio_sdk/export_storage/gcs/types/gcs_create_response.py +52 -0
- label_studio_sdk/export_storage/gcs/types/gcs_update_response.py +52 -0
- label_studio_sdk/export_storage/local/__init__.py +5 -0
- label_studio_sdk/export_storage/local/client.py +688 -0
- label_studio_sdk/export_storage/local/types/__init__.py +6 -0
- label_studio_sdk/export_storage/local/types/local_create_response.py +47 -0
- label_studio_sdk/export_storage/local/types/local_update_response.py +47 -0
- label_studio_sdk/export_storage/redis/__init__.py +5 -0
- label_studio_sdk/export_storage/redis/client.py +714 -0
- label_studio_sdk/export_storage/redis/types/__init__.py +6 -0
- label_studio_sdk/export_storage/redis/types/redis_create_response.py +57 -0
- label_studio_sdk/export_storage/redis/types/redis_update_response.py +57 -0
- label_studio_sdk/export_storage/s3/__init__.py +5 -0
- label_studio_sdk/export_storage/s3/client.py +820 -0
- label_studio_sdk/export_storage/s3/types/__init__.py +6 -0
- label_studio_sdk/export_storage/s3/types/s3create_response.py +74 -0
- label_studio_sdk/export_storage/s3/types/s3update_response.py +74 -0
- label_studio_sdk/export_storage/types/__init__.py +5 -0
- label_studio_sdk/export_storage/types/export_storage_list_types_response_item.py +30 -0
- label_studio_sdk/files/__init__.py +2 -0
- label_studio_sdk/files/client.py +556 -0
- label_studio_sdk/import_storage/__init__.py +28 -0
- label_studio_sdk/import_storage/azure/__init__.py +5 -0
- label_studio_sdk/import_storage/azure/client.py +812 -0
- label_studio_sdk/import_storage/azure/types/__init__.py +6 -0
- label_studio_sdk/import_storage/azure/types/azure_create_response.py +72 -0
- label_studio_sdk/import_storage/azure/types/azure_update_response.py +72 -0
- label_studio_sdk/import_storage/client.py +107 -0
- label_studio_sdk/import_storage/gcs/__init__.py +5 -0
- label_studio_sdk/import_storage/gcs/client.py +812 -0
- label_studio_sdk/import_storage/gcs/types/__init__.py +6 -0
- label_studio_sdk/import_storage/gcs/types/gcs_create_response.py +72 -0
- label_studio_sdk/import_storage/gcs/types/gcs_update_response.py +72 -0
- label_studio_sdk/import_storage/local/__init__.py +5 -0
- label_studio_sdk/import_storage/local/client.py +690 -0
- label_studio_sdk/import_storage/local/types/__init__.py +6 -0
- label_studio_sdk/import_storage/local/types/local_create_response.py +47 -0
- label_studio_sdk/import_storage/local/types/local_update_response.py +47 -0
- label_studio_sdk/import_storage/redis/__init__.py +5 -0
- label_studio_sdk/import_storage/redis/client.py +768 -0
- label_studio_sdk/import_storage/redis/types/__init__.py +6 -0
- label_studio_sdk/import_storage/redis/types/redis_create_response.py +62 -0
- label_studio_sdk/import_storage/redis/types/redis_update_response.py +62 -0
- label_studio_sdk/import_storage/s3/__init__.py +5 -0
- label_studio_sdk/import_storage/s3/client.py +912 -0
- label_studio_sdk/import_storage/s3/types/__init__.py +6 -0
- label_studio_sdk/import_storage/s3/types/s3create_response.py +99 -0
- label_studio_sdk/import_storage/s3/types/s3update_response.py +99 -0
- label_studio_sdk/import_storage/types/__init__.py +5 -0
- label_studio_sdk/import_storage/types/import_storage_list_types_response_item.py +30 -0
- label_studio_sdk/ml/__init__.py +19 -0
- label_studio_sdk/ml/client.py +981 -0
- label_studio_sdk/ml/types/__init__.py +17 -0
- label_studio_sdk/ml/types/ml_create_request_auth_method.py +5 -0
- label_studio_sdk/ml/types/ml_create_response.py +78 -0
- label_studio_sdk/ml/types/ml_create_response_auth_method.py +5 -0
- label_studio_sdk/ml/types/ml_update_request_auth_method.py +5 -0
- label_studio_sdk/ml/types/ml_update_response.py +78 -0
- label_studio_sdk/ml/types/ml_update_response_auth_method.py +5 -0
- label_studio_sdk/predictions/__init__.py +2 -0
- label_studio_sdk/predictions/client.py +638 -0
- label_studio_sdk/projects/__init__.py +6 -0
- label_studio_sdk/projects/client.py +1053 -0
- label_studio_sdk/projects/exports/__init__.py +2 -0
- label_studio_sdk/projects/exports/client.py +930 -0
- label_studio_sdk/projects/types/__init__.py +7 -0
- label_studio_sdk/projects/types/projects_create_response.py +96 -0
- label_studio_sdk/projects/types/projects_import_tasks_response.py +71 -0
- label_studio_sdk/projects/types/projects_list_response.py +33 -0
- label_studio_sdk/py.typed +0 -0
- label_studio_sdk/tasks/__init__.py +5 -0
- label_studio_sdk/tasks/client.py +811 -0
- label_studio_sdk/tasks/types/__init__.py +6 -0
- label_studio_sdk/tasks/types/tasks_list_request_fields.py +5 -0
- label_studio_sdk/tasks/types/tasks_list_response.py +48 -0
- label_studio_sdk/types/__init__.py +115 -0
- label_studio_sdk/types/annotation.py +116 -0
- label_studio_sdk/types/annotation_filter_options.py +42 -0
- label_studio_sdk/types/annotation_last_action.py +19 -0
- label_studio_sdk/types/azure_blob_export_storage.py +112 -0
- label_studio_sdk/types/azure_blob_export_storage_status.py +7 -0
- label_studio_sdk/types/azure_blob_import_storage.py +113 -0
- label_studio_sdk/types/azure_blob_import_storage_status.py +7 -0
- label_studio_sdk/types/base_task.py +113 -0
- label_studio_sdk/types/base_user.py +42 -0
- label_studio_sdk/types/converted_format.py +36 -0
- label_studio_sdk/types/converted_format_status.py +5 -0
- label_studio_sdk/types/export.py +48 -0
- label_studio_sdk/types/export_convert.py +32 -0
- label_studio_sdk/types/export_create.py +54 -0
- label_studio_sdk/types/export_create_status.py +5 -0
- label_studio_sdk/types/export_status.py +5 -0
- label_studio_sdk/types/file_upload.py +30 -0
- label_studio_sdk/types/filter.py +53 -0
- label_studio_sdk/types/filter_group.py +35 -0
- label_studio_sdk/types/gcs_export_storage.py +112 -0
- label_studio_sdk/types/gcs_export_storage_status.py +7 -0
- label_studio_sdk/types/gcs_import_storage.py +113 -0
- label_studio_sdk/types/gcs_import_storage_status.py +7 -0
- label_studio_sdk/types/local_files_export_storage.py +97 -0
- label_studio_sdk/types/local_files_export_storage_status.py +7 -0
- label_studio_sdk/types/local_files_import_storage.py +92 -0
- label_studio_sdk/types/local_files_import_storage_status.py +7 -0
- label_studio_sdk/types/ml_backend.py +89 -0
- label_studio_sdk/types/ml_backend_auth_method.py +5 -0
- label_studio_sdk/types/ml_backend_state.py +5 -0
- label_studio_sdk/types/prediction.py +78 -0
- label_studio_sdk/types/project.py +198 -0
- label_studio_sdk/types/project_import.py +63 -0
- label_studio_sdk/types/project_import_status.py +5 -0
- label_studio_sdk/types/project_label_config.py +32 -0
- label_studio_sdk/types/project_sampling.py +7 -0
- label_studio_sdk/types/project_skip_queue.py +5 -0
- label_studio_sdk/types/redis_export_storage.py +117 -0
- label_studio_sdk/types/redis_export_storage_status.py +7 -0
- label_studio_sdk/types/redis_import_storage.py +112 -0
- label_studio_sdk/types/redis_import_storage_status.py +7 -0
- label_studio_sdk/types/s3export_storage.py +134 -0
- label_studio_sdk/types/s3export_storage_status.py +7 -0
- label_studio_sdk/types/s3import_storage.py +140 -0
- label_studio_sdk/types/s3import_storage_status.py +7 -0
- label_studio_sdk/types/serialization_option.py +36 -0
- label_studio_sdk/types/serialization_options.py +45 -0
- label_studio_sdk/types/task.py +157 -0
- label_studio_sdk/types/task_filter_options.py +49 -0
- label_studio_sdk/types/user_simple.py +37 -0
- label_studio_sdk/types/view.py +55 -0
- label_studio_sdk/types/webhook.py +67 -0
- label_studio_sdk/types/webhook_actions_item.py +21 -0
- label_studio_sdk/types/webhook_serializer_for_update.py +67 -0
- label_studio_sdk/types/webhook_serializer_for_update_actions_item.py +21 -0
- label_studio_sdk/users/__init__.py +5 -0
- label_studio_sdk/users/client.py +830 -0
- label_studio_sdk/users/types/__init__.py +6 -0
- label_studio_sdk/users/types/users_get_token_response.py +36 -0
- label_studio_sdk/users/types/users_reset_token_response.py +36 -0
- label_studio_sdk/version.py +4 -0
- label_studio_sdk/views/__init__.py +31 -0
- label_studio_sdk/views/client.py +564 -0
- label_studio_sdk/views/types/__init__.py +29 -0
- label_studio_sdk/views/types/views_create_request_data.py +43 -0
- label_studio_sdk/views/types/views_create_request_data_filters.py +43 -0
- label_studio_sdk/views/types/views_create_request_data_filters_conjunction.py +5 -0
- label_studio_sdk/views/types/views_create_request_data_filters_items_item.py +47 -0
- label_studio_sdk/views/types/views_create_request_data_ordering_item.py +38 -0
- label_studio_sdk/views/types/views_create_request_data_ordering_item_direction.py +5 -0
- label_studio_sdk/views/types/views_update_request_data.py +43 -0
- label_studio_sdk/views/types/views_update_request_data_filters.py +43 -0
- label_studio_sdk/views/types/views_update_request_data_filters_conjunction.py +5 -0
- label_studio_sdk/views/types/views_update_request_data_filters_items_item.py +47 -0
- label_studio_sdk/views/types/views_update_request_data_ordering_item.py +38 -0
- label_studio_sdk/views/types/views_update_request_data_ordering_item_direction.py +5 -0
- label_studio_sdk/webhooks/__init__.py +5 -0
- label_studio_sdk/webhooks/client.py +636 -0
- label_studio_sdk/webhooks/types/__init__.py +5 -0
- label_studio_sdk/webhooks/types/webhooks_update_request_actions_item.py +21 -0
- label_studio_sdk-1.0.0.dist-info/METADATA +307 -0
- label_studio_sdk-1.0.0.dist-info/RECORD +239 -0
- {label_studio_sdk-0.0.32.dist-info → label_studio_sdk-1.0.0.dist-info}/WHEEL +1 -2
- docs/__init__.py +0 -3
- label_studio_sdk-0.0.32.dist-info/LICENSE +0 -201
- label_studio_sdk-0.0.32.dist-info/METADATA +0 -22
- label_studio_sdk-0.0.32.dist-info/RECORD +0 -15
- label_studio_sdk-0.0.32.dist-info/top_level.txt +0 -3
- tests/test_client.py +0 -26
- {tests → label_studio_sdk/_extensions}/__init__.py +0 -0
|
@@ -0,0 +1,1053 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
from json.decoder import JSONDecodeError
|
|
5
|
+
|
|
6
|
+
from ..core.api_error import ApiError
|
|
7
|
+
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
|
8
|
+
from ..core.jsonable_encoder import jsonable_encoder
|
|
9
|
+
from ..core.pagination import AsyncPager, SyncPager
|
|
10
|
+
from ..core.pydantic_utilities import pydantic_v1
|
|
11
|
+
from ..core.request_options import RequestOptions
|
|
12
|
+
from ..errors.bad_request_error import BadRequestError
|
|
13
|
+
from ..types.project import Project
|
|
14
|
+
from ..types.project_label_config import ProjectLabelConfig
|
|
15
|
+
from .exports.client import AsyncExportsClient, ExportsClient
|
|
16
|
+
from .types.projects_create_response import ProjectsCreateResponse
|
|
17
|
+
from .types.projects_import_tasks_response import ProjectsImportTasksResponse
|
|
18
|
+
from .types.projects_list_response import ProjectsListResponse
|
|
19
|
+
|
|
20
|
+
# this is used as the default value for optional parameters
|
|
21
|
+
OMIT = typing.cast(typing.Any, ...)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ProjectsClient:
|
|
25
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
|
26
|
+
self._client_wrapper = client_wrapper
|
|
27
|
+
self.exports = ExportsClient(client_wrapper=self._client_wrapper)
|
|
28
|
+
|
|
29
|
+
def list(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
ordering: typing.Optional[str] = None,
|
|
33
|
+
ids: typing.Optional[str] = None,
|
|
34
|
+
title: typing.Optional[str] = None,
|
|
35
|
+
page: typing.Optional[int] = None,
|
|
36
|
+
page_size: typing.Optional[int] = None,
|
|
37
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
38
|
+
) -> SyncPager[Project]:
|
|
39
|
+
"""
|
|
40
|
+
Return a list of the projects within your organization.
|
|
41
|
+
|
|
42
|
+
To perform most tasks with the Label Studio API, you must specify the project ID, sometimes referred to as the `pk`. The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using this API call.
|
|
43
|
+
|
|
44
|
+
To retrieve a list of your Label Studio projects, update the following command to match your own environment.
|
|
45
|
+
Replace the domain name, port, and authorization token, then run the following from the command line:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
curl -X GET https://localhost:8080/api/projects/ -H 'Authorization: Token abc123'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
ordering : typing.Optional[str]
|
|
54
|
+
Which field to use when ordering the results.
|
|
55
|
+
|
|
56
|
+
ids : typing.Optional[str]
|
|
57
|
+
ids
|
|
58
|
+
|
|
59
|
+
title : typing.Optional[str]
|
|
60
|
+
title
|
|
61
|
+
|
|
62
|
+
page : typing.Optional[int]
|
|
63
|
+
A page number within the paginated result set.
|
|
64
|
+
|
|
65
|
+
page_size : typing.Optional[int]
|
|
66
|
+
Number of results to return per page.
|
|
67
|
+
|
|
68
|
+
request_options : typing.Optional[RequestOptions]
|
|
69
|
+
Request-specific configuration.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
SyncPager[Project]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
Examples
|
|
77
|
+
--------
|
|
78
|
+
from label_studio_sdk.client import LabelStudio
|
|
79
|
+
|
|
80
|
+
client = LabelStudio(
|
|
81
|
+
api_key="YOUR_API_KEY",
|
|
82
|
+
)
|
|
83
|
+
client.projects.list()
|
|
84
|
+
"""
|
|
85
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
86
|
+
"api/projects/",
|
|
87
|
+
method="GET",
|
|
88
|
+
params={"ordering": ordering, "ids": ids, "title": title, "page": page, "page_size": page_size},
|
|
89
|
+
request_options=request_options,
|
|
90
|
+
)
|
|
91
|
+
if 200 <= _response.status_code < 300:
|
|
92
|
+
_parsed_response = pydantic_v1.parse_obj_as(ProjectsListResponse, _response.json()) # type: ignore
|
|
93
|
+
_has_next = True
|
|
94
|
+
_get_next = lambda: self.list(
|
|
95
|
+
ordering=ordering,
|
|
96
|
+
ids=ids,
|
|
97
|
+
title=title,
|
|
98
|
+
page=page + 1 if page is not None else 1,
|
|
99
|
+
page_size=page_size,
|
|
100
|
+
request_options=request_options,
|
|
101
|
+
)
|
|
102
|
+
_items = _parsed_response.results
|
|
103
|
+
return SyncPager(has_next=_has_next, items=_items, get_next=_get_next)
|
|
104
|
+
try:
|
|
105
|
+
_response_json = _response.json()
|
|
106
|
+
except JSONDecodeError:
|
|
107
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
108
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
109
|
+
|
|
110
|
+
def create(
|
|
111
|
+
self,
|
|
112
|
+
*,
|
|
113
|
+
title: typing.Optional[str] = OMIT,
|
|
114
|
+
description: typing.Optional[str] = OMIT,
|
|
115
|
+
label_config: typing.Optional[str] = OMIT,
|
|
116
|
+
expert_instruction: typing.Optional[str] = OMIT,
|
|
117
|
+
show_instruction: typing.Optional[bool] = OMIT,
|
|
118
|
+
show_skip_button: typing.Optional[bool] = OMIT,
|
|
119
|
+
enable_empty_annotation: typing.Optional[bool] = OMIT,
|
|
120
|
+
show_annotation_history: typing.Optional[bool] = OMIT,
|
|
121
|
+
reveal_preannotations_interactively: typing.Optional[bool] = OMIT,
|
|
122
|
+
show_collab_predictions: typing.Optional[bool] = OMIT,
|
|
123
|
+
maximum_annotations: typing.Optional[int] = OMIT,
|
|
124
|
+
color: typing.Optional[str] = OMIT,
|
|
125
|
+
control_weights: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
|
|
126
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
127
|
+
) -> ProjectsCreateResponse:
|
|
128
|
+
"""
|
|
129
|
+
Create a project and set up the labeling interface. For more information about setting up projects, see the following:
|
|
130
|
+
|
|
131
|
+
- [Create and configure projects](https://labelstud.io/guide/setup_project)
|
|
132
|
+
- [Configure labeling interface](https://labelstud.io/guide/setup)
|
|
133
|
+
- [Project settings](https://labelstud.io/guide/project_settings)
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
curl -H Content-Type:application/json -H 'Authorization: Token abc123' -X POST 'https://localhost:8080/api/projects' --data '{"label_config": "<View>[...]</View>"}'
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
title : typing.Optional[str]
|
|
142
|
+
Project title
|
|
143
|
+
|
|
144
|
+
description : typing.Optional[str]
|
|
145
|
+
Project description
|
|
146
|
+
|
|
147
|
+
label_config : typing.Optional[str]
|
|
148
|
+
Label config in XML format
|
|
149
|
+
|
|
150
|
+
expert_instruction : typing.Optional[str]
|
|
151
|
+
Labeling instructions to show to the user
|
|
152
|
+
|
|
153
|
+
show_instruction : typing.Optional[bool]
|
|
154
|
+
Show labeling instructions
|
|
155
|
+
|
|
156
|
+
show_skip_button : typing.Optional[bool]
|
|
157
|
+
Show skip button
|
|
158
|
+
|
|
159
|
+
enable_empty_annotation : typing.Optional[bool]
|
|
160
|
+
Allow empty annotations
|
|
161
|
+
|
|
162
|
+
show_annotation_history : typing.Optional[bool]
|
|
163
|
+
Show annotation history
|
|
164
|
+
|
|
165
|
+
reveal_preannotations_interactively : typing.Optional[bool]
|
|
166
|
+
Reveal preannotations interactively. If set to True, predictions will be shown to the user only after selecting the area of interest
|
|
167
|
+
|
|
168
|
+
show_collab_predictions : typing.Optional[bool]
|
|
169
|
+
Show predictions to annotators
|
|
170
|
+
|
|
171
|
+
maximum_annotations : typing.Optional[int]
|
|
172
|
+
Maximum annotations per task
|
|
173
|
+
|
|
174
|
+
color : typing.Optional[str]
|
|
175
|
+
Project color in HEX format
|
|
176
|
+
|
|
177
|
+
control_weights : typing.Optional[typing.Dict[str, typing.Any]]
|
|
178
|
+
Dict of weights for each control tag in metric calculation. Each control tag (e.g. label or choice) will have its own key in control weight dict with weight for each label and overall weight. For example, if a bounding box annotation with a control tag named my_bbox should be included with 0.33 weight in agreement calculation, and the first label Car should be twice as important as Airplane, then you need to specify: {'my_bbox': {'type': 'RectangleLabels', 'labels': {'Car': 1.0, 'Airplane': 0.5}, 'overall': 0.33}
|
|
179
|
+
|
|
180
|
+
request_options : typing.Optional[RequestOptions]
|
|
181
|
+
Request-specific configuration.
|
|
182
|
+
|
|
183
|
+
Returns
|
|
184
|
+
-------
|
|
185
|
+
ProjectsCreateResponse
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
Examples
|
|
189
|
+
--------
|
|
190
|
+
from label_studio_sdk.client import LabelStudio
|
|
191
|
+
|
|
192
|
+
client = LabelStudio(
|
|
193
|
+
api_key="YOUR_API_KEY",
|
|
194
|
+
)
|
|
195
|
+
client.projects.create()
|
|
196
|
+
"""
|
|
197
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
198
|
+
"api/projects/",
|
|
199
|
+
method="POST",
|
|
200
|
+
json={
|
|
201
|
+
"title": title,
|
|
202
|
+
"description": description,
|
|
203
|
+
"label_config": label_config,
|
|
204
|
+
"expert_instruction": expert_instruction,
|
|
205
|
+
"show_instruction": show_instruction,
|
|
206
|
+
"show_skip_button": show_skip_button,
|
|
207
|
+
"enable_empty_annotation": enable_empty_annotation,
|
|
208
|
+
"show_annotation_history": show_annotation_history,
|
|
209
|
+
"reveal_preannotations_interactively": reveal_preannotations_interactively,
|
|
210
|
+
"show_collab_predictions": show_collab_predictions,
|
|
211
|
+
"maximum_annotations": maximum_annotations,
|
|
212
|
+
"color": color,
|
|
213
|
+
"control_weights": control_weights,
|
|
214
|
+
},
|
|
215
|
+
request_options=request_options,
|
|
216
|
+
omit=OMIT,
|
|
217
|
+
)
|
|
218
|
+
if 200 <= _response.status_code < 300:
|
|
219
|
+
return pydantic_v1.parse_obj_as(ProjectsCreateResponse, _response.json()) # type: ignore
|
|
220
|
+
try:
|
|
221
|
+
_response_json = _response.json()
|
|
222
|
+
except JSONDecodeError:
|
|
223
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
224
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
225
|
+
|
|
226
|
+
def get(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> Project:
|
|
227
|
+
"""
|
|
228
|
+
Retrieve information about a specific project by project ID. The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
229
|
+
|
|
230
|
+
Parameters
|
|
231
|
+
----------
|
|
232
|
+
id : int
|
|
233
|
+
A unique integer value identifying this project.
|
|
234
|
+
|
|
235
|
+
request_options : typing.Optional[RequestOptions]
|
|
236
|
+
Request-specific configuration.
|
|
237
|
+
|
|
238
|
+
Returns
|
|
239
|
+
-------
|
|
240
|
+
Project
|
|
241
|
+
Project information
|
|
242
|
+
|
|
243
|
+
Examples
|
|
244
|
+
--------
|
|
245
|
+
from label_studio_sdk.client import LabelStudio
|
|
246
|
+
|
|
247
|
+
client = LabelStudio(
|
|
248
|
+
api_key="YOUR_API_KEY",
|
|
249
|
+
)
|
|
250
|
+
client.projects.get(
|
|
251
|
+
id=1,
|
|
252
|
+
)
|
|
253
|
+
"""
|
|
254
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
255
|
+
f"api/projects/{jsonable_encoder(id)}/", method="GET", request_options=request_options
|
|
256
|
+
)
|
|
257
|
+
if 200 <= _response.status_code < 300:
|
|
258
|
+
return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
|
|
259
|
+
try:
|
|
260
|
+
_response_json = _response.json()
|
|
261
|
+
except JSONDecodeError:
|
|
262
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
263
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
264
|
+
|
|
265
|
+
def delete(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
|
|
266
|
+
"""
|
|
267
|
+
Delete a project by specified project ID. Deleting a project permanently removes all tasks, annotations, and project data from Label Studio.
|
|
268
|
+
|
|
269
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
270
|
+
|
|
271
|
+
Parameters
|
|
272
|
+
----------
|
|
273
|
+
id : int
|
|
274
|
+
A unique integer value identifying this project.
|
|
275
|
+
|
|
276
|
+
request_options : typing.Optional[RequestOptions]
|
|
277
|
+
Request-specific configuration.
|
|
278
|
+
|
|
279
|
+
Returns
|
|
280
|
+
-------
|
|
281
|
+
None
|
|
282
|
+
|
|
283
|
+
Examples
|
|
284
|
+
--------
|
|
285
|
+
from label_studio_sdk.client import LabelStudio
|
|
286
|
+
|
|
287
|
+
client = LabelStudio(
|
|
288
|
+
api_key="YOUR_API_KEY",
|
|
289
|
+
)
|
|
290
|
+
client.projects.delete(
|
|
291
|
+
id=1,
|
|
292
|
+
)
|
|
293
|
+
"""
|
|
294
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
295
|
+
f"api/projects/{jsonable_encoder(id)}/", method="DELETE", request_options=request_options
|
|
296
|
+
)
|
|
297
|
+
if 200 <= _response.status_code < 300:
|
|
298
|
+
return
|
|
299
|
+
try:
|
|
300
|
+
_response_json = _response.json()
|
|
301
|
+
except JSONDecodeError:
|
|
302
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
303
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
304
|
+
|
|
305
|
+
def update(self, id: int, *, request: Project, request_options: typing.Optional[RequestOptions] = None) -> Project:
|
|
306
|
+
"""
|
|
307
|
+
Update the project settings for a specific project. For more information, see the following:
|
|
308
|
+
|
|
309
|
+
- [Create and configure projects](https://labelstud.io/guide/setup_project)
|
|
310
|
+
- [Configure labeling interface](https://labelstud.io/guide/setup)
|
|
311
|
+
- [Project settings](https://labelstud.io/guide/project_settings)
|
|
312
|
+
|
|
313
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
314
|
+
|
|
315
|
+
<Warning>
|
|
316
|
+
If you are modifying the labeling config for project that has in-progress work, note the following:
|
|
317
|
+
* You cannot remove labels or change the type of labeling being performed unless you delete any existing annotations that are using those labels.
|
|
318
|
+
* If you make changes to the labeling configuration, any tabs that you might have created in the Data Manager are removed.
|
|
319
|
+
</Warning>
|
|
320
|
+
|
|
321
|
+
Parameters
|
|
322
|
+
----------
|
|
323
|
+
id : int
|
|
324
|
+
A unique integer value identifying this project.
|
|
325
|
+
|
|
326
|
+
request : Project
|
|
327
|
+
|
|
328
|
+
request_options : typing.Optional[RequestOptions]
|
|
329
|
+
Request-specific configuration.
|
|
330
|
+
|
|
331
|
+
Returns
|
|
332
|
+
-------
|
|
333
|
+
Project
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
Examples
|
|
337
|
+
--------
|
|
338
|
+
from label_studio_sdk import Project
|
|
339
|
+
from label_studio_sdk.client import LabelStudio
|
|
340
|
+
|
|
341
|
+
client = LabelStudio(
|
|
342
|
+
api_key="YOUR_API_KEY",
|
|
343
|
+
)
|
|
344
|
+
client.projects.update(
|
|
345
|
+
id=1,
|
|
346
|
+
request=Project(),
|
|
347
|
+
)
|
|
348
|
+
"""
|
|
349
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
350
|
+
f"api/projects/{jsonable_encoder(id)}/",
|
|
351
|
+
method="PATCH",
|
|
352
|
+
json=request,
|
|
353
|
+
request_options=request_options,
|
|
354
|
+
omit=OMIT,
|
|
355
|
+
)
|
|
356
|
+
if 200 <= _response.status_code < 300:
|
|
357
|
+
return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
|
|
358
|
+
try:
|
|
359
|
+
_response_json = _response.json()
|
|
360
|
+
except JSONDecodeError:
|
|
361
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
362
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
363
|
+
|
|
364
|
+
def import_tasks(
|
|
365
|
+
self,
|
|
366
|
+
id: int,
|
|
367
|
+
*,
|
|
368
|
+
request: typing.Sequence[typing.Dict[str, typing.Any]],
|
|
369
|
+
commit_to_project: typing.Optional[bool] = None,
|
|
370
|
+
return_task_ids: typing.Optional[bool] = None,
|
|
371
|
+
preannotated_from_fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
|
|
372
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
373
|
+
) -> ProjectsImportTasksResponse:
|
|
374
|
+
"""
|
|
375
|
+
Use this API endpoint to import labeling tasks in bulk. Note that each POST request is limited at 250K tasks and 200 MB.
|
|
376
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](../projects/list).
|
|
377
|
+
|
|
378
|
+
<Note>
|
|
379
|
+
Imported data is verified against a project *label_config* and must include all variables that were used in the *label_config*.
|
|
380
|
+
|
|
381
|
+
For example, if the label configuration has a _$text_ variable, then each item in a data object must include a `text` field.
|
|
382
|
+
</Note>
|
|
383
|
+
|
|
384
|
+
There are three possible ways to import tasks with this endpoint:
|
|
385
|
+
|
|
386
|
+
#### 1\. **POST with data**
|
|
387
|
+
|
|
388
|
+
Send JSON tasks as POST data. Only JSON is supported for POSTing files directly.
|
|
389
|
+
|
|
390
|
+
Update this example to specify your authorization token and Label Studio instance host, then run the following from
|
|
391
|
+
the command line:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
curl -H 'Content-Type: application/json' -H 'Authorization: Token abc123' \
|
|
395
|
+
-X POST 'https://localhost:8080/api/projects/1/import' --data '[{"text": "Some text 1"}, {"text": "Some text 2"}]'
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### 2\. **POST with files**
|
|
399
|
+
|
|
400
|
+
Send tasks as files. You can attach multiple files with different names.
|
|
401
|
+
|
|
402
|
+
- **JSON**: text files in JavaScript object notation format
|
|
403
|
+
- **CSV**: text files with tables in Comma Separated Values format
|
|
404
|
+
- **TSV**: text files with tables in Tab Separated Value format
|
|
405
|
+
- **TXT**: simple text files are similar to CSV with one column and no header, supported for projects with one source only
|
|
406
|
+
|
|
407
|
+
Update this example to specify your authorization token, Label Studio instance host, and file name and path,
|
|
408
|
+
then run the following from the command line:
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
curl -H 'Authorization: Token abc123' \
|
|
412
|
+
-X POST 'https://localhost:8080/api/projects/1/import' -F ‘file=@path/to/my_file.csv’
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
#### 3\. **POST with URL**
|
|
416
|
+
|
|
417
|
+
You can also provide a URL to a file with labeling tasks. Supported file formats are the same as in option 2.
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
curl -H 'Content-Type: application/json' -H 'Authorization: Token abc123' \
|
|
421
|
+
-X POST 'https://localhost:8080/api/projects/1/import' \
|
|
422
|
+
--data '[{"url": "http://example.com/test1.csv"}, {"url": "http://example.com/test2.csv"}]'
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
<br>
|
|
426
|
+
|
|
427
|
+
Parameters
|
|
428
|
+
----------
|
|
429
|
+
id : int
|
|
430
|
+
A unique integer value identifying this project.
|
|
431
|
+
|
|
432
|
+
request : typing.Sequence[typing.Dict[str, typing.Any]]
|
|
433
|
+
|
|
434
|
+
commit_to_project : typing.Optional[bool]
|
|
435
|
+
Set to "true" to immediately commit tasks to the project.
|
|
436
|
+
|
|
437
|
+
return_task_ids : typing.Optional[bool]
|
|
438
|
+
Set to "true" to return task IDs in the response.
|
|
439
|
+
|
|
440
|
+
preannotated_from_fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
|
|
441
|
+
List of fields to preannotate from the task data. For example, if you provide a list of `{"text": "text", "prediction": "label"}` items in the request, the system will create a task with the `text` field and a prediction with the `label` field when `preannoted_from_fields=["prediction"]`.
|
|
442
|
+
|
|
443
|
+
request_options : typing.Optional[RequestOptions]
|
|
444
|
+
Request-specific configuration.
|
|
445
|
+
|
|
446
|
+
Returns
|
|
447
|
+
-------
|
|
448
|
+
ProjectsImportTasksResponse
|
|
449
|
+
Tasks successfully imported
|
|
450
|
+
|
|
451
|
+
Examples
|
|
452
|
+
--------
|
|
453
|
+
from label_studio_sdk.client import LabelStudio
|
|
454
|
+
|
|
455
|
+
client = LabelStudio(
|
|
456
|
+
api_key="YOUR_API_KEY",
|
|
457
|
+
)
|
|
458
|
+
client.projects.import_tasks(
|
|
459
|
+
id=1,
|
|
460
|
+
request=[{}],
|
|
461
|
+
)
|
|
462
|
+
"""
|
|
463
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
464
|
+
f"api/projects/{jsonable_encoder(id)}/import",
|
|
465
|
+
method="POST",
|
|
466
|
+
params={
|
|
467
|
+
"commit_to_project": commit_to_project,
|
|
468
|
+
"return_task_ids": return_task_ids,
|
|
469
|
+
"preannotated_from_fields": preannotated_from_fields,
|
|
470
|
+
},
|
|
471
|
+
json=request,
|
|
472
|
+
request_options=request_options,
|
|
473
|
+
omit=OMIT,
|
|
474
|
+
)
|
|
475
|
+
if 200 <= _response.status_code < 300:
|
|
476
|
+
return pydantic_v1.parse_obj_as(ProjectsImportTasksResponse, _response.json()) # type: ignore
|
|
477
|
+
if _response.status_code == 400:
|
|
478
|
+
raise BadRequestError(pydantic_v1.parse_obj_as(str, _response.json())) # type: ignore
|
|
479
|
+
try:
|
|
480
|
+
_response_json = _response.json()
|
|
481
|
+
except JSONDecodeError:
|
|
482
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
483
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
484
|
+
|
|
485
|
+
def validate_config(
|
|
486
|
+
self, id: int, *, request: ProjectLabelConfig, request_options: typing.Optional[RequestOptions] = None
|
|
487
|
+
) -> ProjectLabelConfig:
|
|
488
|
+
"""
|
|
489
|
+
Determine whether the label configuration for a specific project is valid. For more information about setting up labeling configs, see [Configure labeling interface](https://labelstud.io/guide/setup) and our [Tags reference](https://labelstud.io/tags/).
|
|
490
|
+
|
|
491
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
492
|
+
|
|
493
|
+
Parameters
|
|
494
|
+
----------
|
|
495
|
+
id : int
|
|
496
|
+
A unique integer value identifying this project.
|
|
497
|
+
|
|
498
|
+
request : ProjectLabelConfig
|
|
499
|
+
|
|
500
|
+
request_options : typing.Optional[RequestOptions]
|
|
501
|
+
Request-specific configuration.
|
|
502
|
+
|
|
503
|
+
Returns
|
|
504
|
+
-------
|
|
505
|
+
ProjectLabelConfig
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
Examples
|
|
509
|
+
--------
|
|
510
|
+
from label_studio_sdk import ProjectLabelConfig
|
|
511
|
+
from label_studio_sdk.client import LabelStudio
|
|
512
|
+
|
|
513
|
+
client = LabelStudio(
|
|
514
|
+
api_key="YOUR_API_KEY",
|
|
515
|
+
)
|
|
516
|
+
client.projects.validate_config(
|
|
517
|
+
id=1,
|
|
518
|
+
request=ProjectLabelConfig(
|
|
519
|
+
label_config="label_config",
|
|
520
|
+
),
|
|
521
|
+
)
|
|
522
|
+
"""
|
|
523
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
524
|
+
f"api/projects/{jsonable_encoder(id)}/validate/",
|
|
525
|
+
method="POST",
|
|
526
|
+
json=request,
|
|
527
|
+
request_options=request_options,
|
|
528
|
+
omit=OMIT,
|
|
529
|
+
)
|
|
530
|
+
if 200 <= _response.status_code < 300:
|
|
531
|
+
return pydantic_v1.parse_obj_as(ProjectLabelConfig, _response.json()) # type: ignore
|
|
532
|
+
try:
|
|
533
|
+
_response_json = _response.json()
|
|
534
|
+
except JSONDecodeError:
|
|
535
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
536
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
class AsyncProjectsClient:
|
|
540
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
541
|
+
self._client_wrapper = client_wrapper
|
|
542
|
+
self.exports = AsyncExportsClient(client_wrapper=self._client_wrapper)
|
|
543
|
+
|
|
544
|
+
async def list(
|
|
545
|
+
self,
|
|
546
|
+
*,
|
|
547
|
+
ordering: typing.Optional[str] = None,
|
|
548
|
+
ids: typing.Optional[str] = None,
|
|
549
|
+
title: typing.Optional[str] = None,
|
|
550
|
+
page: typing.Optional[int] = None,
|
|
551
|
+
page_size: typing.Optional[int] = None,
|
|
552
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
553
|
+
) -> AsyncPager[Project]:
|
|
554
|
+
"""
|
|
555
|
+
Return a list of the projects within your organization.
|
|
556
|
+
|
|
557
|
+
To perform most tasks with the Label Studio API, you must specify the project ID, sometimes referred to as the `pk`. The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using this API call.
|
|
558
|
+
|
|
559
|
+
To retrieve a list of your Label Studio projects, update the following command to match your own environment.
|
|
560
|
+
Replace the domain name, port, and authorization token, then run the following from the command line:
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
curl -X GET https://localhost:8080/api/projects/ -H 'Authorization: Token abc123'
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
Parameters
|
|
567
|
+
----------
|
|
568
|
+
ordering : typing.Optional[str]
|
|
569
|
+
Which field to use when ordering the results.
|
|
570
|
+
|
|
571
|
+
ids : typing.Optional[str]
|
|
572
|
+
ids
|
|
573
|
+
|
|
574
|
+
title : typing.Optional[str]
|
|
575
|
+
title
|
|
576
|
+
|
|
577
|
+
page : typing.Optional[int]
|
|
578
|
+
A page number within the paginated result set.
|
|
579
|
+
|
|
580
|
+
page_size : typing.Optional[int]
|
|
581
|
+
Number of results to return per page.
|
|
582
|
+
|
|
583
|
+
request_options : typing.Optional[RequestOptions]
|
|
584
|
+
Request-specific configuration.
|
|
585
|
+
|
|
586
|
+
Returns
|
|
587
|
+
-------
|
|
588
|
+
AsyncPager[Project]
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
Examples
|
|
592
|
+
--------
|
|
593
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
594
|
+
|
|
595
|
+
client = AsyncLabelStudio(
|
|
596
|
+
api_key="YOUR_API_KEY",
|
|
597
|
+
)
|
|
598
|
+
await client.projects.list()
|
|
599
|
+
"""
|
|
600
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
601
|
+
"api/projects/",
|
|
602
|
+
method="GET",
|
|
603
|
+
params={"ordering": ordering, "ids": ids, "title": title, "page": page, "page_size": page_size},
|
|
604
|
+
request_options=request_options,
|
|
605
|
+
)
|
|
606
|
+
if 200 <= _response.status_code < 300:
|
|
607
|
+
_parsed_response = pydantic_v1.parse_obj_as(ProjectsListResponse, _response.json()) # type: ignore
|
|
608
|
+
_has_next = True
|
|
609
|
+
_get_next = lambda: self.list(
|
|
610
|
+
ordering=ordering,
|
|
611
|
+
ids=ids,
|
|
612
|
+
title=title,
|
|
613
|
+
page=page + 1 if page is not None else 1,
|
|
614
|
+
page_size=page_size,
|
|
615
|
+
request_options=request_options,
|
|
616
|
+
)
|
|
617
|
+
_items = _parsed_response.results
|
|
618
|
+
return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next)
|
|
619
|
+
try:
|
|
620
|
+
_response_json = _response.json()
|
|
621
|
+
except JSONDecodeError:
|
|
622
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
623
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
624
|
+
|
|
625
|
+
async def create(
|
|
626
|
+
self,
|
|
627
|
+
*,
|
|
628
|
+
title: typing.Optional[str] = OMIT,
|
|
629
|
+
description: typing.Optional[str] = OMIT,
|
|
630
|
+
label_config: typing.Optional[str] = OMIT,
|
|
631
|
+
expert_instruction: typing.Optional[str] = OMIT,
|
|
632
|
+
show_instruction: typing.Optional[bool] = OMIT,
|
|
633
|
+
show_skip_button: typing.Optional[bool] = OMIT,
|
|
634
|
+
enable_empty_annotation: typing.Optional[bool] = OMIT,
|
|
635
|
+
show_annotation_history: typing.Optional[bool] = OMIT,
|
|
636
|
+
reveal_preannotations_interactively: typing.Optional[bool] = OMIT,
|
|
637
|
+
show_collab_predictions: typing.Optional[bool] = OMIT,
|
|
638
|
+
maximum_annotations: typing.Optional[int] = OMIT,
|
|
639
|
+
color: typing.Optional[str] = OMIT,
|
|
640
|
+
control_weights: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
|
|
641
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
642
|
+
) -> ProjectsCreateResponse:
|
|
643
|
+
"""
|
|
644
|
+
Create a project and set up the labeling interface. For more information about setting up projects, see the following:
|
|
645
|
+
|
|
646
|
+
- [Create and configure projects](https://labelstud.io/guide/setup_project)
|
|
647
|
+
- [Configure labeling interface](https://labelstud.io/guide/setup)
|
|
648
|
+
- [Project settings](https://labelstud.io/guide/project_settings)
|
|
649
|
+
|
|
650
|
+
```bash
|
|
651
|
+
curl -H Content-Type:application/json -H 'Authorization: Token abc123' -X POST 'https://localhost:8080/api/projects' --data '{"label_config": "<View>[...]</View>"}'
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Parameters
|
|
655
|
+
----------
|
|
656
|
+
title : typing.Optional[str]
|
|
657
|
+
Project title
|
|
658
|
+
|
|
659
|
+
description : typing.Optional[str]
|
|
660
|
+
Project description
|
|
661
|
+
|
|
662
|
+
label_config : typing.Optional[str]
|
|
663
|
+
Label config in XML format
|
|
664
|
+
|
|
665
|
+
expert_instruction : typing.Optional[str]
|
|
666
|
+
Labeling instructions to show to the user
|
|
667
|
+
|
|
668
|
+
show_instruction : typing.Optional[bool]
|
|
669
|
+
Show labeling instructions
|
|
670
|
+
|
|
671
|
+
show_skip_button : typing.Optional[bool]
|
|
672
|
+
Show skip button
|
|
673
|
+
|
|
674
|
+
enable_empty_annotation : typing.Optional[bool]
|
|
675
|
+
Allow empty annotations
|
|
676
|
+
|
|
677
|
+
show_annotation_history : typing.Optional[bool]
|
|
678
|
+
Show annotation history
|
|
679
|
+
|
|
680
|
+
reveal_preannotations_interactively : typing.Optional[bool]
|
|
681
|
+
Reveal preannotations interactively. If set to True, predictions will be shown to the user only after selecting the area of interest
|
|
682
|
+
|
|
683
|
+
show_collab_predictions : typing.Optional[bool]
|
|
684
|
+
Show predictions to annotators
|
|
685
|
+
|
|
686
|
+
maximum_annotations : typing.Optional[int]
|
|
687
|
+
Maximum annotations per task
|
|
688
|
+
|
|
689
|
+
color : typing.Optional[str]
|
|
690
|
+
Project color in HEX format
|
|
691
|
+
|
|
692
|
+
control_weights : typing.Optional[typing.Dict[str, typing.Any]]
|
|
693
|
+
Dict of weights for each control tag in metric calculation. Each control tag (e.g. label or choice) will have its own key in control weight dict with weight for each label and overall weight. For example, if a bounding box annotation with a control tag named my_bbox should be included with 0.33 weight in agreement calculation, and the first label Car should be twice as important as Airplane, then you need to specify: {'my_bbox': {'type': 'RectangleLabels', 'labels': {'Car': 1.0, 'Airplane': 0.5}, 'overall': 0.33}
|
|
694
|
+
|
|
695
|
+
request_options : typing.Optional[RequestOptions]
|
|
696
|
+
Request-specific configuration.
|
|
697
|
+
|
|
698
|
+
Returns
|
|
699
|
+
-------
|
|
700
|
+
ProjectsCreateResponse
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
Examples
|
|
704
|
+
--------
|
|
705
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
706
|
+
|
|
707
|
+
client = AsyncLabelStudio(
|
|
708
|
+
api_key="YOUR_API_KEY",
|
|
709
|
+
)
|
|
710
|
+
await client.projects.create()
|
|
711
|
+
"""
|
|
712
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
713
|
+
"api/projects/",
|
|
714
|
+
method="POST",
|
|
715
|
+
json={
|
|
716
|
+
"title": title,
|
|
717
|
+
"description": description,
|
|
718
|
+
"label_config": label_config,
|
|
719
|
+
"expert_instruction": expert_instruction,
|
|
720
|
+
"show_instruction": show_instruction,
|
|
721
|
+
"show_skip_button": show_skip_button,
|
|
722
|
+
"enable_empty_annotation": enable_empty_annotation,
|
|
723
|
+
"show_annotation_history": show_annotation_history,
|
|
724
|
+
"reveal_preannotations_interactively": reveal_preannotations_interactively,
|
|
725
|
+
"show_collab_predictions": show_collab_predictions,
|
|
726
|
+
"maximum_annotations": maximum_annotations,
|
|
727
|
+
"color": color,
|
|
728
|
+
"control_weights": control_weights,
|
|
729
|
+
},
|
|
730
|
+
request_options=request_options,
|
|
731
|
+
omit=OMIT,
|
|
732
|
+
)
|
|
733
|
+
if 200 <= _response.status_code < 300:
|
|
734
|
+
return pydantic_v1.parse_obj_as(ProjectsCreateResponse, _response.json()) # type: ignore
|
|
735
|
+
try:
|
|
736
|
+
_response_json = _response.json()
|
|
737
|
+
except JSONDecodeError:
|
|
738
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
739
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
740
|
+
|
|
741
|
+
async def get(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> Project:
|
|
742
|
+
"""
|
|
743
|
+
Retrieve information about a specific project by project ID. The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
744
|
+
|
|
745
|
+
Parameters
|
|
746
|
+
----------
|
|
747
|
+
id : int
|
|
748
|
+
A unique integer value identifying this project.
|
|
749
|
+
|
|
750
|
+
request_options : typing.Optional[RequestOptions]
|
|
751
|
+
Request-specific configuration.
|
|
752
|
+
|
|
753
|
+
Returns
|
|
754
|
+
-------
|
|
755
|
+
Project
|
|
756
|
+
Project information
|
|
757
|
+
|
|
758
|
+
Examples
|
|
759
|
+
--------
|
|
760
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
761
|
+
|
|
762
|
+
client = AsyncLabelStudio(
|
|
763
|
+
api_key="YOUR_API_KEY",
|
|
764
|
+
)
|
|
765
|
+
await client.projects.get(
|
|
766
|
+
id=1,
|
|
767
|
+
)
|
|
768
|
+
"""
|
|
769
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
770
|
+
f"api/projects/{jsonable_encoder(id)}/", method="GET", request_options=request_options
|
|
771
|
+
)
|
|
772
|
+
if 200 <= _response.status_code < 300:
|
|
773
|
+
return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
|
|
774
|
+
try:
|
|
775
|
+
_response_json = _response.json()
|
|
776
|
+
except JSONDecodeError:
|
|
777
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
778
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
779
|
+
|
|
780
|
+
async def delete(self, id: int, *, request_options: typing.Optional[RequestOptions] = None) -> None:
|
|
781
|
+
"""
|
|
782
|
+
Delete a project by specified project ID. Deleting a project permanently removes all tasks, annotations, and project data from Label Studio.
|
|
783
|
+
|
|
784
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
785
|
+
|
|
786
|
+
Parameters
|
|
787
|
+
----------
|
|
788
|
+
id : int
|
|
789
|
+
A unique integer value identifying this project.
|
|
790
|
+
|
|
791
|
+
request_options : typing.Optional[RequestOptions]
|
|
792
|
+
Request-specific configuration.
|
|
793
|
+
|
|
794
|
+
Returns
|
|
795
|
+
-------
|
|
796
|
+
None
|
|
797
|
+
|
|
798
|
+
Examples
|
|
799
|
+
--------
|
|
800
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
801
|
+
|
|
802
|
+
client = AsyncLabelStudio(
|
|
803
|
+
api_key="YOUR_API_KEY",
|
|
804
|
+
)
|
|
805
|
+
await client.projects.delete(
|
|
806
|
+
id=1,
|
|
807
|
+
)
|
|
808
|
+
"""
|
|
809
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
810
|
+
f"api/projects/{jsonable_encoder(id)}/", method="DELETE", request_options=request_options
|
|
811
|
+
)
|
|
812
|
+
if 200 <= _response.status_code < 300:
|
|
813
|
+
return
|
|
814
|
+
try:
|
|
815
|
+
_response_json = _response.json()
|
|
816
|
+
except JSONDecodeError:
|
|
817
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
818
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
819
|
+
|
|
820
|
+
async def update(
|
|
821
|
+
self, id: int, *, request: Project, request_options: typing.Optional[RequestOptions] = None
|
|
822
|
+
) -> Project:
|
|
823
|
+
"""
|
|
824
|
+
Update the project settings for a specific project. For more information, see the following:
|
|
825
|
+
|
|
826
|
+
- [Create and configure projects](https://labelstud.io/guide/setup_project)
|
|
827
|
+
- [Configure labeling interface](https://labelstud.io/guide/setup)
|
|
828
|
+
- [Project settings](https://labelstud.io/guide/project_settings)
|
|
829
|
+
|
|
830
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
831
|
+
|
|
832
|
+
<Warning>
|
|
833
|
+
If you are modifying the labeling config for project that has in-progress work, note the following:
|
|
834
|
+
* You cannot remove labels or change the type of labeling being performed unless you delete any existing annotations that are using those labels.
|
|
835
|
+
* If you make changes to the labeling configuration, any tabs that you might have created in the Data Manager are removed.
|
|
836
|
+
</Warning>
|
|
837
|
+
|
|
838
|
+
Parameters
|
|
839
|
+
----------
|
|
840
|
+
id : int
|
|
841
|
+
A unique integer value identifying this project.
|
|
842
|
+
|
|
843
|
+
request : Project
|
|
844
|
+
|
|
845
|
+
request_options : typing.Optional[RequestOptions]
|
|
846
|
+
Request-specific configuration.
|
|
847
|
+
|
|
848
|
+
Returns
|
|
849
|
+
-------
|
|
850
|
+
Project
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
Examples
|
|
854
|
+
--------
|
|
855
|
+
from label_studio_sdk import Project
|
|
856
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
857
|
+
|
|
858
|
+
client = AsyncLabelStudio(
|
|
859
|
+
api_key="YOUR_API_KEY",
|
|
860
|
+
)
|
|
861
|
+
await client.projects.update(
|
|
862
|
+
id=1,
|
|
863
|
+
request=Project(),
|
|
864
|
+
)
|
|
865
|
+
"""
|
|
866
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
867
|
+
f"api/projects/{jsonable_encoder(id)}/",
|
|
868
|
+
method="PATCH",
|
|
869
|
+
json=request,
|
|
870
|
+
request_options=request_options,
|
|
871
|
+
omit=OMIT,
|
|
872
|
+
)
|
|
873
|
+
if 200 <= _response.status_code < 300:
|
|
874
|
+
return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore
|
|
875
|
+
try:
|
|
876
|
+
_response_json = _response.json()
|
|
877
|
+
except JSONDecodeError:
|
|
878
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
879
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
880
|
+
|
|
881
|
+
async def import_tasks(
|
|
882
|
+
self,
|
|
883
|
+
id: int,
|
|
884
|
+
*,
|
|
885
|
+
request: typing.Sequence[typing.Dict[str, typing.Any]],
|
|
886
|
+
commit_to_project: typing.Optional[bool] = None,
|
|
887
|
+
return_task_ids: typing.Optional[bool] = None,
|
|
888
|
+
preannotated_from_fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
|
|
889
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
890
|
+
) -> ProjectsImportTasksResponse:
|
|
891
|
+
"""
|
|
892
|
+
Use this API endpoint to import labeling tasks in bulk. Note that each POST request is limited at 250K tasks and 200 MB.
|
|
893
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](../projects/list).
|
|
894
|
+
|
|
895
|
+
<Note>
|
|
896
|
+
Imported data is verified against a project *label_config* and must include all variables that were used in the *label_config*.
|
|
897
|
+
|
|
898
|
+
For example, if the label configuration has a _$text_ variable, then each item in a data object must include a `text` field.
|
|
899
|
+
</Note>
|
|
900
|
+
|
|
901
|
+
There are three possible ways to import tasks with this endpoint:
|
|
902
|
+
|
|
903
|
+
#### 1\. **POST with data**
|
|
904
|
+
|
|
905
|
+
Send JSON tasks as POST data. Only JSON is supported for POSTing files directly.
|
|
906
|
+
|
|
907
|
+
Update this example to specify your authorization token and Label Studio instance host, then run the following from
|
|
908
|
+
the command line:
|
|
909
|
+
|
|
910
|
+
```bash
|
|
911
|
+
curl -H 'Content-Type: application/json' -H 'Authorization: Token abc123' \
|
|
912
|
+
-X POST 'https://localhost:8080/api/projects/1/import' --data '[{"text": "Some text 1"}, {"text": "Some text 2"}]'
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
#### 2\. **POST with files**
|
|
916
|
+
|
|
917
|
+
Send tasks as files. You can attach multiple files with different names.
|
|
918
|
+
|
|
919
|
+
- **JSON**: text files in JavaScript object notation format
|
|
920
|
+
- **CSV**: text files with tables in Comma Separated Values format
|
|
921
|
+
- **TSV**: text files with tables in Tab Separated Value format
|
|
922
|
+
- **TXT**: simple text files are similar to CSV with one column and no header, supported for projects with one source only
|
|
923
|
+
|
|
924
|
+
Update this example to specify your authorization token, Label Studio instance host, and file name and path,
|
|
925
|
+
then run the following from the command line:
|
|
926
|
+
|
|
927
|
+
```bash
|
|
928
|
+
curl -H 'Authorization: Token abc123' \
|
|
929
|
+
-X POST 'https://localhost:8080/api/projects/1/import' -F ‘file=@path/to/my_file.csv’
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
#### 3\. **POST with URL**
|
|
933
|
+
|
|
934
|
+
You can also provide a URL to a file with labeling tasks. Supported file formats are the same as in option 2.
|
|
935
|
+
|
|
936
|
+
```bash
|
|
937
|
+
curl -H 'Content-Type: application/json' -H 'Authorization: Token abc123' \
|
|
938
|
+
-X POST 'https://localhost:8080/api/projects/1/import' \
|
|
939
|
+
--data '[{"url": "http://example.com/test1.csv"}, {"url": "http://example.com/test2.csv"}]'
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
<br>
|
|
943
|
+
|
|
944
|
+
Parameters
|
|
945
|
+
----------
|
|
946
|
+
id : int
|
|
947
|
+
A unique integer value identifying this project.
|
|
948
|
+
|
|
949
|
+
request : typing.Sequence[typing.Dict[str, typing.Any]]
|
|
950
|
+
|
|
951
|
+
commit_to_project : typing.Optional[bool]
|
|
952
|
+
Set to "true" to immediately commit tasks to the project.
|
|
953
|
+
|
|
954
|
+
return_task_ids : typing.Optional[bool]
|
|
955
|
+
Set to "true" to return task IDs in the response.
|
|
956
|
+
|
|
957
|
+
preannotated_from_fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
|
|
958
|
+
List of fields to preannotate from the task data. For example, if you provide a list of `{"text": "text", "prediction": "label"}` items in the request, the system will create a task with the `text` field and a prediction with the `label` field when `preannoted_from_fields=["prediction"]`.
|
|
959
|
+
|
|
960
|
+
request_options : typing.Optional[RequestOptions]
|
|
961
|
+
Request-specific configuration.
|
|
962
|
+
|
|
963
|
+
Returns
|
|
964
|
+
-------
|
|
965
|
+
ProjectsImportTasksResponse
|
|
966
|
+
Tasks successfully imported
|
|
967
|
+
|
|
968
|
+
Examples
|
|
969
|
+
--------
|
|
970
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
971
|
+
|
|
972
|
+
client = AsyncLabelStudio(
|
|
973
|
+
api_key="YOUR_API_KEY",
|
|
974
|
+
)
|
|
975
|
+
await client.projects.import_tasks(
|
|
976
|
+
id=1,
|
|
977
|
+
request=[{}],
|
|
978
|
+
)
|
|
979
|
+
"""
|
|
980
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
981
|
+
f"api/projects/{jsonable_encoder(id)}/import",
|
|
982
|
+
method="POST",
|
|
983
|
+
params={
|
|
984
|
+
"commit_to_project": commit_to_project,
|
|
985
|
+
"return_task_ids": return_task_ids,
|
|
986
|
+
"preannotated_from_fields": preannotated_from_fields,
|
|
987
|
+
},
|
|
988
|
+
json=request,
|
|
989
|
+
request_options=request_options,
|
|
990
|
+
omit=OMIT,
|
|
991
|
+
)
|
|
992
|
+
if 200 <= _response.status_code < 300:
|
|
993
|
+
return pydantic_v1.parse_obj_as(ProjectsImportTasksResponse, _response.json()) # type: ignore
|
|
994
|
+
if _response.status_code == 400:
|
|
995
|
+
raise BadRequestError(pydantic_v1.parse_obj_as(str, _response.json())) # type: ignore
|
|
996
|
+
try:
|
|
997
|
+
_response_json = _response.json()
|
|
998
|
+
except JSONDecodeError:
|
|
999
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
1000
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
1001
|
+
|
|
1002
|
+
async def validate_config(
|
|
1003
|
+
self, id: int, *, request: ProjectLabelConfig, request_options: typing.Optional[RequestOptions] = None
|
|
1004
|
+
) -> ProjectLabelConfig:
|
|
1005
|
+
"""
|
|
1006
|
+
Determine whether the label configuration for a specific project is valid. For more information about setting up labeling configs, see [Configure labeling interface](https://labelstud.io/guide/setup) and our [Tags reference](https://labelstud.io/tags/).
|
|
1007
|
+
|
|
1008
|
+
The project ID can be found in the URL when viewing the project in Label Studio, or you can retrieve all project IDs using [List all projects](list).
|
|
1009
|
+
|
|
1010
|
+
Parameters
|
|
1011
|
+
----------
|
|
1012
|
+
id : int
|
|
1013
|
+
A unique integer value identifying this project.
|
|
1014
|
+
|
|
1015
|
+
request : ProjectLabelConfig
|
|
1016
|
+
|
|
1017
|
+
request_options : typing.Optional[RequestOptions]
|
|
1018
|
+
Request-specific configuration.
|
|
1019
|
+
|
|
1020
|
+
Returns
|
|
1021
|
+
-------
|
|
1022
|
+
ProjectLabelConfig
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
Examples
|
|
1026
|
+
--------
|
|
1027
|
+
from label_studio_sdk import ProjectLabelConfig
|
|
1028
|
+
from label_studio_sdk.client import AsyncLabelStudio
|
|
1029
|
+
|
|
1030
|
+
client = AsyncLabelStudio(
|
|
1031
|
+
api_key="YOUR_API_KEY",
|
|
1032
|
+
)
|
|
1033
|
+
await client.projects.validate_config(
|
|
1034
|
+
id=1,
|
|
1035
|
+
request=ProjectLabelConfig(
|
|
1036
|
+
label_config="label_config",
|
|
1037
|
+
),
|
|
1038
|
+
)
|
|
1039
|
+
"""
|
|
1040
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
1041
|
+
f"api/projects/{jsonable_encoder(id)}/validate/",
|
|
1042
|
+
method="POST",
|
|
1043
|
+
json=request,
|
|
1044
|
+
request_options=request_options,
|
|
1045
|
+
omit=OMIT,
|
|
1046
|
+
)
|
|
1047
|
+
if 200 <= _response.status_code < 300:
|
|
1048
|
+
return pydantic_v1.parse_obj_as(ProjectLabelConfig, _response.json()) # type: ignore
|
|
1049
|
+
try:
|
|
1050
|
+
_response_json = _response.json()
|
|
1051
|
+
except JSONDecodeError:
|
|
1052
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
1053
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|