superannotate 4.4.27__tar.gz → 4.4.29.dev1__tar.gz

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.
Files changed (142) hide show
  1. {superannotate-4.4.27/src/superannotate.egg-info → superannotate-4.4.29.dev1}/PKG-INFO +1 -1
  2. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/__init__.py +3 -1
  3. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/sdk_interface.py +258 -7
  4. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/__init__.py +1 -0
  5. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/enums.py +2 -0
  6. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/exceptions.py +6 -0
  7. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/service_types.py +4 -0
  8. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/serviceproviders.py +39 -0
  9. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/annotations.py +9 -47
  10. superannotate-4.4.29.dev1/src/superannotate/lib/core/utils.py +48 -0
  11. superannotate-4.4.29.dev1/src/superannotate/lib/infrastructure/annotation_adapter.py +120 -0
  12. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/controller.py +60 -1
  13. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/annotation.py +89 -24
  14. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/http_client.py +5 -4
  15. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/item_service.py +1 -1
  16. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/project.py +23 -0
  17. {superannotate-4.4.27 → superannotate-4.4.29.dev1/src/superannotate.egg-info}/PKG-INFO +1 -1
  18. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate.egg-info/SOURCES.txt +2 -0
  19. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/LICENSE +0 -0
  20. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/MANIFEST.in +0 -0
  21. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/README.rst +0 -0
  22. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/requirements.txt +0 -0
  23. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/setup.cfg +0 -0
  24. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/setup.py +0 -0
  25. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/__init__.py +0 -0
  26. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/__init__.py +0 -0
  27. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/analytics/__init__.py +0 -0
  28. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/analytics/aggregators.py +0 -0
  29. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/analytics/common.py +0 -0
  30. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/bin/__init__.py +0 -0
  31. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/bin/superannotate.py +0 -0
  32. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/common.py +0 -0
  33. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/exceptions.py +0 -0
  34. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/helpers.py +0 -0
  35. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/__init__.py +0 -0
  36. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/conversion.py +0 -0
  37. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/__init__.py +0 -0
  38. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/baseStrategy.py +0 -0
  39. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/__init__.py +0 -0
  40. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_api.py +0 -0
  41. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_converter.py +0 -0
  42. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_strategies.py +0 -0
  43. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_to_sa_pixel.py +0 -0
  44. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_to_sa_vector.py +0 -0
  45. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_pixel_to_coco.py +0 -0
  46. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py +0 -0
  47. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/converters.py +0 -0
  48. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/__init__.py +0 -0
  49. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_helper.py +0 -0
  50. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_strategies.py +0 -0
  51. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_to_sa_vector.py +0 -0
  52. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/__init__.py +0 -0
  53. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_strategies.py +0 -0
  54. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_to_sa_vector.py +0 -0
  55. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/__init__.py +0 -0
  56. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_helper.py +0 -0
  57. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_strategies.py +0 -0
  58. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_to_sa_pixel.py +0 -0
  59. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_to_sa_vector.py +0 -0
  60. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/sa_json_helper.py +0 -0
  61. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/__init__.py +0 -0
  62. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_strategies.py +0 -0
  63. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_to_sa_pixel.py +0 -0
  64. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_to_sa_vector.py +0 -0
  65. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/__init__.py +0 -0
  66. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_helper.py +0 -0
  67. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_strategies.py +0 -0
  68. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_to_sa_pixel.py +0 -0
  69. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_to_sa_vector.py +0 -0
  70. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/__init__.py +0 -0
  71. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_helper.py +0 -0
  72. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_strategies.py +0 -0
  73. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_to_sa_vector.py +0 -0
  74. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/__init__.py +0 -0
  75. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_helper.py +0 -0
  76. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_strategies.py +0 -0
  77. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_pixel.py +0 -0
  78. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_vector.py +0 -0
  79. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/__init__.py +0 -0
  80. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_strategies.py +0 -0
  81. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_to_sa_vector.py +0 -0
  82. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/__init__.py +0 -0
  83. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_strategies.py +0 -0
  84. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_to_sa_vector.py +0 -0
  85. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/export_from_sa_conversions.py +0 -0
  86. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/import_to_sa_conversions.py +0 -0
  87. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/input_converters/sa_conversion.py +0 -0
  88. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/__init__.py +0 -0
  89. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/base_interface.py +0 -0
  90. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/cli_interface.py +0 -0
  91. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/sdk/__init__.py +0 -0
  92. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/sdk/folders.py +0 -0
  93. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/sdk/project.py +0 -0
  94. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/interface/types.py +0 -0
  95. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/app/serializers.py +0 -0
  96. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/base_usecases.py +0 -0
  97. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/conditions.py +0 -0
  98. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/config.py +0 -0
  99. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/__init__.py +0 -0
  100. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/base.py +0 -0
  101. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/classes.py +0 -0
  102. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/folder.py +0 -0
  103. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/integrations.py +0 -0
  104. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/items.py +0 -0
  105. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/project.py +0 -0
  106. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/entities/project_entities.py +0 -0
  107. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/jsx_conditions.py +0 -0
  108. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/plugin.py +0 -0
  109. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/pydantic_v1.py +0 -0
  110. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/reporter.py +0 -0
  111. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/repositories.py +0 -0
  112. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/response.py +0 -0
  113. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/types.py +0 -0
  114. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/__init__.py +0 -0
  115. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/base.py +0 -0
  116. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/classes.py +0 -0
  117. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/custom_fields.py +0 -0
  118. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/folders.py +0 -0
  119. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/images.py +0 -0
  120. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/integrations.py +0 -0
  121. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/items.py +0 -0
  122. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/models.py +0 -0
  123. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/usecases/projects.py +0 -0
  124. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/core/video_convertor.py +0 -0
  125. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/__init__.py +0 -0
  126. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/helpers.py +0 -0
  127. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/repositories.py +0 -0
  128. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/serviceprovider.py +0 -0
  129. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/__init__.py +0 -0
  130. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/annotation_class.py +0 -0
  131. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/explore.py +0 -0
  132. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/folder.py +0 -0
  133. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/integration.py +0 -0
  134. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/item.py +0 -0
  135. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/services/work_management.py +0 -0
  136. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/stream_data_handler.py +0 -0
  137. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/utils.py +0 -0
  138. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate/lib/infrastructure/validators.py +0 -0
  139. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate.egg-info/dependency_links.txt +0 -0
  140. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate.egg-info/entry_points.txt +0 -0
  141. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate.egg-info/requires.txt +0 -0
  142. {superannotate-4.4.27 → superannotate-4.4.29.dev1}/src/superannotate.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: superannotate
