superannotate 4.4.31.dev1__tar.gz → 4.4.32__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 (147) hide show
  1. {superannotate-4.4.31.dev1/src/superannotate.egg-info → superannotate-4.4.32}/PKG-INFO +1 -1
  2. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/__init__.py +1 -1
  3. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/sdk_interface.py +80 -12
  4. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/serviceproviders.py +10 -0
  5. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/annotations.py +1 -1
  6. superannotate-4.4.32/src/superannotate/lib/core/usecases/integrations.py +179 -0
  7. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/items.py +46 -0
  8. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/annotation_adapter.py +1 -1
  9. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/controller.py +23 -1
  10. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/annotation.py +32 -14
  11. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/explore.py +23 -0
  12. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/integration.py +5 -0
  13. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/stream_data_handler.py +77 -41
  14. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/utils.py +72 -2
  15. {superannotate-4.4.31.dev1 → superannotate-4.4.32/src/superannotate.egg-info}/PKG-INFO +1 -1
  16. superannotate-4.4.31.dev1/src/superannotate/lib/core/usecases/integrations.py +0 -78
  17. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/LICENSE +0 -0
  18. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/MANIFEST.in +0 -0
  19. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/README.rst +0 -0
  20. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/requirements.txt +0 -0
  21. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/setup.cfg +0 -0
  22. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/setup.py +0 -0
  23. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/__init__.py +0 -0
  24. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/__init__.py +0 -0
  25. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/analytics/__init__.py +0 -0
  26. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/analytics/aggregators.py +0 -0
  27. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/analytics/common.py +0 -0
  28. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/bin/__init__.py +0 -0
  29. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/bin/superannotate.py +0 -0
  30. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/common.py +0 -0
  31. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/exceptions.py +0 -0
  32. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/helpers.py +0 -0
  33. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/__init__.py +0 -0
  34. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/conversion.py +0 -0
  35. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/__init__.py +0 -0
  36. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/baseStrategy.py +0 -0
  37. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/__init__.py +0 -0
  38. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_api.py +0 -0
  39. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_converter.py +0 -0
  40. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_strategies.py +0 -0
  41. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_to_sa_pixel.py +0 -0
  42. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_to_sa_vector.py +0 -0
  43. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_pixel_to_coco.py +0 -0
  44. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py +0 -0
  45. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/converters.py +0 -0
  46. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/__init__.py +0 -0
  47. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_helper.py +0 -0
  48. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_strategies.py +0 -0
  49. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_to_sa_vector.py +0 -0
  50. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/__init__.py +0 -0
  51. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_strategies.py +0 -0
  52. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_to_sa_vector.py +0 -0
  53. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/__init__.py +0 -0
  54. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_helper.py +0 -0
  55. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_strategies.py +0 -0
  56. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_to_sa_pixel.py +0 -0
  57. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_to_sa_vector.py +0 -0
  58. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/sa_json_helper.py +0 -0
  59. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/__init__.py +0 -0
  60. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_strategies.py +0 -0
  61. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_to_sa_pixel.py +0 -0
  62. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_to_sa_vector.py +0 -0
  63. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/__init__.py +0 -0
  64. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_helper.py +0 -0
  65. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_strategies.py +0 -0
  66. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_to_sa_pixel.py +0 -0
  67. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_to_sa_vector.py +0 -0
  68. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/vgg_converters/__init__.py +0 -0
  69. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_helper.py +0 -0
  70. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_strategies.py +0 -0
  71. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_to_sa_vector.py +0 -0
  72. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/voc_converters/__init__.py +0 -0
  73. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_helper.py +0 -0
  74. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_strategies.py +0 -0
  75. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_pixel.py +0 -0
  76. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_vector.py +0 -0
  77. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/vott_converters/__init__.py +0 -0
  78. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_strategies.py +0 -0
  79. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_to_sa_vector.py +0 -0
  80. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/yolo_converters/__init__.py +0 -0
  81. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_strategies.py +0 -0
  82. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_to_sa_vector.py +0 -0
  83. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/export_from_sa_conversions.py +0 -0
  84. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/import_to_sa_conversions.py +0 -0
  85. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/input_converters/sa_conversion.py +0 -0
  86. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/__init__.py +0 -0
  87. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/base_interface.py +0 -0
  88. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/cli_interface.py +0 -0
  89. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/sdk/__init__.py +0 -0
  90. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/sdk/folders.py +0 -0
  91. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/sdk/project.py +0 -0
  92. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/interface/types.py +0 -0
  93. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/app/serializers.py +0 -0
  94. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/__init__.py +0 -0
  95. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/base_usecases.py +0 -0
  96. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/conditions.py +0 -0
  97. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/config.py +0 -0
  98. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/__init__.py +0 -0
  99. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/base.py +0 -0
  100. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/classes.py +0 -0
  101. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/filters.py +0 -0
  102. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/folder.py +0 -0
  103. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/integrations.py +0 -0
  104. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/items.py +0 -0
  105. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/project.py +0 -0
  106. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/project_entities.py +0 -0
  107. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/entities/work_managament.py +0 -0
  108. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/enums.py +0 -0
  109. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/exceptions.py +0 -0
  110. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/jsx_conditions.py +0 -0
  111. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/plugin.py +0 -0
  112. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/pydantic_v1.py +0 -0
  113. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/reporter.py +0 -0
  114. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/repositories.py +0 -0
  115. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/response.py +0 -0
  116. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/service_types.py +0 -0
  117. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/types.py +0 -0
  118. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/__init__.py +0 -0
  119. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/base.py +0 -0
  120. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/classes.py +0 -0
  121. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/custom_fields.py +0 -0
  122. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/folders.py +0 -0
  123. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/images.py +0 -0
  124. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/models.py +0 -0
  125. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/usecases/projects.py +0 -0
  126. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/utils.py +0 -0
  127. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/core/video_convertor.py +0 -0
  128. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/__init__.py +0 -0
  129. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/custom_entities.py +0 -0
  130. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/helpers.py +0 -0
  131. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/query_builder.py +0 -0
  132. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/repositories.py +0 -0
  133. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/serviceprovider.py +0 -0
  134. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/__init__.py +0 -0
  135. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/annotation_class.py +0 -0
  136. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/folder.py +0 -0
  137. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/http_client.py +0 -0
  138. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/item.py +0 -0
  139. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/item_service.py +0 -0
  140. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/project.py +0 -0
  141. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/services/work_management.py +0 -0
  142. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate/lib/infrastructure/validators.py +0 -0
  143. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate.egg-info/SOURCES.txt +0 -0
  144. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate.egg-info/dependency_links.txt +0 -0
  145. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate.egg-info/entry_points.txt +0 -0
  146. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/src/superannotate.egg-info/requires.txt +0 -0
  147. {superannotate-4.4.31.dev1 → superannotate-4.4.32}/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.31.dev1
