ob-metaflow-extensions 1.3.0__tar.gz → 1.3.1__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 (136) hide show
  1. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/PKG-INFO +1 -1
  2. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/__init__.py +3 -0
  3. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/_state_machine.py +9 -9
  4. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/app_cli.py +8 -8
  5. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/capsule.py +10 -12
  6. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/dependencies.py +1 -1
  7. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/secrets.py +1 -1
  8. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/utils.py +2 -2
  9. ob_metaflow_extensions-1.3.1/metaflow_extensions/outerbounds/plugins/s3_proxy/__init__.py +7 -0
  10. ob_metaflow_extensions-1.3.1/metaflow_extensions/outerbounds/plugins/s3_proxy/constants.py +8 -0
  11. ob_metaflow_extensions-1.3.1/metaflow_extensions/outerbounds/plugins/s3_proxy/exceptions.py +13 -0
  12. ob_metaflow_extensions-1.3.1/metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_api.py +93 -0
  13. ob_metaflow_extensions-1.3.1/metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_decorator.py +106 -0
  14. ob_metaflow_extensions-1.3.1/metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_manager.py +222 -0
  15. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/global_aliases_for_metaflow_package.py +33 -1
  16. ob_metaflow_extensions-1.3.1/metaflow_extensions/outerbounds/toplevel/s3_proxy.py +88 -0
  17. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/ob_metaflow_extensions.egg-info/PKG-INFO +1 -1
  18. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/ob_metaflow_extensions.egg-info/SOURCES.txt +7 -0
  19. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/setup.py +1 -1
  20. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/MANIFEST.in +0 -0
  21. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/README.md +0 -0
  22. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/__init__.py +0 -0
  23. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/config/__init__.py +0 -0
  24. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/__init__.py +0 -0
  25. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/app_cli.py +0 -0
  26. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/app_deploy_decorator.py +0 -0
  27. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/app_utils.py +0 -0
  28. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/consts.py +0 -0
  29. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/__init__.py +0 -0
  30. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/_vendor/__init__.py +0 -0
  31. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/__init__.py +0 -0
  32. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/spinners.py +0 -0
  33. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/app_config.py +0 -0
  34. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/artifacts.py +0 -0
  35. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/click_importer.py +0 -0
  36. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/code_package/__init__.py +0 -0
  37. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/code_package/code_packager.py +0 -0
  38. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/code_package/examples.py +0 -0
  39. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py +0 -0
  40. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config/cli_generator.py +0 -0
  41. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config/config_utils.py +0 -0
  42. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config/schema_export.py +0 -0
  43. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config/typed_configs.py +0 -0
  44. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config/typed_init_generator.py +0 -0
  45. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py +0 -0
  46. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/config_schema.yaml +0 -0
  47. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/deployer.py +0 -0
  48. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/experimental/__init__.py +0 -0
  49. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/perimeters.py +0 -0
  50. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/core/validations.py +0 -0
  51. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/deploy_decorator.py +0 -0
  52. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/apps/supervisord_utils.py +0 -0
  53. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/auth_server.py +0 -0
  54. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/aws/__init__.py +0 -0
  55. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/aws/assume_role.py +0 -0
  56. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/aws/assume_role_decorator.py +0 -0
  57. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/card_utilities/__init__.py +0 -0
  58. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/card_utilities/async_cards.py +0 -0
  59. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/card_utilities/extra_components.py +0 -0
  60. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/card_utilities/injector.py +0 -0
  61. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/__init__.py +0 -0
  62. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/coreweave.py +0 -0
  63. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/external_chckpt.py +0 -0
  64. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/nebius.py +0 -0
  65. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/fast_bakery/__init__.py +0 -0
  66. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/fast_bakery/baker.py +0 -0
  67. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/fast_bakery/docker_environment.py +0 -0
  68. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery.py +0 -0
  69. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_cli.py +0 -0
  70. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_decorator.py +0 -0
  71. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/kubernetes/__init__.py +0 -0
  72. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/kubernetes/kubernetes_client.py +0 -0
  73. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/kubernetes/pod_killer.py +0 -0
  74. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nim/card.py +0 -0
  75. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nim/nim_decorator.py +0 -0
  76. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nim/nim_manager.py +0 -0
  77. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nim/utils.py +0 -0
  78. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/__init__.py +0 -0
  79. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/constants.py +0 -0
  80. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/exceptions.py +0 -0
  81. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/heartbeat_store.py +0 -0
  82. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/nvcf.py +0 -0
  83. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/nvcf_cli.py +0 -0
  84. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/nvcf_decorator.py +0 -0
  85. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvcf/utils.py +0 -0
  86. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvct/__init__.py +0 -0
  87. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvct/exceptions.py +0 -0
  88. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvct/nvct.py +0 -0
  89. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvct/nvct_cli.py +0 -0
  90. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvct/nvct_decorator.py +0 -0
  91. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvct/nvct_runner.py +0 -0
  92. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/nvct/utils.py +0 -0
  93. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/ollama/__init__.py +0 -0
  94. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/ollama/constants.py +0 -0
  95. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/ollama/exceptions.py +0 -0
  96. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/ollama/ollama.py +0 -0
  97. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/ollama/status_card.py +0 -0
  98. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/perimeters.py +0 -0
  99. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/profilers/deco_injector.py +0 -0
  100. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/profilers/gpu_profile_decorator.py +0 -0
  101. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/profilers/simple_card_decorator.py +0 -0
  102. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/secrets/__init__.py +0 -0
  103. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/secrets/secrets.py +0 -0
  104. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowflake/__init__.py +0 -0
  105. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowflake/snowflake.py +0 -0
  106. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/__init__.py +0 -0
  107. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark.py +0 -0
  108. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_cli.py +0 -0
  109. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_client.py +0 -0
  110. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_decorator.py +0 -0
  111. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_exceptions.py +0 -0
  112. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_job.py +0 -0
  113. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_service_spec.py +0 -0
  114. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/tensorboard/__init__.py +0 -0
  115. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/torchtune/__init__.py +0 -0
  116. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/vllm/__init__.py +0 -0
  117. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/vllm/constants.py +0 -0
  118. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/vllm/exceptions.py +0 -0
  119. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/vllm/status_card.py +0 -0
  120. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/plugins/vllm/vllm_manager.py +0 -0
  121. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/profilers/__init__.py +0 -0
  122. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/profilers/gpu.py +0 -0
  123. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/remote_config.py +0 -0
  124. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/__init__.py +0 -0
  125. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/ob_internal.py +0 -0
  126. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/plugins/azure/__init__.py +0 -0
  127. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/plugins/gcp/__init__.py +0 -0
  128. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/plugins/kubernetes/__init__.py +0 -0
  129. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/plugins/ollama/__init__.py +0 -0
  130. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/plugins/snowflake/__init__.py +0 -0
  131. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/plugins/torchtune/__init__.py +0 -0
  132. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/metaflow_extensions/outerbounds/toplevel/plugins/vllm/__init__.py +0 -0
  133. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/ob_metaflow_extensions.egg-info/dependency_links.txt +0 -0
  134. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/ob_metaflow_extensions.egg-info/requires.txt +0 -0
  135. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/ob_metaflow_extensions.egg-info/top_level.txt +0 -0
  136. {ob_metaflow_extensions-1.3.0 → ob_metaflow_extensions-1.3.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ob_metaflow_extensions
3
- Version: 1.3.0
3
+ Version: 1.3.1
4
4
  Summary: Outerbounds Platform Extensions for Metaflow
5
5
  Author: Outerbounds, Inc.
6
6
  License: Commercial
@@ -340,6 +340,9 @@ STEP_DECORATORS_DESC = [
340
340
  ("ollama", ".ollama.OllamaDecorator"),
341
341
  ("vllm", ".vllm.VLLMDecorator"),
342
342
  ("app_deploy", ".apps.app_deploy_decorator.AppDeployDecorator"),
343
+ ("s3_proxy", ".s3_proxy.s3_proxy_decorator.S3ProxyDecorator"),
344
+ ("nebius_s3_proxy", ".s3_proxy.s3_proxy_decorator.NebiusS3ProxyDecorator"),
345
+ ("coreweave_s3_proxy", ".s3_proxy.s3_proxy_decorator.CoreWeaveS3ProxyDecorator"),
343
346
  ]
344
347
 
345
348
  TOGGLE_STEP_DECORATOR = [
@@ -199,29 +199,29 @@ class DEPLOYMENT_READY_CONDITIONS:
199
199
  This allows users or platform designers to configure the criteria for deployment readiness.
200
200
 
201
201
  Why do we need deployment readiness conditions?
202
- - Deployments might be taking place from a CI/CD esq environment, In these setups, the downstream build triggers might be depending on a specific criteria for deployment completion. Having readiness conditions allows the CI/CD systems to get a signal of when the deployment is ready.
202
+ - Deployments might be taking place from a CI/CD-esque environment, In these setups, the downstream build triggers might be depending on a specific criteria for deployment completion. Having readiness conditions allows the CI/CD systems to get a signal of when the deployment is ready.
203
203
  - Users might be calling the deployment API under different conditions:
204
204
  - Some users might want a cluster of workers ready before serving traffic while others might want just one worker ready to start serving traffic.
205
205
 
206
206
  Some readiness conditions include:
207
- 1) [at_least_one_running] Atleast min(min_replicas, 1) workers of the current deployment instance's version have started running.
207
+ 1) [at_least_one_running] At least min(min_replicas, 1) workers of the current deployment instance's version have started running.
208
208
  - Usecase: Some endpoints may be deployed ephemerally and are considered ready when at least one instance is running; additional instances are for load management.