3
- Version: 4.4.27
3
+ Version: 4.4.29.dev1
4
4
  Summary: Python SDK to SuperAnnotate platform
5
5
  Home-page: https://github.com/superannotateai/superannotate-python-sdk
6
6
  Author: SuperAnnotate AI
@@ -3,7 +3,7 @@ import os
3
3
  import sys
4
4
 
5
5
 
6
- __version__ = "4.4.27"
6
+ __version__ = "4.4.29dev1"
7
7
 
8
8
  os.environ.update({"sa_version": __version__})
9
9
  sys.path.append(os.path.split(os.path.realpath(__file__))[0])
@@ -15,6 +15,7 @@ from lib.core import PACKAGE_VERSION_UPGRADE
15
15
  from lib.core import PACKAGE_VERSION_INFO_MESSAGE
16
16
  from lib.core import PACKAGE_VERSION_MAJOR_UPGRADE
17
17
  from lib.core.exceptions import AppException
18
+ from lib.core.exceptions import FileChangedError
18
19
  from superannotate.lib.app.input_converters import convert_project_type
19
20
  from superannotate.lib.app.input_converters import export_annotation
20
21
  from superannotate.lib.app.input_converters import import_annotation
@@ -30,6 +31,7 @@ __all__ = [
30
31
  # Utils
31
32
  "enums",
32
33
  "AppException",
34
+ "FileChangedError",
33
35
  "import_annotation",
34
36
  "export_annotation",
35
37
  "convert_project_type",
@@ -5,6 +5,7 @@ import json
5
5
  import logging
6
6
  import os
7
7
  import sys
8
+ import typing
8
9
  import warnings
9
10
  from pathlib import Path
10
11
  from typing import Any
@@ -28,11 +29,13 @@ import boto3
28
29
  from tqdm import tqdm
29
30
 
30
31
  import lib.core as constants
32
+ from lib.infrastructure.controller import Controller
31
33
  from lib.app.helpers import get_annotation_paths
32
34
  from lib.app.helpers import get_name_url_duplicated_from_csv
33
35
  from lib.app.helpers import wrap_error as wrap_validation_errors
34
36
  from lib.app.interface.base_interface import BaseInterfaceFacade
35
37
  from lib.app.interface.base_interface import TrackableMeta
38
+
36
39
  from lib.app.interface.types import EmailStr
37
40
  from lib.app.serializers import BaseSerializer
38
41
  from lib.app.serializers import FolderSerializer
@@ -45,7 +48,7 @@ from lib.core.conditions import CONDITION_EQ as EQ
45
48
  from lib.core.conditions import Condition
46
49
  from lib.core.jsx_conditions import Filter, OperatorEnum
47
50
  from lib.core.conditions import EmptyCondition
48
- from lib.core.entities import AttachmentEntity
51
+ from lib.core.entities import AttachmentEntity, FolderEntity, BaseItemEntity
49
52
  from lib.core.entities import SettingEntity
50
53
  from lib.core.entities.classes import AnnotationClassEntity
51
54
  from lib.core.entities.classes import AttributeGroup
@@ -61,6 +64,9 @@ from lib.core.pydantic_v1 import ValidationError
61
64
  from lib.core.pydantic_v1 import constr
62
65
  from lib.core.pydantic_v1 import conlist
63
66
  from lib.core.pydantic_v1 import parse_obj_as
67
+ from lib.infrastructure.annotation_adapter import BaseMultimodalAnnotationAdapter
68
+ from lib.infrastructure.annotation_adapter import MultimodalSmallAnnotationAdapter
69
+ from lib.infrastructure.annotation_adapter import MultimodalLargeAnnotationAdapter
64
70
  from lib.infrastructure.utils import extract_project_folder
65
71
  from lib.infrastructure.validators import wrap_error
66
72
 
@@ -69,7 +75,6 @@ logger = logging.getLogger("sa")
69
75
  # NotEmptyStr = TypeVar("NotEmptyStr", bound=constr(strict=True, min_length=1))
70
76
  NotEmptyStr = constr(strict=True, min_length=1)
71
77
 
72
-
73
78
  PROJECT_STATUS = Literal["NotStarted", "InProgress", "Completed", "OnHold"]
74
79
 
75
80
  PROJECT_TYPE = Literal[
@@ -82,7 +87,6 @@ PROJECT_TYPE = Literal[
82
87
  "Multimodal",
83
88
  ]
84
89
 
85
-
86
90
  APPROVAL_STATUS = Literal["Approved", "Disapproved", None]
87
91
 
88
92
  IMAGE_QUALITY = Literal["compressed", "original"]
@@ -110,6 +114,87 @@ class Attachment(TypedDict, total=False):
110
114
  integration: NotRequired[str] # noqa
111
115
 
112
116
 
117
+ class ItemContext:
118
+ def __init__(
119
+ self,
120
+ controller: Controller,
121
+ project: Project,
122
+ folder: FolderEntity,
123
+ item: BaseItemEntity,
124
+ overwrite: bool = True,
125
+ ):
126
+ self.controller = controller
127
+ self.project = project
128
+ self.folder = folder
129
+ self.item = item
130
+ self._annotation_adapter: Optional[BaseMultimodalAnnotationAdapter] = None
131
+ self._overwrite = overwrite
132
+ self._annotation = None
133
+
134
+ def _set_small_annotation_adapter(self, annotation: dict = None):
135
+ self._annotation_adapter = MultimodalSmallAnnotationAdapter(
136
+ project=self.project,
137
+ folder=self.folder,
138
+ item=self.item,
139
+ controller=self.controller,
140
+ overwrite=self._overwrite,
141
+ annotation=annotation,
142
+ )
143
+
144
+ def _set_large_annotation_adapter(self, annotation: dict = None):
145
+ self._annotation_adapter = MultimodalLargeAnnotationAdapter(
146
+ project=self.project,
147
+ folder=self.folder,
148
+ item=self.item,
149
+ controller=self.controller,
150
+ annotation=annotation,
151
+ )
152
+
153
+ @property
154
+ def annotation_adapter(self) -> BaseMultimodalAnnotationAdapter:
155
+ if self._annotation_adapter is None:
156
+ res = self.controller.service_provider.annotations.get_upload_chunks(
157
+ project=self.project, item_ids=[self.item.id]
158
+ )
159
+ small_item = next(iter(res["small"]), None)
160
+ if small_item:
161
+ self._set_small_annotation_adapter()
162
+ else:
163
+ self._set_large_annotation_adapter()
164
+ return self._annotation_adapter
165
+
166
+ @property
167
+ def annotation(self):
168
+ return self.annotation_adapter.annotation
169
+
170
+ def __enter__(self):
171
+ return self
172
+
173
+ def __exit__(self, exc_type, exc_val, exc_tb):
174
+ if exc_type:
175
+ return False
176
+
177
+ self.save()
178
+ return True
179
+
180
+ def save(self):
181
+ if len(json.dumps(self.annotation).encode("utf-8")) > 16 * 1024 * 1024:
182
+ self._set_large_annotation_adapter(self.annotation)
183
+ else:
184
+ self._set_small_annotation_adapter(self.annotation)
185
+ self._annotation_adapter.save()
186
+
187
+ def get_metadata(self):
188
+ return self.annotation["metadata"]
189
+
190
+ def get_component_value(self, component_id: str):
191
+ return self.annotation_adapter.get_component_value(component_id)
192
+
193
+ def set_component_value(self, component_id: str, value: Any):
194
+ self.annotation_adapter.set_component_value(component_id, value)
195
+ return self
196
+
197
+
113
198
  class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
114
199
  """Create SAClient instance to authorize SDK in a team scope.
115
200
  In case of no argument has been provided, SA_TOKEN environmental variable
@@ -193,6 +278,55 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
193
278
  response = self.controller.get_team()
194
279
  return TeamSerializer(response.data).serialize()
195
280
 
281
+ def get_component_config(self, project: Union[NotEmptyStr, int], component_id: str):
282
+ """
283
+ Retrieves the configuration for a given project and component ID.
284
+
285
+ :param project: The identifier of the project, which can be a string or an integer representing the project ID.
286
+ :type project: Union[str, int]
287
+
288
+ :param component_id: The ID of the component for which the context is to be retrieved.
289
+ :type component_id: str
290
+
291
+ :return: The context associated with the `webComponent`.
292
+ :rtype: Any
293
+
294
+ :raises AppException: If the project type is not `MULTIMODAL` or no `webComponent` context is found.
295
+ """
296
+
297
+ def retrieve_context(
298
+ component_data: List[dict], component_pk: str
299
+ ) -> Tuple[bool, typing.Any]:
300
+ for component in component_data:
301
+ if (
302
+ component["type"] == "webComponent"
303
+ and component["id"] == component_pk
304
+ ):
305
+ return True, component.get("context")
306
+ if component["type"] == "group" and "children" in component:
307
+ found, val = retrieve_context(component["children"], component_pk)
308
+ if found:
309
+ return found, val
310
+ return False, None
311
+
312
+ project = (
313
+ self.controller.get_project_by_id(project).data
314
+ if isinstance(project, int)
315
+ else self.controller.get_project(project)
316
+ )
317
+ if project.type != ProjectType.MULTIMODAL:
318
+ raise AppException(
319
+ "This function is only supported for Multimodal projects."
320
+ )
321
+
322
+ editor_template = self.controller.projects.get_editor_template(project)
323
+ components = editor_template.get("components", [])
324
+
325
+ _found, _context = retrieve_context(components, component_id)
326
+ if not _found:
327
+ raise AppException("No component context found for project.")
328
+ return _context
329
+
196
330
  def search_team_contributors(
197
331
  self,
198
332
  email: EmailStr = None,
@@ -2616,7 +2750,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
2616
2750
  ]
2617
2751
  """
2618
2752
  project, folder = self.controller.get_project_folder_by_path(project)
2619
- query_kwargs = {}
2753
+ query_kwargs = {"include": ["assignments"]}
2620
2754
  if name_contains:
2621
2755
  query_kwargs["name__contains"] = name_contains
2622
2756
  if annotation_status:
@@ -2634,7 +2768,9 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
2634
2768
  f"{project.name}{f'/{folder.name}' if not folder.is_root else ''}"
2635
2769
  )
2636
2770
  _items = self.controller.items.list_items(
2637
- project, folder, **query_kwargs
2771
+ project,
2772
+ folder,
2773
+ **query_kwargs,
2638
2774
  )
2639
2775
  for i in _items:
2640
2776
  i.path = path
@@ -2780,7 +2916,10 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
2780
2916
  ).data
