label-studio-sdk 0.0.34__py3-none-any.whl → 1.0.1__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 (272) hide show
  1. label_studio_sdk/__init__.py +232 -9
  2. label_studio_sdk/_extensions/label_studio_tools/__init__.py +0 -0
  3. label_studio_sdk/_extensions/label_studio_tools/core/__init__.py +0 -0
  4. label_studio_sdk/_extensions/label_studio_tools/core/label_config.py +163 -0
  5. label_studio_sdk/_extensions/label_studio_tools/core/utils/__init__.py +0 -0
  6. label_studio_sdk/_extensions/label_studio_tools/core/utils/exceptions.py +2 -0
  7. label_studio_sdk/_extensions/label_studio_tools/core/utils/io.py +228 -0
  8. label_studio_sdk/_extensions/label_studio_tools/core/utils/params.py +45 -0
  9. label_studio_sdk/_extensions/label_studio_tools/etl/__init__.py +1 -0
  10. label_studio_sdk/_extensions/label_studio_tools/etl/beam.py +34 -0
  11. label_studio_sdk/_extensions/label_studio_tools/etl/example.py +17 -0
  12. label_studio_sdk/_extensions/label_studio_tools/etl/registry.py +67 -0
  13. label_studio_sdk/_extensions/label_studio_tools/postprocessing/__init__.py +0 -0
  14. label_studio_sdk/_extensions/label_studio_tools/postprocessing/video.py +97 -0
  15. label_studio_sdk/_extensions/pager_ext.py +49 -0
  16. label_studio_sdk/_legacy/__init__.py +11 -0
  17. label_studio_sdk/_legacy/client.py +471 -0
  18. label_studio_sdk/_legacy/objects.py +74 -0
  19. label_studio_sdk/{project.py → _legacy/project.py} +2 -2
  20. label_studio_sdk/{schema → _legacy/schema}/label_config_schema.json +14 -14
  21. label_studio_sdk/actions/__init__.py +27 -0
  22. label_studio_sdk/actions/client.py +223 -0
  23. label_studio_sdk/actions/types/__init__.py +25 -0
  24. label_studio_sdk/actions/types/actions_create_request_filters.py +43 -0
  25. label_studio_sdk/actions/types/actions_create_request_filters_conjunction.py +5 -0
  26. label_studio_sdk/actions/types/actions_create_request_filters_items_item.py +49 -0
  27. label_studio_sdk/actions/types/actions_create_request_filters_items_item_filter.py +31 -0
  28. label_studio_sdk/actions/types/actions_create_request_filters_items_item_operator.py +23 -0
  29. label_studio_sdk/actions/types/actions_create_request_id.py +19 -0
  30. label_studio_sdk/actions/types/actions_create_request_ordering_item.py +31 -0
  31. label_studio_sdk/actions/types/actions_create_request_selected_items.py +10 -0
  32. label_studio_sdk/actions/types/actions_create_request_selected_items_excluded.py +39 -0
  33. label_studio_sdk/actions/types/actions_create_request_selected_items_included.py +39 -0
  34. label_studio_sdk/annotations/__init__.py +2 -0
  35. label_studio_sdk/annotations/client.py +750 -0
  36. label_studio_sdk/base_client.py +183 -0
  37. label_studio_sdk/client.py +17 -463
  38. label_studio_sdk/converter/__init__.py +7 -0
  39. label_studio_sdk/converter/audio.py +56 -0
  40. label_studio_sdk/converter/brush.py +452 -0
  41. label_studio_sdk/converter/converter.py +1175 -0
  42. label_studio_sdk/converter/exports/__init__.py +0 -0
  43. label_studio_sdk/converter/exports/csv.py +82 -0
  44. label_studio_sdk/converter/exports/csv2.py +103 -0
  45. label_studio_sdk/converter/funsd.py +85 -0
  46. label_studio_sdk/converter/imports/__init__.py +0 -0
  47. label_studio_sdk/converter/imports/coco.py +314 -0
  48. label_studio_sdk/converter/imports/colors.py +198 -0
  49. label_studio_sdk/converter/imports/label_config.py +45 -0
  50. label_studio_sdk/converter/imports/pathtrack.py +269 -0
  51. label_studio_sdk/converter/imports/yolo.py +236 -0
  52. label_studio_sdk/converter/main.py +202 -0
  53. label_studio_sdk/converter/utils.py +473 -0
  54. label_studio_sdk/core/__init__.py +33 -0
  55. label_studio_sdk/core/api_error.py +15 -0
  56. label_studio_sdk/core/client_wrapper.py +55 -0
  57. label_studio_sdk/core/datetime_utils.py +28 -0
  58. label_studio_sdk/core/file.py +38 -0
  59. label_studio_sdk/core/http_client.py +447 -0
  60. label_studio_sdk/core/jsonable_encoder.py +99 -0
  61. label_studio_sdk/core/pagination.py +87 -0
  62. label_studio_sdk/core/pydantic_utilities.py +28 -0
  63. label_studio_sdk/core/query_encoder.py +33 -0
  64. label_studio_sdk/core/remove_none_from_dict.py +11 -0
  65. label_studio_sdk/core/request_options.py +32 -0
  66. label_studio_sdk/environment.py +7 -0
  67. label_studio_sdk/errors/__init__.py +6 -0
  68. label_studio_sdk/errors/bad_request_error.py +8 -0
  69. label_studio_sdk/errors/internal_server_error.py +8 -0
  70. label_studio_sdk/export_storage/__init__.py +28 -0
  71. label_studio_sdk/export_storage/azure/__init__.py +5 -0
  72. label_studio_sdk/export_storage/azure/client.py +888 -0
  73. label_studio_sdk/export_storage/azure/types/__init__.py +6 -0
  74. label_studio_sdk/export_storage/azure/types/azure_create_response.py +67 -0
  75. label_studio_sdk/export_storage/azure/types/azure_update_response.py +67 -0
  76. label_studio_sdk/export_storage/client.py +107 -0
  77. label_studio_sdk/export_storage/gcs/__init__.py +5 -0
  78. label_studio_sdk/export_storage/gcs/client.py +888 -0
  79. label_studio_sdk/export_storage/gcs/types/__init__.py +6 -0
  80. label_studio_sdk/export_storage/gcs/types/gcs_create_response.py +67 -0
  81. label_studio_sdk/export_storage/gcs/types/gcs_update_response.py +67 -0
  82. label_studio_sdk/export_storage/local/__init__.py +5 -0
  83. label_studio_sdk/export_storage/local/client.py +834 -0
  84. label_studio_sdk/export_storage/local/types/__init__.py +6 -0
  85. label_studio_sdk/export_storage/local/types/local_create_response.py +57 -0
  86. label_studio_sdk/export_storage/local/types/local_update_response.py +57 -0
  87. label_studio_sdk/export_storage/redis/__init__.py +5 -0
  88. label_studio_sdk/export_storage/redis/client.py +918 -0
  89. label_studio_sdk/export_storage/redis/types/__init__.py +6 -0
  90. label_studio_sdk/export_storage/redis/types/redis_create_response.py +72 -0
  91. label_studio_sdk/export_storage/redis/types/redis_update_response.py +72 -0
  92. label_studio_sdk/export_storage/s3/__init__.py +5 -0
  93. label_studio_sdk/export_storage/s3/client.py +1008 -0
  94. label_studio_sdk/export_storage/s3/types/__init__.py +6 -0
  95. label_studio_sdk/export_storage/s3/types/s3create_response.py +89 -0
  96. label_studio_sdk/export_storage/s3/types/s3update_response.py +89 -0
  97. label_studio_sdk/export_storage/types/__init__.py +5 -0
  98. label_studio_sdk/export_storage/types/export_storage_list_types_response_item.py +30 -0
  99. label_studio_sdk/files/__init__.py +2 -0
  100. label_studio_sdk/files/client.py +556 -0
  101. label_studio_sdk/import_storage/__init__.py +28 -0
  102. label_studio_sdk/import_storage/azure/__init__.py +5 -0
  103. label_studio_sdk/import_storage/azure/client.py +988 -0
  104. label_studio_sdk/import_storage/azure/types/__init__.py +6 -0
  105. label_studio_sdk/import_storage/azure/types/azure_create_response.py +82 -0
  106. label_studio_sdk/import_storage/azure/types/azure_update_response.py +82 -0
  107. label_studio_sdk/import_storage/client.py +107 -0
  108. label_studio_sdk/import_storage/gcs/__init__.py +5 -0
  109. label_studio_sdk/import_storage/gcs/client.py +988 -0
  110. label_studio_sdk/import_storage/gcs/types/__init__.py +6 -0
  111. label_studio_sdk/import_storage/gcs/types/gcs_create_response.py +82 -0
  112. label_studio_sdk/import_storage/gcs/types/gcs_update_response.py +82 -0
  113. label_studio_sdk/import_storage/local/__init__.py +5 -0
  114. label_studio_sdk/import_storage/local/client.py +836 -0
  115. label_studio_sdk/import_storage/local/types/__init__.py +6 -0
  116. label_studio_sdk/import_storage/local/types/local_create_response.py +57 -0
  117. label_studio_sdk/import_storage/local/types/local_update_response.py +57 -0
  118. label_studio_sdk/import_storage/redis/__init__.py +5 -0
  119. label_studio_sdk/import_storage/redis/client.py +924 -0
  120. label_studio_sdk/import_storage/redis/types/__init__.py +6 -0
  121. label_studio_sdk/import_storage/redis/types/redis_create_response.py +72 -0
  122. label_studio_sdk/import_storage/redis/types/redis_update_response.py +72 -0
  123. label_studio_sdk/import_storage/s3/__init__.py +5 -0
  124. label_studio_sdk/import_storage/s3/client.py +1138 -0
  125. label_studio_sdk/import_storage/s3/types/__init__.py +6 -0
  126. label_studio_sdk/import_storage/s3/types/s3create_response.py +109 -0
  127. label_studio_sdk/import_storage/s3/types/s3update_response.py +109 -0
  128. label_studio_sdk/import_storage/types/__init__.py +5 -0
  129. label_studio_sdk/import_storage/types/import_storage_list_types_response_item.py +30 -0
  130. label_studio_sdk/label_interface/base.py +10 -0
  131. label_studio_sdk/label_interface/control_tags.py +109 -71
  132. label_studio_sdk/label_interface/data_examples.json +96 -0
  133. label_studio_sdk/label_interface/interface.py +102 -53
  134. label_studio_sdk/label_interface/object_tags.py +8 -13
  135. label_studio_sdk/label_interface/region.py +33 -1
  136. label_studio_sdk/ml/__init__.py +19 -0
  137. label_studio_sdk/ml/client.py +981 -0
  138. label_studio_sdk/ml/types/__init__.py +17 -0
  139. label_studio_sdk/ml/types/ml_create_request_auth_method.py +5 -0
  140. label_studio_sdk/ml/types/ml_create_response.py +78 -0
  141. label_studio_sdk/ml/types/ml_create_response_auth_method.py +5 -0
  142. label_studio_sdk/ml/types/ml_update_request_auth_method.py +5 -0
  143. label_studio_sdk/ml/types/ml_update_response.py +78 -0
  144. label_studio_sdk/ml/types/ml_update_response_auth_method.py +5 -0
  145. label_studio_sdk/predictions/__init__.py +2 -0
  146. label_studio_sdk/predictions/client.py +638 -0
  147. label_studio_sdk/projects/__init__.py +6 -0
  148. label_studio_sdk/projects/client.py +1055 -0
  149. label_studio_sdk/projects/client_ext.py +19 -0
  150. label_studio_sdk/projects/exports/__init__.py +2 -0
  151. label_studio_sdk/projects/exports/client.py +930 -0
  152. label_studio_sdk/projects/types/__init__.py +7 -0
  153. label_studio_sdk/projects/types/projects_create_response.py +96 -0
  154. label_studio_sdk/projects/types/projects_import_tasks_response.py +71 -0
  155. label_studio_sdk/projects/types/projects_list_response.py +33 -0
  156. label_studio_sdk/py.typed +0 -0
  157. label_studio_sdk/tasks/__init__.py +5 -0
  158. label_studio_sdk/tasks/client.py +835 -0
  159. label_studio_sdk/tasks/client_ext.py +18 -0
  160. label_studio_sdk/tasks/types/__init__.py +6 -0
  161. label_studio_sdk/tasks/types/tasks_list_request_fields.py +5 -0
  162. label_studio_sdk/tasks/types/tasks_list_response.py +48 -0
  163. label_studio_sdk/types/__init__.py +115 -0
  164. label_studio_sdk/types/annotation.py +116 -0
  165. label_studio_sdk/types/annotation_filter_options.py +42 -0
  166. label_studio_sdk/types/annotation_last_action.py +19 -0
  167. label_studio_sdk/types/azure_blob_export_storage.py +112 -0
  168. label_studio_sdk/types/azure_blob_export_storage_status.py +7 -0
  169. label_studio_sdk/types/azure_blob_import_storage.py +113 -0
  170. label_studio_sdk/types/azure_blob_import_storage_status.py +7 -0
  171. label_studio_sdk/types/base_task.py +113 -0
  172. label_studio_sdk/types/base_user.py +42 -0
  173. label_studio_sdk/types/converted_format.py +36 -0
  174. label_studio_sdk/types/converted_format_status.py +5 -0
  175. label_studio_sdk/types/export.py +48 -0
  176. label_studio_sdk/types/export_convert.py +32 -0
  177. label_studio_sdk/types/export_create.py +54 -0
  178. label_studio_sdk/types/export_create_status.py +5 -0
  179. label_studio_sdk/types/export_status.py +5 -0
  180. label_studio_sdk/types/file_upload.py +30 -0
  181. label_studio_sdk/types/filter.py +53 -0
  182. label_studio_sdk/types/filter_group.py +35 -0
  183. label_studio_sdk/types/gcs_export_storage.py +112 -0
  184. label_studio_sdk/types/gcs_export_storage_status.py +7 -0
  185. label_studio_sdk/types/gcs_import_storage.py +113 -0
  186. label_studio_sdk/types/gcs_import_storage_status.py +7 -0
  187. label_studio_sdk/types/local_files_export_storage.py +97 -0
  188. label_studio_sdk/types/local_files_export_storage_status.py +7 -0
  189. label_studio_sdk/types/local_files_import_storage.py +92 -0
  190. label_studio_sdk/types/local_files_import_storage_status.py +7 -0
  191. label_studio_sdk/types/ml_backend.py +89 -0
  192. label_studio_sdk/types/ml_backend_auth_method.py +5 -0
  193. label_studio_sdk/types/ml_backend_state.py +5 -0
  194. label_studio_sdk/types/prediction.py +78 -0
  195. label_studio_sdk/types/project.py +198 -0
  196. label_studio_sdk/types/project_import.py +63 -0
  197. label_studio_sdk/types/project_import_status.py +5 -0
  198. label_studio_sdk/types/project_label_config.py +32 -0
  199. label_studio_sdk/types/project_sampling.py +7 -0
  200. label_studio_sdk/types/project_skip_queue.py +5 -0
  201. label_studio_sdk/types/redis_export_storage.py +117 -0
  202. label_studio_sdk/types/redis_export_storage_status.py +7 -0
  203. label_studio_sdk/types/redis_import_storage.py +112 -0
  204. label_studio_sdk/types/redis_import_storage_status.py +7 -0
  205. label_studio_sdk/types/s3export_storage.py +134 -0
  206. label_studio_sdk/types/s3export_storage_status.py +7 -0
  207. label_studio_sdk/types/s3import_storage.py +140 -0
  208. label_studio_sdk/types/s3import_storage_status.py +7 -0
  209. label_studio_sdk/types/serialization_option.py +36 -0
  210. label_studio_sdk/types/serialization_options.py +45 -0
  211. label_studio_sdk/types/task.py +157 -0
  212. label_studio_sdk/types/task_filter_options.py +49 -0
  213. label_studio_sdk/types/user_simple.py +37 -0
  214. label_studio_sdk/types/view.py +55 -0
  215. label_studio_sdk/types/webhook.py +67 -0
  216. label_studio_sdk/types/webhook_actions_item.py +21 -0
  217. label_studio_sdk/types/webhook_serializer_for_update.py +67 -0
  218. label_studio_sdk/types/webhook_serializer_for_update_actions_item.py +21 -0
  219. label_studio_sdk/users/__init__.py +5 -0
  220. label_studio_sdk/users/client.py +830 -0
  221. label_studio_sdk/users/types/__init__.py +6 -0
  222. label_studio_sdk/users/types/users_get_token_response.py +36 -0
  223. label_studio_sdk/users/types/users_reset_token_response.py +36 -0
  224. label_studio_sdk/version.py +4 -0
  225. label_studio_sdk/views/__init__.py +35 -0
  226. label_studio_sdk/views/client.py +564 -0
  227. label_studio_sdk/views/types/__init__.py +33 -0
  228. label_studio_sdk/views/types/views_create_request_data.py +43 -0
  229. label_studio_sdk/views/types/views_create_request_data_filters.py +43 -0
  230. label_studio_sdk/views/types/views_create_request_data_filters_conjunction.py +5 -0
  231. label_studio_sdk/views/types/views_create_request_data_filters_items_item.py +49 -0
  232. label_studio_sdk/views/types/views_create_request_data_filters_items_item_filter.py +31 -0
  233. label_studio_sdk/views/types/views_create_request_data_filters_items_item_operator.py +23 -0
  234. label_studio_sdk/views/types/views_create_request_data_ordering_item.py +31 -0
  235. label_studio_sdk/views/types/views_update_request_data.py +43 -0
  236. label_studio_sdk/views/types/views_update_request_data_filters.py +43 -0
  237. label_studio_sdk/views/types/views_update_request_data_filters_conjunction.py +5 -0
  238. label_studio_sdk/views/types/views_update_request_data_filters_items_item.py +49 -0
  239. label_studio_sdk/views/types/views_update_request_data_filters_items_item_filter.py +31 -0
  240. label_studio_sdk/views/types/views_update_request_data_filters_items_item_operator.py +23 -0
  241. label_studio_sdk/views/types/views_update_request_data_ordering_item.py +31 -0
  242. label_studio_sdk/webhooks/__init__.py +5 -0
  243. label_studio_sdk/webhooks/client.py +636 -0
  244. label_studio_sdk/webhooks/types/__init__.py +5 -0
  245. label_studio_sdk/webhooks/types/webhooks_update_request_actions_item.py +21 -0
  246. label_studio_sdk-1.0.1.dist-info/METADATA +163 -0
  247. label_studio_sdk-1.0.1.dist-info/RECORD +256 -0
  248. {label_studio_sdk-0.0.34.dist-info → label_studio_sdk-1.0.1.dist-info}/WHEEL +1 -2
  249. label_studio_sdk/objects.py +0 -35
  250. label_studio_sdk-0.0.34.dist-info/LICENSE +0 -201
  251. label_studio_sdk-0.0.34.dist-info/METADATA +0 -24
  252. label_studio_sdk-0.0.34.dist-info/RECORD +0 -37
  253. label_studio_sdk-0.0.34.dist-info/top_level.txt +0 -2
  254. tests/test_client.py +0 -37
  255. tests/test_export.py +0 -105
  256. tests/test_interface/__init__.py +0 -1
  257. tests/test_interface/configs.py +0 -137
  258. tests/test_interface/mockups.py +0 -22
  259. tests/test_interface/test_compat.py +0 -64
  260. tests/test_interface/test_control_tags.py +0 -55
  261. tests/test_interface/test_data_generation.py +0 -45
  262. tests/test_interface/test_lpi.py +0 -15
  263. tests/test_interface/test_main.py +0 -196
  264. tests/test_interface/test_object_tags.py +0 -36
  265. tests/test_interface/test_region.py +0 -36
  266. tests/test_interface/test_validate_summary.py +0 -35
  267. tests/test_interface/test_validation.py +0 -59
  268. {tests → label_studio_sdk/_extensions}/__init__.py +0 -0
  269. /label_studio_sdk/{exceptions.py → _legacy/exceptions.py} +0 -0
  270. /label_studio_sdk/{users.py → _legacy/users.py} +0 -0
  271. /label_studio_sdk/{utils.py → _legacy/utils.py} +0 -0
  272. /label_studio_sdk/{workspaces.py → _legacy/workspaces.py} +0 -0