3
+ Version: 4.4.32
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.31dev1"
6
+ __version__ = "4.4.32"
7
7
 
8
8
  os.environ.update({"sa_version": __version__})
9
9
  sys.path.append(os.path.split(os.path.realpath(__file__))[0])
@@ -461,6 +461,16 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
461
461
  def pause_user_activity(
462
462
  self, pk: Union[int, str], projects: Union[List[int], List[str], Literal["*"]]
463
463
  ):
464
+ """
465
+ Block the team contributor from requesting items from the projects.
466
+
467
+ :param pk: The email address or user ID of the team contributor.
468
+ :type pk: str or int
469
+
470
+ :param projects: A list of project names or IDs from which the user should be blocked.
471
+ The special value "*" means block access to all projects
472
+ :type projects: Union[List[int], List[str], Literal["*"]]
473
+ """
464
474
  user = self.controller.work_management.get_user_metadata(pk=pk)
465
475
  if user.role is not WMUserTypeEnum.Contributor:
466
476
  raise AppException("User must have a contributor role to pause activity.")
@@ -474,6 +484,16 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
474
484
  def resume_user_activity(
475
485
  self, pk: Union[int, str], projects: Union[List[int], List[str], Literal["*"]]
476
486
  ):
487
+ """
488
+ Resume the team contributor from requesting items from the projects.
489
+
490
+ :param pk: The email address or user ID of the team contributor.
491
+ :type pk: str or int
492
+
493
+ :param projects: A list of project names or IDs from which the user should be resumed.
494
+ The special value "*" means resume access to all projects
495
+ :type projects: Union[List[int], List[str], Literal["*"]]
496
+ """
477
497
  user = self.controller.work_management.get_user_metadata(pk=pk)
