dtlpy 1.118.14__tar.gz → 1.119.5__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 (240) hide show
  1. {dtlpy-1.118.14 → dtlpy-1.119.5}/PKG-INFO +1 -1
  2. dtlpy-1.119.5/dtlpy/__version__.py +1 -0
  3. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation.py +0 -7
  4. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/app.py +19 -9
  5. dtlpy-1.119.5/dtlpy/entities/compute.py +241 -0
  6. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/dpk.py +315 -2
  7. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/model.py +0 -23
  8. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/service.py +46 -1
  9. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/annotations.py +4 -2
  10. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/apps.py +1 -1
  11. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/computes.py +1 -1
  12. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/feature_sets.py +1 -1
  13. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/models.py +68 -56
  14. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/tasks.py +10 -3
  15. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/uploader.py +18 -2
  16. {dtlpy-1.118.14 → dtlpy-1.119.5}/setup.py +1 -1
  17. dtlpy-1.118.14/dtlpy/__version__.py +0 -1
  18. dtlpy-1.118.14/dtlpy/entities/compute.py +0 -450
  19. {dtlpy-1.118.14 → dtlpy-1.119.5}/LICENSE +0 -0
  20. {dtlpy-1.118.14 → dtlpy-1.119.5}/MANIFEST.in +0 -0
  21. {dtlpy-1.118.14 → dtlpy-1.119.5}/README.md +0 -0
  22. {dtlpy-1.118.14 → dtlpy-1.119.5}/docs/requirements.txt +0 -0
  23. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/__init__.py +0 -0
  24. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/__init__.py +0 -0
  25. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/code_server/config.yaml +0 -0
  26. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/code_server/installation.sh +0 -0
  27. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/code_server/launch.json +0 -0
  28. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/code_server/settings.json +0 -0
  29. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/lock_open.png +0 -0
  30. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/main.py +0 -0
  31. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/main_partial.py +0 -0
  32. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/mock.json +0 -0
  33. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/model_adapter.py +0 -0
  34. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/package.json +0 -0
  35. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/package_catalog.json +0 -0
  36. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/package_gitignore +0 -0
  37. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/project_dataset_recipe_ontology.png +0 -0
  38. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/__init__.py +0 -0
  39. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/converter.py +0 -0
  40. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/multi_method.py +0 -0
  41. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/multi_method_annotation.py +0 -0
  42. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/multi_method_dataset.py +0 -0
  43. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/multi_method_item.py +0 -0
  44. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/multi_method_json.py +0 -0
  45. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/single_method.py +0 -0
  46. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/single_method_annotation.py +0 -0
  47. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/single_method_dataset.py +0 -0
  48. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/single_method_item.py +0 -0
  49. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/single_method_json.py +0 -0
  50. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/service_runners/single_method_multi_input.py +0 -0
  51. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/assets/voc_annotation_template.xml +0 -0
  52. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/caches/__init__.py +0 -0
  53. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/caches/base_cache.py +0 -0
  54. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/caches/cache.py +0 -0
  55. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/caches/dl_cache.py +0 -0
  56. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/caches/filesystem_cache.py +0 -0
  57. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/caches/redis_cache.py +0 -0
  58. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/dlp/__init__.py +0 -0
  59. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/dlp/cli_utilities.py +0 -0
  60. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/dlp/command_executor.py +0 -0
  61. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/dlp/dlp +0 -0
  62. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/dlp/dlp.bat +0 -0
  63. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/dlp/dlp.py +0 -0
  64. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/dlp/parser.py +0 -0
  65. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/__init__.py +0 -0
  66. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/analytic.py +0 -0
  67. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_collection.py +0 -0
  68. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/__init__.py +0 -0
  69. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/base_annotation_definition.py +0 -0
  70. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/box.py +0 -0
  71. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/classification.py +0 -0
  72. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/comparison.py +0 -0
  73. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/cube.py +0 -0
  74. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/cube_3d.py +0 -0
  75. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/description.py +0 -0
  76. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/ellipse.py +0 -0
  77. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/free_text.py +0 -0
  78. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/gis.py +0 -0
  79. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/note.py +0 -0
  80. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/point.py +0 -0
  81. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/polygon.py +0 -0
  82. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/polyline.py +0 -0
  83. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/pose.py +0 -0
  84. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/ref_image.py +0 -0
  85. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/segmentation.py +0 -0
  86. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/subtitle.py +0 -0
  87. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/text.py +0 -0
  88. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/annotation_definitions/undefined_annotation.py +0 -0
  89. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/app_module.py +0 -0
  90. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/artifact.py +0 -0
  91. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/assignment.py +0 -0
  92. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/base_entity.py +0 -0
  93. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/bot.py +0 -0
  94. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/codebase.py +0 -0
  95. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/collection.py +0 -0
  96. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/command.py +0 -0
  97. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/dataset.py +0 -0
  98. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/directory_tree.py +0 -0
  99. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/driver.py +0 -0
  100. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/execution.py +0 -0
  101. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/feature.py +0 -0
  102. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/feature_set.py +0 -0
  103. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/filters.py +0 -0
  104. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/gis_item.py +0 -0
  105. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/integration.py +0 -0
  106. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/item.py +0 -0
  107. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/label.py +0 -0
  108. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/links.py +0 -0
  109. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/message.py +0 -0
  110. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/node.py +0 -0
  111. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/ontology.py +0 -0
  112. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/organization.py +0 -0
  113. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/package.py +0 -0
  114. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/package_defaults.py +0 -0
  115. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/package_function.py +0 -0
  116. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/package_module.py +0 -0
  117. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/package_slot.py +0 -0
  118. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/paged_entities.py +0 -0
  119. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/pipeline.py +0 -0
  120. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/pipeline_execution.py +0 -0
  121. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/project.py +0 -0
  122. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/prompt_item.py +0 -0
  123. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/recipe.py +0 -0
  124. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/reflect_dict.py +0 -0
  125. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/resource_execution.py +0 -0
  126. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/service_driver.py +0 -0
  127. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/setting.py +0 -0
  128. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/task.py +0 -0
  129. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/time_series.py +0 -0
  130. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/trigger.py +0 -0
  131. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/user.py +0 -0
  132. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/entities/webhook.py +0 -0
  133. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/__init__.py +0 -0
  134. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/add_labels.py +0 -0
  135. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/add_metadata_to_item.py +0 -0
  136. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/annotate_items_using_model.py +0 -0
  137. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/annotate_video_using_model_and_tracker.py +0 -0
  138. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/annotations_convert_to_voc.py +0 -0
  139. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/annotations_convert_to_yolo.py +0 -0
  140. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/convert_annotation_types.py +0 -0
  141. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/converter.py +0 -0
  142. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/copy_annotations.py +0 -0
  143. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/copy_folder.py +0 -0
  144. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/create_annotations.py +0 -0
  145. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/create_video_annotations.py +0 -0
  146. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/delete_annotations.py +0 -0
  147. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/filters.py +0 -0
  148. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/move_item.py +0 -0
  149. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/play_video_annotation.py +0 -0
  150. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/show_item_and_mask.py +0 -0
  151. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/triggers.py +0 -0
  152. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/upload_batch_of_items.py +0 -0
  153. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/upload_items_and_custom_format_annotations.py +0 -0
  154. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/upload_items_with_modalities.py +0 -0
  155. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +0 -0
  156. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/examples/upload_yolo_format_annotations.py +0 -0
  157. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/exceptions.py +0 -0
  158. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/miscellaneous/__init__.py +0 -0
  159. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/miscellaneous/dict_differ.py +0 -0
  160. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/miscellaneous/git_utils.py +0 -0
  161. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/miscellaneous/json_utils.py +0 -0
  162. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/miscellaneous/list_print.py +0 -0
  163. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/miscellaneous/path_utils.py +0 -0
  164. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/miscellaneous/zipping.py +0 -0
  165. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/ml/__init__.py +0 -0
  166. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/ml/base_feature_extractor_adapter.py +0 -0
  167. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/ml/base_model_adapter.py +0 -0
  168. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/ml/metrics.py +0 -0
  169. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/ml/predictions_utils.py +0 -0
  170. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/ml/summary_writer.py +0 -0
  171. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/ml/train_utils.py +0 -0
  172. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/new_instance.py +0 -0
  173. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/__init__.py +0 -0
  174. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/analytics.py +0 -0
  175. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/artifacts.py +0 -0
  176. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/assignments.py +0 -0
  177. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/bots.py +0 -0
  178. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/codebases.py +0 -0
  179. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/collections.py +0 -0
  180. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/commands.py +0 -0
  181. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/compositions.py +0 -0
  182. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/datasets.py +0 -0
  183. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/downloader.py +0 -0
  184. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/dpks.py +0 -0
  185. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/drivers.py +0 -0
  186. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/executions.py +0 -0
  187. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/features.py +0 -0
  188. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/integrations.py +0 -0
  189. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/items.py +0 -0
  190. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/messages.py +0 -0
  191. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/nodes.py +0 -0
  192. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/ontologies.py +0 -0
  193. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/organizations.py +0 -0
  194. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/packages.py +0 -0
  195. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/pipeline_executions.py +0 -0
  196. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/pipelines.py +0 -0
  197. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/projects.py +0 -0
  198. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/recipes.py +0 -0
  199. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/resource_executions.py +0 -0
  200. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/schema.py +0 -0
  201. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/service_drivers.py +0 -0
  202. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/services.py +0 -0
  203. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/settings.py +0 -0
  204. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/times_series.py +0 -0
  205. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/triggers.py +0 -0
  206. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/upload_element.py +0 -0
  207. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/repositories/webhooks.py +0 -0
  208. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/__init__.py +0 -0
  209. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/aihttp_retry.py +0 -0
  210. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/api_client.py +0 -0
  211. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/api_reference.py +0 -0
  212. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/async_utils.py +0 -0
  213. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/calls_counter.py +0 -0
  214. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/check_sdk.py +0 -0
  215. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/cookie.py +0 -0
  216. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/create_logger.py +0 -0
  217. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/events.py +0 -0
  218. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/logins.py +0 -0
  219. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/reporter.py +0 -0
  220. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/services/service_defaults.py +0 -0
  221. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/__init__.py +0 -0
  222. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/annotations/__init__.py +0 -0
  223. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/annotations/annotation_converters.py +0 -0
  224. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/base_package_runner.py +0 -0
  225. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/converter.py +0 -0
  226. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/dataset_generators/__init__.py +0 -0
  227. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/dataset_generators/dataset_generator.py +0 -0
  228. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +0 -0
  229. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/dataset_generators/dataset_generator_torch.py +0 -0
  230. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/local_development/__init__.py +0 -0
  231. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/local_development/local_session.py +0 -0
  232. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/reports/__init__.py +0 -0
  233. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/reports/figures.py +0 -0
  234. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/reports/report.py +0 -0
  235. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/videos/__init__.py +0 -0
  236. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/videos/video_player.py +0 -0
  237. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy/utilities/videos/videos.py +0 -0
  238. {dtlpy-1.118.14 → dtlpy-1.119.5}/dtlpy.egg-info/SOURCES.txt +0 -0
  239. {dtlpy-1.118.14 → dtlpy-1.119.5}/requirements.txt +0 -0
  240. {dtlpy-1.118.14 → dtlpy-1.119.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dtlpy
3
- Version: 1.118.14
3
+ Version: 1.119.5
4
4
  Summary: SDK and CLI for Dataloop platform
5
5
  Home-page: https://github.com/dataloop-ai/dtlpy
6
6
  Author: Dataloop Team
@@ -0,0 +1 @@
1
+ version = '1.119.5'
@@ -1168,13 +1168,6 @@ class Annotation(entities.BaseEntity):
1168
1168
  annotation_definition=dl.Box(top=10,left=10,bottom=100, right=100,label='labelName'))
