UncountablePythonSDK 0.0.47__tar.gz → 0.0.49__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.

Potentially problematic release.


This version of UncountablePythonSDK might be problematic. Click here for more details.

Files changed (252) hide show
  1. {uncountablepythonsdk-0.0.47/UncountablePythonSDK.egg-info → uncountablepythonsdk-0.0.49}/PKG-INFO +2 -1
  2. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49/UncountablePythonSDK.egg-info}/PKG-INFO +2 -1
  3. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/UncountablePythonSDK.egg-info/SOURCES.txt +1 -0
  4. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/UncountablePythonSDK.egg-info/requires.txt +1 -0
  5. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/examples/invoke_uploader.py +4 -4
  6. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/filesystem_utils/__init__.py +2 -0
  7. uncountablepythonsdk-0.0.49/pkgs/filesystem_utils/_s3_session.py +116 -0
  8. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/filesystem_utils/file_type_utils.py +10 -0
  9. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pyproject.toml +2 -1
  10. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/executors/generic_upload_executor.py +45 -14
  11. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/uploader/invoke_uploader.py +2 -2
  12. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/async_batch_processor.py +5 -5
  13. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/client_base.py +5 -5
  14. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/generic_upload_t.py +0 -1
  15. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/job_definition.py +2 -0
  16. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/job_definition_t.py +26 -1
  17. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/.github/workflows/documentation.yml +0 -0
  18. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/.github/workflows/publish.yml +0 -0
  19. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/.gitignore +0 -0
  20. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/README.md +0 -0
  21. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/UncountablePythonSDK.egg-info/dependency_links.txt +0 -0
  22. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/UncountablePythonSDK.egg-info/top_level.txt +0 -0
  23. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/.gitignore +0 -0
  24. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/conf.py +0 -0
  25. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/index.md +0 -0
  26. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/justfile +0 -0
  27. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/quickstart.md +0 -0
  28. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/requirements.txt +0 -0
  29. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/android-chrome-192x192.png +0 -0
  30. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/android-chrome-512x512.png +0 -0
  31. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/apple-touch-icon.png +0 -0
  32. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/browserconfig.xml +0 -0
  33. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/favicon-16x16.png +0 -0
  34. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/favicon-32x32.png +0 -0
  35. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/manifest.json +0 -0
  36. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/mstile-150x150.png +0 -0
  37. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/favicons/safari-pinned-tab.svg +0 -0
  38. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/docs/static/logo_blue.png +0 -0
  39. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/examples/async_batch.py +0 -0
  40. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/examples/create_entity.py +0 -0
  41. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/examples/edit_recipe_inputs.py +0 -0
  42. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/examples/upload_files.py +0 -0
  43. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/__init__.py +0 -0
  44. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/argument_parser/__init__.py +0 -0
  45. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/argument_parser/_is_enum.py +0 -0
  46. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/argument_parser/_is_namedtuple.py +0 -0
  47. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/argument_parser/argument_parser.py +0 -0
  48. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/argument_parser/case_convert.py +0 -0
  49. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/filesystem_utils/_gdrive_session.py +0 -0
  50. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/filesystem_utils/_local_session.py +0 -0
  51. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/filesystem_utils/_sftp_session.py +0 -0
  52. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/filesystem_utils/filesystem_session.py +0 -0
  53. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization/__init__.py +0 -0
  54. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization/missing_sentry.py +0 -0
  55. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization/opaque_key.py +0 -0
  56. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization/serial_class.py +0 -0
  57. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization/serial_union.py +0 -0
  58. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization/yaml.py +0 -0
  59. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization_util/__init__.py +0 -0
  60. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization_util/_get_type_for_serialization.py +0 -0
  61. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization_util/convert_to_snakecase.py +0 -0
  62. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/serialization_util/serialization_helpers.py +0 -0
  63. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/strenum_compat/__init__.py +0 -0
  64. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/strenum_compat/strenum_compat.py +0 -0
  65. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/__init__.py +0 -0
  66. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/__main__.py +0 -0
  67. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/actions_registry/__init__.py +0 -0
  68. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/actions_registry/__main__.py +0 -0
  69. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/actions_registry/emit_typescript.py +0 -0
  70. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/builder.py +0 -0
  71. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/config.py +0 -0
  72. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/emit_io_ts.py +0 -0
  73. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/emit_open_api.py +0 -0
  74. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/emit_open_api_util.py +0 -0
  75. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/emit_python.py +0 -0
  76. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/emit_typescript.py +0 -0
  77. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/emit_typescript_util.py +0 -0
  78. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/load_types.py +0 -0
  79. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/open_api_util.py +0 -0
  80. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/parts/base.py.prepart +0 -0
  81. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/parts/base.ts.prepart +0 -0
  82. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/test.py +0 -0
  83. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/type_info/__main__.py +0 -0
  84. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/type_info/emit_type_info.py +0 -0
  85. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/util.py +0 -0
  86. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/value_spec/__init__.py +0 -0
  87. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/value_spec/__main__.py +0 -0
  88. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/value_spec/convert_type.py +0 -0
  89. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/value_spec/emit_python.py +0 -0
  90. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/pkgs/type_spec/value_spec/types.py +0 -0
  91. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/setup.cfg +0 -0
  92. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/__init__.py +0 -0
  93. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/core/__init__.py +0 -0
  94. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/core/async_batch.py +0 -0
  95. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/core/client.py +0 -0
  96. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/core/file_upload.py +0 -0
  97. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/core/types.py +0 -0
  98. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/__init__.py +0 -0
  99. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/construct_client.py +0 -0
  100. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/cron.py +0 -0
  101. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/db/__init__.py +0 -0
  102. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/db/connect.py +0 -0
  103. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/entrypoint.py +0 -0
  104. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/executors/__init__.py +0 -0
  105. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/executors/executors.py +0 -0
  106. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/executors/script_executor.py +0 -0
  107. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/job.py +0 -0
  108. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/secret_retrieval/__init__.py +0 -0
  109. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/secret_retrieval/retrieve_secret.py +0 -0
  110. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/integration/server.py +0 -0
  111. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/py.typed +0 -0
  112. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/__init__.py +0 -0
  113. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/__init__.py +0 -0
  114. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/batch/__init__.py +0 -0
  115. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/batch/execute_batch.py +0 -0
  116. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/batch/execute_batch_load_async.py +0 -0
  117. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/chemical/__init__.py +0 -0
  118. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/chemical/convert_chemical_formats.py +0 -0
  119. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/__init__.py +0 -0
  120. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/create_entities.py +0 -0
  121. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/create_entity.py +0 -0
  122. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/get_entities_data.py +0 -0
  123. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/list_entities.py +0 -0
  124. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/lock_entity.py +0 -0
  125. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/resolve_entity_ids.py +0 -0
  126. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/set_values.py +0 -0
  127. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/transition_entity_phase.py +0 -0
  128. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/entity/unlock_entity.py +0 -0
  129. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/equipment/__init__.py +0 -0
  130. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/equipment/associate_equipment_input.py +0 -0
  131. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/field_options/__init__.py +0 -0
  132. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/field_options/upsert_field_options.py +0 -0
  133. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/id_source/__init__.py +0 -0
  134. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/id_source/list_id_source.py +0 -0
  135. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/id_source/match_id_source.py +0 -0
  136. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/input_groups/__init__.py +0 -0
  137. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/input_groups/get_input_group_names.py +0 -0
  138. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/__init__.py +0 -0
  139. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/create_inputs.py +0 -0
  140. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/get_input_data.py +0 -0
  141. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/get_input_names.py +0 -0
  142. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/get_inputs_data.py +0 -0
  143. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/set_input_attribute_values.py +0 -0
  144. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/set_input_category.py +0 -0
  145. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/set_input_subcategories.py +0 -0
  146. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/inputs/set_intermediate_type.py +0 -0
  147. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/material_families/__init__.py +0 -0
  148. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/material_families/update_entity_material_families.py +0 -0
  149. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/outputs/__init__.py +0 -0
  150. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/outputs/get_output_data.py +0 -0
  151. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/outputs/get_output_names.py +0 -0
  152. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/outputs/resolve_output_conditions.py +0 -0
  153. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/permissions/__init__.py +0 -0
  154. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/permissions/set_core_permissions.py +0 -0
  155. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/project/__init__.py +0 -0
  156. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/project/get_projects.py +0 -0
  157. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/project/get_projects_data.py +0 -0
  158. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipe_links/__init__.py +0 -0
  159. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipe_links/create_recipe_link.py +0 -0
  160. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipe_links/remove_recipe_link.py +0 -0
  161. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipe_metadata/__init__.py +0 -0
  162. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +0 -0
  163. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/__init__.py +0 -0
  164. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/add_recipe_to_project.py +0 -0
  165. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/archive_recipes.py +0 -0
  166. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/associate_recipe_as_input.py +0 -0
  167. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/associate_recipe_as_lot.py +0 -0
  168. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/create_recipe.py +0 -0
  169. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/create_recipes.py +0 -0
  170. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/disassociate_recipe_as_input.py +0 -0
  171. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/edit_recipe_inputs.py +0 -0
  172. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/get_curve.py +0 -0
  173. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/get_recipe_calculations.py +0 -0
  174. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/get_recipe_links.py +0 -0
  175. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/get_recipe_names.py +0 -0
  176. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/get_recipe_output_metadata.py +0 -0
  177. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/get_recipes_data.py +0 -0
  178. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/lock_recipes.py +0 -0
  179. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/remove_recipe_from_project.py +0 -0
  180. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/set_recipe_inputs.py +0 -0
  181. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/set_recipe_metadata.py +0 -0
  182. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/set_recipe_output_annotations.py +0 -0
  183. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/set_recipe_outputs.py +0 -0
  184. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/set_recipe_tags.py +0 -0
  185. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/unarchive_recipes.py +0 -0
  186. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/recipes/unlock_recipes.py +0 -0
  187. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/triggers/__init__.py +0 -0
  188. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/triggers/run_trigger.py +0 -0
  189. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/api/uploader/__init__.py +0 -0
  190. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/async_batch.py +0 -0
  191. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/async_batch_t.py +0 -0
  192. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/base.py +0 -0
  193. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/base_t.py +0 -0
  194. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/calculations.py +0 -0
  195. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/calculations_t.py +0 -0
  196. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/chemical_structure.py +0 -0
  197. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/chemical_structure_t.py +0 -0
  198. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/client_config.py +0 -0
  199. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/client_config_t.py +0 -0
  200. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/curves.py +0 -0
  201. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/curves_t.py +0 -0
  202. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/entity.py +0 -0
  203. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/entity_t.py +0 -0
  204. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/experiment_groups.py +0 -0
  205. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/experiment_groups_t.py +0 -0
  206. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/field_values.py +0 -0
  207. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/field_values_t.py +0 -0
  208. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/fields.py +0 -0
  209. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/fields_t.py +0 -0
  210. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/generic_upload.py +0 -0
  211. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/id_source.py +0 -0
  212. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/id_source_t.py +0 -0
  213. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/identifier.py +0 -0
  214. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/identifier_t.py +0 -0
  215. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/input_attributes.py +0 -0
  216. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/input_attributes_t.py +0 -0
  217. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/inputs.py +0 -0
  218. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/inputs_t.py +0 -0
  219. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/outputs.py +0 -0
  220. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/outputs_t.py +0 -0
  221. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/permissions.py +0 -0
  222. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/permissions_t.py +0 -0
  223. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/phases.py +0 -0
  224. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/phases_t.py +0 -0
  225. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/post_base.py +0 -0
  226. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/post_base_t.py +0 -0
  227. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_identifiers.py +0 -0
  228. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_identifiers_t.py +0 -0
  229. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_inputs.py +0 -0
  230. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_inputs_t.py +0 -0
  231. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_links.py +0 -0
  232. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_links_t.py +0 -0
  233. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_metadata.py +0 -0
  234. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_metadata_t.py +0 -0
  235. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_output_metadata.py +0 -0
  236. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_output_metadata_t.py +0 -0
  237. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_tags.py +0 -0
  238. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_tags_t.py +0 -0
  239. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_workflow_steps.py +0 -0
  240. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipe_workflow_steps_t.py +0 -0
  241. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipes.py +0 -0
  242. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/recipes_t.py +0 -0
  243. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/response.py +0 -0
  244. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/response_t.py +0 -0
  245. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/secret_retrieval.py +0 -0
  246. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/secret_retrieval_t.py +0 -0
  247. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/units.py +0 -0
  248. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/units_t.py +0 -0
  249. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/users.py +0 -0
  250. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/users_t.py +0 -0
  251. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/workflows.py +0 -0
  252. {uncountablepythonsdk-0.0.47 → uncountablepythonsdk-0.0.49}/uncountable/types/workflows_t.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.47