478
498
  if user.role is not WMUserTypeEnum.Contributor:
479
499
  raise AppException("User must have a contributor role to resume activity.")
@@ -501,7 +521,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
501
521
  """
502
522
 
503
523
  def retrieve_context(
504
- component_data: List[dict], component_pk: str
524
+ component_data: List[dict], component_pk: str
505
525
  ) -> Tuple[bool, typing.Any]:
506
526
  try:
507
527
  for component in component_data:
@@ -512,9 +532,9 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
512
532
  if found:
513
533
  return found, val
514
534
  if (
515
- "id" in component and
516
- component["id"] == component_pk
517
- and component["type"] == "webComponent"
535
+ "id" in component
536
+ and component["id"] == component_pk
537
+ and component["type"] == "webComponent"
518
538
  ):
519
539
  return True, json.loads(component.get("context"))
520
540
 
@@ -2919,32 +2939,80 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
2919
2939
  project: NotEmptyStr,
2920
2940
  integration: Union[NotEmptyStr, IntegrationEntity],
2921
2941
  folder_path: Optional[NotEmptyStr] = None,
2942
+ *,
2943
+ query: Optional[NotEmptyStr] = None,
2944
+ item_name_column: Optional[NotEmptyStr] = None,
2945
+ custom_item_name: Optional[NotEmptyStr] = None,
2946
+ component_mapping: Optional[Dict[str, str]] = None,
2922
2947
  ):
2923
- """Link images from integrated external storage to SuperAnnotate.
2948
+ """Link images from integrated external storage to SuperAnnotate from AWS, GCP, Azure, Databricks.
2924
2949
 
2925
2950
  :param project: project name or folder path where items should be attached (e.g., “project1/folder1”).
2926
2951
  :type project: str
2927
2952
 
2928
- :param integration: existing integration name or metadata dict to pull items from.
2929
- Mandatory keys in integration metadata’s dict is “name”.
2953
+ :param integration: The existing integration name or metadata dict to pull items from.
2954
+ Mandatory keys in integration metadata’s dict is “name”.
2930
2955
  :type integration: str or dict
2931
2956
 
2932
2957
  :param folder_path: Points to an exact folder/directory within given storage.
2933
- If None, items are fetched from the root directory.
2958
+ If None, items are fetched from the root directory.
2934
2959
  :type folder_path: str
2960
+
2961
+ :param query: (Only for Databricks). The SQL query to retrieve specific columns from Databricks.
2962
+ If provided, the function will execute the query and use the results for mapping and uploading.
2963
+ :type query: Optional[str]
2964
+
2965
+ :param item_name_column: (Only for Databricks). The column name from the SQL query whose values
2966
+ will be used as item names. If this is provided, custom_item_name cannot be used.
2967
+ The column must exist in the query result.
2968
+ :type item_name_column: Optional[str]
2969
+
2970
+ :param custom_item_name: (Only for Databricks). A manually defined prefix for item names.
2971
+ A random 10-character suffix will be appended to ensure uniqueness.
2972
+ If this is provided, item_name_column cannot be used.
2973
+ :type custom_item_name: Optional[str]
2974
+
2975
+ :param component_mapping: (Only for Databricks). A dictionary mapping Databricks
2976
+ columns to SuperAnnotate component IDs.
2977
+ :type component_mapping: Optional[dict]
2978
+
2979
+
2980
+ Request Example:
2981
+ ::
2982
+
2983
+ client.attach_items_from_integrated_storage(
2984
+ project="project_name",
2985
+ integration="databricks_integration",
2986
+ query="SELECT * FROM integration_data LIMIT 10",
2987
+ item_name_column="prompt",
2988
+ component_mapping={
2989
+ "category": "_item_category",
2990
+ "prompt_id": "id",
2991
+ "prompt": "prompt"
2992
+ }
2993
+ )
2994
+
2935
2995
  """
