fal 1.50.2__tar.gz → 1.59.0__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 (209) hide show
  1. {fal-1.50.2/fal.egg-info → fal-1.59.0}/PKG-INFO +6 -6
  2. {fal-1.50.2 → fal-1.59.0}/README.md +1 -1
  3. {fal-1.50.2 → fal-1.59.0/fal.egg-info}/PKG-INFO +6 -6
  4. {fal-1.50.2 → fal-1.59.0}/fal.egg-info/SOURCES.txt +23 -23
  5. {fal-1.50.2 → fal-1.59.0}/fal.egg-info/requires.txt +4 -4
  6. {fal-1.50.2 → fal-1.59.0}/pyproject.toml +5 -4
  7. {fal-1.50.2 → fal-1.59.0}/src/fal/__init__.py +2 -1
  8. {fal-1.50.2 → fal-1.59.0}/src/fal/_fal_version.py +2 -2
  9. {fal-1.50.2 → fal-1.59.0}/src/fal/api/api.py +33 -2
  10. {fal-1.50.2 → fal-1.59.0}/src/fal/api/apps.py +23 -1
  11. {fal-1.50.2 → fal-1.59.0}/src/fal/api/client.py +66 -1
  12. {fal-1.50.2 → fal-1.59.0}/src/fal/api/deploy.py +16 -28
  13. fal-1.59.0/src/fal/api/keys.py +31 -0
  14. fal-1.59.0/src/fal/api/secrets.py +29 -0
  15. {fal-1.50.2 → fal-1.59.0}/src/fal/app.py +72 -15
  16. {fal-1.50.2 → fal-1.59.0}/src/fal/apps.py +1 -1
  17. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/_utils.py +11 -3
  18. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/api.py +4 -2
  19. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/apps.py +56 -2
  20. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/deploy.py +17 -3
  21. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/files.py +16 -24
  22. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/keys.py +47 -50
  23. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/queue.py +12 -10
  24. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/run.py +11 -7
  25. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/runners.py +51 -24
  26. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/secrets.py +28 -30
  27. {fal-1.50.2 → fal-1.59.0}/src/fal/files.py +31 -8
  28. fal-1.59.0/src/fal/flags.py +50 -0
  29. {fal-1.50.2 → fal-1.59.0}/src/fal/sdk.py +113 -23
  30. {fal-1.50.2 → fal-1.59.0}/src/fal/sync.py +22 -12
  31. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/__init__.py +10 -0
  32. fal-1.59.0/src/fal/toolkit/compilation.py +220 -0
  33. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/file/file.py +10 -9
  34. fal-1.59.0/src/fal/utils.py +111 -0
  35. {fal-1.50.2 → fal-1.59.0}/src/fal/workflows.py +6 -2
  36. {fal-1.50.2/tests → fal-1.59.0/tests/e2e}/test_apps.py +118 -20
  37. fal-1.50.2/tests/integration_test.py → fal-1.59.0/tests/integration/test.py +2 -0
  38. {fal-1.50.2/tests → fal-1.59.0/tests/integration}/test_stability.py +2 -0
  39. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/cli/test_apps.py +3 -0
  40. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/cli/test_deploy.py +137 -0
  41. fal-1.59.0/tests/unit/cli/test_run.py +221 -0
  42. fal-1.59.0/tests/unit/distributed/__init__.py +0 -0
  43. {fal-1.50.2 → fal-1.59.0}/tests/unit/test_app.py +71 -1
  44. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/test_file_sync.py +5 -1
  45. fal-1.59.0/tests/unit/test_utils.py +108 -0
  46. fal-1.50.2/src/fal/flags.py +0 -36
  47. fal-1.50.2/src/fal/rest_client.py +0 -25
  48. fal-1.50.2/src/fal/utils.py +0 -77
  49. fal-1.50.2/tests/cli/test_run.py +0 -114
  50. fal-1.50.2/tests/mainify_package/__init__.py +0 -1
  51. fal-1.50.2/tests/mainify_package/impl.py +0 -8
  52. fal-1.50.2/tests/mainify_package/utils.py +0 -2
  53. fal-1.50.2/tests/mainify_target.py +0 -22
  54. {fal-1.50.2 → fal-1.59.0}/.gitignore +0 -0
  55. {fal-1.50.2 → fal-1.59.0}/Makefile +0 -0
  56. {fal-1.50.2 → fal-1.59.0}/docs/conf.py +0 -0
  57. {fal-1.50.2 → fal-1.59.0}/docs/index.rst +0 -0
  58. {fal-1.50.2 → fal-1.59.0}/fal.egg-info/dependency_links.txt +0 -0
  59. {fal-1.50.2 → fal-1.59.0}/fal.egg-info/entry_points.txt +0 -0
  60. {fal-1.50.2 → fal-1.59.0}/fal.egg-info/top_level.txt +0 -0
  61. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/README.md +0 -0
  62. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
  63. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
  64. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
  65. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
  66. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
  67. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
  68. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
  69. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
  70. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
  71. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
  72. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
  73. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
  74. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
  75. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
  76. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
  77. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
  78. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
  79. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
  80. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
  81. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
  82. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
  83. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
  84. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
  85. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
  86. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
  87. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
  88. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
  89. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
  90. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
  91. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
  92. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
  93. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
  94. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
  95. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
  96. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
  97. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
  98. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
  99. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
  100. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
  101. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
  102. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
  103. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
  104. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
  105. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
  106. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
  107. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
  108. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
  109. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
  110. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
  111. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
  112. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
  113. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
  114. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
  115. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
  116. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
  117. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
  118. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
  119. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
  120. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
  121. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
  122. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
  123. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
  124. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
  125. {fal-1.50.2 → fal-1.59.0}/openapi-fal-rest/pyproject.toml +0 -0
  126. {fal-1.50.2 → fal-1.59.0}/openapi_rest.config.yaml +0 -0
  127. {fal-1.50.2 → fal-1.59.0}/setup.cfg +0 -0
  128. {fal-1.50.2 → fal-1.59.0}/src/fal/__main__.py +0 -0
  129. {fal-1.50.2 → fal-1.59.0}/src/fal/_serialization.py +0 -0
  130. {fal-1.50.2 → fal-1.59.0}/src/fal/_version.py +0 -0
  131. {fal-1.50.2 → fal-1.59.0}/src/fal/api/__init__.py +0 -0
  132. {fal-1.50.2 → fal-1.59.0}/src/fal/api/runners.py +0 -0
  133. {fal-1.50.2 → fal-1.59.0}/src/fal/auth/__init__.py +0 -0
  134. {fal-1.50.2 → fal-1.59.0}/src/fal/auth/auth0.py +0 -0
  135. {fal-1.50.2 → fal-1.59.0}/src/fal/auth/local.py +0 -0
  136. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/__init__.py +0 -0
  137. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/auth.py +0 -0
  138. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/cli_nested_json.py +0 -0
  139. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/create.py +0 -0
  140. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/debug.py +0 -0
  141. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/doctor.py +0 -0
  142. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/main.py +0 -0
  143. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/parser.py +0 -0
  144. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/profile.py +0 -0
  145. {fal-1.50.2 → fal-1.59.0}/src/fal/cli/teams.py +0 -0
  146. {fal-1.50.2 → fal-1.59.0}/src/fal/config.py +0 -0
  147. {fal-1.50.2 → fal-1.59.0}/src/fal/console/__init__.py +0 -0
  148. {fal-1.50.2 → fal-1.59.0}/src/fal/console/icons.py +0 -0
  149. {fal-1.50.2 → fal-1.59.0}/src/fal/console/ux.py +0 -0
  150. {fal-1.50.2 → fal-1.59.0}/src/fal/container.py +0 -0
  151. {fal-1.50.2 → fal-1.59.0}/src/fal/distributed/__init__.py +0 -0
  152. {fal-1.50.2 → fal-1.59.0}/src/fal/distributed/utils.py +0 -0
  153. {fal-1.50.2 → fal-1.59.0}/src/fal/distributed/worker.py +0 -0
  154. {fal-1.50.2 → fal-1.59.0}/src/fal/exceptions/__init__.py +0 -0
  155. {fal-1.50.2 → fal-1.59.0}/src/fal/exceptions/_base.py +0 -0
  156. {fal-1.50.2 → fal-1.59.0}/src/fal/exceptions/_cuda.py +0 -0
  157. {fal-1.50.2 → fal-1.59.0}/src/fal/exceptions/auth.py +0 -0
  158. {fal-1.50.2 → fal-1.59.0}/src/fal/file_sync.py +0 -0
  159. {fal-1.50.2 → fal-1.59.0}/src/fal/logging/__init__.py +0 -0
  160. {fal-1.50.2 → fal-1.59.0}/src/fal/logging/isolate.py +0 -0
  161. {fal-1.50.2 → fal-1.59.0}/src/fal/logging/style.py +0 -0
  162. {fal-1.50.2 → fal-1.59.0}/src/fal/logging/trace.py +0 -0
  163. {fal-1.50.2 → fal-1.59.0}/src/fal/project.py +0 -0
  164. {fal-1.50.2 → fal-1.59.0}/src/fal/py.typed +0 -0
  165. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/audio/__init__.py +0 -0
  166. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/audio/audio.py +0 -0
  167. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/exceptions.py +0 -0
  168. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/file/__init__.py +0 -0
  169. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/file/providers/fal.py +0 -0
  170. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/file/providers/gcp.py +0 -0
  171. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/file/providers/r2.py +0 -0
  172. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/file/providers/s3.py +0 -0
  173. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/file/types.py +0 -0
  174. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/__init__.py +0 -0
  175. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/image.py +0 -0
  176. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
  177. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
  178. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
  179. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
  180. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
  181. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/image/safety_checker.py +0 -0
  182. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/kv.py +0 -0
  183. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/optimize.py +0 -0
  184. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/types.py +0 -0
  185. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/utils/__init__.py +0 -0
  186. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/utils/download_utils.py +0 -0
  187. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/utils/endpoint.py +0 -0
  188. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/utils/retry.py +0 -0
  189. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/utils/setup_utils.py +0 -0
  190. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/video/__init__.py +0 -0
  191. {fal-1.50.2 → fal-1.59.0}/src/fal/toolkit/video/video.py +0 -0
  192. {fal-1.50.2 → fal-1.59.0}/tests/__init__.py +0 -0
  193. {fal-1.50.2 → fal-1.59.0}/tests/assets/cat.png +0 -0
  194. {fal-1.50.2 → fal-1.59.0}/tests/conftest.py +0 -0
  195. {fal-1.50.2/tests → fal-1.59.0/tests/integration}/test_files.py +0 -0
  196. /fal-1.50.2/tests/toolkit/image_test.py → /fal-1.59.0/tests/integration/toolkit/test_image.py +0 -0
  197. {fal-1.50.2/tests → fal-1.59.0/tests/integration/toolkit}/test_kv.py +0 -0
  198. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/cli/__init__.py +0 -0
  199. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/cli/test_auth.py +0 -0
  200. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/cli/test_keys.py +0 -0
  201. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/cli/test_secrets.py +0 -0
  202. {fal-1.50.2 → fal-1.59.0}/tests/unit/distributed/test_integration.py +0 -0
  203. {fal-1.50.2 → fal-1.59.0}/tests/unit/distributed/test_utils.py +0 -0
  204. {fal-1.50.2 → fal-1.59.0}/tests/unit/distributed/test_worker.py +0 -0
  205. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/toolkit/file/providers/test_fal_retry.py +0 -0
  206. /fal-1.50.2/tests/toolkit/file_test.py → /fal-1.59.0/tests/unit/toolkit/test_file.py +0 -0
  207. {fal-1.50.2/tests → fal-1.59.0/tests/unit}/toolkit/test_types.py +0 -0
  208. /fal-1.50.2/tests/toolkit/utils/retry.py → /fal-1.59.0/tests/unit/toolkit/utils/test_retry.py +0 -0
  209. {fal-1.50.2 → fal-1.59.0}/tools/demo_script.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.50.2