3
+ Version: 0.0.49
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -28,6 +28,7 @@ Requires-Dist: google-api-python-client==2.*
28
28
  Requires-Dist: tqdm==4.*
29
29
  Requires-Dist: pysftp==0.*
30
30
  Requires-Dist: paramiko==3.*
31
+ Requires-Dist: boto3==1.*
31
32
  Provides-Extra: test
32
33
  Requires-Dist: mypy==1.*; extra == "test"
33
34
  Requires-Dist: ruff==0.*; extra == "test"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.47
3
+ Version: 0.0.49
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -28,6 +28,7 @@ Requires-Dist: google-api-python-client==2.*
28
28
  Requires-Dist: tqdm==4.*
29
29
  Requires-Dist: pysftp==0.*
30
30
  Requires-Dist: paramiko==3.*
31
+ Requires-Dist: boto3==1.*
31
32
  Provides-Extra: test
32
33
  Requires-Dist: mypy==1.*; extra == "test"
33
34
  Requires-Dist: ruff==0.*; extra == "test"
@@ -38,6 +38,7 @@ pkgs/argument_parser/case_convert.py
38
38
  pkgs/filesystem_utils/__init__.py
39
39
  pkgs/filesystem_utils/_gdrive_session.py
40
40
  pkgs/filesystem_utils/_local_session.py
