ob-metaflow-extensions 1.4.1__tar.gz → 1.4.32__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ob-metaflow-extensions might be problematic. Click here for more details.

Files changed (142) hide show
  1. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/PKG-INFO +1 -1
  2. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/__init__.py +1 -1
  3. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/app_cli.py +44 -25
  4. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/app_config.py +2 -1
  5. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/capsule.py +101 -38
  6. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/code_package/code_packager.py +7 -0
  7. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config/typed_configs.py +4 -1
  8. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py +54 -5
  9. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config_schema.yaml +20 -4
  10. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/experimental/__init__.py +29 -18
  11. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/perimeters.py +1 -1
  12. ob_metaflow_extensions-1.4.32/metaflow_extensions/outerbounds/plugins/optuna/__init__.py +48 -0
  13. ob_metaflow_extensions-1.4.32/metaflow_extensions/outerbounds/plugins/s3_proxy/binary_caller.py +132 -0
  14. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/s3_proxy/constants.py +4 -1
  15. ob_metaflow_extensions-1.4.32/metaflow_extensions/outerbounds/plugins/s3_proxy/proxy_bootstrap.py +59 -0
  16. ob_metaflow_extensions-1.4.32/metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_decorator.py +250 -0
  17. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_manager.py +44 -41
  18. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_client.py +6 -3
  19. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_decorator.py +13 -7
  20. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_job.py +8 -2
  21. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/global_aliases_for_metaflow_package.py +32 -4
  22. ob_metaflow_extensions-1.4.32/metaflow_extensions/outerbounds/toplevel/plugins/optuna/__init__.py +1 -0
  23. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/ob_metaflow_extensions.egg-info/PKG-INFO +1 -1
  24. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/ob_metaflow_extensions.egg-info/SOURCES.txt +4 -0
  25. ob_metaflow_extensions-1.4.32/ob_metaflow_extensions.egg-info/requires.txt +3 -0
  26. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/setup.py +2 -2
  27. ob_metaflow_extensions-1.4.1/metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_decorator.py +0 -106
  28. ob_metaflow_extensions-1.4.1/ob_metaflow_extensions.egg-info/requires.txt +0 -3
  29. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/MANIFEST.in +0 -0
  30. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/README.md +0 -0
  31. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/__init__.py +0 -0
  32. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/config/__init__.py +0 -0
  33. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/__init__.py +0 -0
  34. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/app_cli.py +0 -0
  35. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/app_deploy_decorator.py +0 -0
  36. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/app_utils.py +0 -0
  37. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/consts.py +0 -0
  38. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/__init__.py +0 -0
  39. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/_state_machine.py +0 -0
  40. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/_vendor/__init__.py +0 -0
  41. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/__init__.py +0 -0
  42. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/spinners.py +0 -0
  43. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/artifacts.py +0 -0
  44. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/click_importer.py +0 -0
  45. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/code_package/__init__.py +0 -0
  46. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/code_package/examples.py +0 -0
  47. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py +0 -0
  48. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config/cli_generator.py +0 -0
  49. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config/config_utils.py +0 -0
  50. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config/schema_export.py +0 -0
  51. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/config/typed_init_generator.py +0 -0
  52. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/dependencies.py +0 -0
  53. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/deployer.py +0 -0
  54. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/secrets.py +0 -0
  55. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/utils.py +0 -0
  56. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/core/validations.py +0 -0
  57. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/deploy_decorator.py +0 -0
  58. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/apps/supervisord_utils.py +0 -0
  59. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/auth_server.py +0 -0
  60. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/aws/__init__.py +0 -0
  61. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/aws/assume_role.py +0 -0
  62. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/aws/assume_role_decorator.py +0 -0
  63. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/card_utilities/__init__.py +0 -0
  64. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/card_utilities/async_cards.py +0 -0
  65. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/card_utilities/extra_components.py +0 -0
  66. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/card_utilities/injector.py +0 -0
  67. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/__init__.py +0 -0
  68. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/coreweave.py +0 -0
  69. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/external_chckpt.py +0 -0
  70. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/checkpoint_datastores/nebius.py +0 -0
  71. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/fast_bakery/__init__.py +0 -0
  72. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/fast_bakery/baker.py +0 -0
  73. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/fast_bakery/docker_environment.py +0 -0
  74. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery.py +0 -0
  75. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_cli.py +0 -0
  76. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_decorator.py +0 -0
  77. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/kubernetes/__init__.py +0 -0
  78. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/kubernetes/kubernetes_client.py +0 -0
  79. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/kubernetes/pod_killer.py +0 -0
  80. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nim/card.py +0 -0
  81. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nim/nim_decorator.py +0 -0
  82. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nim/nim_manager.py +0 -0
  83. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nim/utils.py +0 -0
  84. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/__init__.py +0 -0
  85. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/constants.py +0 -0
  86. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/exceptions.py +0 -0
  87. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/heartbeat_store.py +0 -0
  88. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/nvcf.py +0 -0
  89. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/nvcf_cli.py +0 -0
  90. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/nvcf_decorator.py +0 -0
  91. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvcf/utils.py +0 -0
  92. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvct/__init__.py +0 -0
  93. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvct/exceptions.py +0 -0
  94. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvct/nvct.py +0 -0
  95. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvct/nvct_cli.py +0 -0
  96. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvct/nvct_decorator.py +0 -0
  97. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvct/nvct_runner.py +0 -0
  98. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/nvct/utils.py +0 -0
  99. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/ollama/__init__.py +0 -0
  100. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/ollama/constants.py +0 -0
  101. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/ollama/exceptions.py +0 -0
  102. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/ollama/ollama.py +0 -0
  103. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/ollama/status_card.py +0 -0
  104. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/perimeters.py +0 -0
  105. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/profilers/deco_injector.py +0 -0
  106. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/profilers/gpu_profile_decorator.py +0 -0
  107. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/profilers/simple_card_decorator.py +0 -0
  108. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/s3_proxy/__init__.py +0 -0
  109. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/s3_proxy/exceptions.py +0 -0
  110. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_api.py +0 -0
  111. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/secrets/__init__.py +0 -0
  112. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/secrets/secrets.py +0 -0
  113. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowflake/__init__.py +0 -0
  114. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowflake/snowflake.py +0 -0
  115. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/__init__.py +0 -0
  116. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark.py +0 -0
  117. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_cli.py +0 -0
  118. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_exceptions.py +0 -0
  119. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/snowpark/snowpark_service_spec.py +0 -0
  120. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/tensorboard/__init__.py +0 -0
  121. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/torchtune/__init__.py +0 -0
  122. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/vllm/__init__.py +0 -0
  123. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/vllm/constants.py +0 -0
  124. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/vllm/exceptions.py +0 -0
  125. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/vllm/status_card.py +0 -0
  126. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/plugins/vllm/vllm_manager.py +0 -0
  127. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/profilers/__init__.py +0 -0
  128. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/profilers/gpu.py +0 -0
  129. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/remote_config.py +0 -0
  130. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/__init__.py +0 -0
  131. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/ob_internal.py +0 -0
  132. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/plugins/azure/__init__.py +0 -0
  133. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/plugins/gcp/__init__.py +0 -0
  134. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/plugins/kubernetes/__init__.py +0 -0
  135. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/plugins/ollama/__init__.py +0 -0
  136. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/plugins/snowflake/__init__.py +0 -0
  137. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/plugins/torchtune/__init__.py +0 -0
  138. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/plugins/vllm/__init__.py +0 -0
  139. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/metaflow_extensions/outerbounds/toplevel/s3_proxy.py +0 -0
  140. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/ob_metaflow_extensions.egg-info/dependency_links.txt +0 -0
  141. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/ob_metaflow_extensions.egg-info/top_level.txt +0 -0
  142. {ob_metaflow_extensions-1.4.1 → ob_metaflow_extensions-1.4.32}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ob_metaflow_extensions