3
+ Version: 1.59.0
4
4
  Summary: fal is an easy-to-use Serverless Python Framework
5
5
  Author: Features & Labels <support@fal.ai>
6
6
  Requires-Python: >=3.8
7
7
  Description-Content-Type: text/markdown
8
- Requires-Dist: isolate[build]<0.21.0,>=0.18.0
9
- Requires-Dist: isolate-proto<0.23.0,>=0.22.0
8
+ Requires-Dist: isolate[build]<0.22.0,>=0.18.0
9
+ Requires-Dist: isolate-proto>=0.29.2
10
10
  Requires-Dist: grpcio<2,>=1.64.0
11
11
  Requires-Dist: dill==0.3.7
12
12
  Requires-Dist: cloudpickle==3.0.0
@@ -21,8 +21,8 @@ Requires-Dist: rich<15,>=13.3.2
21
21
  Requires-Dist: rich_argparse
22
22
  Requires-Dist: packaging>=21.3
23
23
  Requires-Dist: pathspec<1,>=0.11.1
24
- Requires-Dist: pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<2.11
25
- Requires-Dist: fastapi<1,>=0.99.1
24
+ Requires-Dist: pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*
25
+ Requires-Dist: fastapi<0.119,>=0.99.1
26
26
  Requires-Dist: starlette-exporter>=0.21.0