2936
2996
  project, folder = self.controller.get_project_folder_by_path(project)
2937
2997
  _integration = None
2938
2998
  if isinstance(integration, str):
2939
2999
  integration = IntegrationEntity(name=integration)
2940
3000
  for i in self.controller.integrations.list().data:
2941
- if integration.name == i.name:
3001
+ if integration.name.lower() == i.name.lower():
2942
3002
  _integration = i
2943
3003
  break
2944
3004
  else:
2945
3005
  raise AppException("Integration not found.")
3006
+
2946
3007
  response = self.controller.integrations.attach_items(
2947
- project, folder, _integration, folder_path
3008
+ project=project,
3009
+ folder=folder,
3010
+ integration=_integration,
3011
+ folder_path=folder_path,
3012
+ query=query,
3013
+ item_name_column=item_name_column,
3014
+ custom_item_name=custom_item_name,
3015
+ component_mapping=component_mapping,
2948
3016
  )
2949
3017
  if response.errors:
2950
3018
  raise AppException(response.errors)
@@ -3593,7 +3661,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
3593
3661
  "skip", "replace", "replace_annotations_only"
3594
3662
  ] = "skip",
3595
3663
  ):
3596
- """Copy images in bulk between folders in a project
3664
+ """Copy items in bulk between folders in a project
3597
3665
 
3598
3666
  :param source: project name (root) or folder path to pick items from (e.g., “project1/folder1”).
3599
3667
  :type source: str
@@ -3657,7 +3725,7 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
3657
3725
  "skip", "replace", "replace_annotations_only"
3658
3726
  ] = "skip",
3659
3727
  ):
3660
- """Move images in bulk between folders in a project
3728
+ """Move items in bulk between folders in a project
3661
3729
 
3662
3730
  :param source: project name (root) or folder path to pick items from (e.g., “project1/folder1”).
3663
3731
  :type source: str
@@ -490,6 +490,7 @@ class BaseAnnotationService(SuperannotateServiceProvider):
490
490
  self,
491
491
  project: entities.ProjectEntity,
492
492
  item_ids: List[int],
493
+ chunk_size: int = 1000,
493
494
  ) -> Dict[str, List]:
494
495
  raise NotImplementedError
495
496
 
@@ -592,6 +593,7 @@ class BaseIntegrationService(SuperannotateServiceProvider):
592
593
  folder: entities.FolderEntity,
593
594
  integration: entities.IntegrationEntity,
594
595
  folder_name: str = None,
596
+ options: Dict[str, str] = None,
595
597
  ) -> ServiceResponse:
596
598
  raise NotImplementedError
597
599
 
@@ -670,6 +672,14 @@ class BaseExploreService(SuperannotateServiceProvider):
670
672
  ) -> ServiceResponse:
671
673
  raise NotImplementedError
672
674
 
675
+ @abstractmethod
676
+ def query_item_count(
677
+ self,
678
+ project: entities.ProjectEntity,
679
+ query: str = None,
680
+ ) -> ServiceResponse:
681
+ raise NotImplementedError
682
+
673
683
 
674
684
  class BaseServiceProvider:
675
685
  projects: BaseProjectService
@@ -2046,7 +2046,7 @@ class UploadMultiModalAnnotationsUseCase(BaseReportableUseCase):
2046
2046
  f"annotations to the project {self._project.name}."
2047
2047
  )
2048
2048
  if not self._root_folder.is_root:
2049
- if len(distributed_items) > 1 or None not in distributed_items:
2049
+ if len(distributed_items) > 1 or "" not in distributed_items:
2050
2050
  raise AppException(
2051
2051
  "You can't include a folder when uploading from within a folder."
2052
2052
  )
