superannotate 4.6.0__tar.gz → 4.6.1.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 (146) hide show
  1. {superannotate-4.6.0/src/superannotate.egg-info → superannotate-4.6.1.dev1}/PKG-INFO +1 -1
  2. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/__init__.py +5 -1
  3. superannotate-4.6.1.dev1/src/superannotate/lib/app/interface/base_interface.py +395 -0
  4. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/sdk_interface.py +113 -4
  5. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/__init__.py +18 -5
  6. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/__init__.py +6 -1
  7. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/base.py +6 -2
  8. superannotate-4.6.1.dev1/src/superannotate/lib/core/entities/context.py +106 -0
  9. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/project.py +14 -1
  10. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/work_managament.py +1 -1
  11. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/exceptions.py +12 -0
  12. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/service_types.py +4 -0
  13. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/serviceproviders.py +33 -16
  14. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/annotations.py +72 -53
  15. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/images.py +12 -8
  16. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/items.py +10 -7
  17. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/projects.py +23 -0
  18. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/annotation_adapter.py +3 -3
  19. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/controller.py +112 -75
  20. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/serviceprovider.py +19 -10
  21. superannotate-4.6.1.dev1/src/superannotate/lib/infrastructure/services/auth.py +144 -0
  22. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/http_client.py +34 -19
  23. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/work_management.py +43 -36
  24. {superannotate-4.6.0 → superannotate-4.6.1.dev1/src/superannotate.egg-info}/PKG-INFO +1 -1
  25. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate.egg-info/SOURCES.txt +1 -0
  26. superannotate-4.6.0/src/superannotate/lib/app/interface/base_interface.py +0 -256
  27. superannotate-4.6.0/src/superannotate/lib/infrastructure/services/auth.py +0 -139
  28. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/LICENSE +0 -0
  29. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/MANIFEST.in +0 -0
  30. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/README.rst +0 -0
  31. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/requirements.txt +0 -0
  32. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/setup.cfg +0 -0
  33. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/setup.py +0 -0
  34. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/__init__.py +0 -0
  35. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/__init__.py +0 -0
  36. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/analytics/__init__.py +0 -0
  37. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/analytics/aggregators.py +0 -0
  38. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/analytics/common.py +0 -0
  39. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/bin/__init__.py +0 -0
  40. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/bin/superannotate.py +0 -0
  41. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/common.py +0 -0
  42. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/exceptions.py +0 -0
  43. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/helpers.py +0 -0
  44. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/__init__.py +0 -0
  45. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/conversion.py +0 -0
  46. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/__init__.py +0 -0
  47. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/baseStrategy.py +0 -0
  48. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/__init__.py +0 -0
  49. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_api.py +0 -0
  50. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_converter.py +0 -0
  51. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_strategies.py +0 -0
  52. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/coco_to_sa_vector.py +0 -0
  53. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/coco_converters/sa_vector_to_coco.py +0 -0
  54. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/converters.py +0 -0
  55. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/__init__.py +0 -0
  56. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_helper.py +0 -0
  57. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_strategies.py +0 -0
  58. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/dataloop_converters/dataloop_to_sa_vector.py +0 -0
  59. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/__init__.py +0 -0
  60. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_strategies.py +0 -0
  61. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/googlecloud_converters/googlecloud_to_sa_vector.py +0 -0
  62. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/__init__.py +0 -0
  63. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_helper.py +0 -0
  64. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/labelbox_converters/labelbox_to_sa_vector.py +0 -0
  65. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/sa_json_helper.py +0 -0
  66. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/__init__.py +0 -0
  67. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_strategies.py +0 -0
  68. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/sagemaker_converters/sagemaker_to_sa_vector.py +0 -0
  69. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/__init__.py +0 -0
  70. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_helper.py +0 -0
  71. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_strategies.py +0 -0
  72. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/supervisely_converters/supervisely_to_sa_vector.py +0 -0
  73. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/__init__.py +0 -0
  74. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_helper.py +0 -0
  75. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_strategies.py +0 -0
  76. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/vgg_converters/vgg_to_sa_vector.py +0 -0
  77. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/__init__.py +0 -0
  78. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_helper.py +0 -0
  79. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_strategies.py +0 -0
  80. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_pixel.py +0 -0
  81. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/voc_converters/voc_to_sa_vector.py +0 -0
  82. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/__init__.py +0 -0
  83. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_strategies.py +0 -0
  84. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/vott_converters/vott_to_sa_vector.py +0 -0
  85. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/__init__.py +0 -0
  86. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_strategies.py +0 -0
  87. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/converters/yolo_converters/yolo_to_sa_vector.py +0 -0
  88. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/export_from_sa_conversions.py +0 -0
  89. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/input_converters/import_to_sa_conversions.py +0 -0
  90. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/__init__.py +0 -0
  91. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/cli_interface.py +0 -0
  92. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/responses.py +0 -0
  93. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/sdk/__init__.py +0 -0
  94. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/sdk/folders.py +0 -0
  95. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/sdk/project.py +0 -0
  96. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/interface/types.py +0 -0
  97. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/app/serializers.py +0 -0
  98. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/base_usecases.py +0 -0
  99. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/conditions.py +0 -0
  100. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/config.py +0 -0
  101. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/classes.py +0 -0
  102. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/filters.py +0 -0
  103. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/folder.py +0 -0
  104. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/integrations.py +0 -0
  105. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/items.py +0 -0
  106. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/multimodal_form.py +0 -0
  107. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/entities/project_entities.py +0 -0
  108. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/enums.py +0 -0
  109. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/jsx_conditions.py +0 -0
  110. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/plugin.py +0 -0
  111. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/reporter.py +0 -0
  112. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/repositories.py +0 -0
  113. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/response.py +0 -0
  114. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/types.py +0 -0
  115. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/__init__.py +0 -0
  116. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/base.py +0 -0
  117. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/classes.py +0 -0
  118. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/custom_fields.py +0 -0
  119. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/folders.py +0 -0
  120. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/integrations.py +0 -0
  121. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/models.py +0 -0
  122. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/usecases/work_management.py +0 -0
  123. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/utils.py +0 -0
  124. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/core/video_convertor.py +0 -0
  125. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/__init__.py +0 -0
  126. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/custom_entities.py +0 -0
  127. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/helpers.py +0 -0
  128. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/query_builder.py +0 -0
  129. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/repositories.py +0 -0
  130. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/__init__.py +0 -0
  131. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/annotation.py +0 -0
  132. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/annotation_class.py +0 -0
  133. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/explore.py +0 -0
  134. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/folder.py +0 -0
  135. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/integration.py +0 -0
  136. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/item.py +0 -0
  137. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/item_service.py +0 -0
  138. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/project.py +0 -0
  139. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/services/telemetry_scoring.py +0 -0
  140. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/stream_data_handler.py +0 -0
  141. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/utils.py +0 -0
  142. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate/lib/infrastructure/validators.py +0 -0
  143. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate.egg-info/dependency_links.txt +0 -0
  144. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate.egg-info/entry_points.txt +0 -0
  145. {superannotate-4.6.0 → superannotate-4.6.1.dev1}/src/superannotate.egg-info/requires.txt +0 -0
  146. {superannotate-4.6.0 → superannotate-4.6.1.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.6.0
3
+ Version: 4.6.1.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
@@ -2,7 +2,7 @@ import logging
2
2
  import os
3
3
  import sys
4
4
 
5
- __version__ = "4.6.0"
5
+ __version__ = "4.6.1dev1"
6
6
 
7
7
 
8
8
  os.environ.update({"sa_version": __version__})
@@ -15,10 +15,12 @@ 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 SAAuthError
18
19
  from lib.core.exceptions import FileChangedError
19
20
  from superannotate.lib.app.input_converters import export_annotation
20
21
  from superannotate.lib.app.input_converters import import_annotation
21
22
  from superannotate.lib.app.interface.sdk_interface import SAClient
23
+ from superannotate.lib.app.interface.sdk_interface import SAORGClient
22
24
  from superannotate.lib.app.interface.sdk_interface import ItemContext
23
25
 
24
26
  SESSIONS = {}
@@ -27,10 +29,12 @@ SESSIONS = {}
27
29
  __all__ = [
28
30
  "__version__",
29
31
  "SAClient",
32
+ "SAORGClient",
30
33
  "ItemContext",
31
34
  # Utils
32
35
  "enums",
33
36
  "AppException",
37
+ "SAAuthError",
34
38
  "FileChangedError",
35
39
  "import_annotation",
36
40
  "export_annotation",
@@ -0,0 +1,395 @@
1
+ from __future__ import annotations
2
+
3
+ import functools
4
+ import json
5
+ import logging
6
+ import os
7
+ import platform
8
+ import sys
9
+ from collections.abc import Iterable
10
+ from collections.abc import Sized
11
+ from inspect import signature
12
+ from pathlib import Path
13
+ from types import FunctionType
14
+
15
+ import lib.core as constants
16
+ from lib.app.interface.types import validate_arguments
17
+ from lib.core import CONFIG
18
+ from lib.core import CREDENTIALS_NOT_FOUND_ERROR
19
+ from lib.core import INVALID_CREDENTIALS_ERROR
20
+ from lib.core import INVALID_TOKEN_ERROR
21
+ from lib.core import setup_logging
22
+ from lib.core.entities.base import ConfigEntity
23
+ from lib.core.exceptions import AppException
24
+ from lib.core.exceptions import SAAuthError
25
+ from lib.infrastructure.controller import BaseController
26
+ from lib.infrastructure.utils import extract_project_folder_inputs
27
+ from lib.infrastructure.validators import wrap_error
28
+ from mixpanel import Mixpanel
29
+ from pydantic import ValidationError
30
+
31
+ logger = logging.getLogger("sa")
32
+
33
+
34
+ class BaseInterfaceFacade:
35
+ """Credential resolution, shared by every facade.
36
+
37
+ What a token has to resolve to is the facade's own business - named by its
38
+ CONTROLLER_CLASS rather than configured through this __init__: SAClient needs a
39
+ team, SAORGClient needs an organization key.
40
+ """
41
+
42
+ #: The controller class this facade drives. Named for the class, not the
43
+ #: instance: `self.controller` is the built one.
44
+ CONTROLLER_CLASS: type[BaseController]
45
+
46
+ @validate_arguments
47
+ def __init__(
48
+ self,
49
+ # Plain str, not TokenStr: the token's shape is checked by ConfigEntity in
50
+ # _resolve_config, so a malformed one is reported as the credential failure it
51
+ # is (SAAuthError) rather than as a generic bad argument.
52
+ token: str | None = None,
53
+ config_path: str | None = None,
54
+ team_id: int | None = None,
55
+ *,
56
+ config: dict | None = None,
57
+ ):
58
+ resolved = self._resolve_config(token, config_path, config)
59
+ if team_id is not None:
60
+ # An explicit team_id wins over whatever the config source provided.
61
+ resolved.TEAM_ID = team_id
62
+ setup_logging(resolved.LOGGING_LEVEL, resolved.LOGGING_PATH)
63
+ self.controller = self.CONTROLLER_CLASS(resolved)
64
+
65
+ @classmethod
66
+ def _resolve_config(
67
+ cls,
68
+ token: str | None,
69
+ config_path: str | None,
70
+ settings: dict | None = None,
71
+ ) -> ConfigEntity:
72
+ """Resolve credentials and settings.
73
+
74
+ Credentials come from the first source that carries them: the ``token``
75
+ argument, a config file, inline ``settings``, then the environment and the
76
+ default config files. Inline settings are applied over whatever that produced,
77
+ so a caller can configure a client - another backend, bigger chunks - without
78
+ writing a file for it.
79
+
80
+ Shared by every facade's ``__init__`` (``SAClient``, ``SAORGClient``).
81
+ """
82
+ settings = cls._validated_settings(settings)
83
+ try:
84
+ if token:
85
+ config = ConfigEntity(**{**settings, "SA_TOKEN": token})
86
+ elif config_path:
87
+ config = cls._merge_settings(
88
+ cls._resolve_config_from_path(config_path), settings
89
+ )
90
+ elif "SA_TOKEN" in settings:
91
+ config = ConfigEntity(**settings)
92
+ else:
93
+ config = cls._merge_settings(
94
+ cls._resolve_config_from_env_or_files(), settings
95
+ )
96
+ except ValidationError as e:
97
+ raise SAAuthError(wrap_error(e))
98
+ if not config:
99
+ raise SAAuthError(INVALID_CREDENTIALS_ERROR)
100
+ return config
101
+
102
+ @staticmethod
103
+ def _validated_settings(settings: dict | None) -> dict:
104
+ """Inline settings, with anything the SDK has no such setting for rejected.
105
+
106
+ ConfigEntity ignores what it does not recognise, so a mistyped key would
107
+ otherwise be dropped without a word - and a mistyped SA_TOKEN would send the
108
+ client off to authenticate as whatever the environment happens to hold.
109
+ """
110
+ if not settings:
111
+ return {}
112
+ known = set(ConfigEntity.model_fields) | {
113
+ field.alias
114
+ for field in ConfigEntity.model_fields.values()
115
+ if field.alias is not None
116
+ }
117
+ unknown = sorted(set(settings) - known)
118
+ if unknown:
119
+ raise AppException(
120
+ f"Unknown configuration: {', '.join(unknown)}. "
121
+ f"Available: {', '.join(sorted(known))}."
122
+ )
123
+ return dict(settings)
124
+
125
+ @staticmethod
126
+ def _merge_settings(config: ConfigEntity, settings: dict) -> ConfigEntity:
127
+ """``config`` with inline settings applied over it."""
128
+ if not settings:
129
+ return config
130
+ return ConfigEntity(**{**config.model_dump(by_alias=True), **settings})
131
+
132
+ @classmethod
133
+ def _resolve_config_from_path(cls, config_path: str) -> ConfigEntity:
134
+ """A config file the caller named explicitly (``.ini`` or ``.json``)."""
135
+ path = Path(config_path).expanduser()
136
+ if not path.is_file() or not os.access(path, os.R_OK):
137
+ raise AppException(f"SuperAnnotate config file {config_path} not found.")
138
+ if path.suffix == ".json":
139
+ return cls._retrieve_configs_from_json(path)
140
+ return cls._retrieve_configs_from_ini(path)
141
+
142
+ @classmethod
143
+ def _resolve_config_from_env_or_files(cls) -> ConfigEntity:
144
+ """No token or config path given: ``SA_TOKEN``, then the default config files."""
145
+ config = cls._retrieve_configs_from_env()
146
+ if config:
147
+ return config
148
+ if Path(constants.CONFIG_INI_FILE_LOCATION).exists():
149
+ return cls._retrieve_configs_from_ini(constants.CONFIG_INI_FILE_LOCATION)
150
+ if Path(constants.CONFIG_JSON_FILE_LOCATION).exists():
151
+ return cls._retrieve_configs_from_json(constants.CONFIG_JSON_FILE_LOCATION)
152
+ raise SAAuthError(CREDENTIALS_NOT_FOUND_ERROR)
153
+
154
+ @staticmethod
155
+ def _retrieve_configs_from_json(path: Path | str) -> ConfigEntity:
156
+ with open(path) as json_file:
157
+ json_data = json.load(json_file)
158
+ token = json_data["token"]
159
+ try:
160
+ config = ConfigEntity(SA_TOKEN=token)
161
+ except ValidationError:
162
+ raise SAAuthError(INVALID_TOKEN_ERROR)
163
+ host = json_data.get("main_endpoint")
164
+ verify_ssl = json_data.get("ssl_verify")
165
+ team_id = json_data.get("team_id")
166
+ if team_id is not None:
167
+ config.TEAM_ID = int(team_id)
168
+ if host:
169
+ config.API_URL = host
170
+ if verify_ssl:
171
+ config.VERIFY_SSL = verify_ssl
172
+ return config
173
+
174
+ @staticmethod
175
+ def _retrieve_configs_from_ini(path: Path | str) -> ConfigEntity:
176
+ import configparser
177
+
178
+ config_parser = configparser.ConfigParser()
179
+ config_parser.optionxform = str
180
+ config_parser.read(path)
181
+ config_data = {}
182
+ for key in config_parser["DEFAULT"]:
183
+ config_data[key.upper()] = config_parser["DEFAULT"][key]
184
+ return ConfigEntity(**config_data)
185
+
186
+ @staticmethod
187
+ def _retrieve_configs_from_env() -> ConfigEntity | None:
188
+ token = os.environ.get("SA_TOKEN")
189
+ if not token:
190
+ return None
191
+ config = ConfigEntity(**dict(os.environ))
192
+ host = os.environ.get("SA_URL")
193
+ verify_ssl = not os.environ.get("SA_SSL", "True").lower() in ("false", "f", "0")
194
+ if host:
195
+ config.API_URL = host
196
+ if verify_ssl:
197
+ config.VERIFY_SSL = verify_ssl
198
+ return config
199
+
200
+
201
+ class Tracker:
202
+ def get_mp_instance(self, client, explicit_credentials: bool = False) -> Mixpanel:
203
+ # client may have no .controller yet (e.g. __init__ failed before setting one).
204
+ controller = getattr(client, "controller", None)
205
+ if controller is not None:
206
+ api_url = controller.config["SA_URL"]
207
+ elif explicit_credentials:
208
+ api_url = constants.BACKEND_URL
209
+ else:
210
+ api_url = os.environ.get("SA_URL", constants.BACKEND_URL)
211
+ if api_url == constants.BACKEND_URL:
212
+ mp_token = "ca95ed96f80e8ec3be791e2d3097cf51"
213
+ else:
214
+ mp_token = "e741d4863e7e05b1a45833d01865ef0d"
215
+ return Mixpanel(mp_token)
216
+
217
+ @staticmethod
218
+ def get_default_payload(team_name, user_email, auth_type) -> dict:
219
+ """Built fresh per event: a cached dict would be shared between callers, and
220
+ would freeze sa_version and SA_ENV as they were on the first tracked call.
221
+ """
222
+ return {
223
+ "SDK": True,
224
+ "Team": team_name,
225
+ "User Email": user_email,
226
+ "Auth Type": auth_type,
227
+ "Version": os.environ["sa_version"],
228
+ "Python version": platform.python_version(),
229
+ "Python interpreter type": platform.python_implementation(),
230
+ "Env": os.environ.get("SA_ENV", "N/A"),
231
+ }
232
+
233
+ def __init__(self, function):
234
+ self.function = function
235
+ functools.update_wrapper(self, function)
236
+
237
+ @staticmethod
238
+ def _metrics_disabled() -> bool:
239
+ """Whether the caller turned telemetry off.
240
+
241
+ Read per call: a Tracker is built while its class is being created, so a value
242
+ captured in __init__ would ignore anything set after ``import superannotate``.
243
+ """
244
+ return os.environ.get("SA_SKIP_METRICS", "False").lower() in ("true", "1", "t")
245
+
246
+ @staticmethod
247
+ def extract_arguments(function, *args, **kwargs) -> dict:
248
+ bound_arguments = signature(function).bind(*args, **kwargs)
249
+ bound_arguments.apply_defaults()
250
+ return dict(bound_arguments.arguments)
251
+
252
+ @staticmethod
253
+ def default_parser(function_name: str, kwargs: dict) -> tuple:
254
+ properties = {}
255
+ for key, value in kwargs.items():
256
+ if key == "self":
257
+ continue
258
+ if key == "token":
259
+ properties["sa_token"] = str(bool(value))
260
+ elif key == "config_path":
261
+ properties[key] = str(bool(value))
262
+ elif value is None:
263
+ properties[key] = value
264
+ elif key == "project":
265
+ properties.update(extract_project_folder_inputs(value))
266
+ elif isinstance(value, (str, int, float, bool)):
267
+ properties[key] = value
268
+ elif isinstance(value, dict):
269
+ properties[key] = list(value.keys())
270
+ elif isinstance(value, Sized):
271
+ properties[key] = len(value)
272
+ elif isinstance(value, Iterable):
273
+ properties[key] = "N/A"
274
+ else:
275
+ properties[key] = str(value)
276
+ return function_name, properties
277
+
278
+ def _track(
279
+ self,
280
+ user_id: str,
281
+ event_name: str,
282
+ data: dict,
283
+ *,
284
+ client,
285
+ explicit_credentials: bool = False,
286
+ ):
287
+ if "pytest" in sys.modules:
288
+ return
289
+ self.get_mp_instance(client, explicit_credentials).track(
290
+ user_id, event_name, data
291
+ )
292
+
293
+ @classmethod
294
+ def _failure_reason(
295
+ cls, function_name: str, success: bool, error: BaseException | None
296
+ ):
297
+ """The original error message, for the "Auth Failure" event property.
298
+
299
+ Scoped to __init__ auth/credential failures only.
300
+ """
301
+ if success or function_name != "__init__" or error is None:
302
+ return None
303
+ return str(error) if isinstance(error, SAAuthError) else None
304
+
305
+ def _track_method(
306
+ self,
307
+ instance,
308
+ args,
309
+ kwargs,
310
+ success: bool,
311
+ error: BaseException | None = None,
312
+ ):
313
+ # Before anything is gathered: building the payload reads controller.team_name,
314
+ # which fetches the team from the backend. A caller who turned metrics off
315
+ # should not pay for a request that is never sent.
316
+ if self._metrics_disabled():
317
+ return
318
+ try:
319
+ function_name = self.function.__name__ if self.function else ""
320
+ arguments = self.extract_arguments(self.function, *args, **kwargs)
321
+ event_name, properties = self.default_parser(function_name, arguments)
322
+
323
+ # instance is args[0] - the actual object the call was made on, captured
324
+ # locally per call (see __call__), not shared/mutable state. It has no
325
+ # .controller yet when __init__ fails before setting one.
326
+ controller = getattr(instance, "controller", None)
327
+ user_email = team_name = auth_type = None
328
+ if controller is not None:
329
+ user_email = controller.current_user.email
330
+ auth_type = controller.token_context.scope.label
331
+ team_name = controller.team_name
332
+ elif instance is None:
333
+ return
334
+
335
+ properties["Success"] = success
336
+ properties["Class"] = instance.__class__.__name__
337
+ if error:
338
+ properties["Failure Reason"] = self._failure_reason(
339
+ function_name, success, error
340
+ )
341
+ default = self.get_default_payload(
342
+ team_name=team_name, user_email=user_email, auth_type=auth_type
343
+ )
344
+ self._track(
345
+ user_email or "",
346
+ event_name,
347
+ {**default, **properties, **CONFIG.get_current_session().data},
348
+ client=instance,
349
+ explicit_credentials=bool(
350
+ arguments.get("token") or arguments.get("config_path")
351
+ ),
352
+ )
353
+ except BaseException:
354
+ logger.debug("Skipped telemetry for this call.", exc_info=True)
355
+
356
+ def __get__(self, obj, owner=None):
357
+ if obj is not None:
358
+ tmp = functools.partial(self.__call__, obj)
359
+ functools.update_wrapper(tmp, self.function)
360
+ return tmp
361
+ return self
362
+
363
+ def __call__(self, *args, **kwargs):
364
+ success = True
365
+ error = None
366
+ # The instance the call is bound to (set by __get__ via functools.partial) -
367
+ # captured locally here, per call, rather than read back from shared state.
368
+ instance = args[0] if args else None
369
+ try:
370
+ result = self.function(*args, **kwargs)
371
+ except BaseException as e:
372
+ # BaseException, not Exception: a KeyboardInterrupt used to skip this and
373
+ # leave the call reported as a success.
374
+ success = False
375
+ error = e
376
+ raise
377
+ else:
378
+ return result
379
+ finally:
380
+ self._track_method(
381
+ instance, args=args, kwargs=kwargs, success=success, error=error
382
+ )
383
+
384
+
385
+ class TrackableMeta(type):
386
+ def __new__(mcs, name, bases, attrs):
387
+ for attr_name, attr_value in attrs.items():
388
+ if isinstance(
389
+ attr_value, FunctionType
390
+ ) and not attr_value.__name__.startswith("_"):
391
+ attrs[attr_name] = Tracker(validate_arguments(attr_value))
392
+ if "__init__" in attrs:
393
+ attrs["__init__"] = Tracker(validate_arguments(attrs["__init__"]))
394
+ tmp = super().__new__(mcs, name, bases, attrs)
395
+ return tmp
@@ -32,7 +32,8 @@ from pydantic import ValidationError
32
32
  from pydantic import TypeAdapter
33
33
 
34
34
  import lib.core as constants
35
- from lib.infrastructure.controller import Controller
35
+ from lib.infrastructure.controller import OrgController
36
+ from lib.infrastructure.controller import TeamController
36
37
  from lib.app.helpers import get_annotation_paths
37
38
  from lib.app.helpers import get_name_url_duplicated_from_csv
38
39
  from lib.app.helpers import wrap_error as wrap_validation_errors
@@ -67,6 +68,8 @@ from lib.core.enums import CustomFieldEntityEnum
67
68
  from lib.core.enums import ProjectType
68
69
  from lib.core.enums import ClassTypeEnum
69
70
  from lib.core.exceptions import AppException
71
+ from lib.core.exceptions import SAAuthError
72
+ from lib.core import INVALID_TEAM_ID_ERROR
70
73
  from lib.core.types import PriorityScoreEntity
71
74
  from lib.infrastructure.annotation_adapter import BaseMultimodalAnnotationAdapter
72
75
  from lib.infrastructure.annotation_adapter import MultimodalSmallAnnotationAdapter
@@ -141,7 +144,7 @@ class ItemContext:
141
144
 
142
145
  def __init__(
143
146
  self,
144
- controller: Controller,
147
+ controller: TeamController,
145
148
  project: ProjectEntity,
146
149
  folder: FolderEntity,
147
150
  item: BaseItemEntity,
@@ -301,10 +304,41 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
301
304
  :param config_path: path to config file
302
305
  :type config_path: path-like (str or Path)
303
306
 
307
+ :param team_id: the team to operate in. Required for an Organization API key, which
308
+ is not bound to a team; for any other key it is optional and, when given, must
309
+ match the team the key grants access to.
310
+ :type team_id: int
311
+
312
+ :param config: configuration applied on creation, instead of or on top of a config
313
+ file. Keys are a config file's keys - ``SA_TOKEN``, ``SA_URL``, ``SA_TEAM_ID``,
314
+ ``VERIFY_SSL``, ``LOGGING_LEVEL``, ``LOGGING_PATH``, ``ANNOTATION_CHUNK_SIZE``,
315
+ ``ITEM_CHUNK_SIZE``, ``MAX_THREAD_COUNT``, ``MAX_COROUTINE_COUNT`` - and an
316
+ unrecognised one is an error rather than silently ignored. Explicit ``token``
317
+ and ``team_id`` arguments win over the same keys here.
318
+ :type config: dict
319
+
320
+ Request Example:
321
+ ::
322
+
323
+ sa = SAClient(config={"SA_TOKEN": "<API key>", "SA_URL": "<host>"})
304
324
  """
305
325
 
306
- def __init__(self, token: str | None = None, config_path: str | None = None):
307
- super().__init__(token, config_path)
326
+ CONTROLLER_CLASS = TeamController
327
+
328
+ def __init__(
329
+ self,
330
+ token: str | None = None,
331
+ config_path: str | None = None,
332
+ team_id: int | None = None,
333
+ *,
334
+ config: dict | None = None,
335
+ ):
336
+ super().__init__(token, config_path, team_id=team_id, config=config)
337
+
338
+ @property
339
+ def team_id(self) -> int:
340
+ """The team this client operates in."""
341
+ return self.controller.team_id
308
342
 
309
343
  def get_project_by_id(self, project_id: int):
310
344
  """Returns the project metadata
@@ -6135,3 +6169,78 @@ class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
6135
6169
  logger.info(
6136
6170
  f"Successfully removed {success} users(s) out of the {len(users)} provided from the project {project.name}."
6137
6171
  )
6172
+
6173
+
6174
+ class SAORGClient(BaseInterfaceFacade, metaclass=TrackableMeta):
6175
+ """Create SAORGClient instance to authorize SDK in an organization scope.
6176
+ In case of no argument has been provided, SA_TOKEN environmental variable
6177
+ will be checked or $HOME/.superannotate/config.ini will be used.
6178
+
6179
+ Requires an Organization API key.
6180
+
6181
+ :param token: Organization API key
6182
+ :type token: str
6183
+
6184
+ :param config_path: path to config file
6185
+ :type config_path: str
6186
+
6187
+ :param config: configuration applied on creation, instead of or on top of a config
6188
+ file. Keys are a config file's keys - ``SA_TOKEN``, ``SA_URL``, ``SA_TEAM_ID``,
6189
+ ``VERIFY_SSL``, ``LOGGING_LEVEL``, ``LOGGING_PATH``, ``ANNOTATION_CHUNK_SIZE``,
6190
+ ``ITEM_CHUNK_SIZE``, ``MAX_THREAD_COUNT``, ``MAX_COROUTINE_COUNT`` - and an
6191
+ unrecognised one is an error rather than silently ignored. Explicit ``token``
6192
+ and ``team_id`` arguments win over the same keys here.
6193
+ :type config: dict
6194
+ """
6195
+
6196
+ CONTROLLER_CLASS = OrgController
6197
+
6198
+ def __init__(
6199
+ self,
6200
+ token: str | None = None,
6201
+ config_path: str | None = None,
6202
+ *,
6203
+ config: dict | None = None,
6204
+ ):
6205
+ super().__init__(token, config_path, config=config)
6206
+
6207
+ def get_team_client(self, team_id: int) -> SAClient:
6208
+ """Returns a normal SAClient backed by the organization token, with team context returned.
6209
+
6210
+ :param team_id: ID of the team to operate in.
6211
+ :type team_id: int
6212
+
6213
+ :return: a team-scoped client exposing the full team-level SDK surface. The
6214
+ team is fixed at construction; team_id is available as a read-only
6215
+ property.
6216
+ :rtype: SAClient
6217
+
6218
+ Request Example:
6219
+ ::
6220
+
6221
+ team_client = org_client.get_team_client(team_id=12345)
6222
+ team_client.list_projects(name__contains="My Project")
6223
+ """
6224
+ # The whole configuration this client was built with, re-pointed at one team.
6225
+ # Passing the token alone would rebuild the config from defaults and lose
6226
+ # API_URL with it, which means silently moving to production.
6227
+ try:
6228
+ return SAClient(config={**self.controller.config, "SA_TEAM_ID": team_id})
6229
+ except SAAuthError:
6230
+ raise AppException(INVALID_TEAM_ID_ERROR)
6231
+
6232
+ def list_teams(self) -> list[dict]:
6233
+ """Returns the teams in the given organization. Must use Organization API Key for this function.
6234
+
6235
+ :return: the organization's teams; an empty list if it has none.
6236
+ :rtype: list of dicts
6237
+
6238
+ Request Example:
6239
+ ::
6240
+
6241
+ org_client.list_teams()
6242
+ """
6243
+ response = self.controller.list_teams()
6244
+ return BaseSerializer.serialize_iterable(
6245
+ response.data or [], by_alias=True, exclude_unset=True
6246
+ )
@@ -18,16 +18,29 @@ from lib.core.enums import UserRole
18
18
 
19
19
  CONFIG = Config()
20
20
  BACKEND_URL = "https://api.superannotate.com"
21
- HOME_PATH = expanduser("~/.superannotate")
21
+ #: Where the SDK keeps its config. The display form keeps the "~": a message shown to
22
+ #: a user should name the file, not spell out their home directory.
23
+ HOME_DISPLAY_PATH = "~/.superannotate"
24
+ HOME_PATH = expanduser(HOME_DISPLAY_PATH)
22
25
 
23
- CONFIG_JSON_PATH = f"{HOME_PATH}/config.json"
24
- CONFIG_INI_PATH = f"{HOME_PATH}/config.ini"
25
- CONFIG_JSON_FILE_LOCATION = CONFIG_JSON_PATH
26
- CONFIG_INI_FILE_LOCATION = CONFIG_INI_PATH
26
+ CONFIG_JSON_FILE_LOCATION = f"{HOME_PATH}/config.json"
27
+ CONFIG_INI_FILE_LOCATION = f"{HOME_PATH}/config.ini"
28
+ CONFIG_INI_DISPLAY_PATH = f"{HOME_DISPLAY_PATH}/config.ini"
27
29
 
28
30
  LOG_FILE_LOCATION = f"{HOME_PATH}/logs"
29
31
  DEFAULT_LOGGING_LEVEL = "INFO"
30
32
 
33
+ INVALID_TOKEN_ERROR = "Invalid token."
34
+ INVALID_TEAM_ID_ERROR = "Invalid team id provided."
35
+ INVALID_CREDENTIALS_ERROR = "Invalid credentials provided."
36
+ INVALID_TEAM_CONTEXT = (
37
+ 'Team context not provided. An Organization API key requires a "team_id".'
38
+ )
39
+ CREDENTIALS_NOT_FOUND_ERROR = (
40
+ "Credentials not found: SA_TOKEN environment variable is not set and "
41
+ f"config file '{CONFIG_INI_DISPLAY_PATH}' was not found."
42
+ )
43
+
31
44
 
32
45
  def setup_logging(level=DEFAULT_LOGGING_LEVEL, file_path=LOG_FILE_LOCATION):
33
46
  logger = logging.getLogger("sa")
@@ -2,6 +2,8 @@ from lib.core.entities.base import BaseItemEntity
2
2
  from lib.core.entities.base import ConfigEntity
3
3
  from lib.core.entities.base import SubSetEntity
4
4
  from lib.core.entities.classes import AnnotationClassEntity
5
+ from lib.core.entities.context import TokenContext
6
+ from lib.core.entities.context import TokenScope
5
7
  from lib.core.entities.folder import FolderEntity
6
8
  from lib.core.entities.integrations import IntegrationEntity
7
9
  from lib.core.entities.items import CategoryEntity
@@ -16,6 +18,7 @@ from lib.core.entities.multimodal_form import FormModel
16
18
  from lib.core.entities.multimodal_form import generate_classes_from_form
17
19
  from lib.core.entities.project import AttachmentEntity
18
20
  from lib.core.entities.project import CustomFieldEntity
21
+ from lib.core.entities.project import OrgTeamEntity
19
22
  from lib.core.entities.project import ProjectEntity
20
23
  from lib.core.entities.project import SettingEntity
21
24
  from lib.core.entities.project import StepEntity
@@ -30,6 +33,8 @@ from lib.core.entities.work_managament import WMProjectUserEntity
30
33
  __all__ = [
31
34
  # base
32
35
  "ConfigEntity",
36
+ "TokenContext",
37
+ "TokenScope",
33
38
  "SettingEntity",
34
39
  "SubSetEntity",
35
40
  "CustomFieldEntity",
@@ -49,12 +54,12 @@ __all__ = [
49
54
  "WorkflowEntity",
50
55
  "CategoryEntity",
51
56
  "WMProjectUserEntity",
52
- "ConfigEntity",
53
57
  "StepEntity",
54
58
  "FolderEntity",
55
59
  "S3FileEntity",
56
60
  "AnnotationClassEntity",
57
61
  "TeamEntity",
62
+ "OrgTeamEntity",
58
63
  "UserEntity",
59
64
  "IntegrationEntity",
60
65
  "PROJECT_ITEM_ENTITY_MAP",