41
+ pkgs/filesystem_utils/_s3_session.py
41
42
  pkgs/filesystem_utils/_sftp_session.py
42
43
  pkgs/filesystem_utils/file_type_utils.py
43
44
  pkgs/filesystem_utils/filesystem_session.py
@@ -10,6 +10,7 @@ google-api-python-client==2.*
10
10
  tqdm==4.*
11
11
  pysftp==0.*
12
12
  paramiko==3.*
13
+ boto3==1.*
13
14
 
14
15
  [test]
15
16
  mypy==1.*
@@ -10,14 +10,14 @@ client = Client(
10
10
  api_secret_key=os.environ["UNC_API_SECRET_KEY"],
11
11
  ),
12
12
  )
13
- uploaded = client.upload_files(
13
+ uploaded_file = client.upload_files(
14
14
  file_uploads=[
15
15
  MediaFileUpload(path="~/Downloads/my_file_to_upload.csv"),
16
16
  ]
17
- )
17
+ )[0]
18
18
 
19
19
  client.invoke_uploader(
20
- file_ids=[file.file_id for file in uploaded],
20
+ file_id=uploaded_file.file_id,
21
21
  uploader_key=IdentifierKeyId(id=48),
22
- material_family_keys=[IdentifierKeyId(id=1)],
22
+ material_family_key=IdentifierKeyId(id=1),
23
23
  )