1169
1169
  )
1170
1170
  """
1171
- # handle fps
1172
- if self.fps is None:
1173
- if self._item is not None:
1174
- if self._item.fps is not None:
1175
- self.fps = self._item.fps
1176
- if self.fps is None:
1177
- raise PlatformException('400', 'Annotation must have fps in order to perform this action')
1178
1171
 
1179
1172
  # if this is first frame
1180
1173
  if self.annotation_definition is None:
@@ -48,6 +48,7 @@ class App(entities.BaseEntity):
48
48
  metadata = attr.ib(type=dict)
49
49
  status = attr.ib(type=entities.CompositionStatus)
50
50
  settings = attr.ib(type=dict)
51
+ dpk = attr.ib(type=entities.Dpk)
51
52
 
52
53
  # sdk
53
54
  _project = attr.ib(type=entities.Project, repr=False)
@@ -57,11 +58,12 @@ class App(entities.BaseEntity):
57
58
 
58
59
  @_repositories.default
59
60
  def set_repositories(self):
60
- reps = namedtuple('repositories', field_names=['projects', 'apps', 'compositions'])
61
+ reps = namedtuple('repositories', field_names=['projects', 'apps', 'compositions', 'models'])
61
62
  return reps(
62
63
  projects=repositories.Projects(client_api=self._client_api),
63
64
  apps=repositories.Apps(client_api=self._client_api, project=self._project, project_id=self.project_id),
64
- compositions=repositories.Compositions(client_api=self._client_api, project=self._project)
65
+ compositions=repositories.Compositions(client_api=self._client_api, project=self._project),
66
+ models=repositories.Models(client_api=self._client_api, app=self)
65
67
  )
66
68
 
67
69
  @property
@@ -80,6 +82,11 @@ class App(entities.BaseEntity):
80
82
  assert isinstance(self._repositories.apps, repositories.Apps)
81
83
  return self._repositories.apps
82
84
 
85
+ @property
86
+ def models(self):
87
+ assert isinstance(self._repositories.models, repositories.Models)
88
+ return self._repositories.models
89
+
83
90
  @property
84
91
  def compositions(self):
85
92
  assert isinstance(self._repositories.compositions, repositories.Compositions)
@@ -141,15 +148,15 @@ class App(entities.BaseEntity):
141
148
  :return:
142
149
  """
