label-studio-sdk 1.0.5__py3-none-any.whl → 1.0.8__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 (77) hide show
  1. label_studio_sdk/__init__.py +76 -0
  2. label_studio_sdk/_extensions/eval/categorical.py +83 -0
  3. label_studio_sdk/_extensions/label_studio_tools/core/label_config.py +13 -4
  4. label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +35 -17
  5. label_studio_sdk/_extensions/label_studio_tools/core/utils/json_schema.py +86 -0
  6. label_studio_sdk/_legacy/schema/label_config_schema.json +42 -11
  7. label_studio_sdk/annotations/__init__.py +3 -0
  8. label_studio_sdk/annotations/client.py +109 -0
  9. label_studio_sdk/annotations/types/__init__.py +5 -0
  10. label_studio_sdk/annotations/types/annotations_create_bulk_response_item.py +29 -0
  11. label_studio_sdk/base_client.py +9 -0
  12. label_studio_sdk/comments/__init__.py +2 -0
  13. label_studio_sdk/comments/client.py +512 -0
  14. label_studio_sdk/converter/converter.py +11 -4
  15. label_studio_sdk/converter/imports/coco.py +14 -13
  16. label_studio_sdk/converter/utils.py +72 -3
  17. label_studio_sdk/core/client_wrapper.py +1 -1
  18. label_studio_sdk/files/client.py +26 -16
  19. label_studio_sdk/label_interface/control_tags.py +205 -10
  20. label_studio_sdk/label_interface/interface.py +117 -10
  21. label_studio_sdk/label_interface/region.py +1 -10
  22. label_studio_sdk/model_providers/__init__.py +2 -0
  23. label_studio_sdk/model_providers/client.py +708 -0
  24. label_studio_sdk/projects/client.py +32 -16
  25. label_studio_sdk/projects/exports/client.py +133 -40
  26. label_studio_sdk/prompts/__init__.py +21 -0
  27. label_studio_sdk/prompts/client.py +862 -0
  28. label_studio_sdk/prompts/indicators/__init__.py +2 -0
  29. label_studio_sdk/prompts/indicators/client.py +194 -0
  30. label_studio_sdk/prompts/runs/__init__.py +5 -0
  31. label_studio_sdk/prompts/runs/client.py +354 -0
  32. label_studio_sdk/prompts/runs/types/__init__.py +5 -0
  33. label_studio_sdk/prompts/runs/types/runs_list_request_project_subset.py +5 -0
  34. label_studio_sdk/prompts/types/__init__.py +15 -0
  35. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_request_failed_predictions_item.py +42 -0
  36. label_studio_sdk/prompts/types/prompts_batch_failed_predictions_response.py +29 -0
  37. label_studio_sdk/prompts/types/prompts_batch_predictions_request_results_item.py +62 -0
  38. label_studio_sdk/prompts/types/prompts_batch_predictions_response.py +29 -0
  39. label_studio_sdk/prompts/versions/__init__.py +2 -0
  40. label_studio_sdk/prompts/versions/client.py +1046 -0
  41. label_studio_sdk/types/__init__.py +58 -0
  42. label_studio_sdk/types/comment.py +39 -0
  43. label_studio_sdk/types/comment_created_by.py +5 -0
  44. label_studio_sdk/types/inference_run.py +43 -0
  45. label_studio_sdk/types/inference_run_cost_estimate.py +57 -0
  46. label_studio_sdk/types/inference_run_created_by.py +5 -0
  47. label_studio_sdk/types/inference_run_organization.py +5 -0
  48. label_studio_sdk/types/inference_run_project_subset.py +5 -0
  49. label_studio_sdk/types/inference_run_status.py +7 -0
  50. label_studio_sdk/types/key_indicator_value.py +30 -0
  51. label_studio_sdk/types/key_indicators.py +7 -0
  52. label_studio_sdk/types/key_indicators_item.py +51 -0
  53. label_studio_sdk/types/key_indicators_item_additional_kpis_item.py +37 -0
  54. label_studio_sdk/types/key_indicators_item_extra_kpis_item.py +37 -0
  55. label_studio_sdk/types/model_provider_connection.py +71 -0
  56. label_studio_sdk/types/model_provider_connection_budget_reset_period.py +5 -0
  57. label_studio_sdk/types/model_provider_connection_created_by.py +5 -0
  58. label_studio_sdk/types/model_provider_connection_organization.py +5 -0
  59. label_studio_sdk/types/model_provider_connection_provider.py +5 -0
  60. label_studio_sdk/types/model_provider_connection_scope.py +5 -0
  61. label_studio_sdk/types/prompt.py +79 -0
  62. label_studio_sdk/types/prompt_created_by.py +5 -0
  63. label_studio_sdk/types/prompt_organization.py +5 -0
  64. label_studio_sdk/types/prompt_version.py +41 -0
  65. label_studio_sdk/types/prompt_version_created_by.py +5 -0
  66. label_studio_sdk/types/prompt_version_organization.py +5 -0
  67. label_studio_sdk/types/prompt_version_provider.py +5 -0
  68. label_studio_sdk/types/refined_prompt_response.py +64 -0
  69. label_studio_sdk/types/refined_prompt_response_refinement_status.py +7 -0
  70. label_studio_sdk/types/task.py +3 -2
  71. label_studio_sdk/types/task_comment_authors_item.py +5 -0
  72. label_studio_sdk/webhooks/client.py +245 -36
  73. label_studio_sdk/workspaces/client.py +20 -20
  74. label_studio_sdk-1.0.8.dist-info/LICENSE +201 -0
  75. {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/METADATA +19 -3
  76. {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/RECORD +77 -24
  77. {label_studio_sdk-1.0.5.dist-info → label_studio_sdk-1.0.8.dist-info}/WHEEL +1 -1
@@ -14,6 +14,8 @@ from .types import (
14
14
  BaseTaskFileUpload,
15
15
  BaseTaskUpdatedBy,
16
16
  BaseUser,
17
+ Comment,
18
+ CommentCreatedBy,
17
19
  ConvertedFormat,
18
20
  ConvertedFormatStatus,
19
21
  DataManagerTaskSerializer,
@@ -32,6 +34,17 @@ from .types import (
32
34
  GcsExportStorageStatus,
33
35
  GcsImportStorage,
34
36
  GcsImportStorageStatus,
37
+ InferenceRun,
38
+ InferenceRunCostEstimate,
39
+ InferenceRunCreatedBy,
40
+ InferenceRunOrganization,
41
+ InferenceRunProjectSubset,
42
+ InferenceRunStatus,
43
+ KeyIndicatorValue,
44
+ KeyIndicators,
45
+ KeyIndicatorsItem,
46
+ KeyIndicatorsItemAdditionalKpisItem,
47
+ KeyIndicatorsItemExtraKpisItem,
35
48
  LocalFilesExportStorage,
36
49
  LocalFilesExportStorageStatus,
37
50
  LocalFilesImportStorage,
@@ -39,6 +52,12 @@ from .types import (
39
52
  MlBackend,
40
53
  MlBackendAuthMethod,
41
54
  MlBackendState,
55
+ ModelProviderConnection,
56
+ ModelProviderConnectionBudgetResetPeriod,
57
+ ModelProviderConnectionCreatedBy,
58
+ ModelProviderConnectionOrganization,
59
+ ModelProviderConnectionProvider,
60
+ ModelProviderConnectionScope,
42
61
  Prediction,
43
62
  Project,
44
63
  ProjectImport,
@@ -46,10 +65,19 @@ from .types import (
46
65
  ProjectLabelConfig,
47
66
  ProjectSampling,
48
67
  ProjectSkipQueue,
68
+ Prompt,
69
+ PromptCreatedBy,
70
+ PromptOrganization,
71
+ PromptVersion,
72
+ PromptVersionCreatedBy,
73
+ PromptVersionOrganization,
74
+ PromptVersionProvider,
49
75
  RedisExportStorage,
50
76
  RedisExportStorageStatus,
51
77
  RedisImportStorage,
52
78
  RedisImportStorageStatus,
79
+ RefinedPromptResponse,
80
+ RefinedPromptResponseRefinementStatus,
53
81
  S3ExportStorage,
54
82
  S3ExportStorageStatus,
55
83
  S3ImportStorage,
@@ -61,6 +89,7 @@ from .types import (
61
89
  SerializationOptions,
62
90
  Task,
63
91
  TaskAnnotatorsItem,
92
+ TaskCommentAuthorsItem,
64
93
  TaskFilterOptions,
65
94
  UserSimple,
66
95
  View,
@@ -74,12 +103,15 @@ from .errors import BadRequestError, InternalServerError
74
103
  from . import (
75
104
  actions,
76
105
  annotations,
106
+ comments,
77
107
  export_storage,
78
108
  files,
79
109
  import_storage,
80
110
  ml,
111
+ model_providers,
81
112
  predictions,
82
113
  projects,
114
+ prompts,
83
115
  tasks,
84
116
  users,
85
117
  views,
@@ -100,6 +132,7 @@ from .actions import (
100
132
  ActionsCreateRequestSelectedItemsExcluded,
101
133
  ActionsCreateRequestSelectedItemsIncluded,
102
134
  )
135
+ from .annotations import AnnotationsCreateBulkResponseItem
103
136
  from .environment import LabelStudioEnvironment
104
137
  from .export_storage import ExportStorageListTypesResponseItem
105
138
  from .import_storage import ImportStorageListTypesResponseItem
@@ -112,6 +145,12 @@ from .ml import (
112
145
  MlUpdateResponseAuthMethod,
113
146
  )
114
147
  from .projects import ProjectsCreateResponse, ProjectsImportTasksResponse, ProjectsListResponse, ProjectsUpdateResponse
148
+ from .prompts import (
149
+ PromptsBatchFailedPredictionsRequestFailedPredictionsItem,
150
+ PromptsBatchFailedPredictionsResponse,
151
+ PromptsBatchPredictionsRequestResultsItem,
152
+ PromptsBatchPredictionsResponse,
153
+ )
115
154
  from .tasks import TasksListRequestFields, TasksListResponse
116
155
  from .users import UsersGetTokenResponse, UsersResetTokenResponse
117
156
  from .version import __version__
@@ -150,6 +189,7 @@ __all__ = [
150
189
  "Annotation",
151
190
  "AnnotationFilterOptions",
152
191
  "AnnotationLastAction",
192
+ "AnnotationsCreateBulkResponseItem",
153
193
  "AnnotationsDmField",
154
194
  "AnnotationsDmFieldLastAction",
155
195
  "AzureBlobExportStorage",
@@ -162,6 +202,8 @@ __all__ = [
162
202
  "BaseTaskUpdatedBy",
163
203
  "BaseUser",
164
204
  "Client",
205
+ "Comment",
206
+ "CommentCreatedBy",
165
207
  "ConvertedFormat",
166
208
  "ConvertedFormatStatus",
167
209
  "DataManagerTaskSerializer",
@@ -182,7 +224,18 @@ __all__ = [
182
224
  "GcsImportStorage",
183
225
  "GcsImportStorageStatus",
184
226
  "ImportStorageListTypesResponseItem",
227
+ "InferenceRun",
228
+ "InferenceRunCostEstimate",
229
+ "InferenceRunCreatedBy",
230
+ "InferenceRunOrganization",
231
+ "InferenceRunProjectSubset",
232
+ "InferenceRunStatus",
185
233
  "InternalServerError",
234
+ "KeyIndicatorValue",
235
+ "KeyIndicators",
236
+ "KeyIndicatorsItem",
237
+ "KeyIndicatorsItemAdditionalKpisItem",
238
+ "KeyIndicatorsItemExtraKpisItem",
186
239
  "LabelStudioEnvironment",
187
240
  "LocalFilesExportStorage",
188
241
  "LocalFilesExportStorageStatus",
@@ -197,6 +250,12 @@ __all__ = [
197
250
  "MlUpdateRequestAuthMethod",
198
251
  "MlUpdateResponse",
199
252
  "MlUpdateResponseAuthMethod",
253
+ "ModelProviderConnection",
254
+ "ModelProviderConnectionBudgetResetPeriod",
255
+ "ModelProviderConnectionCreatedBy",
256
+ "ModelProviderConnectionOrganization",
257
+ "ModelProviderConnectionProvider",
258
+ "ModelProviderConnectionScope",
200
259
  "Prediction",
201
260
  "Project",
202
261
  "ProjectImport",
@@ -208,10 +267,23 @@ __all__ = [
208
267
  "ProjectsImportTasksResponse",
209
268
  "ProjectsListResponse",
210
269
  "ProjectsUpdateResponse",
270
+ "Prompt",
271
+ "PromptCreatedBy",
272
+ "PromptOrganization",
273
+ "PromptVersion",
274
+ "PromptVersionCreatedBy",
275
+ "PromptVersionOrganization",
276
+ "PromptVersionProvider",
277
+ "PromptsBatchFailedPredictionsRequestFailedPredictionsItem",
278
+ "PromptsBatchFailedPredictionsResponse",
279
+ "PromptsBatchPredictionsRequestResultsItem",
280
+ "PromptsBatchPredictionsResponse",
211
281
  "RedisExportStorage",
212
282
  "RedisExportStorageStatus",
213
283
  "RedisImportStorage",
214
284
  "RedisImportStorageStatus",
285
+ "RefinedPromptResponse",
286
+ "RefinedPromptResponseRefinementStatus",
215
287
  "S3ExportStorage",
216
288
  "S3ExportStorageStatus",
217
289
  "S3ImportStorage",
@@ -223,6 +295,7 @@ __all__ = [
223
295
  "SerializationOptions",
224
296
  "Task",
225
297
  "TaskAnnotatorsItem",
298
+ "TaskCommentAuthorsItem",
226
299
  "TaskFilterOptions",
227
300
  "TasksListRequestFields",
228
301
  "TasksListResponse",
@@ -255,12 +328,15 @@ __all__ = [
255
328
  "__version__",
256
329
  "actions",
257
330
  "annotations",
331
+ "comments",
258
332
  "export_storage",
259
333
  "files",
260
334
  "import_storage",
261
335
  "ml",
336
+ "model_providers",
262
337
  "predictions",
263
338
  "projects",
339
+ "prompts",
264
340
  "tasks",
265
341
  "users",
266
342
  "views",
@@ -0,0 +1,83 @@
1
+ import logging
2
+ from typing import List, Dict, Iterable
3
+
4
+ logger = logging.getLogger(__name__)
5
+
6
+ try:
7
+ # TODO: after python 3.8 support is dropped (Oct'24), remove try-except block
8
+ from sklearn.metrics import precision_recall_fscore_support
9
+ except ImportError:
10
+ logger.warning('scikit-learn is not installed. Please install scikit-learn to use this module.')
11
+ precision_recall_fscore_support = None
12
+
13
+
14
+ def _get_single_choice(annotation: Dict):
15
+ """
16
+ Get the single choice from the annotation.
17
+
18
+ Args:
19
+ annotation: Annotation dict
20
+
21
+ Returns:
22
+ Single choice
23
+ """
24
+ maybe_choice = next((r['value']['choices'][0] for r in annotation['result'] if r['type'] == 'choices'), None)
25
+ if maybe_choice:
26
+ return maybe_choice
27
+ raise NotImplementedError('Only single choice is supported')
28
+
29
+
30
+ def get_precision_recall_f1_per_choice(annotations: Iterable[Dict], predictions: Iterable[Dict]) -> Dict:
31
+ """
32
+ Given the iterator over annotations and predictions, calculate precision, recall, and F1 per choice.
33
+ Each annotation and prediction follows the format of the Label Studio output.
34
+
35
+ Args:
36
+ annotations: Iterable of annotation dicts
37
+ predictions: Iterable of prediction dicts
38
+
39
+ Returns:
40
+ Dict of the following format:
41
+ {
42
+ 'precision': {
43
+ 'choice1': 0.5,
44
+ 'choice2': 0.7,
45
+ ...
46
+ },
47
+ 'recall': {
48
+ 'choice1': 0.5,
49
+ 'choice2': 0.7,
50
+ ...
51
+ },
52
+ 'f1': {
53
+ 'choice1': 0.5,
54
+ 'choice2': 0.7,
55
+ ...
56
+ },
57
+ 'support': {
58
+ 'choice1': 10,
59
+ 'choice2': 20,
60
+ ...
61
+ },
62
+ }
63
+ """
64
+
65
+ if precision_recall_fscore_support is None:
66
+ raise ImportError('scikit-learn is not installed. Please install scikit-learn to use this module.')
67
+
68
+ annotation_choices = [_get_single_choice(annotation) for annotation in annotations]
69
+ prediction_choices = [_get_single_choice(prediction) for prediction in predictions]
70
+ # get unique choices names
71
+ unique_choices = sorted(set(annotation_choices + prediction_choices))
72
+
73
+ metrics_per_choice = precision_recall_fscore_support(
74
+ annotation_choices, prediction_choices,
75
+ average=None, labels=unique_choices)
76
+
77
+ results = {}
78
+ for metric_name, metric_per_choice in zip(['precision', 'recall', 'f1', 'support'], metrics_per_choice):
79
+ results[metric_name] = {}
80
+ for choice, metric in zip(unique_choices, metric_per_choice):
81
+ results[metric_name][choice] = metric
82
+
83
+ return results
@@ -82,17 +82,26 @@ def parse_config(config_string):
82
82
  elif _is_input_tag(tag):
83
83
  inputs[tag.attrib["name"]] = {
84
84
  "type": tag.tag,
85
- "value": tag.attrib["value"].lstrip("$"),
86
85
  "valueType": tag.attrib.get("valueType"),
87
86
  }
87
+ if 'value' in tag.attrib:
88
+ inputs[tag.attrib["name"]]["value"] = tag.attrib["value"].lstrip("$")
89
+ elif 'valueList' in tag.attrib:
90
+ inputs[tag.attrib["name"]]["valueList"] = tag.attrib["valueList"].lstrip("$")
91
+ else:
92
+ raise ValueError(
93
+ 'Inspecting tag {tag_name}... found no "value" or "valueList" attributes.'.format(
94
+ tag_name=etree.tostring(tag, encoding="unicode").strip()[:50]
95
+ )
96
+ )
88
97
  if tag.tag not in _LABEL_TAGS:
89
98
  continue
90
99
  parent_name = _get_parent_output_tag_name(tag, outputs)
91
100
  if parent_name is not None:
92
- actual_value = tag.attrib.get("alias") or tag.attrib.get("value")
101
+ actual_value = tag.attrib.get("alias") or tag.attrib.get("value") or tag.attrib.get("valueList")
93
102
  if not actual_value:
94
103
  logger.debug(
95
- 'Inspecting tag {tag_name}... found no "value" or "alias" attributes.'.format(
104
+ 'Inspecting tag {tag_name}... found no "value", "valueList", or "alias" attributes.'.format(
96
105
  tag_name=etree.tostring(tag, encoding="unicode").strip()[:50]
97
106
  )
98
107
  )
@@ -137,7 +146,7 @@ def _is_input_tag(tag):
137
146
  """
138
147
  Check if tag is input
139
148
  """
140
- return tag.attrib.get("name") and tag.attrib.get("value")
149
+ return tag.attrib.get("name") and (tag.attrib.get("value") or tag.attrib.get("valueList"))
141
150
 
142
151
 
143
152
  def _is_output_tag(tag):
@@ -1,15 +1,14 @@
1
- import logging
2
- import io
3
- import shutil
4
- import urllib
5
1
  import hashlib
6
- import requests
2
+ import io
3
+ import logging
7
4
  import os
8
-
9
- from appdirs import user_cache_dir, user_data_dir
10
- from urllib.parse import urlparse, urljoin
5
+ import shutil
11
6
  from contextlib import contextmanager
12
7
  from tempfile import mkdtemp
8
+ from urllib.parse import urlparse
9
+
10
+ import requests
11
+ from appdirs import user_cache_dir, user_data_dir
13
12
 
14
13
  from label_studio_sdk._extensions.label_studio_tools.core.utils.params import get_env
15
14
 
@@ -17,6 +16,7 @@ _DIR_APP_NAME = "label-studio"
17
16
  LOCAL_FILES_DOCUMENT_ROOT = get_env(
18
17
  "LOCAL_FILES_DOCUMENT_ROOT", default=os.path.abspath(os.sep)
19
18
  )
19
+ VERIFY_SSL = get_env("VERIFY_SSL", default=True, is_bool=True)
20
20
 
21
21
  logger = logging.getLogger(__name__)
22
22
 
@@ -80,6 +80,13 @@ def get_local_path(
80
80
  f"`localhost` is not accessible inside of docker containers. "
81
81
  f"You can check your IP with utilities like `ifconfig` and set it as LABEL_STUDIO_URL."
82
82
  )
83
+ if hostname and not (
84
+ hostname.startswith("http://") or hostname.startswith("https://")
85
+ ):
86
+ raise ValueError(
87
+ f"Invalid hostname in LABEL_STUDIO_URL: {hostname}. "
88
+ "Please provide full URL starting with protocol (http:// or https://)."
89
+ )
83
90
 
84
91
  # fix file upload url
85
92
  if url.startswith("upload") or url.startswith("/upload"):
@@ -180,13 +187,17 @@ def download_and_cache(
180
187
  # File specified by remote URL - download and cache it
181
188
  cache_dir = cache_dir or get_cache_dir()
182
189
  parsed_url = urlparse(url)
183
- url_filename = (
184
- # /data/local-files?d=dir/1.jpg => 1.jpg
185
- os.path.basename(url)
186
- if is_local_storage_file or is_cloud_storage_file
187
- # /some/url/1.jpg?expire=xxx => 1.jpg
188
- else os.path.basename(parsed_url.path)
189
- )
190
+
191
+ # local storage: /data/local-files?d=dir/1.jpg => 1.jpg
192
+ if is_local_storage_file:
193
+ url_filename = os.path.basename(url.split('?d=')[1])
194
+ # cloud storage: s3://bucket/1.jpg => 1.jpg
195
+ elif is_cloud_storage_file:
196
+ url_filename = os.path.basename(url)
197
+ # all others: /some/url/1.jpg?expire=xxx => 1.jpg
198
+ else:
199
+ url_filename = os.path.basename(parsed_url.path)
200
+
190
201
  url_hash = hashlib.md5(url.encode()).hexdigest()[:8]
191
202
  filepath = os.path.join(cache_dir, url_hash + "__" + url_filename)
192
203
 
@@ -205,8 +216,15 @@ def download_and_cache(
205
216
  ):
206
217
  headers["Authorization"] = "Token " + access_token
207
218
  logger.debug("Authorization token is used for download_and_cache")
208
- r = requests.get(url, stream=True, headers=headers)
209
- r.raise_for_status()
219
+ try:
220
+ r = requests.get(url, stream=True, headers=headers, verify=VERIFY_SSL)
221
+ r.raise_for_status()
222
+ except requests.exceptions.SSLError as e:
223
+ logger.error(
224
+ f"SSL error during requests.get('{url}'): {e}\n"
225
+ f"Try to set VERIFY_SSL=False in environment variables to bypass SSL verification."
226
+ )
227
+ raise e
210
228
  with io.open(filepath, mode="wb") as fout:
211
229
  fout.write(r.content)
212
230
  return filepath
@@ -0,0 +1,86 @@
1
+ import json
2
+ import types
3
+ import sys
4
+ import functools
5
+ from typing import Type, Dict, Any, Tuple, Generator
6
+ from pathlib import Path
7
+ from tempfile import TemporaryDirectory
8
+ from datamodel_code_generator import DataModelType, PythonVersion, LiteralType
9
+ from datamodel_code_generator.model import get_data_model_types
10
+ from datamodel_code_generator.parser.jsonschema import JsonSchemaParser
11
+ from pydantic import BaseModel
12
+ from contextlib import contextmanager
13
+
14
+
15
+ @functools.lru_cache(maxsize=128)
16
+ def _generate_model_code(json_schema_str: str, class_name: str = 'MyModel') -> str:
17
+
18
+ data_model_types = get_data_model_types(
19
+ DataModelType.PydanticV2BaseModel,
20
+ target_python_version=PythonVersion.PY_311
21
+ )
22
+
23
+ parser = JsonSchemaParser(
24
+ json_schema_str,
25
+ data_model_type=data_model_types.data_model,
26
+ data_model_root_type=data_model_types.root_model,
27
+ data_model_field_type=data_model_types.field_model,
28
+ data_type_manager_type=data_model_types.data_type_manager,
29
+ dump_resolve_reference_action=data_model_types.dump_resolve_reference_action,
30
+ enum_field_as_literal=LiteralType.All,
31
+ class_name=class_name
32
+ )
33
+
34
+ model_code = parser.parse()
35
+ return model_code
36
+
37
+ @contextmanager
38
+ def json_schema_to_pydantic(json_schema: dict, class_name: str = 'MyModel') -> Generator[Type[BaseModel], None, None]:
39
+ """
40
+ Convert a JSON schema to a Pydantic model and provide it as a context manager.
41
+
42
+ Args:
43
+ json_schema (dict): The JSON schema to convert.
44
+ class_name (str, optional): The name of the generated Pydantic class. Defaults to 'MyModel'.
45
+
46
+ Example:
47
+ ```python
48
+ example_schema = {
49
+ "type": "object",
50
+ "properties": {
51
+ "sentiment": {
52
+ "type": "string",
53
+ "description": "Sentiment of the text",
54
+ "enum": ["Positive", "Negative", "Neutral"],
55
+ }
56
+ },
57
+ "required": ["sentiment"]
58
+ }
59
+ with json_schema_to_pydantic(example_schema) as ResponseModel:
60
+ instance = ResponseModel(sentiment='Positive')
61
+ print(instance.model_dump())
62
+ ```
63
+ """
64
+ # Convert the JSON schema dictionary to a JSON string
65
+ json_schema_str = json.dumps(json_schema)
66
+
67
+ # Generate Pydantic model code from the JSON schema string
68
+ model_code: str = _generate_model_code(json_schema_str, class_name)
69
+
70
+ # Create a unique module name using the id of the JSON schema string
71
+ module_name = f'dynamic_module_{id(json_schema_str)}'
72
+
73
+ # Create a new module object with the unique name and execute the generated model code in the context of the new module
74
+ mod = types.ModuleType(module_name)
75
+ exec(model_code, mod.__dict__)
76
+ model_class = getattr(mod, class_name)
77
+
78
+ try:
79
+ # Add the new module to sys.modules to make it importable
80
+ # This is necessary to avoid Pydantic errors related to undefined models
81
+ sys.modules[module_name] = mod
82
+ yield model_class
83
+ finally:
84
+ if module_name in sys.modules:
85
+ del sys.modules[module_name]
86
+
@@ -35,22 +35,44 @@
35
35
  }
36
36
  }
37
37
  },
38
- "tag_with_value_required_name": {
38
+ "tag_with_name_and_toname": {
39
39
  "type": "object",
40
- "anyOf": [
41
- {
42
- "required": [
43
- "@name",
44
- "@valueList"
45
- ]
46
- },
40
+ "oneOf": [
47
41
  {
48
42
  "required": [
49
43
  "@name",
50
- "@value"
44
+ "@toName"
51
45
  ]
52
46
  }
53
47
  ],
48
+ "properties": {
49
+ "@name": {
50
+ "$ref": "#/definitions/@name"
51
+ },
52
+ "@toName": {
53
+ "$ref": "#/definitions/@toName"
54
+ },
55
+ "$": {
56
+ "$ref": "#/definitions/$"
57
+ }
58
+ }
59
+ },
60
+ "tag_with_value_required_name": {
61
+ "type": "object",
62
+ "oneOf": [
63
+ {
64
+ "required": [
65
+ "@name",
66
+ "@value"
67
+ ]
68
+ },
69
+ {
70
+ "required": [
71
+ "@name",
72
+ "@valueList"
73
+ ]
74
+ }
75
+ ],
54
76
  "properties": {
55
77
  "@value": {
56
78
  "$ref": "#/definitions/@value"
@@ -80,6 +102,13 @@
80
102
  "items": {"$ref": "#/definitions/tag_with_value_required_name"}
81
103
  }, {"$ref": "#/definitions/tag_with_value_required_name"}]
82
104
  },
105
+ "tags_with_name_and_toname": {
106
+ "anyOf": [{"$ref": "#/definitions/tag_with_name_and_toname"},
107
+ {
108
+ "type": "array",
109
+ "items": {"$ref": "#/definitions/tag_with_name_and_toname"}
110
+ }]
111
+ },
83
112
  "View": {
84
113
  "type": "object",
85
114
  "additionalProperties": true,
@@ -92,7 +121,8 @@
92
121
  "Text": {"$ref": "#/definitions/tags_with_value_required_name"},
93
122
  "HyperText": {"$ref": "#/definitions/tags_with_value_required_name"},
94
123
  "View": {"$ref": "#/definitions/MaybeMultipleView"},
95
- "TextArea": {"$ref": "#/definitions/MaybeMultipleTextAreas"}
124
+ "TextArea": {"$ref": "#/definitions/MaybeMultipleTextAreas"},
125
+ "Number": {"$ref": "#/definitions/tags_with_name_and_toname"}
96
126
  }
97
127
  },
98
128
  "MaybeMultipleView": {
@@ -219,7 +249,8 @@
219
249
  "Image": {"$ref": "#/definitions/tags_with_value_required_name"},
220
250
  "Text": {"$ref": "#/definitions/tags_with_value_required_name"},
221
251
  "HyperText": {"$ref": "#/definitions/tags_with_value_required_name"},
222
- "TextArea": {"$ref": "#/definitions/MaybeMultipleTextAreas"}
252
+ "TextArea": {"$ref": "#/definitions/MaybeMultipleTextAreas"},
253
+ "Number": {"$ref": "#/definitions/tags_with_name_and_toname"}
223
254
  }
224
255
  }
225
256
  }
@@ -1,2 +1,5 @@
1
1
  # This file was auto-generated by Fern from our API Definition.
2
2
 
3
+ from .types import AnnotationsCreateBulkResponseItem
4
+
5
+ __all__ = ["AnnotationsCreateBulkResponseItem"]