@@ -0,0 +1,179 @@
1
+ from typing import Dict
2
+ from typing import Optional
3
+
4
+ from lib.core.conditions import Condition
5
+ from lib.core.conditions import CONDITION_EQ as EQ
6
+ from lib.core.entities import FolderEntity
7
+ from lib.core.entities import IntegrationEntity
8
+ from lib.core.entities import ProjectEntity
9
+ from lib.core.entities.integrations import IntegrationTypeEnum
10
+ from lib.core.enums import ProjectType
11
+ from lib.core.exceptions import AppException
12
+ from lib.core.reporter import Reporter
13
+ from lib.core.response import Response
14
+ from lib.core.serviceproviders import BaseServiceProvider
15
+ from lib.core.usecases import BaseReportableUseCase
16
+
17
+
18
+ class GetIntegrations(BaseReportableUseCase):
19
+ def __init__(self, reporter: Reporter, service_provider: BaseServiceProvider):
20
+
21
+ super().__init__(reporter)
22
+ self._service_provider = service_provider
23
+
24
+ def execute(self) -> Response:
25
+ integrations = self._service_provider.integrations.list().data.integrations
26
+ integrations = list(sorted(integrations, key=lambda x: x.createdAt))
27
+ integrations.reverse()
28
+ self._response.data = integrations
29
+ return self._response
30
+
31
+
32
+ class AttachIntegrations(BaseReportableUseCase):
33
+ MULTIMODAL_INTEGRATIONS = [
34
+ IntegrationTypeEnum.DATABRICKS,
35
+ IntegrationTypeEnum.SNOWFLAKE,
36
+ ]
37
+
38
+ def __init__(
39
+ self,
40
+ reporter: Reporter,
41
+ project: ProjectEntity,
42
+ folder: FolderEntity,
43
+ service_provider: BaseServiceProvider,
44
+ integration: IntegrationEntity,
45
+ folder_path: str = None,
46
+ query: Optional[str] = None,
47
+ item_name_column: Optional[str] = None,
48
+ custom_item_name: Optional[str] = None,
49
+ component_mapping: Optional[Dict[str, str]] = None,
50
+ ):
51
+ super().__init__(reporter)
52
+ self._project = project
53
+ self._folder = folder
54
+ self._integration = integration
55
+ self._service_provider = service_provider
56
+ self._folder_path = folder_path
57
+ self._query = query
58
+ self._item_name_column = item_name_column
59
+ self._custom_item_name = custom_item_name
60
+ self._component_mapping = component_mapping
61
+ self._options = {} # using only for Databricks and Snowflake
62
+ self._item_category_column = None
63
+
64
+ @property
65
+ def _upload_path(self):
66
+ return f"{self._project.name}{f'/{self._folder.name}' if self._folder.name != 'root' else ''}"
67
+
68
+ def validate_integration(self):
69
+ # TODO add support in next iterations
70
+ if self._integration.type == IntegrationTypeEnum.SNOWFLAKE:
71
+ raise AppException(
72
+ "Attaching items is not supported with Snowflake integration."
73
+ )
74
+
75
+ if self._integration.type in self.MULTIMODAL_INTEGRATIONS:
76
+ if self._project.type != ProjectType.MULTIMODAL:
77
+ raise AppException(
78
+ f"{self._integration.name} integration is supported only for Multimodal projects."
79
+ )
80
+
81
+ def validate_options_for_multimodal_integration(self):
82
+ if self._integration.type in self.MULTIMODAL_INTEGRATIONS:
83
+ if self._item_name_column and self._custom_item_name:
84
+ raise AppException(
85
+ "‘item_name_column and custom_item_name cannot be used simultaneously."
86
+ )
87
+
88
+ if not self._item_name_column and not self._custom_item_name:
89
+ raise AppException(
90
+ "Either item_name_column or custom_item_name is required."
91
+ )
92
+
93
+ if not all((self._query, self._component_mapping)):
94
+ raise AppException(
95
+ f"{self._integration.name} integration requires both a query and component_mapping."
96
+ )
97
+
98
+ category_setting: bool = bool(
99
+ next(
100
+ (
101
+ setting.value
102
+ for setting in self._service_provider.projects.list_settings(
103
+ self._project
104
+ ).data
105
+ if setting.attribute == "CategorizeItems"
106
+ ),
107
+ None,
108
+ )
109
+ )
110
+ if (
111
+ not category_setting
112
+ and "_item_category" in self._component_mapping.values()
113
+ ):
114
+ raise AppException(
115
+ "Item Category must be enabled for a project to use _item_category"
116
+ )
117
+
118
+ self._item_category_column = next(
119
+ (
120
+ k
121
+ for k, v in self._component_mapping.items()
122
+ if v == "_item_category"
123
+ ),
124
+ None,
125
+ )
126
+ if self._item_category_column:
127
+ del self._component_mapping[self._item_category_column]
128
+
129
+ sa_components = [
130
+ c.name.lower()
131
+ for c in self._service_provider.annotation_classes.list(
132
+ condition=Condition("project_id", self._project.id, EQ)
133
+ ).data
134
+ ]
135
+
136
+ for i in self._component_mapping.values():
137
+ if i.lower() not in sa_components:
138
+ raise AppException(
139
+ f"Component mapping contains invalid component ID: `{i}`"
140
+ )
141
+
142
+ def generate_options_for_multimodal_integration(self):
143
+ self._options["query"] = self._query
144
+ self._options["item_name"] = (
145
+ self._custom_item_name if self._custom_item_name else self._item_name_column
146
+ )
147
+ self._options["prefix"] = True if self._custom_item_name else False
148
+ self._options["column_class_map"] = self._component_mapping
149
+ if self._item_category_column:
150
+ self._options["item_category"] = self._item_category_column
151
+
152
+ def execute(self) -> Response:
153
+ if self.is_valid():
154
+ if self._integration.type in self.MULTIMODAL_INTEGRATIONS:
155
+ self.generate_options_for_multimodal_integration()
156
+
157
+ self.reporter.log_info(
158
+ "Attaching file(s) from "
159
+ f"{self._integration.root}{f'/{self._folder_path}' if self._folder_path else ''} "
160
+ f"to {self._upload_path}. This may take some time."
161
+ )
162
+
163
+ attache_response = self._service_provider.integrations.attach_items(
164
+ project=self._project,
165
+ folder=self._folder,
166
+ integration=self._integration,
167
+ folder_name=self._folder_path
168
+ if self._integration.type not in self.MULTIMODAL_INTEGRATIONS
169
+ else None,
170
+ options=self._options if self._options else None,
171
+ )
172
+ if not attache_response.ok:
173
+ self._response.errors = AppException(
174
+ f"An error occurred for {self._integration.name}. Please make sure: "
175
+ "\n - The bucket exists."
176
+ "\n - The connection is valid."
177
+ "\n - The path to a specified directory is correct."
178
+ )
179
+ return self._response
@@ -163,6 +163,52 @@ class QueryEntitiesUseCase(BaseReportableUseCase):
163
163
  return self._response