143
150
  try:
144
- package = App.from_json(_json=_json,
145
- client_api=client_api,
146
- project=project,
147
- is_fetched=is_fetched)
151
+ app = App.from_json(_json=_json,
152
+ client_api=client_api,
153
+ project=project,
154
+ is_fetched=is_fetched)
148
155
  status = True
149
156
  except Exception:
150
- package = traceback.format_exc()
157
+ app = traceback.format_exc()
151
158
  status = False
152
- return status, package
159
+ return status, app
153
160
 
154
161
  def to_json(self):
155
162
  _json = {}
@@ -189,6 +196,8 @@ class App(entities.BaseEntity):
189
196
  _json['settings'] = self.settings
190
197
  if self.integrations is not None:
191
198
  _json['integrations'] = self.integrations
199
+ if self.dpk is not None:
200
+ _json['dpk'] = self.dpk.to_json()
192
201
 
193
202
  return _json
194
203
 
@@ -214,7 +223,8 @@ class App(entities.BaseEntity):
214
223
  metadata=_json.get('metadata', None),
215
224
  status=_json.get('status', None),
216
225
  settings=_json.get('settings', {}),
217
- integrations=_json.get('integrations', None)
226
+ integrations=_json.get('integrations', None),
227
+ dpk=entities.Dpk.from_json(_json=_json.get('dpk', {}), client_api=client_api, project=project, is_fetched=is_fetched)
218
228
  )