3
- Version: 1.4.1
3
+ Version: 1.4.32
4
4
  Summary: Outerbounds Platform Extensions for Metaflow
5
5
  Author: Outerbounds, Inc.
6
6
  License: Commercial
@@ -361,4 +361,4 @@ SECRETS_PROVIDERS_DESC = [
361
361
  ("outerbounds", ".secrets.secrets.OuterboundsSecretsProvider"),
362
362
  ]
363
363
  # Adding an override here so the library can be imported at the metaflow.plugins level
364
- __mf_promote_submodules__ = ["snowflake", "ollama", "torchtune"]
364
+ __mf_promote_submodules__ = ["snowflake", "ollama", "torchtune", "optuna"]
@@ -339,7 +339,7 @@ def deployment_instance_options(func):
339
339
  "--readiness-wait-time",
340
340
  type=int,
341
341
  help="The time (in seconds) to monitor the deployment for readiness after the readiness condition is met.",
342
- default=4,
342
+ default=15,
343
343
  )
344
344
  @click.option(
345
345
  "--deployment-timeout",
@@ -377,8 +377,8 @@ def _package_necessary_things(app_config: AppConfig, logger):
377
377
  # from the command line and that will alleviate any need to package any other directories for
378
378
  #
379
379
 
380
- package_dir = app_config.get_state("packaging_directory")
381
- if package_dir is None:
380
+ package_dirs = app_config.get_state("packaging_directories")
381
+ if package_dirs is None:
382
382
  app_config.set_state("code_package_url", None)
383
383
  app_config.set_state("code_package_key", None)
384
384
  return
@@ -391,13 +391,26 @@ def _package_necessary_things(app_config: AppConfig, logger):
391
391
  datastore_type=DEFAULT_DATASTORE, code_package_prefix=CODE_PACKAGE_PREFIX
392
392
  )