2781
2917
  else:
2782
2918
  folder = self.controller.get_folder(project, folder)
2783
- include = include or []
2919
+ _include = {"assignments"}
2920
+ if include:
2921
+ _include.update(set(include))
2922
+ include = list(_include)
2784
2923
  include_custom_metadata = "custom_metadata" in include
2785
2924
  if include_custom_metadata:
2786
2925
  include.remove("custom_metadata")
@@ -2792,7 +2931,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
2792
2931
  project=project, item_ids=[i.id for i in res]
2793
2932
  )
2794
2933
  for i in res:
2795
- i["custom_metadata"] = item_custom_fields[i.id]
2934
+ i.custom_metadata = item_custom_fields[i.id]
2796
2935
  exclude = {"meta", "annotator_email", "qa_email"}
2797
2936
  if include:
2798
2937
  if "custom_metadata" not in include:
@@ -3540,3 +3679,115 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
3540
3679
  )
3541
3680
  if response.errors:
3542
3681
  raise AppException(response.errors)
3682
+
3683
+ def item_context(
3684
+ self,
3685
+ path: Union[str, Tuple[NotEmptyStr, NotEmptyStr], Tuple[int, int]],
3686
+ item: Union[NotEmptyStr, int],
3687
+ overwrite: bool = True,
3688
+ ) -> ItemContext:
3689
+ """
3690
+ Creates an “ItemContext” for managing item annotations and metadata.
3691
+
3692
+ This function allows you to manage annotations and metadata for an item located within a
3693
+ specified project and folder. The path to the item can be provided either as a string or a tuple,
3694
+ and you can specify the item using its name or ID.
3695
+ It returns an “ItemContext” that automatically saves any changes to annotations when the context is exited.
3696
+
3697
+ :param path: Specifies the project and folder containing the item. Can be one of:
3698
+ - A string path, e.g., "project_name/folder_name".
3699
+ - A tuple of strings, e.g., ("project_name", "folder_name").
3700
+ - A tuple of integers (IDs), e.g., (project_id, folder_id).
3701
+ :type path: Union[str, Tuple[str, str], Tuple[int, int]]
3702
+
3703
+ :param item: The name or ID of the item for which the context is being created.
3704
+ :type item: Union[str, int]
3705
+
3706
+ :param overwrite: If `True`, annotations are overwritten during saving. Defaults is `True`.
3707
+ If `False`, raises a `FileChangedError` if the item was modified concurrently.
3708
+ :type overwrite: bool
3709
+
3710
+ :raises AppException: If the provided `path` is invalid or if the item cannot be located.
3711
+
3712
+ :return: An `ItemContext` object to manage the specified item's annotations and metadata.
3713
+ :rtype: ItemContext
3714
+
3715
+ **Examples:**
3716
+
3717
+ Create an `ItemContext` using a string path and item name:
3718
+
3719
+ .. code-block:: python
3720
+
3721
+ with client.item_context("project_name/folder_name", "item_name") as item_context:
3722
+ metadata = item_context.get_metadata()
3723
+ value = item_context.get_component_value("prompts")
3724
+ item_context.set_component_value("prompts", value)
3725
+
3726
+ Create an `ItemContext` using a tuple of strings and an item ID:
3727
+
3728
+ .. code-block:: python
3729
+
3730
+ with client.item_context(("project_name", "folder_name"), 12345) as context:
3731
+ metadata = context.get_metadata()
3732
+ print(metadata)
3733
+
3734
+ Create an `ItemContext` using a tuple of IDs and an item name:
3735
+
3736
+ .. code-block:: python
3737
+
3738
+ with client.item_context((101, 202), "item_name") as context:
3739
+ value = context.get_component_value("component_id")
3740
+ print(value)
3741
+
3742
+ Save annotations automatically after modifying component values:
3743
+
3744
+ .. code-block:: python
3745
+
3746
+ with client.item_context("project_name/folder_name", "item_name", overwrite=True) as context:
3747
+ context.set_component_value("component_id", "new_value")
3748
+ # No need to call .save(), changes are saved automatically on context exit.
3749
+
3750
+ Handle exceptions during context execution:
3751
+
3752
+ .. code-block:: python
3753
+
3754
+ from superannotate import FileChangedError
3755
+
3756
+ try:
3757
+ with client.item_context((101, 202), "item_name") as context:
3758
+ context.set_component_value("component_id", "new_value")
3759
+ except FileChangedError as e:
3760
+ print(f"An error occurred: {e}")
3761
+ """
3762
+ if isinstance(path, str):
3763
+ project, folder = self.controller.get_project_folder_by_path(path)
3764
+ elif len(path) == 2 and all([isinstance(i, str) for i in path]):
3765
+ project = self.controller.get_project(path[0])
3766
+ folder = self.controller.get_folder(project, path[1])
3767
+ elif len(path) == 2 and all([isinstance(i, int) for i in path]):
3768
+ project = self.controller.get_project_by_id(path[0]).data
3769
+ folder = self.controller.get_folder_by_id(path[1], project.id).data
3770
+ else:
3771
+ raise AppException("Invalid path provided.")
3772
+ if project.type != ProjectType.MULTIMODAL:
3773
+ raise AppException(
3774
+ "This function is only supported for Multimodal projects."
3775
+ )
3776
+ if isinstance(item, int):
3777
+ _item = self.controller.get_item_by_id(item_id=item, project=project)
3778
+ else:
3779
+ items = self.controller.items.list_items(project, folder, name=item)
3780
+ if not items:
3781
+ raise AppException("Item not found.")
3782
+ _item = items[0]
3783
+ if project.type != ProjectType.MULTIMODAL:
3784
+ raise AppException(
3785
+ f"The function is not supported for {project.type.name} projects."
3786
+ )
3787
+ return ItemContext(
3788
+ controller=self.controller,
3789
+ project=project,
3790
+ folder=folder,
3791
+ item=_item,
3792
+ overwrite=overwrite,
3793
+ )
@@ -178,6 +178,7 @@ PROJECT_SETTINGS_VALID_ATTRIBUTES = [
178
178
  "UploadFileType",
179
179
  "Tokenization",
180
180
  "ImageAutoAssignEnable",
181
+ "TemplateState",
181
182
  ]