164
164
 
165
165
 
166
+ class QueryEntitiesCountUseCase(BaseReportableUseCase):
167
+ def __init__(
168
+ self,
169
+ reporter: Reporter,
170
+ project: ProjectEntity,
171
+ service_provider: BaseServiceProvider,
172
+ query: str,
173
+ ):
174
+ super().__init__(reporter)
175
+ self._project = project
176
+ self._service_provider = service_provider
177
+ self._query = query
178
+
179
+ def validate_arguments(self):
180
+ if self._query:
181
+ response = self._service_provider.explore.validate_saqul_query(
182
+ project=self._project, query=self._query
183
+ )
184
+
185
+ if not response.ok:
186
+ raise AppException(response.error)
187
+ if response.data["isValidQuery"]:
188
+ self._query = response.data["parsedQuery"]
189
+ else:
190
+ raise AppException("Incorrect query.")
191
+ else:
192
+ response = self._service_provider.explore.validate_saqul_query(
193
+ self._project, "-"
194
+ )
195
+ if not response.ok:
196
+ raise AppException(response.error)
197
+
198
+ def execute(self) -> Response:
199
+ if self.is_valid():
200
+ query_kwargs = {"query": self._query}
201
+ service_response = self._service_provider.explore.query_item_count(
202
+ self._project,
203
+ **query_kwargs,
204
+ )
205
+ if service_response.ok:
206
+ self._response.data = service_response.data
207
+ else:
208
+ self._response.errors = service_response.data
209
+ return self._response
210
+
211
+
166
212
  class AssignItemsUseCase(BaseUseCase):