393
393
  package_url, package_key = packager.store(
394
- paths_to_include=[package_dir], file_suffixes=suffixes
394
+ paths_to_include=package_dirs, file_suffixes=suffixes
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
398
  logger("💾 Code package saved to : %s" % app_config.get_state("code_package_url"))
399
399
 
400
400
 
401
+ def _sniff_pyproject_and_requirements(packaging_directories: List[str]):
402
+ pyproject_path = None
403
+ requirements_path = None
404
+ for directory in packaging_directories:
405
+ pyproject_toml = os.path.join(directory, "pyproject.toml")
406
+ requirements_txt = os.path.join(directory, "requirements.txt")
407
+ if os.path.exists(pyproject_toml):
408
+ pyproject_path = pyproject_toml
409
+ elif os.path.exists(requirements_txt):
410
+ requirements_path = requirements_txt
411
+ return pyproject_path, requirements_path
412
+
413
+
401
414
  @app.command(help="Deploy an app to the Outerbounds Platform.")
402
415
  @click.option(
403
416
  "--config-file",
@@ -449,23 +462,19 @@ def deploy(
449
462
  system_msg=True,
450
463
  )
451
464
 
452
- packaging_directory = None
453
- package_src_path = app_config.get("package", {}).get("src_path", None)
454
- if package_src_path:
455
- if os.path.isfile(package_src_path):
456
- raise AppConfigError("src_path must be a directory, not a file")
457
- elif os.path.isdir(package_src_path):
458
- packaging_directory = os.path.abspath(package_src_path)
459
- else:
460
- raise AppConfigError(f"src_path '{package_src_path}' does not exist")
461
- else:
462
- # If src_path is None then we assume then we can assume for the moment
465
+ package_src_paths = app_config.get("package", {}).get("src_paths", [])
466
+ if package_src_paths is None:
467
+ package_src_paths = []
468
+
469
+ if len(package_src_paths) == 0:
470
+ # If src_paths is None then we assume then we can assume for the moment
463
471
  # that we can package the current working directory.
464
- packaging_directory = os.getcwd()
472
+ package_src_paths = [os.getcwd()]
465
473
 
466
- app_config.set_state("packaging_directory", packaging_directory)
474
+ app_config.set_state("packaging_directories", package_src_paths)
467
475
  logger(
468
- "📦 Packaging directory : %s" % app_config.get_state("packaging_directory"),
476
+ "📦 Packaging directories : %s"
477
+ % ", ".join(app_config.get_state("packaging_directories")),
469
478
  )
470
479
 
471
480
  if app_config.get("no_deps", False):
@@ -484,22 +493,32 @@ def deploy(
484
493
  dependencies.get("conda", None) is None,
485
494
  ]
486
495
  ):
496
+ python_version = dependencies.get(
497
+ "python"
498
+ ) # python gets a default value so it's always set.
487
499
  # The user has not set any dependencies, so we can sniff the packaging directory
488
500
  # for a dependencies file.
489
- requirements_file = os.path.join(
490
- packaging_directory, "requirements.txt"
501
+ pyproject_toml, requirements_file = _sniff_pyproject_and_requirements(
502
+ package_src_paths
491
503
  )
492
- pyproject_toml = os.path.join(packaging_directory, "pyproject.toml")
493
- if os.path.exists(pyproject_toml):
504
+ if pyproject_toml:
494
505
  app_config.set_state(
495
- "dependencies", {"from_pyproject_toml": pyproject_toml}
506
+ "dependencies",
507
+ {
508
+ "from_pyproject_toml": pyproject_toml,
509
+ "python": python_version,
510
+ },
496
511
  )
497
512
  logger(
498
513
  "📦 Using dependencies from pyproject.toml: %s" % pyproject_toml
499
514
  )
500
- elif os.path.exists(requirements_file):
515
+ elif requirements_file:
501
516
  app_config.set_state(
502
- "dependencies", {"from_requirements_file": requirements_file}
517
+ "dependencies",
518
+ {
519
+ "from_requirements_file": requirements_file,
520
+ "python": python_version,
521
+ },
503
522
  )
504
523
  logger(
505
524
  "📦 Using dependencies from requirements.txt: %s"
@@ -45,10 +45,11 @@ def _try_loading_yaml(file):
45
45
  class AuthType:
46
46
  BROWSER = "Browser"
47
47
  API = "API"
48
+ BROWSER_AND_API = "BrowserAndApi"
48
49
 
49
50
  @classmethod
50
51
  def enums(cls):
51
- return [cls.BROWSER, cls.API]
52
+ return [cls.BROWSER, cls.API, cls.BROWSER_AND_API]
52
53
 
53
54
  @classproperty
54
55
  def default(cls):
@@ -7,7 +7,7 @@ import sys
7
7
  import time
8
8
  from functools import partial
9
9
  import shlex
10
- from typing import Optional, List, Dict, Any, Tuple, Union
10
+ from typing import Optional, List, Dict, Any, Tuple, Union, Callable
11
11
  from .utils import TODOException, safe_requests_wrapper, MaximumRetriesExceeded
12
12
  from .app_config import AppConfig, CAPSULE_DEBUG, AuthType
13
13
  from . import experimental
@@ -75,7 +75,6 @@ class CapsuleStateMachine:
75
75
  return self._status_trail
76
76
 
77
77
  def add_status(self, status: CapsuleStatus):
78
- assert type(status) == dict, "TODO: Make this check somewhere else"
79
78
  self._status_trail.append({"timestamp": time.time(), "status": status})
80
79
 
81
80
  @property
@@ -116,7 +115,9 @@ class CapsuleStateMachine:
116
115
  pass
117
116
 
118
117
  def save_debug_info(self, state_dir: str):
119
- debug_path = os.path.join(state_dir, f"debug_capsule_{self._capsule_id}.json")
118
+ debug_path = os.path.join(
119
+ state_dir, f"debug_capsule_sm_{self._capsule_id}.json"
120
+ )
120
121
  with open(debug_path, "w") as f:
121
122
  json.dump(self._status_trail, f, indent=4)
122
123
 
@@ -427,7 +428,7 @@ class CapsuleApi:
427
428
  message="Capsule JSON decode failed",
428
429
  )
429
430
 
430
- def get(self, capsule_id: str):
431
+ def get(self, capsule_id: str) -> Dict[str, Any]:
431
432
  _url = os.path.join(self._base_url, capsule_id)
432
433
  response = self._wrapped_api_caller(
433
434
  requests.get,
@@ -446,6 +447,35 @@ class CapsuleApi:
446
447
  message="Capsule JSON decode failed",
447
448
  )
448
449
 
450
+ # TODO: refactor me since name *currently(9/8/25)* is unique across capsules.
451
+ def get_by_name(self, name: str, most_recent_only: bool = True):
452
+ _url = os.path.join(self._base_url, f"?displayName={name}")
453
+ response = self._wrapped_api_caller(
454
+ requests.get,
455
+ _url,
456
+ retryable_status_codes=[409], # todo : verify me
457
+ conn_error_retries=3,
458
+ )
459
+ try:
460
+ if most_recent_only:
461
+ result = response.json()
462
+ candidates = result["capsules"]
463
+ if not candidates:
464
+ return None
465
+ return sorted(
466
+ candidates, key=lambda x: x["metadata"]["createdAt"], reverse=True
467
+ )[0]
468
+ else:
469
+ return response.json()
470
+ except json.JSONDecodeError as e:
471
+ raise CapsuleApiException(
472
+ _url,
473
+ "get",
474
+ response.status_code,
475
+ response.text,
476
+ message="Capsule JSON decode failed",
477
+ )
478
+
449
479
  def list(self):
450
480
  response = self._wrapped_api_caller(
451
481
  requests.get,
@@ -648,7 +678,7 @@ class CapsuleDeployer:
648
678
  auth_type = self._app_config.get_state("auth", {}).get("type", AuthType.default)
649
679
  if auth_type == AuthType.BROWSER:
650
680
  return "App"
651
- elif auth_type == AuthType.API:
681
+ elif auth_type == AuthType.API or auth_type == AuthType.BROWSER_AND_API:
652
682
  return "Endpoint"
653
683
  else:
654
684
  raise TODOException(f"Unknown auth type: {auth_type}")
@@ -698,17 +728,51 @@ class CapsuleDeployer:
698
728
  f"A capsule upgrade was triggered outside current deployment instance. Current deployment version was discarded. Current deployment version: {current_deployment_instance_version} and new version: {capsule_response.get('version', None)}",
699
729
  )
700
730
 
731
+ def _update_capsule_and_worker_sm(
732
+ self,
733
+ capsule_sm: "CapsuleStateMachine",
734
+ workers_sm: "CapsuleWorkersStateMachine",
735
+ logger: Callable[[str], None],
736
+ ) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
737
+ capsule_response = self.get()
738
+ capsule_sm.add_status(capsule_response.get("status", {})) # type: ignore
739
+
740
+ # We need to check if someone has not upgraded the capsule under the hood and
741
+ # the current deployment instance is invalid.
742
+ self._backend_version_mismatch_check(
743
+ capsule_response, self.current_deployment_instance_version # type: ignore
744
+ )
745
+ workers_response = self.get_workers()
746
+ capsule_sm.report_current_status(logger)
747
+ workers_sm.add_status(workers_response)
748
+ workers_sm.report_current_status(logger)
749
+ return capsule_response, workers_response
750
+
751
+ def _publish_capsule_debug_info(
752
+ self,
753
+ capsule_sm: "CapsuleStateMachine",
754
+ workers_sm: "CapsuleWorkersStateMachine",
755
+ capsule_response: Dict[str, Any],
756
+ ):
757
+ if CAPSULE_DEBUG and self._debug_dir:
758
+ capsule_sm.save_debug_info(self._debug_dir)
759
+ workers_sm.save_debug_info(self._debug_dir)
760
+ debug_path = os.path.join(
761
+ self._debug_dir, f"debug_capsule_{self.identifier}.json"
762
+ )
763
+ with open(debug_path, "w") as f:
764
+ f.write(json.dumps(capsule_response, indent=4))
765
+
701
766
  def _monitor_worker_readiness(
702
767
  self,
703
768
  workers_sm: "CapsuleWorkersStateMachine",
769
+ capsule_sm: "CapsuleStateMachine",
704
770
  ):
705
771
  """returns True if the worker is crashlooping, False otherwise"""
706
772
  logger = self._logger_fn or partial(print, file=sys.stderr)
707
773
  for i in range(self._readiness_wait_time):
708
774
  time.sleep(1)
709
- workers_response = self.get_workers()
710
- workers_sm.add_status(workers_response)
711
- workers_sm.report_current_status(logger)
775
+ self._update_capsule_and_worker_sm(capsule_sm, workers_sm, logger)
712
776
  if workers_sm.is_crashlooping:
713
777
  return True
714
778
  return False
@@ -754,21 +818,19 @@ class CapsuleDeployer:
754
818
  minimum_replicas=min_replicas,
755
819
  )
756
820
  self.status = state_machine
821
+
822
+ # This loop will check all the conditions that help verify the terminal state.
823
+ # How it works is by extracting the statuses of the capsule and workers and
824
+ # then adding them as a part of a state-machine that helps track transitions and
825
+ # helps derive terminal states.
826
+ # We will first keep checking for terminal conditions or outright failure conditions
827
+ # If we reach a teminal condition like described in `DEPLOYMENT_READY_CONDITIONS`, then
828
+ # we will further check for readiness conditions.
757
829
  for i in range(self._create_timeout):
758
830
  time.sleep(1)
759
- capsule_response = self.get()
760
- workers_response = self.get_workers()
761
-
762
- # We first need to check if someone has not upgraded the capsule under the hood and
763
- # the current deployment instance is invalid.
764
- self._backend_version_mismatch_check(
765
- capsule_response, self.current_deployment_instance_version # type: ignore
831
+ capsule_response, _ = self._update_capsule_and_worker_sm(
832
+ state_machine, workers_state_machine, logger
766
833
  )
767
- state_machine.add_status(capsule_response.get("status", {})) # type: ignore
768
- workers_state_machine.add_status(workers_response)
769
- state_machine.report_current_status(logger)
770
-
771
- workers_state_machine.report_current_status(logger)
772
834
  # Deployment readiness checks will determine what is the terminal state
773
835
  # of the workerstate machine. If we detect a terminal state in the workers,
774
836
  # then even if the capsule upgrade is still in progress we will end up crashing
@@ -793,9 +855,11 @@ class CapsuleDeployer:
793
855
  "💊 %s deployment status: %s "
794
856
  % (
795
857
  self.capsule_type.title(),
796
- "in progress"
797
- if state_machine.update_in_progress
798
- else "completed",
858
+ (
859
+ "in progress"
860
+ if state_machine.update_in_progress
861
+ else "completed"
862
+ ),
799
863
  )
800
864
  )
801
865
  _further_readiness_check_failed = False
@@ -809,7 +873,8 @@ class CapsuleDeployer:
809
873
  % self.identifier
810
874
  )