209
- 2) [all_running] Atleast min_replicas number of workers are running for the deployment to be considered ready.
209
+ 2) [all_running] At least min_replicas number of workers are running for the deployment to be considered ready.
210
210
  - Usecase: Operators may require that all replicas are available before traffic is routed. Needed when inference endpoints maybe under some SLA or require a larger load
211
- 3) [fully_finished] Atleast min_replicas number of workers are running for the deployment and there are no pending or crashlooping workers from previous versions lying around.
211
+ 3) [fully_finished] At least min_replicas number of workers are running for the deployment and there are no pending or crashlooping workers from previous versions lying around.
212
212
  - Usecase: Ensuring endpoint is fully available and no other versions are running or endpoint has been fully scaled down.
213
213
  4) [async] The deployment will be assumed ready as soon as the server responds with a 200.
214
214
  - Usecase: Operators may only care that the URL is minted for the deployment or the deployment eventually scales down to 0.
215
215
  """
216
216
 
217
- # `ATLEAST_ONE_RUNNING` implies that atleast one worker of the current deployment instance's version has started running.
217
+ # `ATLEAST_ONE_RUNNING` implies that at least one worker of the current deployment instance's version has started running.
218
218
  ATLEAST_ONE_RUNNING = "at_least_one_running"
219
219
 
220
220
  # `ALL_RUNNING` implies that all workers of the current deployment instance's version have started running (i.e. all workers aligning to the minimum number of replicas).
221
221
  # It doesn't imply that all the workers relating to other deployments have been torn down.
222
222
  ALL_RUNNING = "all_running"
223
223
 
224
- # `FULLY_FINISHED` implies Atleast min_replicas number of workers are running for the deployment and there are no pending or crashlooping workers from previous versions lying around.
224
+ # `FULLY_FINISHED` implies at least min_replicas number of workers are running for the deployment and there are no pending or crashlooping workers from previous versions lying around.
225
225
  FULLY_FINISHED = "fully_finished"
226
226
 
227
227
  # `ASYNC` implies that the deployment will be assumed ready after the URL is minted and the worker statuses are not checked.
@@ -447,9 +447,9 @@ def _capsule_worker_semantic_status(
447
447
  crashlooping_workers = _make_version_dict(workers, "CrashLoopBackOff")
448
448
 
449
449
  # current_status (formulated basis):
450
- # - atleast one pods are pending for `_end_state_capsule_version`
451
- # - atleast one pod is in Running state for `_end_state_capsule_version` (maybe terminal) [Might require heath-check thing here]
452
- # - alteast one pod is crashlooping for `_end_state_capsule_version` (maybe terminal)
450
+ # - at least one pods are pending for `_end_state_capsule_version`
451
+ # - at least one pod is in Running state for `_end_state_capsule_version` (maybe terminal) [Might require health-check thing here]
452
+ # - at least one pod is crashlooping for `_end_state_capsule_version` (maybe terminal)
453
453
  # - all pods are running for `_end_state_capsule_version` that match the minimum number of replicas
454
454
  # - all pods are running for `_end_state_capsule_version` that match the maximum number of replicas and no other pods of older versions are running
455
455
  # - no pods relating to `_end_state_capsule_version` are pending/running/crashlooping
@@ -239,7 +239,7 @@ def _bake_image(app_config: AppConfig, cache_dir: str, logger):
239
239
  baking_status.resolved_image,
240
240
  )
241
241
  app_config.set_state("python_path", baking_status.python_path)
242
- logger("🐳 Using The Docker Image : %s" % app_config.get_state("image"))
242
+ logger("🐳 Using the docker image : %s" % app_config.get_state("image"))
243
243
 
244
244
 
245
245
  def print_table(data, headers):
@@ -374,7 +374,7 @@ def _package_necessary_things(app_config: AppConfig, logger):
374
374
  # or is it relative to where the caller command is sitting. Ideally it should work
375
375
  # like Kustomizations where its relative to where the yaml file sits for simplicity
376
376
  # of understanding relationships between config files. Ideally users can pass the src_path
377
- # from the command line and that will aliviate any need to package any other directories for
377
+ # from the command line and that will alleviate any need to package any other directories for
378
378
  #
379
379
 
380
380
  package_dir = app_config.get_state("packaging_directory")
@@ -395,7 +395,7 @@ def _package_necessary_things(app_config: AppConfig, logger):
395
395
  )
396
396
  app_config.set_state("code_package_url", package_url)
397
397
  app_config.set_state("code_package_key", package_key)
398
- logger("💾 Code Package Saved to : %s" % app_config.get_state("code_package_url"))
398
+ logger("💾 Code package saved to : %s" % app_config.get_state("code_package_url"))
399
399
 
400
400
 
401
401
  @app.command(help="Deploy an app to the Outerbounds Platform.")
@@ -465,7 +465,7 @@ def deploy(
465
465
 
466
466
  app_config.set_state("packaging_directory", packaging_directory)
467
467
  logger(
468
- "📦 Packaging Directory : %s" % app_config.get_state("packaging_directory"),
468
+ "📦 Packaging directory : %s" % app_config.get_state("packaging_directory"),
469
469
  )
470
470
 
471
471
  if app_config.get("no_deps", False):
@@ -611,7 +611,7 @@ def deploy(
611
611
  )
612
612
  raise AppConfigError(message)
613
613
  capsule_logger(
614
- f"🚀 {'' if not force_upgrade else 'Force'} Upgrading {capsule.capsule_type.lower()} `{capsule.name}`....",
614
+ f"🚀 {'Upgrading' if not force_upgrade else 'Force upgrading'} {capsule.capsule_type.lower()} `{capsule.name}`....",
615
615
  color=ColorTheme.INFO_COLOR,
616
616
  system_msg=True,
617
617
  )
@@ -632,7 +632,7 @@ def deploy(
632
632
  capsule_spinner.stop()
633
633
 
634
634
  logger(
635
- f"💊 {capsule.capsule_type} {app_config.config['name']} ({capsule.identifier}) deployed! {capsule.capsule_type} exposed on the URL: {capsule.url}",
635
+ f"💊 {capsule.capsule_type} {app_config.config['name']} ({capsule.identifier}) deployed! {capsule.capsule_type} available on the URL: {capsule.url}",
636
636
  color=ColorTheme.INFO_COLOR,
637
637
  system_msg=True,
638
638
  )
@@ -761,7 +761,7 @@ def list(ctx, project, branch, name, tags, format, auth_type):
761
761
  def delete(ctx, name, cap_id, project, branch, tags, auto_approve):
762
762
 
763
763
  """Delete an app/apps from the Outerbounds Platform."""
764
- # Atleast one of the args need to be provided
764
+ # At least one of the args need to be provided
765
765
  if not any(
766
766
  [
767
767
  name is not None,
@@ -772,7 +772,7 @@ def delete(ctx, name, cap_id, project, branch, tags, auto_approve):
772
772
  ]
773
773
  ):
774
774
  raise AppConfigError(
775
- "Atleast one of the options need to be provided. You can use --name, --id, --project, --branch, --tag"
775
+ "At least one of the options need to be provided. You can use --name, --id, --project, --branch, --tag"
776
776
  )
777
777
 
778
778
  capsule_api = CapsuleApi(ctx.obj.api_url, ctx.obj.perimeter)
@@ -44,24 +44,24 @@ class CapsuleStateMachine:
44
44
  - Happy Path:
45
45
  - First time Create :
46
46
  - wait for status.updateInProgress to be set to False
47
- - (interleved) Poll the worker endpoints to check their status
47
+ - (interleaved) Poll the worker endpoints to check their status
48
48
  - showcase how many workers are coming up if things are on the cli side.
49
49
  - If the user has set some flag like `--dont-wait-to-fully-finish` then we check the `status.currentlyServedVersion` to see if even one replica is ready to
50
50
  serve traffic.
51
51
  - once the status.updateInProgress is set to False, it means that the replicas are ready
52
52
  - Upgrade:
53
53
  - wait for status.updateInProgress to be set to False
54
- - (interleved) Poll the worker endpoints to check their status and signal the user the number replicas coming up
54
+ - (interleaved) Poll the worker endpoints to check their status and signal the user the number replicas coming up
55
55
  - If the user has set some flag like `--dont-wait-to-fully-finish` then we check the `status.currentlyServedVersion` to see if even one replica is ready to
56
56
  serve traffic.
57
57
  - Unhappy Path:
58
58
  - First time Create :
59
59
  - wait for status.updateInProgress to be set to False,
60
- - (interleved) Poll the workers to check their status.
60
+ - (interleaved) Poll the workers to check their status.
61
61
  - If the worker pertaining the current deployment instance version is crashlooping then crash the deployment process with the error messages and logs.
62
62
  - Upgrade:
63
63
  - wait for status.updateInProgress to be set to False,
64
- - (interleved) Poll the workers to check their status.
64
+ - (interleaved) Poll the workers to check their status.
65
65
  - If the worker pertaining the current deployment instance version is crashlooping then crash the deployment process with the error messages and logs.
66
66
 
67
67
  """