@@ -5,12 +5,14 @@ from ._gdrive_session import list_gdrive_files as list_gdrive_files
5
5
  from ._gdrive_session import move_gdrive_file as move_gdrive_file
6
6
  from ._gdrive_session import upload_file_gdrive as upload_file_gdrive
7
7
  from ._local_session import LocalSession as LocalSession
8
+ from ._s3_session import S3Session as S3Session
8
9
  from ._sftp_session import SFTPSession as SFTPSession
9
10
  from ._sftp_session import list_sftp_files as list_sftp_files
10
11
  from ._sftp_session import move_sftp_files as move_sftp_files
11
12
  from .file_type_utils import FileObjectData as FileObjectData
12
13
  from .file_type_utils import FileSystemFileReference as FileSystemFileReference
13
14
  from .file_type_utils import FileSystemObject as FileSystemObject
15
+ from .file_type_utils import FileSystemS3Config as FileSystemS3Config
14
16
  from .file_type_utils import FileSystemSFTPConfig as FileSystemSFTPConfig
15
17
  from .file_type_utils import FileTransfer as FileTransfer
16
18
  from .file_type_utils import IncompatibleFileReference as IncompatibleFileReference
@@ -0,0 +1,116 @@
1
+ from io import BytesIO
2
+
3
+ from boto3.session import Session
4
+
5
+ from pkgs.filesystem_utils.file_type_utils import (
6
+ FileObjectData,
7
+ FileSystemFileReference,
8
+ FileSystemObject,
9
+ FileSystemS3Config,
10
+ FileTransfer,
11
+ IncompatibleFileReference,
12
+ )
13
+
14
+ from .filesystem_session import FileSystemSession
15
+
16
+
17
+ def _add_slash(prefix: str) -> str:
18
+ if len(prefix) > 0 and prefix[-1] != "/":
19
+ prefix = prefix + "/"
20
+ return prefix
21
+
22
+
23
+ class S3Session(FileSystemSession):
24
+ config: FileSystemS3Config
25
+
26
+ def __init__(self, s3_config: FileSystemS3Config) -> None:
27
+ super().__init__()
28
+ self.config = s3_config
29
+
30
+ def start(self) -> None:
31
+ session = Session(region_name=self.config.region_name)
32
+ s3_resource = session.resource(
33
+ service_name="s3",
34
+ endpoint_url=self.config.endpoint_url,
35
+ aws_access_key_id=self.config.access_key_id,
36
+ aws_secret_access_key=self.config.secret_access_key,
37
+ aws_session_token=self.config.session_token,
38
+ )
39
+
40
+ self.bucket = s3_resource.Bucket(self.config.bucket_name)
41
+
42
+ def __enter__(self) -> "S3Session":
43
+ self.start()
44
+ return self
45
+
46
+ def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None:
47
+ self.bucket = None
48
+
49
+ def list_files(
50
+ self,
51
+ dir_path: FileSystemObject,
52
+ *,
53
+ recursive: bool = False,
54
+ valid_extensions: list[str] | None = None,
55
+ ) -> list[FileSystemObject]:
56
+ if recursive:
57
+ raise NotImplementedError("recursive file listings not implemented for s3")
58
+
59
+ if not isinstance(dir_path, FileSystemFileReference):
60
+ raise IncompatibleFileReference()
61
+
62
+ assert self.bucket is not None, "call to list_files on uninitialized s3 session"
63
+
64
+ filesystem_references: list[FileSystemObject] = []
65
+ for obj in self.bucket.objects.filter(Prefix=dir_path.filepath):
66
+ if valid_extensions is None or any(
67
+ obj.key.endswith(valid_extension) for valid_extension in valid_extensions
68
+ ):
69
+ filesystem_references.append(FileSystemFileReference(obj.key))
70
+
71
+ return filesystem_references
72
+
73
+ def download_files(
74
+ self,
75
+ filepaths: list[FileSystemObject],
76
+ ) -> list[FileObjectData]:
77
+ downloaded_files: list[FileObjectData] = []
78
+ assert (
79
+ self.bucket is not None
80
+ ), "call to download_files on uninitialized s3 session"
81
+
82
+ for file_object in filepaths:
83
+ if (
84
+ not isinstance(file_object, FileSystemFileReference)
85
+ or file_object.filename is None
86
+ ):
87
+ raise IncompatibleFileReference()
88
+ s3_file_obj = self.bucket.Object(_add_slash(file_object.filepath))
89
+ response = s3_file_obj.get()
90
+ file_obj_bytes = response["Body"].read()
91
+ downloaded_files.append(
92
+ FileObjectData(
93
+ file_data=file_obj_bytes,
94
+ file_IO=BytesIO(file_obj_bytes),
95
+ filename=file_object.filename,
96
+ filepath=file_object.filepath,
97
+ )
98
+ )
99
+
100
+ return downloaded_files
101
+
102
+ def move_files(self, file_mappings: list[FileTransfer]) -> None:
103
+ assert self.bucket is not None, "call to move_files on uninitialized s3 session"
104
+
105
+ for src_file, dest_file in file_mappings:
106
+ if not isinstance(src_file, FileSystemFileReference) or not isinstance(
107
+ dest_file, FileSystemFileReference
108
+ ):
109
+ raise IncompatibleFileReference()
110
+ self.bucket.Object(_add_slash(dest_file.filepath)).copy_from(
111
+ CopySource={
112
+ "Bucket": self.bucket.name,
113
+ "Key": _add_slash(src_file.filepath),
114
+ }
115
+ )
116
+ self.bucket.Object(_add_slash(src_file.filepath)).delete()
@@ -59,3 +59,13 @@ class FileSystemSFTPConfig:
59
59
  password: str | None = None