811
875
  _further_readiness_check_failed = self._monitor_worker_readiness(
812
- workers_state_machine
876
+ workers_state_machine,
877
+ state_machine,
813
878
  )
814
879
 
815
880
  if CAPSULE_DEBUG:
@@ -853,13 +918,18 @@ class CapsuleDeployer:
853
918
 
854
919
  break
855
920
 
856
- if CAPSULE_DEBUG and self._debug_dir:
857
- state_machine.save_debug_info(self._debug_dir)
858
- workers_state_machine.save_debug_info(self._debug_dir)
859
- if i % 3 == 0: # Every 3 seconds report the status
860
- logger(
861
- f"[debug] 💊 {self.capsule_type} {self.identifier} deployment status: {state_machine.current_status} | worker states: {workers_state_machine.current_status} | capsule_ready : {capsule_ready} | further_check_worker_readiness {further_check_worker_readiness}"
862
- )
921
+ self._publish_capsule_debug_info(
922
+ state_machine, workers_state_machine, capsule_response
923
+ )
924
+
925
+ if CAPSULE_DEBUG and i % 3 == 0: # Every 3 seconds report the status
926
+ logger(
927
+ f"[debug] 💊 {self.capsule_type} {self.identifier} deployment status: {state_machine.current_status} | worker states: {workers_state_machine.current_status} | capsule_ready : {capsule_ready} | further_check_worker_readiness {further_check_worker_readiness}"
928
+ )
929
+
930
+ self._publish_capsule_debug_info(
931
+ state_machine, workers_state_machine, capsule_response
932
+ )
863
933
 