27
27
  Requires-Dist: httpx>=0.15.4
28
28
  Requires-Dist: httpx-sse
@@ -60,7 +60,7 @@ Requires-Dist: fal[docs,test]; extra == "dev"
60
60
  Requires-Dist: openapi-python-client<1,>=0.14.1; extra == "dev"
61
61
 
62
62
  [![PyPI](https://img.shields.io/pypi/v/fal.svg?logo=PyPI)](https://pypi.org/project/fal)
63
- [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/integration_tests.yaml?label=Tests)](https://github.com/fal-ai/fal/actions)
63
+ [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/fal-unit-tests.yml?label=Tests)](https://github.com/fal-ai/fal/actions)
64
64
 
65
65
  # fal
66
66
 
@@ -1,5 +1,5 @@
1
1
  [![PyPI](https://img.shields.io/pypi/v/fal.svg?logo=PyPI)](https://pypi.org/project/fal)
2
- [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/integration_tests.yaml?label=Tests)](https://github.com/fal-ai/fal/actions)
2
+ [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/fal-unit-tests.yml?label=Tests)](https://github.com/fal-ai/fal/actions)
3
3
 
4
4
  # fal
5
5
 
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.50.2
3
+ Version: 1.59.0
4
4
  Summary: fal is an easy-to-use Serverless Python Framework
5
5
  Author: Features & Labels <support@fal.ai>
6
6
  Requires-Python: >=3.8
7
7
  Description-Content-Type: text/markdown
8
- Requires-Dist: isolate[build]<0.21.0,>=0.18.0
9
- Requires-Dist: isolate-proto<0.23.0,>=0.22.0
8
+ Requires-Dist: isolate[build]<0.22.0,>=0.18.0
9
+ Requires-Dist: isolate-proto>=0.29.2
10
10
  Requires-Dist: grpcio<2,>=1.64.0
11
11
  Requires-Dist: dill==0.3.7
12
12
  Requires-Dist: cloudpickle==3.0.0
@@ -21,8 +21,8 @@ Requires-Dist: rich<15,>=13.3.2
21
21
  Requires-Dist: rich_argparse
22
22
  Requires-Dist: packaging>=21.3
23
23
  Requires-Dist: pathspec<1,>=0.11.1
24
- Requires-Dist: pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<2.11
25
- Requires-Dist: fastapi<1,>=0.99.1
24
+ Requires-Dist: pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*
25
+ Requires-Dist: fastapi<0.119,>=0.99.1
26
26
  Requires-Dist: starlette-exporter>=0.21.0
27
27
  Requires-Dist: httpx>=0.15.4
28
28
  Requires-Dist: httpx-sse
@@ -60,7 +60,7 @@ Requires-Dist: fal[docs,test]; extra == "dev"
60
60
  Requires-Dist: openapi-python-client<1,>=0.14.1; extra == "dev"
61
61
 
62
62
  [![PyPI](https://img.shields.io/pypi/v/fal.svg?logo=PyPI)](https://pypi.org/project/fal)
63
- [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/integration_tests.yaml?label=Tests)](https://github.com/fal-ai/fal/actions)
63
+ [![Tests](https://img.shields.io/github/actions/workflow/status/fal-ai/fal/fal-unit-tests.yml?label=Tests)](https://github.com/fal-ai/fal/actions)
64
64
 
65
65
  # fal
66
66
 
@@ -90,7 +90,6 @@ src/fal/files.py
90
90
  src/fal/flags.py
91
91
  src/fal/project.py
92
92
  src/fal/py.typed
93
- src/fal/rest_client.py
94
93
  src/fal/sdk.py
95
94
  src/fal/sync.py
96
95
  src/fal/utils.py
@@ -100,7 +99,9 @@ src/fal/api/api.py
100
99
  src/fal/api/apps.py
101
100
  src/fal/api/client.py
102
101
  src/fal/api/deploy.py
102
+ src/fal/api/keys.py
103
103
  src/fal/api/runners.py
104
+ src/fal/api/secrets.py
104
105
  src/fal/auth/__init__.py
105
106
  src/fal/auth/auth0.py
106
107
  src/fal/auth/local.py
@@ -139,6 +140,7 @@ src/fal/logging/isolate.py
139
140
  src/fal/logging/style.py
140
141
  src/fal/logging/trace.py
141
142
  src/fal/toolkit/__init__.py
143
+ src/fal/toolkit/compilation.py
142
144
  src/fal/toolkit/exceptions.py
143
145
  src/fal/toolkit/kv.py
144
146
  src/fal/toolkit/optimize.py
@@ -169,31 +171,29 @@ src/fal/toolkit/video/__init__.py
169
171
  src/fal/toolkit/video/video.py
170
172
  tests/__init__.py
171
173
  tests/conftest.py
172
- tests/integration_test.py
173
- tests/mainify_target.py
174
- tests/test_apps.py
175
- tests/test_file_sync.py
176
- tests/test_files.py
177
- tests/test_kv.py
178
- tests/test_stability.py
179
174
  tests/assets/cat.png
180
- tests/cli/__init__.py
181
- tests/cli/test_apps.py
182
- tests/cli/test_auth.py
183
- tests/cli/test_deploy.py
184
- tests/cli/test_keys.py
185
- tests/cli/test_run.py
186
- tests/cli/test_secrets.py
187
- tests/mainify_package/__init__.py
188
- tests/mainify_package/impl.py
189
- tests/mainify_package/utils.py
190
- tests/toolkit/file_test.py
191
- tests/toolkit/image_test.py
192
- tests/toolkit/test_types.py
193
- tests/toolkit/file/providers/test_fal_retry.py
194
- tests/toolkit/utils/retry.py
175
+ tests/e2e/test_apps.py
176
+ tests/integration/test.py
177
+ tests/integration/test_files.py
178
+ tests/integration/test_stability.py
179
+ tests/integration/toolkit/test_image.py
180
+ tests/integration/toolkit/test_kv.py
195
181
  tests/unit/test_app.py
182
+ tests/unit/test_file_sync.py
183
+ tests/unit/test_utils.py
184
+ tests/unit/cli/__init__.py
185
+ tests/unit/cli/test_apps.py
186
+ tests/unit/cli/test_auth.py
187
+ tests/unit/cli/test_deploy.py
188
+ tests/unit/cli/test_keys.py
189
+ tests/unit/cli/test_run.py
190
+ tests/unit/cli/test_secrets.py
191
+ tests/unit/distributed/__init__.py
196
192
  tests/unit/distributed/test_integration.py
197
193
  tests/unit/distributed/test_utils.py
198
194
  tests/unit/distributed/test_worker.py
195
+ tests/unit/toolkit/test_file.py
196
+ tests/unit/toolkit/test_types.py
197
+ tests/unit/toolkit/file/providers/test_fal_retry.py
198
+ tests/unit/toolkit/utils/test_retry.py
199
199
  tools/demo_script.py
@@ -1,5 +1,5 @@
1
- isolate[build]<0.21.0,>=0.18.0
2
- isolate-proto<0.23.0,>=0.22.0
1
+ isolate[build]<0.22.0,>=0.18.0
2
+ isolate-proto>=0.29.2
3
3
  grpcio<2,>=1.64.0
4
4
  dill==0.3.7
5
5
  cloudpickle==3.0.0
@@ -14,8 +14,8 @@ rich<15,>=13.3.2
14
14
  rich_argparse
15
15
  packaging>=21.3
16
16
  pathspec<1,>=0.11.1
17
- pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<2.11
18
- fastapi<1,>=0.99.1
17
+ pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*
18
+ fastapi<0.119,>=0.99.1
19
19
  starlette-exporter>=0.21.0
20
20
  httpx>=0.15.4
21
21
  httpx-sse
@@ -22,8 +22,8 @@ authors = [{ name = "Features & Labels <support@fal.ai>"}]
22
22
  readme = "README.md"
23
23
  requires-python = ">=3.8"
24
24
  dependencies = [
25
- "isolate[build]>=0.18.0,<0.21.0",
26
- "isolate-proto>=0.22.0,<0.23.0",
25
+ "isolate[build]>=0.18.0,<0.22.0",
26
+ "isolate-proto>=0.29.2",
27
27
  "grpcio>=1.64.0,<2",
28
28
  "dill==0.3.7",
29
29
  "cloudpickle==3.0.0",
@@ -38,9 +38,10 @@ dependencies = [
38
38
  "rich_argparse",
39
39
  "packaging>=21.3",
40
40
  "pathspec>=0.11.1,<1",
41
- "pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<2.11",
41
+ "pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*",
42
42
  # serve=True dependencies
43
- "fastapi>=0.99.1,<1",
43
+ # https://github.com/fastapi/fastapi/issues/14221
44
+ "fastapi>=0.99.1,<0.119",
44
45
  "starlette-exporter>=0.21.0",
45
46
  # rest-api-client dependencies
46
47
  "httpx>=0.15.4",
@@ -5,7 +5,7 @@ from fal.api import FalServerlessHost, LocalHost, cached, function
5
5
  from fal.api import function as isolated # noqa: F401
6
6
  from fal.app import App, endpoint, realtime, wrap_app # noqa: F401
7
7
  from fal.container import ContainerImage
8
- from fal.sdk import FalServerlessKeyCredentials
8
+ from fal.sdk import FalServerlessKeyCredentials, HealthCheck
9
9
  from fal.sync import sync_dir
10
10
 
11
11
  from ._version import __version__, version_tuple # noqa: F401
@@ -23,6 +23,7 @@ __all__ = [
23
23
  "endpoint",
24
24
  "realtime",
25
25
  # "wrap_app",
26
+ "HealthCheck",
26
27
  "FalServerlessKeyCredentials",
27
28
  "sync_dir",
28
29
  "__version__",
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.50.2'
32
- __version_tuple__ = version_tuple = (1, 50, 2)
31
+ __version__ = version = '1.59.0'
32
+ __version_tuple__ = version_tuple = (1, 59, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -66,8 +66,10 @@ from fal.sdk import (
66
66
  FalServerlessClient,
67
67
  FalServerlessConnection,
68
68
  File,
69
+ HealthCheck,
69
70
  HostedRunState,
70
71
  MachineRequirements,
72
+ RegisterApplicationResult,
71
73
  get_agent_credentials,
72
74
  get_default_credentials,
73
75
  )
@@ -84,6 +86,7 @@ _UNSET = object()
84
86
  SERVE_REQUIREMENTS = [
85
87
  f"fastapi=={fastapi_version}",
86
88
  f"pydantic=={pydantic_version}",
89
+ f"tblib=={tblib.__version__}",
87
90
  "uvicorn",
88
91
  "starlette_exporter",
89
92
  # workaround for prometheus_client 0.23.0
@@ -426,12 +429,14 @@ class FalServerlessHost(Host):
426
429
  {
427
430
  "machine_type",
428
431
  "machine_types",
432
+ "regions",
429
433
  "num_gpus",
430
434
  "keep_alive",
431
435
  "max_concurrency",
432
436
  "min_concurrency",
433
437
  "concurrency_buffer",
434
438
  "concurrency_buffer_perc",
439
+ "scaling_delay",
435
440
  "max_multiplexing",
436
441
  "setup_function",
437
442
  "metadata",
@@ -444,6 +449,7 @@ class FalServerlessHost(Host):
444
449
  "app_files",
445
450
  "app_files_ignore",
446
451
  "app_files_context_dir",
452
+ "health_check_config",
447
453
  }
448
454
  )
449
455
 
@@ -518,7 +524,7 @@ class FalServerlessHost(Host):
518
524
  metadata: Optional[dict[str, Any]] = None,
519
525
  deployment_strategy: DeploymentStrategyLiteral,
520
526
  scale: bool = True,
521
- ) -> Optional[str]:
527
+ ) -> Optional[RegisterApplicationResult]:
522
528
  from isolate.backends.common import active_python
523
529
 
524
530
  environment_options = options.environment.copy()
@@ -536,10 +542,12 @@ class FalServerlessHost(Host):
536
542
  min_concurrency = options.host.get("min_concurrency")
537
543
  concurrency_buffer = options.host.get("concurrency_buffer")
538
544
  concurrency_buffer_perc = options.host.get("concurrency_buffer_perc")
545
+ scaling_delay = options.host.get("scaling_delay")
539
546
  max_multiplexing = options.host.get("max_multiplexing")
540
547
  exposed_port = options.get_exposed_port()
541
548
  request_timeout = options.host.get("request_timeout")
542
549
  startup_timeout = options.host.get("startup_timeout")
550
+ regions = options.host.get("regions")
543
551
  machine_requirements = MachineRequirements(
544
552
  machine_types=machine_type, # type: ignore
545
553
  num_gpus=options.host.get("num_gpus"),
@@ -553,10 +561,14 @@ class FalServerlessHost(Host):
553
561
  min_concurrency=min_concurrency,
554
562
  concurrency_buffer=concurrency_buffer,
555
563
  concurrency_buffer_perc=concurrency_buffer_perc,
564
+ scaling_delay=scaling_delay,
556
565
  request_timeout=request_timeout,
557
566
  startup_timeout=startup_timeout,
567
+ valid_regions=regions,
558
568
  )
559
569
 
570
+ health_check_config = options.host.get("health_check_config")
571
+
560
572
  app_files = self._app_files_sync(options)
561
573
 
562
574
  partial_func = _prepare_partial_func(func)
@@ -580,6 +592,7 @@ class FalServerlessHost(Host):
580
592
  metadata=metadata,
581
593
  deployment_strategy=deployment_strategy,
582
594
  scale=scale,
595
+ health_check_config=health_check_config,
583
596
  # By default, logs are public
584
597
  private_logs=options.host.get("private_logs", False),
585
598
  files=app_files,
@@ -588,7 +601,7 @@ class FalServerlessHost(Host):
588
601
  self._log_printer.print(log)
589
602
 
590
603
  if partial_result.result:
591
- return partial_result.result.application_id
604
+ return partial_result
592
605
 
593
606
  return None
594
607
 
@@ -615,6 +628,7 @@ class FalServerlessHost(Host):
615
628
  min_concurrency = options.host.get("min_concurrency")
616
629
  concurrency_buffer = options.host.get("concurrency_buffer")
617
630
  concurrency_buffer_perc = options.host.get("concurrency_buffer_perc")
631
+ scaling_delay = options.host.get("scaling_delay")
618
632
  max_multiplexing = options.host.get("max_multiplexing")
619
633
  base_image = options.host.get("_base_image", None)
620
634
  scheduler = options.host.get("_scheduler", None)
@@ -636,6 +650,7 @@ class FalServerlessHost(Host):
636
650
  min_concurrency=min_concurrency,
637
651
  concurrency_buffer=concurrency_buffer,
638
652
  concurrency_buffer_perc=concurrency_buffer_perc,
653
+ scaling_delay=scaling_delay,
639
654
  request_timeout=request_timeout,
640
655
  startup_timeout=startup_timeout,
641
656
  )
@@ -824,12 +839,14 @@ def function(
824
839
  # FalServerlessHost options
825
840
  metadata: dict[str, Any] | None = None,
826
841
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
842
+ regions: list[str] | None = None,
827
843
  num_gpus: int | None = None,
828
844
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
829
845
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
830
846
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
831
847
  concurrency_buffer: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER,
832
848
  concurrency_buffer_perc: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER_PERC,
849
+ scaling_delay: int | None = None,
833
850
  request_timeout: int | None = None,
834
851
  startup_timeout: int | None = None,
835
852
  setup_function: Callable[..., None] | None = None,
@@ -855,12 +872,14 @@ def function(
855
872
  # FalServerlessHost options
856
873
  metadata: dict[str, Any] | None = None,
857
874
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
875
+ regions: list[str] | None = None,
858
876
  num_gpus: int | None = None,
859
877
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
860
878
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
861
879
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
862
880
  concurrency_buffer: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER,
863
881
  concurrency_buffer_perc: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER_PERC,
882
+ scaling_delay: int | None = None,
864
883
  request_timeout: int | None = None,
865
884
  startup_timeout: int | None = None,
866
885
  setup_function: Callable[..., None] | None = None,
@@ -938,12 +957,14 @@ def function(
938
957
  # FalServerlessHost options
939
958
  metadata: dict[str, Any] | None = None,
940
959
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
960
+ regions: list[str] | None = None,
941
961
  num_gpus: int | None = None,
942
962
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
943
963
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
944
964
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
945
965
  concurrency_buffer: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER,
946
966
  concurrency_buffer_perc: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER_PERC,
967
+ scaling_delay: int | None = None,
947
968
  request_timeout: int | None = None,
948
969
  startup_timeout: int | None = None,
949
970
  setup_function: Callable[..., None] | None = None,
@@ -974,12 +995,14 @@ def function(
974
995
  # FalServerlessHost options
975
996
  metadata: dict[str, Any] | None = None,
976
997
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
998
+ regions: list[str] | None = None,
977
999
  num_gpus: int | None = None,
978
1000
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
979
1001
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
980
1002
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
981
1003
  concurrency_buffer: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER,
982
1004
  concurrency_buffer_perc: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER_PERC,
1005
+ scaling_delay: int | None = None,
983
1006
  request_timeout: int | None = None,
984
1007
  startup_timeout: int | None = None,
985
1008
  setup_function: Callable[..., None] | None = None,
@@ -1004,12 +1027,14 @@ def function(
1004
1027
  # FalServerlessHost options
1005
1028
  metadata: dict[str, Any] | None = None,
1006
1029
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
1030
+ regions: list[str] | None = None,
1007
1031
  num_gpus: int | None = None,
1008
1032
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
1009
1033
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
1010
1034
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
1011
1035
  concurrency_buffer: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER,
1012
1036
  concurrency_buffer_perc: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER_PERC,
1037
+ scaling_delay: int | None = None,
1013
1038
  request_timeout: int | None = None,
1014
1039
  startup_timeout: int | None = None,
1015
1040
  setup_function: Callable[..., None] | None = None,
@@ -1034,12 +1059,14 @@ def function(
1034
1059
  # FalServerlessHost options
1035
1060
  metadata: dict[str, Any] | None = None,
1036
1061
  machine_type: str | list[str] = FAL_SERVERLESS_DEFAULT_MACHINE_TYPE,
1062
+ regions: list[str] | None = None,
1037
1063
  num_gpus: int | None = None,
1038
1064
  keep_alive: int = FAL_SERVERLESS_DEFAULT_KEEP_ALIVE,
1039
1065
  max_multiplexing: int = FAL_SERVERLESS_DEFAULT_MAX_MULTIPLEXING,
1040
1066
  min_concurrency: int = FAL_SERVERLESS_DEFAULT_MIN_CONCURRENCY,
1041
1067
  concurrency_buffer: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER,
1042
1068
  concurrency_buffer_perc: int = FAL_SERVERLESS_DEFAULT_CONCURRENCY_BUFFER_PERC,
1069
+ scaling_delay: int | None = None,
1043
1070
  request_timeout: int | None = None,
1044
1071
  startup_timeout: int | None = None,
1045
1072
  setup_function: Callable[..., None] | None = None,
@@ -1065,6 +1092,9 @@ def function( # type: ignore
1065
1092
  if config.get("image"):
1066
1093
  kind = "container"
1067
1094
 
1095
+ if kind == "container" and config.get("app_files"):
1096
+ raise ValueError("app_files is not supported for container apps.")
1097
+
1068
1098
  options = host.parse_options(kind=kind, **config)
1069
1099
 
1070
1100
  def wrapper(func: Callable[ArgsT, ReturnT]):
@@ -1141,6 +1171,7 @@ class FalFastAPI(FastAPI):
1141
1171
  class RouteSignature(NamedTuple):
1142
1172
  path: str
1143
1173
  is_websocket: bool = False
1174
+ health_check: HealthCheck | None = None
1144
1175
  input_modal: type | None = None
1145
1176
  buffering: int | None = None
1146
1177
  session_timeout: float | None = None
@@ -34,7 +34,14 @@ def apps_runners(
34
34
 
35
35
  if state and "all" not in set(state):
36
36
  states = set(state)
37
- alias_runners = [r for r in alias_runners if r.state.value in states]
37
+ alias_runners = [
38
+ r
39
+ for r in alias_runners
40
+ if r.state.value.lower() in states
41
+ or (
42
+ "terminated" in states and r.state.value.lower() == "dead"
43
+ ) # TODO for backwards compatibility. remove later
44
+ ]
38
45
  return alias_runners
39
46
 
40
47
 
@@ -48,6 +55,7 @@ def scale_app(
48
55
  min_concurrency: int | None = None,
49
56
  concurrency_buffer: int | None = None,
50
57
  concurrency_buffer_perc: int | None = None,
58
+ scaling_delay: int | None = None,
51
59
  request_timeout: int | None = None,
52
60
  startup_timeout: int | None = None,
53
61
  machine_types: list[str] | None = None,
@@ -62,8 +70,22 @@ def scale_app(
62
70
  min_concurrency=min_concurrency,
63
71
  concurrency_buffer=concurrency_buffer,
64
72
  concurrency_buffer_perc=concurrency_buffer_perc,
73
+ scaling_delay=scaling_delay,
65
74
  request_timeout=request_timeout,
66
75
  startup_timeout=startup_timeout,
67
76
  machine_types=machine_types,
68
77
  valid_regions=regions,
69
78
  )
79
+
80
+
81
+ def rollout_app(
82
+ client: SyncServerlessClient,
83
+ app_name: str,
84
+ *,
85
+ force: bool = False,
86
+ ) -> None:
87
+ with FalServerlessClient(client._grpc_host, client._credentials).connect() as conn:
88
+ conn.rollout_application(
89
+ application_name=app_name,
90
+ force=force,
91
+ )
@@ -2,18 +2,26 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  from dataclasses import dataclass
5
- from typing import List, Optional
5
+ from typing import TYPE_CHECKING, List, Optional
6
6
 
7
7
  from fal.api import FAL_SERVERLESS_DEFAULT_URL, FalServerlessHost
8
8
  from fal.sdk import (
9
9
  AliasInfo,
10
10
  Credentials,
11
+ KeyScope,
11
12
  RunnerInfo,
13
+ ServerlessSecret,
14
+ UserKeyInfo,
12
15
  )
13
16
 
17
+ if TYPE_CHECKING:
18
+ from openapi_fal_rest.client import Client
19
+
14
20
  from . import apps as apps_api
15
21
  from . import deploy as deploy_api
22
+ from . import keys as keys_api
16
23
  from . import runners as runners_api
24
+ from . import secrets as secrets_api
17
25
 
18
26
 
19
27
  class _AppsNamespace:
@@ -38,6 +46,7 @@ class _AppsNamespace:
38
46
  min_concurrency: int | None = None,
39
47
  concurrency_buffer: int | None = None,
40
48
  concurrency_buffer_perc: int | None = None,
49
+ scaling_delay: int | None = None,
41
50
  request_timeout: int | None = None,
42
51
  startup_timeout: int | None = None,
43
52
  machine_types: List[str] | None = None,
@@ -52,12 +61,16 @@ class _AppsNamespace:
52
61
  min_concurrency=min_concurrency,
53
62
  concurrency_buffer=concurrency_buffer,
54
63
  concurrency_buffer_perc=concurrency_buffer_perc,
64
+ scaling_delay=scaling_delay,
55
65
  request_timeout=request_timeout,
56
66
  startup_timeout=startup_timeout,
57
67
  machine_types=machine_types,
58
68
  regions=regions,
59
69
  )
60
70
 
71
+ def rollout(self, app_name: str, *, force: bool = False) -> None:
72
+ return apps_api.rollout_app(self.client, app_name, force=force)
73
+
61
74
 
62
75
  class _RunnersNamespace:
63
76
  def __init__(self, client: SyncServerlessClient):
@@ -73,6 +86,36 @@ class _RunnersNamespace:
73
86
  return runners_api.kill_runner(self.client, runner_id)
74
87
 
75
88
 
89
+ class _KeysNamespace:
90
+ def __init__(self, client: SyncServerlessClient):
91
+ self.client = client
92
+
93
+ def create(
94
+ self, *, scope: KeyScope, description: str | None = None
95
+ ) -> tuple[str, str]:
96
+ return keys_api.create_key(self.client, scope=scope, description=description)
97
+
98
+ def list(self) -> List[UserKeyInfo]:
99
+ return keys_api.list_keys(self.client)
100
+
101
+ def revoke(self, key_id: str) -> None:
102
+ return keys_api.revoke_key(self.client, key_id)
103
+
104
+
105
+ class _SecretsNamespace:
106
+ def __init__(self, client: SyncServerlessClient):
107
+ self.client = client
108
+
109
+ def set(self, name: str, value: str) -> None:
110
+ return secrets_api.set_secret(self.client, name, value)
111
+
112
+ def list(self) -> List[ServerlessSecret]:
113
+ return secrets_api.list_secrets(self.client)
114
+
115
+ def unset(self, name: str) -> None:
116
+ return secrets_api.unset_secret(self.client, name)
117
+
118
+
76
119
  @dataclass
77
120
  class SyncServerlessClient:
78
121
  host: Optional[str] = None
@@ -83,6 +126,8 @@ class SyncServerlessClient:
83
126
  def __post_init__(self) -> None:
84
127
  self.apps = _AppsNamespace(self)
85
128
  self.runners = _RunnersNamespace(self)
129
+ self.keys = _KeysNamespace(self)
130
+ self.secrets = _SecretsNamespace(self)
86
131
 
87
132
  # Top-level verbs
88
133
  def deploy(self, *args, **kwargs):
@@ -93,6 +138,12 @@ class SyncServerlessClient:
93
138
  def _grpc_host(self) -> str:
94
139
  return self.host or FAL_SERVERLESS_DEFAULT_URL
95
140
 
141
+ @property
142
+ def _rest_url(self) -> str:
143
+ from fal.flags import REST_SCHEME
144
+
145
+ return f"{REST_SCHEME}://{self._grpc_host.replace('api', 'rest', 1)}"
146
+
96
147
  @property
97
148
  def _credentials(self) -> Credentials:
98
149
  from fal.sdk import FalServerlessKeyCredentials, get_default_credentials
@@ -127,3 +178,17 @@ class SyncServerlessClient:
127
178
  local_file_path=local_file_path,
128
179
  credentials=self._credentials,
129
180
  )
181
+
182
+ def _create_rest_client(self) -> Client:
183
+ from openapi_fal_rest.client import Client
184
+
185
+ import fal.flags as flags
186
+
187
+ return Client(
188
+ self._rest_url,
189
+ headers=self._credentials.to_headers(),
190
+ timeout=30,
191
+ verify_ssl=not flags.TEST_MODE,
192
+ raise_on_unexpected_status=False,
193
+ follow_redirects=True,
194
+ )