60
60
  valid_extensions: Optional[tuple[str]] = None
61
61
  recursive: bool = True
62
+
63
+
64
+ @dataclass(kw_only=True)
65
+ class FileSystemS3Config:
66
+ endpoint_url: str
67
+ bucket_name: str
68
+ region_name: Optional[str]
69
+ access_key_id: Optional[str]
70
+ secret_access_key: Optional[str]
71
+ session_token: Optional[str]
@@ -59,7 +59,8 @@ dependencies = [
59
59
  "google-api-python-client == 2.*",
60
60
  "tqdm == 4.*",
61
61
  "pysftp == 0.*",
62
- "paramiko == 3.*"
62
+ "paramiko == 3.*",
63
+ "boto3 == 1.*"
63
64
  ]
64
65
  dynamic = ["version"]
65
66
 
@@ -9,12 +9,13 @@ from pkgs.filesystem_utils import (
9
9
  FileObjectData,
10
10
  FileSystemFileReference,
11
11
  FileSystemObject,
12
+ FileSystemS3Config,
12
13
  FileSystemSFTPConfig,
13
14
  FileTransfer,
15
+ S3Session,
14
16
  SFTPSession,
15
17
  )
16
18
  from pkgs.filesystem_utils.filesystem_session import FileSystemSession