167
213
  CHUNK_SIZE = 500
168
214
 
@@ -44,7 +44,7 @@ class BaseMultimodalAnnotationAdapter(ABC):
44
44
  return None
45
45
 
46
46
  def set_component_value(self, component_id: str, value: Any):
47
- self.annotation["data"][component_id] = {"value": value}
47
+ self.annotation.setdefault("data", {}).setdefault(component_id, {})["value"] = value
48
48
  return self
49
49
 
50
50
 
@@ -1138,7 +1138,11 @@ class IntegrationManager(BaseManager):
1138
1138
  project: ProjectEntity,
1139
1139
  folder: FolderEntity,
1140
1140
  integration: IntegrationEntity,
1141
- folder_path: str,
1141
+ folder_path: str = None,
1142
+ query: Optional[str] = None,
1143
+ item_name_column: Optional[str] = None,
1144
+ custom_item_name: Optional[str] = None,
1145
+ component_mapping: Optional[Dict[str, str]] = None,
1142
1146
  ):
1143
1147
  use_case = usecases.AttachIntegrations(
1144
1148
  reporter=Reporter(),
@@ -1147,6 +1151,10 @@ class IntegrationManager(BaseManager):
1147
1151
  folder=folder,
1148
1152
  integration=integration,
1149
1153
  folder_path=folder_path,
1154
+ query=query,
1155
+ item_name_column=item_name_column,
1156
+ custom_item_name=custom_item_name,
1157
+ component_mapping=component_mapping,
1150
1158
  )
1151
1159
  return use_case.execute()
1152
1160
 
@@ -1670,3 +1678,17 @@ class Controller(BaseController):
1670
1678
  return ItemManager.process_response(
1671
1679
  self.service_provider, items, project, folder, map_fields=False
1672
1680
  )
1681
+
1682
+ def query_items_count(self, project_name: str, query: str = None) -> int:
1683
+ project = self.get_project(project_name)
1684
+
1685
+ use_case = usecases.QueryEntitiesCountUseCase(
1686
+ reporter=self.get_default_reporter(),
1687
+ project=project,
1688
+ query=query,
1689
+ service_provider=self.service_provider,
1690
+ )
1691
+ response = use_case.execute()
1692
+ if response.errors:
1693
+ raise AppException(response.errors)
1694
+ return response.data["count"]
@@ -18,6 +18,8 @@ from lib.core.service_types import UploadAnnotations
18
18
  from lib.core.service_types import UploadAnnotationsResponse
19
19
  from lib.core.serviceproviders import BaseAnnotationService
20
20
  from lib.infrastructure.stream_data_handler import StreamedAnnotations
21
+ from lib.infrastructure.utils import annotation_is_valid
22
+ from lib.infrastructure.utils import divide_to_chunks
21
23
 
22
24
  try:
23
25
  from pydantic.v1 import parse_obj_as
@@ -170,21 +172,29 @@ class AnnotationService(BaseAnnotationService):
170
172
  self,
171
173
  project: entities.ProjectEntity,
172
174
  item_ids: List[int],
175
+ chunk_size: int = 1000,
173
176
  ) -> Dict[str, List]:
174
- response_data = {"small": [], "large": []}
175
- response = self.client.request(
176
- url=urljoin(self.get_assets_provider_url(), self.URL_CLASSIFY_ITEM_SIZE),
177
- method="POST",
178
- params={"limit": len(item_ids)},
179
- data={"project_id": project.id, "item_ids": item_ids},
180
- )
181
- if not response.ok:
182
- raise AppException(response.error)
183
- response_data["small"] = [
184
- i["data"] for i in response.data.get("small", {}).values()
185
- ]
186
- response_data["large"] = response.data.get("large", [])
187
- return response_data
177
+ small = []
178
+ large = []
179
+
180
+ chunks = divide_to_chunks(item_ids, chunk_size)
181
+ for chunk in chunks:
182
+ response = self.client.request(
183
+ method="POST",
184
+ url=urljoin(
185
+ self.get_assets_provider_url(), self.URL_CLASSIFY_ITEM_SIZE
186
+ ),
187
+ params={"limit": len(chunk)},
188
+ data={
189
+ "project_id": project.id,
190
+ "item_ids": chunk,
191
+ },
192
+ )
193
+ if not response.ok:
194
+ raise AppException(response.error)
195
+ small.extend([i["data"] for i in response.data.get("small", {}).values()])
196
+ large.extend(response.data.get("large", []))
197
+ return {"small": small, "large": large}
188
198
 