219
229
  app.is_fetched = is_fetched
220
230
  return app
@@ -0,0 +1,241 @@
1
+ import traceback
2
+ from enum import Enum
3
+ from typing import List, Dict
4
+ from ..services.api_client import ApiClient
5
+ from .. import repositories, entities
6
+
7
+
8
+ class ClusterProvider(str, Enum):
9
+ GCP = 'gcp'
10
+ AWS = 'aws'
11
+ AZURE = 'azure'
12
+ HPC = 'hpc'
13
+ LOCAL = 'local'
14
+ RANCHER_K3S = 'rancher-k3s'
15
+ RANCHER_RKE = 'rancher-rke'
16
+ OPENSHIFT = 'openshift'
17
+
18
+
19
+ class ComputeType(str, Enum):
20
+ KUBERNETES = "kubernetes"
21
+
22
+
23
+ class ComputeStatus(str, Enum):
24
+ READY = "ready"
25
+ INITIALIZING = "initializing"
26
+ PAUSE = "pause"
27
+ FAILED = "failed"
28
+ VALIDATING = "validating"
29
+
30
+
31
+ class ComputeConsumptionMethod(str, Enum):
32
+ MQ = "MQ",
33
+ API = "API"
34
+
35
+
36
+ class ComputeSettings(entities.DlEntity):
37
+ default_namespace: str = entities.DlProperty(location=['defaultNamespace'], _type=str)
38
+ consumption_method: str = entities.DlProperty(location=['consumptionMethod'], _type=str)
39
+
40
+ def to_json(self) -> dict:
41
+ return self._dict.copy()
42
+
43
+ @classmethod
44
+ def from_json(cls, _json):
45
+ return cls(_dict=_json)
46
+
47
+
48
+ class Toleration(entities.DlEntity):
49
+ effect: str = entities.DlProperty(location=['effect'], _type=str)
50
+ key: str = entities.DlProperty(location=['key'], _type=str)
51
+ operator: str = entities.DlProperty(location=['operator'], _type=str)
52
+ value: str = entities.DlProperty(location=['value'], _type=str)
53
+
54
+ def to_json(self) -> dict:
55
+ return self._dict.copy()
56
+
57
+ @classmethod
58
+ def from_json(cls, _json):
59
+ return cls(_dict=_json)
60
+
61
+
62
+ class DeploymentResource(entities.DlEntity):
63
+ gpu: int = entities.DlProperty(location=['gpu'], _type=int)
64
+ cpu: int = entities.DlProperty(location=['cpu'], _type=int)
65
+ memory: str = entities.DlProperty(location=['memory'], _type=str)
66
+
67
+ def to_json(self) -> dict:
68
+ return self._dict.copy()
69
+
70
+ @classmethod
71
+ def from_json(cls, _json):
72
+ return cls(_dict=_json)
73
+
74
+
75
+ class DeploymentResources(entities.DlEntity):
76
+ request: DeploymentResource = entities.DlProperty(location=['request'], _kls='DeploymentResource')
77
+ limit: DeploymentResource = entities.DlProperty(location=['limit'], _kls='DeploymentResource')
78
+
79
+ def to_json(self) -> dict:
80
+ return self._dict.copy()
81
+
82
+ @classmethod
83
+ def from_json(cls, _json):
84
+ return cls(_dict=_json)
85
+
86
+
87
+ class NodePool(entities.DlEntity):
88
+ name: str = entities.DlProperty(location=['name'], _type=str)
89
+ is_dl_type_default: bool = entities.DlProperty(location=['isDlTypeDefault'], _type=bool)
90
+ is_monitoring_configuration: bool = entities.DlProperty(location=['isMonitoringConfiguration'], _type=bool)
91
+ dl_types: List[str] = entities.DlProperty(location=['dlTypes'], _type=list)
92
+ tolerations: List[Toleration] = entities.DlProperty(location=['tolerations'], _kls='Toleration', default=[])
93
+ description: str = entities.DlProperty(location=['description'], _type=str, default='')
94
+ node_selector: str = entities.DlProperty(location=['nodeSelector'], _type=str, default='')
95
+ preemptible: bool = entities.DlProperty(location=['preemptible'], _type=bool, default=False)
96
+ deployment_resources: DeploymentResources = entities.DlProperty(location=['deploymentResources'], _kls='DeploymentResources')
97
+
98
+ def to_json(self) -> dict:
99
+ return self._dict.copy()
100
+
101
+ @classmethod
102
+ def from_json(cls, _json):
103
+ return cls(_dict=_json)
104
+
105
+
106
+ class AuthenticationIntegration(entities.DlEntity):
107
+ id: str = entities.DlProperty(location=['id'], _type=str)
108
+ type: str = entities.DlProperty(location=['type'], _type=str)
109
+
110
+ def to_json(self) -> dict:
111
+ return self._dict.copy()
112
+
113
+ @classmethod
114
+ def from_json(cls, _json):
115
+ return cls(_dict=_json)
116
+
117
+
118
+ class Authentication(entities.DlEntity):
119
+ integration: AuthenticationIntegration = entities.DlProperty(location=['integration'], _kls='AuthenticationIntegration')
120
+
121
+ def to_json(self) -> dict:
122
+ return self._dict.copy()
123
+
124
+ @classmethod
125
+ def from_json(cls, _json):
126
+ return cls(_dict=_json)
127
+
128
+
129
+ class ComputeCluster(entities.DlEntity):
130
+ name: str = entities.DlProperty(location=['name'], _type=str)
131
+ endpoint: str = entities.DlProperty(location=['endpoint'], _type=str)
132
+ kubernetes_version: str = entities.DlProperty(location=['kubernetesVersion'], _type=str)
133
+ provider: str = entities.DlProperty(location=['provider'], _type=str)
134
+ node_pools: List[NodePool] = entities.DlProperty(location=['nodePools'], _kls='NodePool', default=[])
135
+ metadata: Dict = entities.DlProperty(location=['metadata'], _type=dict, default={})
136
+ authentication: Authentication = entities.DlProperty(location=['authentication'], _kls='Authentication')
137
+ plugins: dict = entities.DlProperty(location=['plugins'], _type=dict)
138
+ deployment_configuration: Dict = entities.DlProperty(location=['deploymentConfiguration'], _type=dict, default={})
139
+
140
+ def to_json(self) -> dict:
141
+ return self._dict.copy()
142
+
143
+ @classmethod
144
+ def from_json(cls, _json):
145
+ return cls(_dict=_json)
146
+
147
+ @classmethod
148
+ def from_setup_json(cls, devops_output, integration):
149
+ _json = {
150
+ 'name': devops_output['config']['name'],
151
+ 'endpoint': devops_output['config']['endpoint'],
152
+ 'kubernetesVersion': devops_output['config']['kubernetesVersion'],
153
+ 'provider': devops_output['config']['provider'],
154
+ 'nodePools': devops_output['config']['nodePools'],
155
+ 'metadata': {},
156
+ 'authentication': {'integration': {'id': integration.id, 'type': integration.type}},
157
+ 'plugins': devops_output['config'].get('plugins'),
158
+ 'deploymentConfiguration': devops_output['config'].get('deploymentConfiguration', {})
159
+ }
160
+ return cls(_dict=_json)
161
+
162
+
163
+ class ComputeContext(entities.DlEntity):
164
+ labels: List[str] = entities.DlProperty(location=['labels'], _type=list, default=[])
165
+ org: str = entities.DlProperty(location=['org'], _type=str)
166
+ project: str = entities.DlProperty(location=['project'], _type=str)
167
+
168
+ def to_json(self) -> dict:
169
+ return self._dict.copy()
170
+
171
+ @classmethod
172
+ def from_json(cls, _json):
173
+ return cls(_dict=_json)
174
+
175
+
176
+ class Compute(entities.DlEntity):
177
+ id: str = entities.DlProperty(location=['id'], _type=str)
178
+ name: str = entities.DlProperty(location=['name'], _type=str)
179
+ context: ComputeContext = entities.DlProperty(location=['context'], _kls='ComputeContext')
180
+ shared_contexts: List[ComputeContext] = entities.DlProperty(location=['sharedContexts'], _kls='ComputeContext', default=[])
181
+ global_: bool = entities.DlProperty(location=['global'], _type=bool)
182
+ status: str = entities.DlProperty(location=['status'], _type=str, default=ComputeStatus.INITIALIZING.value)
183
+ type: str = entities.DlProperty(location=['type'], _type=str, default=ComputeType.KUBERNETES.value)
184
+ features: Dict = entities.DlProperty(location=['features'], _type=dict, default={})
185
+ metadata: Dict = entities.DlProperty(location=['metadata'], _type=dict, default={})
186
+ settings: ComputeSettings = entities.DlProperty(location=['settings'], _kls='ComputeSettings')
187
+ url: str = entities.DlProperty(location=['url'], _type=str)
188
+
189
+ def __init__(self, _dict=None, client_api: ApiClient = None, **kwargs):
190
+ super().__init__(_dict=_dict, **kwargs)
191
+ self._client_api = client_api
192
+ self._computes = None
193
+ self._serviceDrivers = None
194
+
195
+ @property
196
+ def computes(self):
197
+ if self._computes is None:
198
+ self._computes = repositories.Computes(client_api=self._client_api)
199
+ return self._computes
200
+
201
+ def delete(self, skip_destroy: bool = False):
202
+ return self.computes.delete(compute_id=self.id, skip_destroy=skip_destroy)
203
+
204
+ def update(self):
205
+ return self.computes.update(compute=self)
206
+
207
+ @staticmethod
208
+ def _protected_from_json(_json: dict, client_api: ApiClient):
209
+ """
210
+ Same as from_json but with try-except to catch if error
211
+
212
+ :param _json: platform json
213
+ :param client_api: ApiClient entity
214
+ :return:
215
+ """
216
+ try:
217
+ compute = Compute.from_json(_json=_json,
218
+ client_api=client_api)
219
+ status = True
220
+ except Exception:
221
+ compute = traceback.format_exc()
222
+ status = False
223
+ return status, compute
224
+
225
+ @classmethod
226
+ def from_json(cls, _json, client_api: ApiClient):
227
+ return cls(_dict=_json, client_api=client_api)
228
+
229
+ def to_json(self) -> dict:
230
+ return self._dict.copy()
231
+
232
+
233
+ class KubernetesCompute(Compute):
234
+ cluster: ComputeCluster = entities.DlProperty(location=['cluster'], _kls='ComputeCluster')
235
+
236
+ @classmethod
237
+ def from_json(cls, _json, client_api: ApiClient):
238
+ return cls(_dict=_json, client_api=client_api)
239
+
240
+ def to_json(self) -> dict:
241
+ return self._dict.copy()
@@ -1,10 +1,15 @@
1
1
  from collections import namedtuple