182
183
 
183
184
  __alL__ = (
@@ -174,6 +174,8 @@ class IntegrationTypeEnum(BaseTitledEnum):
174
174
  GCP = "gcp", 2
175
175
  AZURE = "azure", 3
176
176
  CUSTOM = "custom", 4
177
+ DATABRICKS = "databricks", 5
178
+ SNOWFLAKE = "snowflake", 6
177
179
 
178
180
 
179
181
  class TrainingStatus(BaseTitledEnum):
@@ -35,3 +35,9 @@ class PathError(AppException):
35
35
  """
36
36
  User input Error
37
37
  """
38
+
39
+
40
+ class FileChangedError(AppException):
41
+ """
42
+ User input Error
43
+ """
@@ -114,6 +114,10 @@ class ServiceResponse(BaseModel):
114
114
  return 199 < self.status < 300
115
115
  return False
116
116
 
117
+ def raise_for_status(self):
118
+ if not self.ok:
119
+ raise AppException(self.error)
120
+
117
121
  @property
118
122
  def error(self):
119
123
  if self.res_error:
@@ -97,6 +97,18 @@ class BaseProjectService(SuperannotateServiceProvider):
97
97
  def create(self, entity: entities.ProjectEntity) -> ProjectResponse:
98
98
  raise NotImplementedError
99
99
 
100
+ @abstractmethod
101
+ def attach_editor_template(
102
+ self, team: entities.TeamEntity, project: entities.ProjectEntity, template: dict
103
+ ) -> ServiceResponse:
104
+ raise NotImplementedError
105
+
106
+ @abstractmethod
107
+ def get_editor_template(
108
+ self, team: entities.TeamEntity, project: entities.ProjectEntity
109
+ ) -> ServiceResponse:
110
+ raise NotImplementedError
111
+
100
112
  @abstractmethod
101
113
  def list(self, condition: Condition = None) -> ProjectListResponse:
102
114
  raise NotImplementedError
@@ -346,6 +358,7 @@ class BaseAnnotationService(SuperannotateServiceProvider):
346
358
  project: entities.ProjectEntity,
347
359
  item: entities.BaseItemEntity,
348
360
  reporter: Reporter,
361
+ transform_version: str = None,
349
362
  ) -> dict:
350
363
  raise NotImplementedError
351
364
 
@@ -357,6 +370,7 @@ class BaseAnnotationService(SuperannotateServiceProvider):
357
370
  item_ids: List[int],
358
371
  reporter: Reporter,
359
372
  callback: Callable = None,
373
+ transform_version: str = None,
360
374
  ) -> List[dict]:
361
375
  raise NotImplementedError
362
376
 
@@ -396,6 +410,7 @@ class BaseAnnotationService(SuperannotateServiceProvider):
396
410
  project: entities.ProjectEntity,
397
411
  folder: entities.FolderEntity,
398
412
  items_name_data_map: Dict[str, dict],
413
+ transform_version: str = None,
399
414
  ) -> UploadAnnotationsResponse:
400
415
  raise NotImplementedError
401
416
 
@@ -407,6 +422,7 @@ class BaseAnnotationService(SuperannotateServiceProvider):
407
422
  item_id: int,
408
423
  data: io.StringIO,
409
424
  chunk_size: int,
425
+ transform_version: str = None,
410
426
  ) -> bool:
411
427
  raise NotImplementedError
412
428
 
@@ -429,6 +445,29 @@ class BaseAnnotationService(SuperannotateServiceProvider):
429
445
  def get_schema(self, project_type: int, version: str) -> ServiceResponse:
430
446
  raise NotImplementedError
431
447
 
448
+ @abstractmethod
449
+ def get_item_annotations(
450
+ self,
451
+ project: entities.ProjectEntity,
452
+ folder: entities.FolderEntity,
453
+ item_id: int,
454
+ transform_version: str = "llmJsonV2",
455
+ ) -> ServiceResponse:
456
+ raise NotImplementedError
457
+
458
+ @abstractmethod
459
+ def set_item_annotations(
460
+ self,
461
+ project: entities.ProjectEntity,
462
+ folder: entities.FolderEntity,
463
+ item_id: int,
464
+ data: dict,
465
+ overwrite: bool,
466
+ transform_version: str = "llmJsonV2",
467
+ etag: str = None,
468
+ ) -> ServiceResponse:
469
+ raise NotImplementedError
470
+
432
471
 
433
472
  class BaseIntegrationService(SuperannotateServiceProvider):
434
473
  @abstractmethod
@@ -9,12 +9,10 @@ import platform
9
9
  import re
10
10
  import time
11
11
  import traceback
12
- import typing
13
12
  from dataclasses import dataclass
14
13
  from itertools import islice
15
14
  from operator import itemgetter
16
15
  from pathlib import Path
17
- from threading import Thread
18
16
  from typing import Any