17
- from uncountable.core.async_batch import AsyncBatchProcessor
18
19
  from uncountable.core.file_upload import DataFileUpload, FileUpload
19
20
  from uncountable.integration.job import Job, JobArguments, JobLogger
20
21
  from uncountable.integration.secret_retrieval import retrieve_secret
@@ -24,8 +25,10 @@ from uncountable.types.generic_upload_t import (
24
25
  )
25
26
  from uncountable.types.job_definition_t import (
26
27
  GenericUploadDataSource,
28
+ GenericUploadDataSourceS3,
27
29
  GenericUploadDataSourceSFTP,
28
30
  JobResult,
31
+ S3CloudProvider,
29
32
  )
30
33
 
31
34
 
@@ -186,12 +189,48 @@ class GenericUploadJob(Job):
186
189
  pem_key=pem_key,
187
190
  )
188
191
  return SFTPSession(sftp_config=sftp_config)
192
+ case GenericUploadDataSourceS3():
193
+ if self.data_source.access_key_secret is not None:
194
+ secret_access_key = retrieve_secret(
195
+ self.data_source.access_key_secret,
196
+ profile_metadata=args.profile_metadata,
197
+ )
198
+ else:
199
+ secret_access_key = None
200
+
201
+ if self.data_source.endpoint_url is None:
202
+ assert (
203
+ self.data_source.cloud_provider is not None
204
+ ), "either cloud_provider or endpoint_url must be specified"
205
+ match self.data_source.cloud_provider:
206
+ case S3CloudProvider.AWS:
207
+ endpoint_url = "https://s3.amazonaws.com"
208
+ case S3CloudProvider.OVH:
209
+ assert (
210
+ self.data_source.region_name is not None
211
+ ), "region_name must be specified for cloud_provider OVH"
212
+ endpoint_url = (
213
+ f"https://s3.{self.data_source.region_name}.cloud.ovh.net"
214
+ )
215
+ else:
216
+ endpoint_url = self.data_source.endpoint_url
217
+
218
+ s3_config = FileSystemS3Config(
219
+ endpoint_url=endpoint_url,
220
+ bucket_name=self.data_source.bucket_name,
221
+ region_name=self.data_source.region_name,
222
+ access_key_id=self.data_source.access_key_id,
223
+ secret_access_key=secret_access_key,
224
+ session_token=None,
225
+ )
226
+
227
+ return S3Session(s3_config=s3_config)
189
228
 