@@ -210,9 +210,9 @@ class CapsuleInput:
210
210
  def construct_exec_command(cls, commands: List[str]):
211
211
  commands = ["set -eEuo pipefail"] + commands
212
212
  command_string = "\n".join(commands)
213
- # First constuct a base64 encoded string of the quoted command
213
+ # First construct a base64 encoded string of the quoted command
214
214
  # One of the reasons we don't directly pass the command string to the backend with a `\n` join
215
- # is because the backend controller doesnt play nice when the command can be a multi-line string.
215
+ # is because the backend controller doesn't play nice when the command can be a multi-line string.
216
216
  # So we encode it to a base64 string and then decode it back to a command string at runtime to provide to
217
217
  # `bash -c`. The ideal thing to have done is to run "bash -c {shlex.quote(command_string)}" and call it a day
218
218
  # but the backend controller yields the following error:
@@ -682,7 +682,7 @@ class CapsuleDeployer:
682
682
  """
683
683
  - `capsule_response.version` contains the version of the object present in the database
684
684
  - `current_deployment_instance_version` contains the version of the object that was deployed by this instance of the deployer.
685
- In the situtation that the versions of the objects become a mismatch then it means that current deployment process is not giving the user the
685
+ In the situation that the versions of the objects become a mismatch then it means that current deployment process is not giving the user the
686
686
  output that they desire.
687
687
  """