@@ -0,0 +1,96 @@
1
+ {
2
+ "editor_preview": {
3
+ "TextRaw": "To have faith is to trust yourself to the water",
4
+ "TextUrl": "https://htx-pub.s3.amazonaws.com/example.txt",
5
+ "HyperText": "<div style=\"max-width: 750px\"><div style=\"clear: both\"><div style=\"float: right; display: inline-block; border: 1px solid #F2F3F4; background-color: #F8F9F9; border-radius: 5px; padding: 7px; margin: 10px 0;\"><p><b>Jules<\/b>: No no, Mr. Wolfe, it's not like that. Your help is definitely appreciated.<\/p><\/div><\/div><div style=\"clear: both\"><div style=\"float: right; display: inline-block; border: 1px solid #F2F3F4; background-color: #F8F9F9; border-radius: 5px; padding: 7px; margin: 10px 0;\"><p><b>Vincent<\/b>: Look, Mr. Wolfe, I respect you. I just don't like people barking orders at me, that's all.<\/p><\/div><\/div><div style=\"clear: both\"><div style=\"display: inline-block; border: 1px solid #D5F5E3; background-color: #EAFAF1; border-radius: 5px; padding: 7px; margin: 10px 0;\"><p><b>The Wolf<\/b>: If I'm curt with you, it's because time is a factor. I think fast, I talk fast, and I need you two guys to act fast if you want to get out of this. So pretty please, with sugar on top, clean the car.<\/p><\/div><\/div><\/div>",
6
+ "HyperTextUrl": "<HOSTNAME>/static/samples/hypertext.html",
7
+ "Image": "<HOSTNAME>/static/samples/sample.jpg",
8
+ "Audio": "<HOSTNAME>/static/samples/game.wav",
9
+ "AudioPlus": "<HOSTNAME>/static/samples/game.wav",
10
+ "Header": "Task header",
11
+ "Paragraphs": [{"author": "Alice", "text": "Hi, Bob."}, {"author": "Bob", "text": "Hello, Alice!"}, {"author": "Alice", "text": "What's up?"}, {"author": "Bob", "text": "Good. Ciao!"}, {"author": "Alice", "text": "Bye, Bob."}],
12
+ "ParagraphsUrl": "<HOSTNAME>/samples/paragraphs.json?",
13
+ "Table": {"Card number": 18799210, "First name": "Max", "Last name": "Nobel"},
14
+ "$videoHack": "<video src='<HOSTNAME>/static/samples/opossum_snow.mp4' width=100% controls>",
15
+ "Video": "<HOSTNAME>/static/samples/opossum_snow.mp4",
16
+ "Labels": [
17
+ { "value": "DynamicLabel1", "background": "#ff0000" },
18
+ { "value": "DynamicLabel2", "background": "#0000ff" }
19
+ ],
20
+ "Choices": [
21
+ { "value": "DynamicChoice1" },
22
+ { "value": "DynamicChoice2" },
23
+ { "value": "DynamicChoice3" }
24
+ ],
25
+ "NestedChoices": [
26
+ {
27
+ "value": "DynamicChoiceHeader1",
28
+ "children": [
29
+ { "value": "DynamicChoice1.1" },
30
+ { "value": "DynamicChoice1.2" }
31
+ ]
32
+ },
33
+ {
34
+ "value": "DynamicChoiceHeader2",
35
+ "children": [
36
+ { "value": "DynamicChoice2.1" },
37
+ { "value": "DynamicChoice2.2" },
38
+ { "value": "DynamicChoice2.3" }
39
+ ]
40
+ }
41
+ ],
42
+ "List": [
43
+ {
44
+ "id": 1,
45
+ "title": "The Amazing World of Opossums",
46
+ "body": "Opossums are fascinating marsupials native to North America. They have prehensile tails, which help them to climb trees and navigate their surroundings with ease. Additionally, they are known for their unique defense mechanism, called 'playing possum,' where they mimic the appearance and smell of a dead animal to deter predators."
47
+ },
48
+ {
49
+ "id": 2,
50
+ "title": "Opossums: Nature's Pest Control",
51
+ "body": "Opossums play a crucial role in controlling insect and rodent populations, as they consume a variety of pests like cockroaches, beetles, and mice. This makes them valuable allies for gardeners and homeowners, as they help to maintain a balanced ecosystem and reduce the need for chemical pest control methods."
52
+ },
53
+ {
54
+ "id": 3,
55
+ "title": "Fun Fact: Opossums Are Immune to Snake Venom",
56
+ "body": "One surprising characteristic of opossums is their natural immunity to snake venom. They have a unique protein in their blood called 'Lethal Toxin-Neutralizing Factor' (LTNF), which neutralizes venom from a variety of snake species, including rattlesnakes and cottonmouths. This allows opossums to prey on snakes without fear of harm, further highlighting their important role in the ecosystem."
57
+ }
58
+ ],
59
+ "$longText": "Opossums are frequently considered to be living fossils, and as a result are often used to approximate the ancestral therian condition in comparative studies. However, this is inaccurate, the oldest opossum fossils are early Miocene in age (roughly 20 million years old) and the last common ancestor of all living opossums approximately dates to the Oligocene-Miocene boundary (roughly 23 million years ago) and is at most no older than Oligocene in age. Many extinct metatherians once considered early opossums, such as Alphadon, Peradectes, Herpetotherium, and Pucadelphys, have since been recognized to have been previously grouped with opossums on the basis of plesiomorphies and are now considered to represent older branches of Metatheria only distantly related to modern opossums.",
60
+ "$corefText": "I voted for Obama because he was most aligned with my values, she said.",
61
+ "$pdf": "<embed src='<HOSTNAME>/static/samples/sample.pdf' width='100%' height='600px'/>",
62
+ "$website": "<iframe src='http://heartex.ai' width='100%' height='600px'/>",
63
+ "$headlessCsv": "<HOSTNAME>/static/samples/sample-task-sin-headless.csv",
64
+ "$humanMachineDialogue": [
65
+ {"author": "Human", "text": "Hi, Robot!"},
66
+ {"author": "Robot", "text": "Nice to meet you, man! Tell me what you want."},
67
+ {"author": "Human", "text": "Order me a pizza from Golden Boy at Green Street "},
68
+ {"author": "Robot", "text": "Done. When do you want to get the order?"},
69
+ {"author": "Human", "text": "At 3am in the morning, please"}],
70
+ "$respone": "Sure, no problem!",
71
+ "$resptwo": "Sorry, it's too early. May be we can change the time?",
72
+ "$respthree": "Don't eat junk food man, it's bad for you...",
73
+ "$ocr": "https://htx-pub.s3.amazonaws.com/demo/ocr/example.jpg",
74
+ "$ner": "A Florida restaurant paid 10,925 pounds ($16,935) for the draft of \\\"Ain't no telling\\\", which Hendrix penned on a piece of London hotel stationery in late 1966.",
75
+ "$captioning": "<HOSTNAME>/static/samples/trees_in_snow.jpg",
76
+ "$pairText1": "Look at this! It's a brand new product",
77
+ "$pairText2": "Look at this! It's an awesome piece of sh*t"
78
+ },
79
+ "upload": {
80
+ "TextRaw": "To have faith is to trust yourself to the water",
81
+ "TextUrl": "https://htx-pub.s3.amazonaws.com/example.txt",
82
+ "HyperText": "<a href='heartex.net'>Heartex</a>",
83
+ "Image": "<HOSTNAME>/static/samples/sample.jpg",
84
+ "Audio": "<HOSTNAME>/static/samples/game.wav",
85
+ "AudioPlus": "<HOSTNAME>/static/samples/game.wav",
86
+ "Header": "Task header",
87
+ "Paragraphs": [{"author": "Alice", "text": "Hi, Bob."}, {"author": "Bob", "text": "Hello, Alice!"}, {"author": "Alice", "text": "What's up?"}, {"author": "Bob", "text": "Good. Ciao!"}, {"author": "Alice", "text": "Bye, Bob."}],
88
+ "Table": {"Card number": 18799210, "First name": "Max", "Last name": "Nobel"},
89
+ "$videoHack": "<video src='static/samples/opossum_snow.mp4' width=100% controls>",
90
+ "Video": "<HOSTNAME>/static/samples/opossum_snow.mp4",
91
+ "$longText": "Opossums are frequently considered to be living fossils, and as a result are often used to approximate the ancestral therian condition in comparative studies. However, this is inaccurate, the oldest opossum fossils are early Miocene in age (roughly 20 million years old) and the last common ancestor of all living opossums approximately dates to the Oligocene-Miocene boundary (roughly 23 million years ago) and is at most no older than Oligocene in age. Many extinct metatherians once considered early opossums, such as Alphadon, Peradectes, Herpetotherium, and Pucadelphys, have since been recognized to have been previously grouped with opossums on the basis of plesiomorphies and are now considered to represent older branches of Metatheria only distantly related to modern opossums.",
92
+ "$pdf": "<embed src='<HOSTNAME>/static/samples/sample.pdf' width='100%' height='600px'/>",
93
+ "$website": "<iframe src='https://heartex.ai' width='100%' height='600px'/>",
94
+ "$headlessCsv": "<HOSTNAME>/static/samples/sample-task-sin-headless.csv"
95
+ }
96
+ }
@@ -12,28 +12,28 @@ from typing import Dict, Optional, List, Tuple, Any, Callable, Union
12
12
  from pydantic import BaseModel