190
229
  def run(self, args: JobArguments) -> JobResult:
191
230
  client = args.client
231
+ batch_processor = args.batch_processor
192
232
  logger = args.logger
193
233
 
194
- batch_executor = AsyncBatchProcessor(client=client)
195
234
  with self._construct_filesystem_session(args) as filesystem_session:
196
235
  files_to_upload: list[FileUpload] = []
197
236
  for remote_directory in self.remote_directories:
@@ -227,20 +266,12 @@ class GenericUploadJob(Job):
227
266
 
228
267
  file_ids = [file.file_id for file in uploaded_files]
229
268
 
230
- if self.upload_strategy.parse_files_individually:
269
+ for material_family_key in self.upload_strategy.material_family_keys:
231
270
  for file_id in file_ids:
232
- batch_executor.invoke_uploader(
233
- file_ids=[file_id],
271
+ batch_processor.invoke_uploader(
272
+ file_id=file_id,
234
273
  uploader_key=self.upload_strategy.uploader_key,
235
- material_family_keys=self.upload_strategy.material_family_keys,
274
+ material_family_key=material_family_key,
236
275
  )
237
- else:
238
- batch_executor.invoke_uploader(
239
- file_ids=file_ids,
240
- uploader_key=self.upload_strategy.uploader_key,
241
- material_family_keys=self.upload_strategy.material_family_keys,
242
- )
243
-
244
- batch_executor.send()
245
276
 
246
277
  return JobResult(success=True)
@@ -26,9 +26,9 @@ ENDPOINT_PATH = "api/external/uploader/invoke_uploader"
26
26
  # DO NOT MODIFY -- This file is generated by type_spec
27
27
  @dataclasses.dataclass(kw_only=True)
28
28
  class Arguments:
29
- file_ids: list[base_t.ObjectId]
29
+ file_id: base_t.ObjectId
30
30
  uploader_key: identifier_t.IdentifierKey
31
- material_family_keys: list[identifier_t.IdentifierKey]
31
+ material_family_key: identifier_t.IdentifierKey
32
32
 
33
33
 
34
34
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -160,19 +160,19 @@ class AsyncBatchProcessorBase(ABC):
160
160
  def invoke_uploader(
161
161
  self,
162
162
  *,
163
- file_ids: list[base_t.ObjectId],
163
+ file_id: base_t.ObjectId,
164
164
  uploader_key: identifier_t.IdentifierKey,
165
- material_family_keys: list[identifier_t.IdentifierKey],
165
+ material_family_key: identifier_t.IdentifierKey,
166
166
  depends_on: typing.Optional[list[str]] = None,
167
167
  ) -> async_batch_t.QueuedAsyncBatchRequest:
168
- """Runs files through an uploader.
168
+ """Runs a file through an uploader.
169
169
 
170
170
  :param depends_on: A list of batch reference keys to process before processing this request
171
171
  """
172
172
  args = invoke_uploader_t.Arguments(
173
- file_ids=file_ids,
173
+ file_id=file_id,
174
174
  uploader_key=uploader_key,
175
- material_family_keys=material_family_keys,
175
+ material_family_key=material_family_key,
176
176
  )
177
177
  json_data = serialize_for_api(args)
178
178
 
@@ -854,17 +854,17 @@ class ClientMethods(ABC):
854
854
  def invoke_uploader(
855
855
  self,
856
856
  *,
857
- file_ids: list[base_t.ObjectId],
857
+ file_id: base_t.ObjectId,
858
858
  uploader_key: identifier_t.IdentifierKey,
859
- material_family_keys: list[identifier_t.IdentifierKey],
859
+ material_family_key: identifier_t.IdentifierKey,
860
860
  ) -> invoke_uploader_t.Data:
861
- """Runs files through an uploader.
861
+ """Runs a file through an uploader.
862
862
 
863
863
  """
864
864
  args = invoke_uploader_t.Arguments(
865
- file_ids=file_ids,
865
+ file_id=file_id,
866
866
  uploader_key=uploader_key,
867
- material_family_keys=material_family_keys,
867
+ material_family_key=material_family_key,
868
868
  )
869
869
  api_request = APIRequest(
870
870
  method=invoke_uploader_t.ENDPOINT_METHOD,
@@ -36,6 +36,5 @@ class GenericRemoteDirectoryScope:
36
36
  class GenericUploadStrategy:
37
37
  uploader_key: identifier_t.IdentifierKey
38
38
  material_family_keys: list[identifier_t.IdentifierKey]
39
- parse_files_individually: bool
40
39
  skip_moving_files: bool = False
41
40
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -12,6 +12,8 @@ from .job_definition_t import JobExecutorBase as JobExecutorBase
12
12
  from .job_definition_t import JobExecutorScript as JobExecutorScript
13
13
  from .job_definition_t import GenericUploadDataSourceBase as GenericUploadDataSourceBase
14
14
  from .job_definition_t import GenericUploadDataSourceSFTP as GenericUploadDataSourceSFTP
15
+ from .job_definition_t import S3CloudProvider as S3CloudProvider
16
+ from .job_definition_t import GenericUploadDataSourceS3 as GenericUploadDataSourceS3
15
17
  from .job_definition_t import GenericUploadDataSource as GenericUploadDataSource
16
18
  from .job_definition_t import JobExecutorGenericUpload as JobExecutorGenericUpload
17
19
  from .job_definition_t import JobExecutor as JobExecutor
@@ -23,6 +23,7 @@ __all__: list[str] = [
23
23
  "CronJobDefinition",
24
24
  "GenericUploadDataSource",
25
25
  "GenericUploadDataSourceBase",
26
+ "GenericUploadDataSourceS3",
26
27
  "GenericUploadDataSourceSFTP",
27
28
  "GenericUploadDataSourceType",
28
29
  "JobDefinition",
@@ -36,6 +37,7 @@ __all__: list[str] = [
36
37
  "JobResult",
37
38
  "ProfileDefinition",
38
39
  "ProfileMetadata",
40
+ "S3CloudProvider",
39
41
  ]
40
42
 
41
43
 
@@ -58,6 +60,7 @@ class AuthRetrievalType(StrEnum):
58
60
  # DO NOT MODIFY -- This file is generated by type_spec
59
61
  class GenericUploadDataSourceType(StrEnum):
60
62
  SFTP = "sftp"
63
+ S3 = "s3"
61
64
 
62
65
 
63
66
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -94,13 +97,35 @@ class GenericUploadDataSourceSFTP(GenericUploadDataSourceBase):
94
97
  pem_secret: secret_retrieval_t.SecretRetrieval
95
98
 
96
99
 
100
+ # DO NOT MODIFY -- This file is generated by type_spec
101
+ class S3CloudProvider(StrEnum):
102
+ OVH = "ovh"
103
+ AWS = "aws"
104
+
105
+
106
+ # DO NOT MODIFY -- This file is generated by type_spec
107
+ @serial_class(
108
+ parse_require={"type"},
109
+ )
110
+ @dataclasses.dataclass(kw_only=True)
111
+ class GenericUploadDataSourceS3(GenericUploadDataSourceBase):
112
+ type: typing.Literal[GenericUploadDataSourceType.S3] = GenericUploadDataSourceType.S3
113
+ bucket_name: str
114
+ cloud_provider: typing.Optional[S3CloudProvider] = None
115
+ endpoint_url: typing.Optional[str] = None
116
+ region_name: typing.Optional[str] = None
117
+ access_key_id: typing.Optional[str] = None
118
+ access_key_secret: typing.Optional[secret_retrieval_t.SecretRetrieval] = None
119
+
120
+
97
121
  # DO NOT MODIFY -- This file is generated by type_spec
98
122
  GenericUploadDataSource = typing.Annotated[
99
- typing.Union[GenericUploadDataSourceSFTP],
123
+ typing.Union[GenericUploadDataSourceSFTP, GenericUploadDataSourceS3],
100
124
  serial_union_annotation(
101
125
  discriminator="type",
102
126
  discriminator_map={
103
127
  "sftp": GenericUploadDataSourceSFTP,
128
+ "s3": GenericUploadDataSourceS3,
104
129
  },
105
130
  ),
106
131
  ]