688
688
  if capsule_response.get("version", None) != current_deployment_instance_version:
@@ -783,24 +783,22 @@ class CapsuleDeployer:
783
783
  )
784
784
  if capsule_ready or failure_condition_satisfied:
785
785
  logger(
786
- "💊 %s deployment status: %s | worker states: [success :%s | failure :%s ] "
786
+ "💊 %s deployment status: %s "
787
787
  % (
788
788
  self.capsule_type.title(),
789
789
  "in progress"
790
790
  if state_machine.update_in_progress
791
791
  else "completed",
792
- capsule_ready,
793
- failure_condition_satisfied,
794
792
  )
795
793
  )
796
794
  _further_readiness_check_failed = False
797
795
  if further_check_worker_readiness:
798
796
  # HACK : monitor the workers for N seconds to make sure they are healthy
799
- # this is a hack. Ideally we should implment a healtcheck as a first class citizen
797
+ # this is a hack. Ideally we should implement a healthcheck as a first class citizen
800
798
  # but it will take some time to do that so in the meanwhile a timeout set on the cli
801
799
  # side will be really helpful.
802
800
  logger(
803
- "💊 running last minute readiness check for %s..."
801
+ "💊 Running last minute readiness check for %s..."
804
802
  % self.identifier
805
803
  )