13
13
 
14
14
  # from typing import Dict, Optional, List, Tuple, Any
15
- from collections import defaultdict
15
+ from collections import defaultdict, OrderedDict
16
16
  from lxml import etree
17
17
  import xmljson
18
18
 
19
- from label_studio_sdk.exceptions import (
19
+ from label_studio_sdk._legacy.exceptions import (
20
20
  LSConfigParseException,
21
21
  LabelStudioXMLSyntaxErrorSentryIgnored,
22
22
  LabelStudioValidationErrorSentryIgnored,
23
23
  )
24
24
 
25
- from label_studio_sdk.label_interface.control_tags import (
25
+ from .control_tags import (
26
26
  ControlTag,
27
27
  ChoicesTag,
28
28
  LabelsTag,
29
29
  )
30
- from label_studio_sdk.label_interface.object_tags import ObjectTag
31
- from label_studio_sdk.label_interface.label_tags import LabelTag
32
- from label_studio_sdk.objects import AnnotationValue, TaskValue, PredictionValue
30
+ from .object_tags import ObjectTag
31
+ from .label_tags import LabelTag
32
+ from label_studio_sdk._legacy.objects import AnnotationValue, TaskValue, PredictionValue
33
33
 
34
34
 
35
35
  dir_path = os.path.dirname(os.path.realpath(__file__))
36
- file_path = os.path.join(dir_path, "..", "schema", "label_config_schema.json")
36
+ file_path = os.path.join(dir_path, "..", "_legacy", "schema", "label_config_schema.json")
37
37
 
38
38
  with open(file_path) as f:
39
39
  _LABEL_CONFIG_SCHEMA_DATA = json.load(f)
@@ -189,23 +189,34 @@ class LabelInterface:
189
189
  ```
190
190
  """
191
191
 
192
- def __init__(self, config: str, *args, **kwargs):
192
+ def __init__(self, config: str, tags_mapping=None, *args, **kwargs):
193
193
  """
194
- Create LabelInterface instance from the config string
195
- Example:
194
+ Initialize a LabelInterface instance using a config string.
195
+
196
+ Args:
197
+ config (str): Configuration string.
198
+ tags_mapping: Provide your own implementation of any tag, this is helpful in cases where you want to override one of the control tags, and have your custom .label() method implemented.
199
+
200
+ The configuration string should be formatted as follows:
201
+
196
202
  ```
197
- label_config = LabelInterface('''
198
203
  <View>
199
- <Choices name="sentiment" toName="txt">
204
+ <Choices name="sentiment" toName="txt">
200
205
  <Choice value="Positive" />
201
206
  <Choice value="Negative" />
202
207
  <Choice value="Neutral" />
203
- </Choices>
204
- <Text name="txt" value="$text" />
205
- ''')
208
+ </Choices>
209
+ <Text name="txt" value="$text" />
210
+ </View>
211
+ ```
212
+ This method will extract the predefined task from the configuration and
213
+ parse the controls, objects, and labels used in it.
206
214
  """
215
+ self.task_loaded = False
216
+
207
217
  self._config = config
208
-
218
+ self._tags_mapping = tags_mapping
219
+
209
220
  # extract predefined task from the config
210
221
  _task_data, _ann, _pred = LabelInterface.get_task_from_labeling_config(config)
211
222
  self._sample_config_task = _task_data
@@ -225,6 +236,8 @@ class LabelInterface:
225
236
  self._labels = labels
226
237
  self._tree = tree
227
238
 
239
+
240
+
228
241
  ##### NEW API
229
242
 
230
243
  @property
@@ -391,7 +404,38 @@ class LabelInterface:
391
404
  lst = list(filter(match_fn, lst))
392
405
 
393
406
  return lst
407
+
408
+ def load_task(self, task):
409
+ """Loads a task and substitutes the value in each object tag
410
+ with actual data from the task, returning a copy of the
411
+ LabelConfig object.
412
+
413
+ If the `value` field in an object tag is designed to take
414
+ variable input (i.e., `value_is_variable` is True), the
415
+ function replaces this value with the corresponding value from
416
+ the task dictionary.
417
+
418
+ Args:
419
+ task (dict): Dictionary representing the task, where
420
+ each key-value pair denotes an attribute-value of the
421
+ task.
422
+
423
+ Returns:
424
+ LabelInterface: A deep copy of the current LabelIntreface
425
+ instance with the object tags' value fields populated with
426
+ data from the task.
427
+
428
+ """
429
+ tree = copy.deepcopy(self)
430
+ tree.task_loaded = True
431
+
432
+ for obj in tree.objects:
433
+ print(obj.value_is_variable, obj.value_name)
434
+ if obj.value_is_variable and obj.value_name in task:
435
+ obj.value = task.get(obj.value_name)
394
436
 
437
+ return tree
438
+
395
439
  def parse(self, config_string: str) -> Tuple[Dict, Dict, Dict, etree._Element]:
396
440
  """Parses the received configuration string into dictionaries
397
441
  of ControlTags, ObjectTags, and Labels, along with an XML tree
@@ -422,14 +466,17 @@ class LabelInterface:
422
466
  variables.append(tag.attrib["indexFlag"])
423
467
 
424
468
  if ControlTag.validate_node(tag):
425
- controls[tag.attrib["name"]] = ControlTag.parse_node(tag)
469
+ controls[tag.attrib["name"]] = ControlTag.parse_node(tag, tags_mapping=self._tags_mapping)
426
470
 
427
471
  elif ObjectTag.validate_node(tag):
428
- objects[tag.attrib["name"]] = ObjectTag.parse_node(tag)
472
+ objects[tag.attrib["name"]] = ObjectTag.parse_node(tag, tags_mapping=self._tags_mapping)
429
473
 
430
474
  elif LabelTag.validate_node(tag):
431
475
  lb = LabelTag.parse_node(tag, controls)
432
- labels[lb.parent_name][lb.value] = lb
476
+ # This case is hit when Label tag is missing `value` and `alias`
477
+ # For now we will skip that Label, but in future might want to raise an error
478
+ if lb:
479
+ labels[lb.parent_name][lb.value] = lb
433
480
 
434
481
  return controls, objects, labels, xml_tree
435
482
 
@@ -485,34 +532,6 @@ class LabelInterface:
485
532
  "Label config contains non-unique names"
486
533
  )
487
534
 
488
- def load_task(self, task):
489
- """Loads a task and substitutes the value in each object tag
490
- with actual data from the task, returning a copy of the
491
- LabelConfig object.
492
-
493
- If the `value` field in an object tag is designed to take
494
- variable input (i.e., `value_is_variable` is True), the
495
- function replaces this value with the corresponding value from
496
- the task dictionary.
497
-
498
- Args:
499
- task (dict): Dictionary representing the task, where
500
- each key-value pair denotes an attribute-value of the
501
- task.
502
-
503
- Returns:
504
- LabelInterface: A deep copy of the current LabelIntreface
505
- instance with the object tags' value fields populated with
506
- data from the task.
507
-
508
- """
509
- tree = copy.deepcopy(self)
510
- for obj in tree.objects:
511
- if obj.value_is_variable and obj.value_name in task:
512
- obj.value = task.get(obj.value_name)
513
-
514
- return tree
515
-
516
535
  @property
517
536
  def is_valid(self):
518
537
  """ """
@@ -565,6 +584,23 @@ class LabelInterface:
565
584
 
566
585
  return True
567
586
 
587
+ def _validate_object(self, obj):
588
+ """ """
589
+ regions = []
590
+ for r in obj.get(RESULT_KEY):
591
+ if r.get('type') != "relation":
592
+ if not self.validate_region(r):
593
+ return False
594
+
595
+ regions.append(r)
596
+
597
+ for r in obj.get(RESULT_KEY):
598
+ if r.get('type') == "relation" and \
599
+ not self.validate_relation(r, regions):
600
+ return False
601
+
602
+ return True
603
+
568
604
  def validate_annotation(self, annotation):
569
605
  """Validates the given annotation against the current configuration.
570
606
 
@@ -583,11 +619,11 @@ class LabelInterface:
583
619
  validation, False otherwise.
584
620
 
585
621
  """
586
- return all(self.validate_region(r) for r in annotation.get(RESULT_KEY))
622
+ return self._validate_object(annotation)
587
623
 
588
624
  def validate_prediction(self, prediction):
589
625
  """Same as validate_annotation right now"""
590
- return all(self.validate_region(r) for r in prediction.get(RESULT_KEY))
626
+ return self._validate_object(prediction)
591
627
 
592
628
  def validate_region(self, region) -> bool:
593
629
  """Validates a region from the annotation against the current
@@ -617,22 +653,35 @@ class LabelInterface:
617
653
  if not control or not obj:
618
654
  return False
619
655
 
620
- # type of the region should match the tag name
656
+ # type of the region should match the tag name
621
657
  if control.tag.lower() != region["type"]:
622
658
  return False
623
-
659
+
624
660
  # make sure that in config it connects to the same tag as
625
661
  # immplied by the region data
626
662
  if region["to_name"] not in control.to_name:
627
663
  return False
628
-
664
+
629
665
  # validate the actual value, for example that <Labels /> tag
630
666
  # is producing start, end, and labels
631
667
  if not control.validate_value(region["value"]):
632
668
  return False
633
-
669
+
634
670
  return True
635
671
 
672
+ def validate_relation(self, relation, regions, _mapping=None) -> bool:
673
+ """Validates that the relation is correct and all the associated objects are provided"""
674
+ if _mapping is None:
675
+ _mapping = { r['id']: r for r in regions }
676
+
677
+ if relation.get("type") != "relation" or \
678
+ relation.get("direction") not in ("left", "right", "bi") or \
679
+ relation.get("from_id") not in _mapping or \
680
+ relation.get("to_id") not in _mapping:
681
+ return False
682
+
683
+ return True
684
+
636
685
  ### Generation
637
686
 
638
687
  def _sample_task(self, secure_mode=False):
@@ -8,7 +8,7 @@ import xml.etree.ElementTree
8
8
  from urllib.parse import urlencode
9
9
  from typing import Optional
10
10
 
11
- from .base import LabelStudioTag
11
+ from .base import LabelStudioTag, get_tag_class
12
12
 
13
13
  _TAG_TO_CLASS = {
14
14
  "audio": "AudioTag",
@@ -77,12 +77,6 @@ def data_examples(
77
77
  return _DATA_EXAMPLES[mode]
78
78
 
79
79
 
80
- def get_tag_class(name):
81
- """ """
82
- class_name = _TAG_TO_CLASS.get(name.lower())
83
- return globals().get(class_name, None)
84
-
85
-
86
80
  class ObjectTag(LabelStudioTag):
87
81
  """
88
82
  Class that represents a ObjectTag in Label Studio
@@ -103,7 +97,7 @@ class ObjectTag(LabelStudioTag):
103
97
  # self._value_type = value_type
104
98
 
105
99
  @classmethod
106
- def parse_node(cls, tag: xml.etree.ElementTree.Element) -> "ObjectTag":
100
+ def parse_node(cls, tag: xml.etree.ElementTree.Element, tags_mapping=None) -> "ObjectTag":
107
101
  """
108
102
  This class method parses a node and returns a ObjectTag object if the node has a name and a value.
109
103
 
@@ -117,8 +111,10 @@ class ObjectTag(LabelStudioTag):
117
111
  ObjectTag
118
112
  A new ObjectTag object with the tag name, attributes, name, and value.
119
113
  """
120
- tag_class = get_tag_class(tag.tag) or cls
121
-
114
+ tag_class = get_tag_class(tag.tag, _TAG_TO_CLASS, re_mapping=tags_mapping) or cls
115
+ if isinstance(tag_class, str):
116
+ tag_class = globals().get(tag_class, None)
117
+
122
118
  return tag_class(
123
119
  tag=tag.tag,
124
120
  attr=dict(tag.attrib),
@@ -146,10 +142,9 @@ class ObjectTag(LabelStudioTag):
146
142
  @property
147
143
  def value_is_variable(self) -> bool:
148
144
  """Check if value has variable"""
149
- pattern = re.compile(r"^\$[A-Za-z_]+$")
145
+ pattern = re.compile(r"^\$[^, ]+$")
150
146
  return bool(pattern.fullmatch(self.value))
151
-
152
- # TODO this should not be here as soon as we cover all the tags
147
+
153
148
 
154
149
  # and have generate_example in each
155
150
  def generate_example_value(self, mode="upload", secure_mode=False):
@@ -4,7 +4,7 @@
4
4
  import json
5
5
  from uuid import uuid4
6
6
 
7
- from typing import Any
7
+ from typing import Any, List, Dict, Optional
8
8
  from pydantic import BaseModel, Field
9
9
 
10
10
 
@@ -26,6 +26,7 @@ class Region(BaseModel):
26
26
  from_tag: Any
27
27
  to_tag: Any
28
28
  value: Any
29
+ relations: Optional[List[Dict]] = []
29
30
 
30
31
  def _dict(self):
31
32
  """ """
@@ -38,6 +39,37 @@ class Region(BaseModel):
38
39
  "value": self.value.dict(),
39
40
  }
40
41
 
42
+ def _dict_relations(self):
43
+ """ """
44
+ # this code does not include "labels" key if no labels were passed
45
+ return [
46
+ {**{
47
+ "from_id": self.id,
48
+ "to_id": rel.get("region", {}).id,
49
+ "type": "relation",
50
+ "direction": rel.get("direction", "right")},
51
+ **({"labels": rel["labels"]} if rel.get("labels") else {})
52
+ }
53
+ for rel in self.relations
54
+ ]
55
+
41
56
  def to_json(self):
42
57
  """ """
43
58
  return json.dumps(self._dict())
59
+
60
+ def to_json_relations(self):
61
+ """ """
62
+ return json.dumps(self._dict_relations())
63
+
64
+ @property
65
+ def has_relations(self):
66
+ return len(self.relations) > 0
67
+
68
+ def add_relation(self, region=None, direction="right", label=None):
69
+ """ """
70
+ self.relations.append({ "region": region, "direction": direction, "labels": label })
71
+
72
+ def set_relations(self, rels):
73
+ """ """
74
+ self.relations = rels
75
+
@@ -0,0 +1,19 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from .types import (
4
+ MlCreateRequestAuthMethod,
5
+ MlCreateResponse,
6
+ MlCreateResponseAuthMethod,
7
+ MlUpdateRequestAuthMethod,
8
+ MlUpdateResponse,
9
+ MlUpdateResponseAuthMethod,
10
+ )
11
+
12
+ __all__ = [
13
+ "MlCreateRequestAuthMethod",
14
+ "MlCreateResponse",
15
+ "MlCreateResponseAuthMethod",
16
+ "MlUpdateRequestAuthMethod",
17
+ "MlUpdateResponse",
18
+ "MlUpdateResponseAuthMethod",
19
+ ]