189
199
  async def download_big_annotation(
190
200
  self,
@@ -218,6 +228,14 @@ class AnnotationService(BaseAnnotationService):
218
228
  ) as session:
219
229
  start_response = await session.request("post", url, params=query_params)
220
230
  res = await start_response.json()
231
+ if start_response.status > 299 or not annotation_is_valid(res):
232
+ logger.debug(
233
+ f"Failed to download large annotation; item_id [{item_id}];"
234
+ f" response: {res}; http_status: {start_response.status}"
235
+ )
236
+ raise AppException(
237
+ f"Failed to download large annotation, ID: {item_id}"
238
+ )
221
239
  Path(download_path).mkdir(exist_ok=True, parents=True)
222
240
 
223
241
  dest_path = Path(download_path) / (item_name + ".json")
@@ -10,6 +10,7 @@ from lib.core.service_types import ServiceResponse
10
10
  from lib.core.service_types import SubsetListResponse
11
11
  from lib.core.service_types import UploadCustomFieldValuesResponse
12
12
  from lib.core.serviceproviders import BaseExploreService
13
+ from superannotate import AppException
13
14
 
14
15
 
15
16
  class ExploreService(BaseExploreService):
@@ -25,6 +26,7 @@ class ExploreService(BaseExploreService):
25
26
  URL_UPLOAD_CUSTOM_VALUE = "custom/metadata/item"
26
27
  URL_SAQUL_QUERY = "items/search"
27
28
  URL_VALIDATE_SAQUL_QUERY = "items/parse/query"
29
+ URL_QUERY_COUNT = "items/count"
28
30
 
29
31
  @property
30
32
  def explore_service_url(self):
@@ -201,3 +203,24 @@ class ExploreService(BaseExploreService):
201
203
  else:
202
204
  response = ServiceResponse(status=200, res_data=[])
203
205
  return response
206
+
207
+ def query_item_count(
208
+ self,
209
+ project: entities.ProjectEntity,
210
+ query: str = None,
211
+ ) -> ServiceResponse:
212
+
213
+ params = {
214
+ "project_id": project.id,
215
+ "includeFolderNames": True,
216
+ }
217
+ data = {"query": query}
218
+ response = self.client.request(
219
+ urljoin(self.explore_service_url, self.URL_QUERY_COUNT),
220
+ "post",
221
+ params=params,
222
+ data=data,
223
+ )
224
+ if not response.ok:
225
+ raise AppException(response.error)
226
+ return response
@@ -1,3 +1,5 @@
1
+ from typing import Dict
2
+
1
3
  from lib.core import entities
2
4
  from lib.core.service_types import IntegrationListResponse
3
5
  from lib.core.serviceproviders import BaseIntegrationService
@@ -23,6 +25,7 @@ class IntegrationService(BaseIntegrationService):
23
25
  folder: entities.FolderEntity,
24
26
  integration: entities.IntegrationEntity,
25
27
  folder_name: str = None,
28
+ options: Dict[str, str] = None,
26
29
  ):
27
30
  data = {
28
31
  "team_id": project.team_id,
@@ -32,6 +35,8 @@ class IntegrationService(BaseIntegrationService):
32
35
  }
33
36
  if folder_name:
34
37
  data["customer_folder_name"] = folder_name
38
+ if options:
39
+ data["options"] = options
35
40
  return self.client.request(
36
41
  self.URL_ATTACH_INTEGRATIONS.format(project.team_id), "post", data=data
37
42
  )