806
804
  _further_readiness_check_failed = self._monitor_worker_readiness(
@@ -95,7 +95,7 @@ def bake_deployment_image(
95
95
  pinned_conda_libs = get_pinned_conda_libs(python_version, DEFAULT_DATASTORE)
96
96
  pypi_packages.update(pinned_conda_libs)
97
97
  _reference = app_config.get("name", "default")
98
- # `image` cannot be None. If by change it is none, FB will fart.
98
+ # `image` cannot be None. If by chance it is none, FB will fart.
99
99
  fb_response = bake_image(
100
100
  cache_file_path=cache_file_path,
101
101
  pypi_packages=pypi_packages,
@@ -116,7 +116,7 @@ class SecretRetriever:
116
116
 
117
117
  if not perimeter:
118
118
  raise OuterboundsSecretsException(
119
- "No perimeter set. Please make sure to run `outerbounds configure <...>` command which can be found on the Ourebounds UI or reach out to your Outerbounds support team."
119
+ "No perimeter set. Please make sure to run `outerbounds configure <...>` command which can be found on the Outerbounds UI or reach out to your Outerbounds support team."
120
120
  )
121
121
 
122
122
  if not integrations_url:
@@ -185,8 +185,8 @@ def safe_requests_wrapper(
185
185
  - How to handle retries for this case will be application specific.
186
186
  2. Errors when the API server may not be reachable (DNS resolution / network issues)
187
187
  - In this scenario, we know that something external to the API server is going wrong causing the issue.
188
- - Failing pre-maturely in the case might not be the best course of action since critical user jobs might crash on intermittent issues.
189
- - So in this case, we can just planely retry the request.
188
+ - Failing prematurely in the case might not be the best course of action since critical user jobs might crash on intermittent issues.
189
+ - So in this case, we can just plainly retry the request.
190
190
 
191
191
  This function handles the second case. It's a simple wrapper to handle the retry logic for connection errors.
192
192
  If this function is provided a `conn_error_retries` of 5, then the last retry will have waited 32 seconds.
@@ -0,0 +1,7 @@
1
+ from .s3_proxy_decorator import (
2
+ S3ProxyDecorator,
3
+ NebiusS3ProxyDecorator,
4
+ CoreWeaveS3ProxyDecorator,
5
+ )
6
+
7
+ __all__ = ["S3ProxyDecorator", "NebiusS3ProxyDecorator", "CoreWeaveS3ProxyDecorator"]
@@ -0,0 +1,8 @@
1
+ S3_PROXY_BINARY_URLS = {
2
+ "aarch64": "https://fast-s3-proxy.outerbounds.sh/linux-arm64/s3-proxy-0.1.1.gz",
3
+ "x86_64": "https://fast-s3-proxy.outerbounds.sh/linux-amd64/s3-proxy-0.1.1.gz",
4
+ }
5
+
6
+ DEFAULT_PROXY_PORT = 8081
7
+ DEFAULT_PROXY_HOST = "localhost"
8
+ S3_PROXY_WRITE_MODES = ["origin-and-cache", "origin", "cache"]
@@ -0,0 +1,13 @@
1
+ from metaflow.exception import MetaflowException
2
+
3
+
4
+ class S3ProxyException(MetaflowException):
5
+ headline = "S3 Proxy Error"
6
+
7
+
8
+ class S3ProxyConfigException(S3ProxyException):
9
+ headline = "S3 Proxy Configuration Error"
10
+
11
+
12
+ class S3ProxyApiException(S3ProxyException):
13
+ headline = "S3 Proxy API Error"
@@ -0,0 +1,93 @@
1
+ import json
2
+ import time
3
+ from typing import Dict, Optional
4
+
5
+ from .exceptions import S3ProxyConfigException, S3ProxyApiException
6
+
7
+
8
+ class S3ProxyConfigResponse:
9
+ def __init__(self, data: Dict):
10
+ self.bucket_name = data.get("bucket_name")
11
+ self.endpoint_url = data.get("endpoint_url")
12
+ self.access_key_id = data.get("access_key_id")
13
+ self.secret_access_key = data.get("secret_access_key")
14
+ self.region = data.get("region")
15
+
16
+
17
+ class S3ProxyApiClient:
18
+ def __init__(self):
19
+ self.perimeter, self.integrations_url = self._get_api_configs()
20
+
21
+ def _get_api_configs(self):
22
+ from metaflow_extensions.outerbounds.remote_config import init_config
23
+ from os import environ
24
+
25
+ conf = init_config()
26
+ perimeter = conf.get("OBP_PERIMETER") or environ.get("OBP_PERIMETER", "")
27
+ integrations_url = conf.get("OBP_INTEGRATIONS_URL") or environ.get(
28
+ "OBP_INTEGRATIONS_URL", ""
29
+ )
30
+
31
+ if not perimeter:
32
+ raise S3ProxyConfigException(
33
+ "No perimeter set. Please run `outerbounds configure` command."
34
+ )
35
+
36
+ if not integrations_url:
37
+ raise S3ProxyConfigException(
38
+ "No integrations URL set. Please contact your Outerbounds support team."
39
+ )
40
+
41
+ return perimeter, integrations_url
42
+
43
+ def fetch_s3_proxy_config(
44
+ self, integration_name: Optional[str] = None
45
+ ) -> S3ProxyConfigResponse:
46
+ url = f"{self.integrations_url}/s3proxy"
47
+
48
+ payload = {"perimeter_name": self.perimeter}
49
+ if integration_name:
50
+ payload["integration_name"] = integration_name
51
+
52
+ headers = {"Content-Type": "application/json"}
53
+
54
+ try:
55
+ from metaflow.metaflow_config import SERVICE_HEADERS
56
+
57
+ headers.update(SERVICE_HEADERS or {})
58
+ except ImportError:
59
+ pass
60
+
61
+ response = self._make_request(url, headers, payload)
62
+ return S3ProxyConfigResponse(response)
63
+
64
+ def _make_request(self, url: str, headers: Dict, payload: Dict) -> Dict:
65
+ from metaflow_extensions.outerbounds.plugins.secrets.secrets import (
66
+ _api_server_get,
67
+ )
68
+
69
+ retryable_status_codes = [409]
70
+ json_payload = json.dumps(payload)
71
+
72
+ for attempt in range(3):
73
+ response = _api_server_get(
74
+ url, data=json_payload, headers=headers, conn_error_retries=5
75
+ )
76
+
77
+ if response.status_code not in retryable_status_codes:
78
+ break
79
+
80
+ if attempt < 2:
81
+ time.sleep(0.5 * (attempt + 1))
82
+
83
+ if response.status_code != 200:
84
+ error_msg = f"API request failed with status {response.status_code}"
85
+ try:
86
+ error_data = response.json()
87
+ if "message" in error_data:
88
+ error_msg = error_data["message"]
89
+ except:
90
+ pass
91
+ raise S3ProxyApiException(error_msg)
92
+
93
+ return response.json()
@@ -0,0 +1,106 @@
1
+ import functools
2
+ from typing import Optional
3
+
4
+ from metaflow import current
5
+ from metaflow.decorators import StepDecorator
6
+
7
+ from .s3_proxy_manager import S3ProxyManager
8
+ from .exceptions import S3ProxyException
9
+ from .constants import S3_PROXY_WRITE_MODES
10
+
11
+
12
+ class S3ProxyDecorator(StepDecorator):
13
+ """
14
+ S3 Proxy decorator for routing S3 requests through a local proxy service.
15
+
16
+ Parameters
17
+ ----------
18
+ integration_name : str, optional
19
+ Name of the S3 proxy integration. If not specified, will use the only
20
+ available S3 proxy integration in the namespace (fails if multiple exist).
21
+ write_mode : str, optional
22
+ The desired behavior during write operations to target (origin) S3 bucket.
23
+ allowed options are:
24
+ "origin-and-cache" -> write to both the target S3 bucket and local object
25
+ storage
26
+ "origin" -> only write to the target S3 bucket
27
+ "cache" -> only write to the object storage service used for caching
28
+ debug : bool, optional
29
+ Enable debug logging for proxy operations.
30
+ """
31
+
32
+ name = "s3_proxy"
33
+ defaults = {
34
+ "integration_name": None,
35
+ "write_mode": None,
36
+ "debug": False,
37
+ }
38
+
39
+ def step_init(self, flow, graph, step, decos, environment, flow_datastore, logger):
40
+ write_mode = self.attributes["write_mode"]
41
+ if write_mode and write_mode not in S3_PROXY_WRITE_MODES:
42
+ raise S3ProxyException(
43
+ f"unexpected write_mode specified: {write_mode}. Allowed values are: {','.join(S3_PROXY_WRITE_MODES)}."
44
+ )
45
+
46
+ self.manager = S3ProxyManager(
47
+ integration_name=self.attributes["integration_name"],
48
+ write_mode=self.attributes["write_mode"],
49
+ debug=self.attributes["debug"],
50
+ )
51
+
52
+ current._update_env({"s3_proxy": self.manager})
53
+
54
+ def task_pre_step(
55
+ self,
56
+ step_name,
57
+ task_datastore,
58
+ metadata,
59
+ run_id,
60
+ task_id,
61
+ flow,
62
+ graph,
63
+ retry_count,
64
+ max_user_code_retries,
65
+ ubf_context,
66
+ inputs,
67
+ ):
68
+ """Setup S3 proxy before step execution"""
69
+ self.manager.setup_proxy()
70
+
71
+ def task_finished(
72
+ self, step_name, flow, graph, is_task_ok, retry_count, max_retries
73
+ ):
74
+ """Cleanup S3 proxy after step execution"""
75
+ if self.manager:
76
+ self.manager.cleanup()
77
+
78
+
79
+ class NebiusS3ProxyDecorator(S3ProxyDecorator):
80
+ """
81
+ Nebius-specific S3 Proxy decorator for routing S3 requests through a local proxy service.
82
+ It exists to make it easier for users to know that this decorator should only be used with
83
+ a Neo Cloud like Nebius.
84
+ """
85
+
86
+ name = "nebius_s3_proxy"
87
+ defaults = {
88
+ "integration_name": None,
89
+ "write_mode": None,
90
+ "debug": False,
91
+ }
92
+
93
+
94
+ class CoreWeaveS3ProxyDecorator(S3ProxyDecorator):
95
+ """
96
+ CoreWeave-specific S3 Proxy decorator for routing S3 requests through a local proxy service.
97
+ It exists to make it easier for users to know that this decorator should only be used with
98
+ a Neo Cloud like CoreWeave.
99
+ """
100
+
101
+ name = "coreweave_s3_proxy"
102
+ defaults = {
103
+ "integration_name": None,
104
+ "write_mode": None,
105
+ "debug": False,
106
+ }