19
17
  from typing import Callable
20
18
  from typing import Dict
@@ -48,6 +46,7 @@ from lib.core.serviceproviders import ServiceResponse
48
46
  from lib.core.serviceproviders import UploadAnnotationsResponse
49
47
  from lib.core.types import PriorityScoreEntity
50
48
  from lib.core.usecases.base import BaseReportableUseCase
49
+ from lib.core.utils import run_async
51
50
  from lib.core.video_convertor import VideoFrameGenerator
52
51
  from lib.infrastructure.utils import divide_to_chunks
53
52
 
@@ -66,51 +65,6 @@ ANNOTATION_CHUNK_SIZE_MB = 10 * 1024 * 1024
66
65
  URI_THRESHOLD = 4 * 1024 - 120
67
66
 
68
67
 
69
- class AsyncThread(Thread):
70
- def __init__(
71
- self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None
72
- ):
73
- super().__init__(
74
- group=group,
75
- target=target,
76
- name=name,
77
- args=args,
78
- kwargs=kwargs,
79
- daemon=daemon,
80
- )
81
- self._exc = None
82
- self._response = None
83
-
84
- @property
85
- def response(self):
86
- return self._response
87
-
88
- def run(self):
89
- try:
90
- self._response = super().run()
91
- except BaseException as e:
92
- self._exc = e
93
-
94
- def join(self, timeout=None) -> typing.Any:
95
- Thread.join(self, timeout=timeout)
96
- if self._exc:
97
- raise self._exc
98
- return self._response
99
-
100
-
101
- def run_async(f):
102
- response = [None]
103
-
104
- def wrapper(func: typing.Callable):
105
- response[0] = asyncio.run(func) # noqa
106
- return response[0]
107
-
108
- thread = AsyncThread(target=wrapper, args=(f,))
109
- thread.start()
110
- thread.join()
111
- return response[0]
112
-
113
-
114
68
  @dataclass