2
- from typing import List, Union
2
+ from typing import List, Union, Tuple
3
3
  import traceback
4
4
  import enum
5
+ import tempfile
6
+ import inspect
7
+ import os
8
+ import typing
5
9
 
6
- from .. import entities, repositories, exceptions
10
+ from .. import entities, repositories, exceptions, assets
7
11
  from ..services.api_client import ApiClient
12
+ from . import package_defaults
8
13
 
9
14
 
10
15
  class SlotType(str, enum.Enum):
@@ -29,6 +34,18 @@ DEFAULT_STOPS = {SlotType.ITEM_VIEWER: {"type": "itemViewer",
29
34
  }
30
35
  }
31
36
 
37
+ DEFAULT_RUNTIME = {
38
+ "podType": "regular-xs",
39
+ "concurrency": 1,
40
+ "runnerImage": "docker.io/dataloopai/dtlpy-agent:cpu.py3.10.opencv",
41
+ "autoscaler": {
42
+ "type": "rabbitmq",
43
+ "minReplicas": 0,
44
+ "maxReplicas": 2,
45
+ "queueLength": 100
46
+ }
47
+ }
48
+
32
49
 
33
50
  class Slot(entities.DlEntity):
34
51
  type: str = entities.DlProperty(location=['type'], _type=str)