864
934
  # We will only check ready_to_serve_traffic under the following conditions:
865
935
  # If the readiness condition is not Async and min_replicas in this deployment
@@ -877,13 +947,6 @@ class CapsuleDeployer:
877
947
  f"Capsule {self.identifier} failed to be ready to serve traffic",
878
948
  )
879
949
 
880
- if CAPSULE_DEBUG and self._debug_dir:
881
- state_machine.save_debug_info(self._debug_dir)
882
- workers_state_machine.save_debug_info(self._debug_dir)
883
- logger(
884
- f"[debug] 💊 {self.capsule_type} {self.identifier} deployment status [on return]: {state_machine.current_status} | worker states: {workers_state_machine.current_status}"
885
- )
886
-
887
950
  return dict(
888
951
  id=self.identifier,
889
952
  auth_type=self.capsule_type,
@@ -381,6 +381,7 @@ class CodePackager:
381
381
  "google-auth",
382
382
  "simple-gcp-object-downloader",
383
383
  "google-cloud-secret-manager",
384
+ "packaging",
384
385
  ],
385
386
  "local": [],
386
387
  }
@@ -441,6 +442,7 @@ class CodePackager:
441
442
  root,
442
443
  exclude_hidden=True,
443
444
  suffixes=None,
445
+ normalized_rel_path=False,
444
446
  ) -> List[Tuple[str, str]]:
445
447
  """
446
448
  Walk a directory and yield tuples of (file_path, relative_arcname) for files
@@ -456,6 +458,8 @@ class CodePackager:
456
458
  Whether to exclude hidden files and directories (those starting with '.')
457
459
  suffixes : List[str], optional
458
460
  List of file suffixes to include (e.g. ['.py', '.txt'])
461
+ normalized_rel_path : bool, default False
462
+ Whether to normalize the relative from the root. ie if the root is /a/b/c and the file is /a/b/c/d/e.py then the relative path will be d/e.py
459
463
 
460
464
  Returns
461
465
  -------
@@ -468,6 +472,8 @@ class CodePackager:
468
472
  for file_path, rel_path in symlink_friendly_walk(
469
473
  root, exclude_hidden, suffixes
470
474
  ):
475
+ if normalized_rel_path:
476
+ rel_path = file_path.replace(root, "")
471
477
  files.append((file_path, rel_path))
472
478
  return files
473
479
 
@@ -520,6 +526,7 @@ class CodePackager:
520
526
  path,
521
527
  exclude_hidden=True,
522
528
  suffixes=suffixes,
529
+ normalized_rel_path=True,
523
530
  ):
524
531
  tar.add(
525
532
  file_path,
@@ -40,6 +40,7 @@ class ResourceConfigDict(TypedDict, total=False):
40
40
  memory: Optional[str]
41
41
  gpu: Optional[str]
42
42
  disk: Optional[str]
43
+ shared_memory: Optional[str]
43
44
 
44
45
 
45
46
  class AuthConfigDict(TypedDict, total=False):
@@ -67,7 +68,7 @@ class DependencyConfigDict(TypedDict, total=False):
67
68
 
68
69
 
69
70
  class PackageConfigDict(TypedDict, total=False):
70
- src_path: Optional[str]
71
+ src_paths: Optional[list]
71
72
  suffixes: Optional[list]
72
73
 
73
74
 
@@ -96,6 +97,7 @@ class TypedCoreConfig:
96
97
  branch: Optional[str] = None,
97
98
  models: Optional[list] = None,
98
99
  data: Optional[list] = None,
100
+ generate_static_url: Optional[bool] = None,
99
101
  **kwargs
100
102
  ) -> None:
101
103
  self._kwargs = {
@@ -121,6 +123,7 @@ class TypedCoreConfig:
121
123
  "branch": branch,
122
124
  "models": models,
123
125
  "data": data,
126
+ "generate_static_url": generate_static_url,
124
127
  }
125
128
  # Add any additional kwargs
126
129
  self._kwargs.update(kwargs)
@@ -36,10 +36,11 @@ from .config_utils import (
36
36
  class AuthType:
37
37
  BROWSER = "Browser"
38
38
  API = "API"
39
+ BROWSER_AND_API = "BrowserAndApi"
39
40
 
40
41
  @classmethod
41
42
  def choices(cls):
42
- return [cls.BROWSER, cls.API]
43
+ return [cls.BROWSER, cls.API, cls.BROWSER_AND_API]
43
44
 
44
45
 
45
46
  class UnitParser:
@@ -222,6 +223,18 @@ class ResourceConfig(metaclass=ConfigMeta):
222
223
  parsing_fn=UnitParser("disk").parse,
223
224
  )
224
225
 
226
+ shared_memory = ConfigField(
227
+ cli_meta=CLIOption(
228
+ name="shared_memory",
229
+ cli_option_str="--shared-memory",
230
+ help="Shared memory resource request and limit.",
231
+ ),
232
+ field_type=str,
233
+ example="1Gi",
234
+ validation_fn=UnitParser.validation_wrapper_fn("memory"),
235
+ parsing_fn=UnitParser("memory").parse,
236
+ )
237
+
225
238
 
226
239
  class HealthCheckConfig(metaclass=ConfigMeta):
227
240
  """Health check configuration."""
@@ -480,7 +493,7 @@ class DependencyConfig(metaclass=ConfigMeta):
480
493
  help="The Python version to use for the app.",
481
494
  ),
482
495
  field_type=str,
483
- behavior=FieldBehavior.NOT_ALLOWED,
496
+ behavior=FieldBehavior.UNION,
484
497
  example="3.10",
485
498
  )
486
499
  pypi = ConfigField(
@@ -541,14 +554,16 @@ class DependencyConfig(metaclass=ConfigMeta):
541
554
  class PackageConfig(metaclass=ConfigMeta):
542
555
  """Package configuration."""
543
556
 
544
- src_path = ConfigField(
557
+ src_paths = ConfigField(
545
558
  cli_meta=CLIOption(
546
559
  name="package_src_path",
547
560
  cli_option_str="--package-src-path",
561
+ multiple=True,
548
562
  help="The path to the source code to deploy with the App.",
563
+ click_type=str,
549
564
  ),
550
- field_type=str,
551
- example="./",
565
+ field_type=list,
566
+ example=["./"],
552
567
  )
553
568
  suffixes = ConfigField(
554
569
  cli_meta=CLIOption(
@@ -560,6 +575,28 @@ class PackageConfig(metaclass=ConfigMeta):
560
575
  example=[".py", ".ipynb"],
561
576
  )
562
577
 
578
+ @staticmethod
579
+ def validate(package_config: "PackageConfig"):
580
+ if package_config.src_paths is None:
581
+ return True
582
+ if package_config.src_paths:
583
+ for path in package_config.src_paths:
584
+ if not os.path.exists(path):
585
+ raise ConfigValidationFailedException(
586
+ field_name="src_paths",
587
+ field_info=package_config._get_field("src_paths"), # type: ignore
588
+ current_value=package_config.src_paths,
589
+ message=f"Path does not exist : `{path}`",
590
+ )
591
+ if not os.path.isdir(path):
592
+ raise ConfigValidationFailedException(
593
+ field_name="src_paths",
594
+ field_info=package_config._get_field("src_paths"), # type: ignore
595
+ current_value=package_config.src_paths,
596
+ message=f"Path is not a directory : `{path}`",
597
+ )
598
+ return True
599
+
563
600
 
564
601
  def everything_is_string(*args):
565
602
  return all(isinstance(arg, str) for arg in args)
@@ -852,6 +889,7 @@ How to read this schema:
852
889
  cli_meta=None, # No top-level CLI option, only nested fields have CLI options
853
890
  field_type=PackageConfig,
854
891
  help="Configurations associated with packaging the app.",
892
+ validation_fn=PackageConfig.validate,
855
893
  )
856
894
 
857
895
  no_deps = ConfigField(
@@ -929,6 +967,17 @@ How to read this schema:
929
967
  is_experimental=True,
930
968
  example=[{"asset_id": "data-789", "asset_instance_id": "instance-101"}],
931
969
  )
970
+ generate_static_url = ConfigField(
971
+ cli_meta=CLIOption(
972
+ name="generate_static_url",
973
+ cli_option_str="--generate-static-url",
974
+ help="Generate a static URL for the app based on its name.",
975
+ is_flag=True,
976
+ ),
977
+ field_type=bool,
978
+ default=False,
979
+ help="Generate a static URL for the app based on its name.",
980
+ )
932
981
  # ------- /Experimental -------------
933
982
 
934
983
  def to_dict(self):
@@ -129,6 +129,12 @@ properties:
129
129
  example: 1Gi
130
130
  mutation_behavior: union
131
131
  cli_option: --disk
132
+ shared_memory:
133
+ description: Shared memory resource request and limit. (validation applied)
134
+ type: string
135
+ example: 1Gi
136
+ mutation_behavior: union
137
+ cli_option: --shared-memory
132
138
  mutation_behavior: union
133
139
  auth:
134
140
  title: AuthConfig
@@ -143,6 +149,7 @@ properties:
143
149
  enum:
144
150
  - Browser
145
151
  - API
152
+ - BrowserAndApi
146
153
  example: Browser
147
154
  mutation_behavior: union
148
155
  cli_option: --auth-type
@@ -218,7 +225,7 @@ properties:
218
225
  description: The Python version to use for the app.
219
226
  type: string
220
227
  example: '3.10'
221
- mutation_behavior: not_allowed
228
+ mutation_behavior: union
222
229
  cli_option: --python
223
230
  pypi:
224
231
  description: |-
@@ -247,10 +254,13 @@ properties:
247
254
  type: object
248
255
  required: []
249
256
  properties:
250
- src_path:
257
+ src_paths:
251
258
  description: The path to the source code to deploy with the App.
252
- type: string
253
- example: ./
259
+ type: array
260
+ items:
261
+ type: string
262
+ example:
263
+ - ./
254
264
  mutation_behavior: union
255
265
  cli_option: --package-src-path
256
266
  suffixes:
@@ -319,3 +329,9 @@ properties:
319
329
  asset_instance_id: instance-101
320
330
  experimental: true
321
331
  mutation_behavior: union
332
+ generate_static_url:
333
+ description: Generate a static URL for the app based on its name.
334
+ type: boolean
335
+ default: false
336
+ mutation_behavior: union
337
+ cli_option: --generate-static-url