115
69
  class Report:
116
70
  failed_annotations: list
@@ -188,6 +142,7 @@ async def upload_small_annotations(
188
142
  reporter: Reporter,
189
143
  report: Report,
190
144
  callback: Callable = None,
145
+ transform_version: str = None,
191
146
  ):
192
147
  async def upload(_chunk: List[ItemToUpload]):
193
148
  failed_annotations, missing_classes, missing_attr_groups, missing_attrs = (
@@ -204,6 +159,7 @@ async def upload_small_annotations(
204
159
  project=project,
205
160
  folder=folder,
206
161
  items_name_data_map=items_name_data_map,
162
+ transform_version=transform_version,
207
163
  )
208
164
  if response.ok:
209
165
  if response.data.failed_items: # noqa
@@ -304,6 +260,7 @@ class UploadAnnotationsUseCase(BaseReportableUseCase):
304
260
  service_provider: BaseServiceProvider,
305
261
  user: UserEntity,
306
262
  keep_status: bool = False,
263
+ transform_version: str = None,
307
264
  ):
308
265
  super().__init__(reporter)
309
266
  self._project = project
@@ -313,6 +270,7 @@ class UploadAnnotationsUseCase(BaseReportableUseCase):
313
270
  self._keep_status = keep_status
314
271
  self._report = Report([], [], [], [])
315
272
  self._user = user
273
+ self._transform_version = transform_version
316
274
 
317
275
  def validate_project_type(self):
318
276
  if self._project.type == constants.ProjectType.PIXEL.value:
@@ -420,6 +378,7 @@ class UploadAnnotationsUseCase(BaseReportableUseCase):
420
378
  service_provider=self._service_provider,
421
379
  reporter=self.reporter,
422
380
  report=self._report,
381
+ transform_version=self._transform_version,
423
382
  )
424
383
  )
425
384
 
@@ -1474,6 +1433,7 @@ class GetAnnotations(BaseReportableUseCase):
1474
1433
  service_provider: BaseServiceProvider,
1475
1434
  folder: FolderEntity = None,
1476
1435
  items: Optional[Union[List[str], List[int]]] = None,
1436
+ transform_version: str = None,
1477
1437
  ):
1478
1438
  super().__init__(reporter)
1479
1439
  self._config = config
@@ -1484,6 +1444,7 @@ class GetAnnotations(BaseReportableUseCase):
1484
1444
  self._item_id_name_map = {}
1485
1445
  self._item_names_provided = True
1486
1446
  self._big_annotations_queue = None
1447
+ self._transform_version = transform_version
1487
1448
 
1488
1449
  def validate_project_type(self):
1489
1450
  if self._project.type == constants.ProjectType.PIXEL.value:
@@ -1548,6 +1509,7 @@ class GetAnnotations(BaseReportableUseCase):
1548
1509
  folder=self._folder,
1549
1510
  item_ids=item_ids,
1550
1511
  reporter=self.reporter,
1512
+ transform_version=self._transform_version,
1551
1513
  )
1552
1514
 
1553
1515
  async def run_workers(
@@ -0,0 +1,48 @@
1
+ import asyncio
2
+ import typing
3
+ from threading import Thread
4
+
5
+
6
+ class AsyncThread(Thread):
7
+ def __init__(
8
+ self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None
9
+ ):
10
+ super().__init__(
11
+ group=group,
12
+ target=target,
13
+ name=name,
14
+ args=args,
15
+ kwargs=kwargs,
16
+ daemon=daemon,
17
+ )
18
+ self._exc = None
19
+ self._response = None
20
+
21
+ @property
22
+ def response(self):
23
+ return self._response
24
+
25
+ def run(self):
26
+ try:
27
+ self._response = super().run()
28
+ except BaseException as e:
29
+ self._exc = e
30
+
31
+ def join(self, timeout=None) -> typing.Any:
32
+ Thread.join(self, timeout=timeout)
33
+ if self._exc:
34
+ raise self._exc
35
+ return self._response
36
+
37
+
38
+ def run_async(f):
39
+ response = [None]
40
+
41
+ def wrapper(func: typing.Callable):
42
+ response[0] = asyncio.run(func) # noqa
43
+ return response[0]
44
+
45
+ thread = AsyncThread(target=wrapper, args=(f,))
46
+ thread.start()
47
+ thread.join()
48
+ return response[0]