@@ -468,3 +485,299 @@ class Dpk(entities.DlEntity):
468
485
  )
469
486
 
470
487
  return res
488
+
489
+ @staticmethod
490
+ def _parse_function_io(func) -> Tuple[List[dict], List[dict]]:
491
+ """
492
+ Parse function inputs and outputs from function signature and type hints.
493
+
494
+ This helper function extracts:
495
+ - Inputs: from function parameters (inspect.signature)
496
+ - Outputs: from return type hints (typing.get_type_hints)
497
+
498
+ :param func: The function to parse
499
+ :return: Tuple of (inputs, outputs) where each is a list of dicts with 'name' and 'type' keys
500
+ :rtype: Tuple[List[dict], List[dict]]
501
+ """
502
+ # ============================================
503
+ # PARSE INPUTS FROM FUNCTION SIGNATURE
504
+ # ============================================
505
+ # Get all parameter names from the function signature
506
+ params = list(inspect.signature(func).parameters)
507
+ inputs = []
508
+
509
+ # Create a mapping of known input type names (lowercase) to PackageInputType values
510
+ # This allows matching parameter names like 'item', 'items', 'annotation', etc. to their types
511
+ inputs_types = {i.name.lower(): i.value for i in list(entities.PackageInputType)}
512
+
513
+ # Process each parameter
514
+ for arg in params:
515
+ # Check if the parameter name matches a known PackageInputType (case-insensitive)
516
+ # For example: 'item' -> PackageInputType.ITEM, 'items' -> PackageInputType.ITEMS
517
+ if arg in inputs_types:
518
+ inpt_type = inputs_types[arg]
519
+ else:
520
+ # If parameter name doesn't match a known type, default to JSON
521
+ inpt_type = entities.PackageInputType.JSON
522
+
523
+ # Create input dict with name and type
524
+ inputs.append({
525
+ 'name': arg,
526
+ 'type': inpt_type
527
+ })
528
+
529
+ # ============================================
530
+ # PARSE OUTPUTS FROM TYPE HINTS
531
+ # ============================================
532
+ outputs = []
533
+ try:
534
+ # Get return type hint from function annotations
535
+ # Returns None if no return type is specified
536
+ hint_outputs = typing.get_type_hints(func).get('return', None)
537
+
538
+ if hint_outputs is not None:
539
+ # ============================================
540
+ # STEP 1: Extract output types from type hint
541
+ # ============================================
542
+ # Handle different return type patterns:
543
+ # - Tuple[Type1, Type2, ...] -> multiple outputs
544
+ # - List[Type] -> single output that's a list
545
+ # - Type -> single output
546
+ output_types = []
547
+
548
+ if hasattr(hint_outputs, '__origin__') and hint_outputs.__origin__ is tuple:
549
+ # Multiple returns: Tuple[Type1, Type2, ...]
550
+ # Extract all types from the tuple
551
+ output_types = list(hint_outputs.__args__) if hasattr(hint_outputs, '__args__') else []
552
+ elif hasattr(hint_outputs, '__args__'):
553
+ # Single generic type (e.g., List[Item], Dict[str, int])
554
+ # Extract the inner type from the generic
555
+ output_types = [hint_outputs.__args__[0]]
556
+ else:
557
+ # Single simple type (e.g., Item, str, int)
558
+ output_types = [hint_outputs]
559
+
560
+ # ============================================
561
+ # STEP 2: Process each output type
562
+ # ============================================
563
+ for idx, output_type in enumerate(output_types):
564
+ io_type = output_type
565
+ is_list = False
566
+
567
+ # ============================================
568
+ # STEP 2a: Check if it's a List type
569
+ # ============================================
570
+ # Handle List[Type] patterns (e.g., List[Item], List[Annotation])
571
+ if hasattr(io_type, '__origin__'):
572
+ origin = io_type.__origin__
573
+ origin_str = str(origin)
574
+
575
+ # Check if origin is list or typing.List
576
+ # This handles both 'list' and 'typing.List' cases
577
+ if origin is list or origin_str.startswith('typing.List') or origin_str.startswith('<class \'list\'>'):
578
+ is_list = True
579
+ # Extract inner type from List[InnerType]
580
+ # Example: List[Item] -> extract 'Item'
581
+ if hasattr(io_type, '__args__') and len(io_type.__args__) > 0:
582
+ io_type = io_type.__args__[0]
583
+
584
+ # ============================================
585
+ # STEP 2b: Handle special type cases
586
+ # ============================================
587
+ # Handle Enum types - convert to string name
588
+ if isinstance(io_type, enum.Enum):
589
+ io_type = io_type.name
590
+
591
+ # Handle nested generic types (only if not already extracted from List)
592
+ # Example: Optional[List[Item]] -> extract List[Item] first, then Item
593
+ if not is_list and hasattr(io_type, '__args__'):
594
+ io_type = io_type.__args__[0]
595
+
596
+ # ============================================
597
+ # STEP 2c: Extract type name as string
598
+ # ============================================
599
+ # Convert type to string representation
600
+ if isinstance(io_type, type):
601
+ # Direct type object (e.g., Item class) -> get class name
602
+ type_str = io_type.__name__
603
+ else:
604
+ # Type hint object -> convert to string
605
+ type_str = str(io_type)
606
+ # Extract class name from fully qualified name
607
+ # Example: "dtlpy.entities.item.Item" -> "Item"
608
+ if '.' in type_str:
609
+ type_str = type_str.rsplit('.', maxsplit=1)[-1]
610
+
611
+ # ============================================
612
+ # STEP 2d: Map type string to PackageInputType
613
+ # ============================================
614
+ # Map Python type names to PackageInputType enum values
615
+ # Special case: 'str' maps to STRING
616
+ if type_str == 'str':
617
+ mapped_type = entities.PackageInputType.STRING
618
+ else:
619
+ mapped_type = None
620
+
621
+ # If it's a list, try to find the array version first
622
+ # Example: Item -> ITEMS, Annotation -> ANNOTATIONS
623
+ if is_list:
624
+ array_type_name = f"{type_str.upper()}S" # Item -> ITEMS
625
+ for pkg_input_type in entities.PackageInputType:
626
+ if pkg_input_type.name.upper() == array_type_name:
627
+ mapped_type = pkg_input_type
628
+ break
629
+
630
+ # If not found or not a list, try the regular type
631
+ # Example: Item -> ITEM, Annotation -> ANNOTATION
632
+ if mapped_type is None:
633
+ for pkg_input_type in entities.PackageInputType:
634
+ if pkg_input_type.name.upper() == type_str.upper():
635
+ mapped_type = pkg_input_type
636
+ break
637
+
638
+ # Default to JSON if no match found
639
+ # This handles unknown types gracefully
640
+ if mapped_type is None:
641
+ mapped_type = entities.PackageInputType.JSON
642
+
643
+ # ============================================
644
+ # STEP 2e: Create output dict
645
+ # ============================================
646
+ # Name outputs: 'output' for single, 'output_0', 'output_1', etc. for multiple
647
+ output_name = 'output' if len(output_types) == 1 else f'output_{idx}'
648
+ outputs.append({
649
+ 'name': output_name,
650
+ 'type': mapped_type
651
+ })
652
+ except Exception:
653
+ # If type hints extraction fails (e.g., no type hints, invalid syntax),
654
+ # leave outputs empty - this is not a fatal error
655
+ pass
656
+
657
+ return inputs, outputs
658
+
659
+ @classmethod
660
+ def from_function(
661
+ cls,
662
+ func,
663
+ name: str = None,
664
+ version: str = '1.0.0',
665
+ description: str = None,
666
+ project: 'entities.Project' = None,
667
+ client_api: ApiClient = None,
668
+ scope: str = 'project',
669
+ runtime: dict = None,
670
+ execution_timeout: int = 3600,
671
+ ) -> 'entities.Dpk':
672
+ """
673
+ Build a DPK from a Python function (codebase + components). Does not publish or install.
674
+ Runtime is held on the service component (modules have no runtime). Use the runtime param to override defaults.
675
+
676
+ :param Callable func: Function to deploy
677
+ :param str name: DPK name (default: function __name__)
678
+ :param str version: DPK version (default: '1.0.0')
679
+ :param str description: DPK description
680
+ :param entities.Project project: Project (required)
681
+ :param ApiClient client_api: API client (required)
682
+ :param str scope: 'project' or 'organization'
683
+ :param dict runtime: podType, concurrency, runnerImage, autoscaler; default: DEFAULT_RUNTIME
684
+ :param int execution_timeout: Service timeout in seconds (default: 3600)
685
+ :return: Built DPK (with codebase); use Service.from_function to publish, install, and get the Service
686
+ :rtype: dtlpy.entities.Dpk
687
+ """
688
+ if client_api is None:
689
+ raise ValueError('client_api is required')
690
+ if project is None:
691
+ raise ValueError('project is required for codebase packing')
692
+
693
+ # Get function name if name not provided
694
+ if name is None:
695
+ name = func.__name__
696
+
697
+ # Resolve runtime: use copy to avoid mutating caller's dict or DEFAULT_RUNTIME
698
+ if runtime is None:
699
+ runtime = dict(DEFAULT_RUNTIME)
700
+ else:
701
+ runtime = dict(runtime)
702
+
703
+ # Create temporary directory for the function code
704
+ dpk_dir = tempfile.mkdtemp()
705
+
706
+ # Create main.py file with the function
707
+ main_file = os.path.join(dpk_dir, package_defaults.DEFAULT_PACKAGE_ENTRY_POINT)
708
+
709
+ # Read the partial main template (ServiceRunner class structure)
710
+ with open(assets.paths.PARTIAL_MAIN_FILEPATH, 'r') as f:
711
+ main_template = f.read()
712
+
713
+ # Extract function source code and adjust indentation
714
+ lines = inspect.getsourcelines(func)
715
+ tabs_diff = lines[0][0].count(' ') - 1
716
+ for line_index in range(len(lines[0])):
717
+ line_tabs = lines[0][line_index].count(' ') - tabs_diff
718
+ lines[0][line_index] = (' ' * line_tabs) + lines[0][line_index].strip() + '\n'
719
+
720
+ method_func_string = "".join(lines[0])
721
+
722
+ # Write main.py with ServiceRunner class and function
723
+ with open(main_file, 'w') as f:
724
+ f.write(f'{main_template}\n @staticmethod\n{method_func_string}')
725
+
726
+ # Parse function inputs and outputs from signature and type hints
727
+ inputs, outputs = cls._parse_function_io(func)
728
+
729
+ # Build module dict (no runtime on module/functions)
730
+ function_dict = {
731
+ 'name': func.__name__,
732
+ 'input': inputs,
733
+ 'output': outputs,
734
+ }
735
+ module_dict = {
736
+ 'name': package_defaults.DEFAULT_PACKAGE_MODULE_NAME,
737
+ 'entryPoint': package_defaults.DEFAULT_PACKAGE_ENTRY_POINT,
738
+ 'className': package_defaults.DEFAULT_PACKAGE_CLASS_NAME,
739
+ 'functions': [function_dict],
740
+ }
741
+
742
+ # Service component (smart-search style): holds runtime, references module
743
+ service_name = f"{name}-service".replace("_", "-")
744
+ service_entry = {
745
+ "name": service_name,
746
+ "moduleName": package_defaults.DEFAULT_PACKAGE_MODULE_NAME,
747
+ "packageRevision": "latest",
748
+ "runtime": runtime,
749
+ "executionTimeout": execution_timeout,
750
+ }
751
+
752
+ components_dict = {
753
+ "modules": [module_dict],
754
+ "services": [service_entry],
755
+ }
756
+
757
+ # Create DPK entity
758
+ dpk_json = {
759
+ 'name': name,
760
+ 'version': version,
761
+ 'display_name': name,
762
+ 'description': description or f'DPK created from function {func.__name__}',
763
+ 'scope': scope,
764
+ 'components': components_dict,
765
+ 'context': {
766
+ 'project': project.id
767
+ }
768
+ }
769
+
770
+ dpk = cls.from_json(
771
+ _json=dpk_json,
772
+ client_api=client_api,
773
+ project=project
774
+ )
775
+
776
+ # Pack the temporary directory as codebase
777
+ dpk.codebase = project.codebases.pack(
778
+ directory=dpk_dir,
779
+ name=name,
780
+ extension='dpk'
781
+ )
782
+
783
+ return dpk