fal 1.46.1__tar.gz → 1.47.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.

Potentially problematic release.


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

Files changed (201) hide show
  1. {fal-1.46.1/fal.egg-info → fal-1.47.0}/PKG-INFO +2 -2
  2. {fal-1.46.1 → fal-1.47.0/fal.egg-info}/PKG-INFO +2 -2
  3. {fal-1.46.1 → fal-1.47.0}/fal.egg-info/requires.txt +1 -1
  4. {fal-1.46.1 → fal-1.47.0}/pyproject.toml +1 -1
  5. {fal-1.46.1 → fal-1.47.0}/src/fal/_fal_version.py +2 -2
  6. {fal-1.46.1 → fal-1.47.0}/src/fal/api/api.py +2 -0
  7. {fal-1.46.1 → fal-1.47.0}/src/fal/api/deploy.py +1 -0
  8. {fal-1.46.1 → fal-1.47.0}/src/fal/app.py +74 -4
  9. {fal-1.46.1 → fal-1.47.0}/src/fal/file_sync.py +7 -6
  10. {fal-1.46.1 → fal-1.47.0}/src/fal/sdk.py +2 -0
  11. {fal-1.46.1 → fal-1.47.0}/src/fal/utils.py +7 -1
  12. {fal-1.46.1 → fal-1.47.0}/tests/unit/test_app.py +25 -5
  13. {fal-1.46.1 → fal-1.47.0}/.gitignore +0 -0
  14. {fal-1.46.1 → fal-1.47.0}/Makefile +0 -0
  15. {fal-1.46.1 → fal-1.47.0}/README.md +0 -0
  16. {fal-1.46.1 → fal-1.47.0}/docs/conf.py +0 -0
  17. {fal-1.46.1 → fal-1.47.0}/docs/index.rst +0 -0
  18. {fal-1.46.1 → fal-1.47.0}/fal.egg-info/SOURCES.txt +0 -0
  19. {fal-1.46.1 → fal-1.47.0}/fal.egg-info/dependency_links.txt +0 -0
  20. {fal-1.46.1 → fal-1.47.0}/fal.egg-info/entry_points.txt +0 -0
  21. {fal-1.46.1 → fal-1.47.0}/fal.egg-info/top_level.txt +0 -0
  22. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/README.md +0 -0
  23. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
  24. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
  25. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
  26. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
  27. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
  28. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
  29. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
  30. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
  31. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
  32. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
  33. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
  34. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
  35. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
  36. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
  37. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
  38. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
  39. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
  40. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
  41. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
  42. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
  43. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
  44. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
  45. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
  46. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
  47. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
  48. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
  49. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
  50. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
  51. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
  52. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
  53. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
  54. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
  55. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
  56. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
  57. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
  58. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
  59. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
  60. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
  61. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
  62. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
  63. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
  64. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
  65. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
  66. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
  67. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
  68. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
  69. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
  70. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
  71. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
  72. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
  73. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
  74. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
  75. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
  76. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
  77. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
  78. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
  79. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
  80. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
  81. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
  82. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
  83. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
  84. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
  85. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
  86. {fal-1.46.1 → fal-1.47.0}/openapi-fal-rest/pyproject.toml +0 -0
  87. {fal-1.46.1 → fal-1.47.0}/openapi_rest.config.yaml +0 -0
  88. {fal-1.46.1 → fal-1.47.0}/setup.cfg +0 -0
  89. {fal-1.46.1 → fal-1.47.0}/src/fal/__init__.py +0 -0
  90. {fal-1.46.1 → fal-1.47.0}/src/fal/__main__.py +0 -0
  91. {fal-1.46.1 → fal-1.47.0}/src/fal/_serialization.py +0 -0
  92. {fal-1.46.1 → fal-1.47.0}/src/fal/_version.py +0 -0
  93. {fal-1.46.1 → fal-1.47.0}/src/fal/api/__init__.py +0 -0
  94. {fal-1.46.1 → fal-1.47.0}/src/fal/api/apps.py +0 -0
  95. {fal-1.46.1 → fal-1.47.0}/src/fal/api/client.py +0 -0
  96. {fal-1.46.1 → fal-1.47.0}/src/fal/api/runners.py +0 -0
  97. {fal-1.46.1 → fal-1.47.0}/src/fal/apps.py +0 -0
  98. {fal-1.46.1 → fal-1.47.0}/src/fal/auth/__init__.py +0 -0
  99. {fal-1.46.1 → fal-1.47.0}/src/fal/auth/auth0.py +0 -0
  100. {fal-1.46.1 → fal-1.47.0}/src/fal/auth/local.py +0 -0
  101. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/__init__.py +0 -0
  102. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/_utils.py +0 -0
  103. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/api.py +0 -0
  104. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/apps.py +0 -0
  105. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/auth.py +0 -0
  106. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/cli_nested_json.py +0 -0
  107. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/create.py +0 -0
  108. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/debug.py +0 -0
  109. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/deploy.py +0 -0
  110. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/doctor.py +0 -0
  111. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/files.py +0 -0
  112. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/keys.py +0 -0
  113. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/main.py +0 -0
  114. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/parser.py +0 -0
  115. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/profile.py +0 -0
  116. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/queue.py +0 -0
  117. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/run.py +0 -0
  118. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/runners.py +0 -0
  119. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/secrets.py +0 -0
  120. {fal-1.46.1 → fal-1.47.0}/src/fal/cli/teams.py +0 -0
  121. {fal-1.46.1 → fal-1.47.0}/src/fal/config.py +0 -0
  122. {fal-1.46.1 → fal-1.47.0}/src/fal/console/__init__.py +0 -0
  123. {fal-1.46.1 → fal-1.47.0}/src/fal/console/icons.py +0 -0
  124. {fal-1.46.1 → fal-1.47.0}/src/fal/console/ux.py +0 -0
  125. {fal-1.46.1 → fal-1.47.0}/src/fal/container.py +0 -0
  126. {fal-1.46.1 → fal-1.47.0}/src/fal/distributed/__init__.py +0 -0
  127. {fal-1.46.1 → fal-1.47.0}/src/fal/distributed/utils.py +0 -0
  128. {fal-1.46.1 → fal-1.47.0}/src/fal/distributed/worker.py +0 -0
  129. {fal-1.46.1 → fal-1.47.0}/src/fal/exceptions/__init__.py +0 -0
  130. {fal-1.46.1 → fal-1.47.0}/src/fal/exceptions/_base.py +0 -0
  131. {fal-1.46.1 → fal-1.47.0}/src/fal/exceptions/_cuda.py +0 -0
  132. {fal-1.46.1 → fal-1.47.0}/src/fal/exceptions/auth.py +0 -0
  133. {fal-1.46.1 → fal-1.47.0}/src/fal/files.py +0 -0
  134. {fal-1.46.1 → fal-1.47.0}/src/fal/flags.py +0 -0
  135. {fal-1.46.1 → fal-1.47.0}/src/fal/logging/__init__.py +0 -0
  136. {fal-1.46.1 → fal-1.47.0}/src/fal/logging/isolate.py +0 -0
  137. {fal-1.46.1 → fal-1.47.0}/src/fal/logging/style.py +0 -0
  138. {fal-1.46.1 → fal-1.47.0}/src/fal/logging/trace.py +0 -0
  139. {fal-1.46.1 → fal-1.47.0}/src/fal/project.py +0 -0
  140. {fal-1.46.1 → fal-1.47.0}/src/fal/py.typed +0 -0
  141. {fal-1.46.1 → fal-1.47.0}/src/fal/rest_client.py +0 -0
  142. {fal-1.46.1 → fal-1.47.0}/src/fal/sync.py +0 -0
  143. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/__init__.py +0 -0
  144. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/audio/__init__.py +0 -0
  145. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/audio/audio.py +0 -0
  146. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/exceptions.py +0 -0
  147. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/file/__init__.py +0 -0
  148. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/file/file.py +0 -0
  149. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/file/providers/fal.py +0 -0
  150. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/file/providers/gcp.py +0 -0
  151. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/file/providers/r2.py +0 -0
  152. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/file/providers/s3.py +0 -0
  153. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/file/types.py +0 -0
  154. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/__init__.py +0 -0
  155. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/image.py +0 -0
  156. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
  157. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
  158. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
  159. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
  160. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
  161. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/image/safety_checker.py +0 -0
  162. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/kv.py +0 -0
  163. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/optimize.py +0 -0
  164. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/types.py +0 -0
  165. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/utils/__init__.py +0 -0
  166. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/utils/download_utils.py +0 -0
  167. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/utils/endpoint.py +0 -0
  168. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/utils/retry.py +0 -0
  169. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/utils/setup_utils.py +0 -0
  170. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/video/__init__.py +0 -0
  171. {fal-1.46.1 → fal-1.47.0}/src/fal/toolkit/video/video.py +0 -0
  172. {fal-1.46.1 → fal-1.47.0}/src/fal/workflows.py +0 -0
  173. {fal-1.46.1 → fal-1.47.0}/tests/__init__.py +0 -0
  174. {fal-1.46.1 → fal-1.47.0}/tests/assets/cat.png +0 -0
  175. {fal-1.46.1 → fal-1.47.0}/tests/cli/__init__.py +0 -0
  176. {fal-1.46.1 → fal-1.47.0}/tests/cli/test_apps.py +0 -0
  177. {fal-1.46.1 → fal-1.47.0}/tests/cli/test_auth.py +0 -0
  178. {fal-1.46.1 → fal-1.47.0}/tests/cli/test_deploy.py +0 -0
  179. {fal-1.46.1 → fal-1.47.0}/tests/cli/test_keys.py +0 -0
  180. {fal-1.46.1 → fal-1.47.0}/tests/cli/test_run.py +0 -0
  181. {fal-1.46.1 → fal-1.47.0}/tests/cli/test_secrets.py +0 -0
  182. {fal-1.46.1 → fal-1.47.0}/tests/conftest.py +0 -0
  183. {fal-1.46.1 → fal-1.47.0}/tests/integration_test.py +0 -0
  184. {fal-1.46.1 → fal-1.47.0}/tests/mainify_package/__init__.py +0 -0
  185. {fal-1.46.1 → fal-1.47.0}/tests/mainify_package/impl.py +0 -0
  186. {fal-1.46.1 → fal-1.47.0}/tests/mainify_package/utils.py +0 -0
  187. {fal-1.46.1 → fal-1.47.0}/tests/mainify_target.py +0 -0
  188. {fal-1.46.1 → fal-1.47.0}/tests/test_apps.py +0 -0
  189. {fal-1.46.1 → fal-1.47.0}/tests/test_file_sync.py +0 -0
  190. {fal-1.46.1 → fal-1.47.0}/tests/test_files.py +0 -0
  191. {fal-1.46.1 → fal-1.47.0}/tests/test_kv.py +0 -0
  192. {fal-1.46.1 → fal-1.47.0}/tests/test_stability.py +0 -0
  193. {fal-1.46.1 → fal-1.47.0}/tests/toolkit/file/providers/test_fal_retry.py +0 -0
  194. {fal-1.46.1 → fal-1.47.0}/tests/toolkit/file_test.py +0 -0
  195. {fal-1.46.1 → fal-1.47.0}/tests/toolkit/image_test.py +0 -0
  196. {fal-1.46.1 → fal-1.47.0}/tests/toolkit/test_types.py +0 -0
  197. {fal-1.46.1 → fal-1.47.0}/tests/toolkit/utils/retry.py +0 -0
  198. {fal-1.46.1 → fal-1.47.0}/tests/unit/distributed/test_integration.py +0 -0
  199. {fal-1.46.1 → fal-1.47.0}/tests/unit/distributed/test_utils.py +0 -0
  200. {fal-1.46.1 → fal-1.47.0}/tests/unit/distributed/test_worker.py +0 -0
  201. {fal-1.46.1 → fal-1.47.0}/tools/demo_script.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.46.1
3
+ Version: 1.47.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
8
  Requires-Dist: isolate[build]<0.21.0,>=0.18.0
9
- Requires-Dist: isolate-proto<0.19.0,>=0.18.0
9
+ Requires-Dist: isolate-proto<0.20.0,>=0.19.0
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
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.46.1
3
+ Version: 1.47.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
8
  Requires-Dist: isolate[build]<0.21.0,>=0.18.0
9
- Requires-Dist: isolate-proto<0.19.0,>=0.18.0
9
+ Requires-Dist: isolate-proto<0.20.0,>=0.19.0
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
@@ -1,5 +1,5 @@
1
1
  isolate[build]<0.21.0,>=0.18.0
2
- isolate-proto<0.19.0,>=0.18.0
2
+ isolate-proto<0.20.0,>=0.19.0
3
3
  grpcio<2,>=1.64.0
4
4
  dill==0.3.7
5
5
  cloudpickle==3.0.0
@@ -23,7 +23,7 @@ readme = "README.md"
23
23
  requires-python = ">=3.8"
24
24
  dependencies = [
25
25
  "isolate[build]>=0.18.0,<0.21.0",
26
- "isolate-proto>=0.18.0,<0.19.0",
26
+ "isolate-proto>=0.19.0,<0.20.0",
27
27
  "grpcio>=1.64.0,<2",
28
28
  "dill==0.3.7",
29
29
  "cloudpickle==3.0.0",
@@ -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.46.1'
32
- __version_tuple__ = version_tuple = (1, 46, 1)
31
+ __version__ = version = '1.47.0'
32
+ __version_tuple__ = version_tuple = (1, 47, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -514,6 +514,7 @@ class FalServerlessHost(Host):
514
514
  *,
515
515
  application_name: Optional[str] = None,
516
516
  application_auth_mode: Optional[AuthModeLiteral] = None,
517
+ source_code: Optional[str] = None,
517
518
  metadata: Optional[dict[str, Any]] = None,
518
519
  deployment_strategy: DeploymentStrategyLiteral,
519
520
  scale: bool = True,
@@ -574,6 +575,7 @@ class FalServerlessHost(Host):
574
575
  environments,
575
576
  application_name=application_name,
576
577
  auth_mode=application_auth_mode,
578
+ source_code=source_code,
577
579
  machine_requirements=machine_requirements,
578
580
  metadata=metadata,
579
581
  deployment_strategy=deployment_strategy,
@@ -122,6 +122,7 @@ def _deploy_from_reference(
122
122
  options=isolated_function.options,
123
123
  application_name=app_name,
124
124
  application_auth_mode=app_auth, # type: ignore
125
+ source_code=loaded.source_code,
125
126
  metadata=isolated_function.options.host.get("metadata", {}),
126
127
  deployment_strategy=strategy,
127
128
  scale=scale,
@@ -6,11 +6,13 @@ import json
6
6
  import os
7
7
  import queue
8
8
  import re
9
+ import sys
9
10
  import threading
10
11
  import time
11
12
  import typing
12
13
  from contextlib import asynccontextmanager, contextmanager
13
14
  from dataclasses import dataclass
15
+ from pathlib import Path
14
16
  from typing import Any, Callable, ClassVar, Optional, TypeVar
15
17
 
16
18
  import fastapi
@@ -109,6 +111,10 @@ async def _set_logger_labels(
109
111
  def wrap_app(cls: type[App], **kwargs) -> IsolatedFunction:
110
112
  include_modules_from(cls)
111
113
 
114
+ host = kwargs.get("host", None)
115
+ if host:
116
+ cls.local_file_path = host.local_file_path
117
+
112
118
  def initialize_and_serve():
113
119
  app = cls()
114
120
  app.serve()
@@ -306,12 +312,61 @@ def _print_python_packages() -> None:
306
312
  print("[debug] Python packages installed:", ", ".join(packages))
307
313
 
308
314
 
309
- def _include_app_files_path():
310
- import sys # noqa: PLC0415
315
+ def _include_app_files_path(
316
+ local_file_path: str | None, app_files_context_dir: str | None
317
+ ):
318
+ base_cloud_dir = Path("/app")
319
+ if local_file_path is None:
320
+ return
321
+
322
+ # In case of container apps, the /app directory is not created by default
323
+ # so we need to check if it exists before proceeding
324
+ if not base_cloud_dir.exists():
325
+ return
326
+
327
+ base_path = Path(local_file_path).resolve()
328
+ if base_path.is_dir():
329
+ original_script_dir = base_path
330
+ else:
331
+ original_script_dir = base_path.parent
332
+
333
+ if app_files_context_dir:
334
+ context_path = Path(app_files_context_dir)
335
+ if context_path.is_absolute():
336
+ final_script_dir = context_path.resolve()
337
+ else:
338
+ final_script_dir = (original_script_dir / context_path).resolve()
339
+
340
+ # relative path between the original script dir
341
+ # and where the app_files_context_dir is targetting
342
+ relative_path = os.path.relpath(original_script_dir, final_script_dir)
343
+ # cloud final_path based on the `/app` base dir,
344
+ final_path = base_cloud_dir / Path(relative_path)
345
+ else:
346
+ # if no app_files_context_dir is provided, the base directory is the root
347
+ final_path = base_cloud_dir
348
+
349
+ # Create the final path if it doesn't exist
350
+ # This is for cases when fal app is not in root
351
+ # and its parent directory is not in app_files
352
+ # Which means that the relative path to app won't be created by default
353
+ final_path.mkdir(parents=True, exist_ok=True)
311
354
 
312
355
  # Add local files deployment path to sys.path so imports
313
356
  # work correctly in the isolate agent
314
- sys.path.append("/app_files")
357
+ # Append the final path to sys.path first so that the
358
+ # relative directory is resolved first in case of conflicts
359
+ sys.path.append(str(final_path))
360
+
361
+ # Add the base cloud dir path to sys.path so that
362
+ # the app can access the files in the top level directory
363
+ # This is for cases when fal app is not in root,
364
+ # and user wants to access the files without using relative imports
365
+ sys.path.append(str(base_cloud_dir))
366
+
367
+ # Change the current working directory to the path of the app
368
+ # so that the app can access the files in the current directory
369
+ os.chdir(str(final_path))
315
370
 
316
371
 
317
372
  class App(BaseServable):
@@ -341,6 +396,7 @@ class App(BaseServable):
341
396
  max_multiplexing: ClassVar[Optional[int]] = None
342
397
  kind: ClassVar[Optional[str]] = None
343
398
  image: ClassVar[Optional[ContainerImage]] = None
399
+ local_file_path: ClassVar[Optional[str]] = None
344
400
 
345
401
  isolate_channel: async_grpc.Channel | None = None
346
402
 
@@ -363,6 +419,10 @@ class App(BaseServable):
363
419
 
364
420
  if cls.app_files_context_dir is not None:
365
421
  cls.host_kwargs["app_files_context_dir"] = cls.app_files_context_dir
422
+ if not cls.app_files:
423
+ raise ValueError(
424
+ "app_files_context_dir is only supported when app_files is provided"
425
+ )
366
426
 
367
427
  if cls.min_concurrency is not None:
368
428
  cls.host_kwargs["min_concurrency"] = cls.min_concurrency
@@ -381,12 +441,17 @@ class App(BaseServable):
381
441
 
382
442
  if cls.kind is not None:
383
443
  cls.host_kwargs["kind"] = cls.kind
444
+ if cls.kind == "container" and cls.app_files:
445
+ raise ValueError("app_files is not supported for container apps.")
384
446
 
385
447
  if cls.image is not None:
386
448
  cls.host_kwargs["image"] = cls.image
387
449
 
388
450
  cls.app_name = getattr(cls, "app_name") or app_name
389
451
 
452
+ if kwargs.get("kind") and cls.app_files:
453
+ raise ValueError("app_files is not supported for container apps.")
454
+
390
455
  if cls.__init__ is not App.__init__:
391
456
  raise ValueError(
392
457
  "App classes should not override __init__ directly. "
@@ -418,7 +483,12 @@ class App(BaseServable):
418
483
 
419
484
  @asynccontextmanager
420
485
  async def lifespan(self, app: fastapi.FastAPI):
421
- _include_app_files_path()
486
+ # We want to not do any directory changes for container apps,
487
+ # since we don't have explicit checks to see the kind of app
488
+ # We check for app_files here and check kind and app_files earlier
489
+ # to ensure that container apps don't have app_files
490
+ if self.app_files:
491
+ _include_app_files_path(self.local_file_path, self.app_files_context_dir)
422
492
  _print_python_packages()
423
493
  await _call_any_fn(self.setup)
424
494
  try:
@@ -10,6 +10,7 @@ from typing import Dict, List, Optional, Tuple
10
10
  import httpx
11
11
  from rich.tree import Tree
12
12
 
13
+ import fal.flags as flags
13
14
  from fal._version import version_tuple
14
15
  from fal.console import console
15
16
  from fal.console.icons import CROSS_ICON
@@ -25,7 +26,7 @@ DEFAULT_CONCURRENCY_UPLOADS = 10
25
26
 
26
27
 
27
28
  def print_path_tree(file_paths):
28
- tree = Tree("/app_files")
29
+ tree = Tree("/app")
29
30
 
30
31
  nodes = {"": tree}
31
32
 
@@ -272,8 +273,8 @@ class FileSync:
272
273
  filtered_files: List[FileMetadata] = []
273
274
  for metadata in files:
274
275
  if self._matches_patterns(metadata.relative_path, files_ignore):
275
- # TODO: hide behind DEBUG flag?
276
- console.print(f"Ignoring file: {metadata.relative_path}")
276
+ if flags.DEBUG:
277
+ console.print(f"Ignoring file: {metadata.relative_path}")
277
278
  else:
278
279
  filtered_files.append(metadata)
279
280
 
@@ -344,9 +345,9 @@ class FileSync:
344
345
  else:
345
346
  uploaded_files.append((metadata, future.result()))
346
347
 
347
- # TODO: hide behind DEBUG flag?
348
- console.print("File Structure:")
349
- print_path_tree([m.relative_path for m in unique_files])
348
+ if flags.DEBUG:
349
+ console.print("File Structure:")
350
+ print_path_tree([m.relative_path for m in unique_files])
350
351
 
351
352
  return unique_files, errors
352
353
 
@@ -632,6 +632,7 @@ class FalServerlessConnection:
632
632
  application_name: str | None = None,
633
633
  auth_mode: Optional[AuthModeLiteral] = None,
634
634
  *,
635
+ source_code: str | None = None,
635
636
  serialization_method: str = _DEFAULT_SERIALIZATION_METHOD,
636
637
  machine_requirements: MachineRequirements | None = None,
637
638
  metadata: dict[str, Any] | None = None,
@@ -700,6 +701,7 @@ class FalServerlessConnection:
700
701
  scale=scale,
701
702
  private_logs=private_logs,
702
703
  files=files,
704
+ source_code=source_code,
703
705
  )
704
706
  for partial_result in self.stub.RegisterApplication(request):
705
707
  yield from_grpc(partial_result)
@@ -14,6 +14,7 @@ class LoadedFunction:
14
14
  endpoints: list[str]
15
15
  app_name: str | None
16
16
  app_auth: str | None
17
+ source_code: str | None
17
18
 
18
19
 
19
20
  def load_function_from(
@@ -57,6 +58,9 @@ def load_function_from(
57
58
 
58
59
  target = module[function_name]
59
60
 
61
+ with open(file_path) as f:
62
+ source_code = f.read()
63
+
60
64
  endpoints = ["/"]
61
65
  if isinstance(target, type) and issubclass(target, App):
62
66
  app_name = target.app_name
@@ -68,4 +72,6 @@ def load_function_from(
68
72
  raise FalServerlessError(
69
73
  f"Function '{function_name}' is not a fal.function or a fal.App"
70
74
  )
71
- return LoadedFunction(target, endpoints, app_name=app_name, app_auth=app_auth)
75
+ return LoadedFunction(
76
+ target, endpoints, app_name=app_name, app_auth=app_auth, source_code=source_code
77
+ )
@@ -15,9 +15,6 @@ def test_app_classvars_propagate_to_host_kwargs():
15
15
  class VarsApp(App):
16
16
  request_timeout = 11
17
17
  startup_timeout = 22
18
- app_files = ["a.py", "b.py"]
19
- app_files_ignore = [r"\\.venv/"]
20
- app_files_context_dir = "."
21
18
  min_concurrency = 2
22
19
  max_concurrency = 3
23
20
  concurrency_buffer = 4
@@ -28,6 +25,31 @@ def test_app_classvars_propagate_to_host_kwargs():
28
25
  "FROM python:3.10-slim",
29
26
  )
30
27
 
28
+ hk = VarsApp.host_kwargs
29
+ assert hk["request_timeout"] == 11
30
+ assert hk["startup_timeout"] == 22
31
+ assert hk["min_concurrency"] == 2
32
+ assert hk["max_concurrency"] == 3
33
+ assert hk["concurrency_buffer"] == 4
34
+ assert hk["concurrency_buffer_perc"] == 50
35
+ assert hk["max_multiplexing"] == 7
36
+ assert hk["kind"] == "container"
37
+ assert isinstance(hk["image"], ContainerImage)
38
+
39
+
40
+ def test_app_files_classvars_propagate_to_host_kwargs():
41
+ class VarsApp(App):
42
+ request_timeout = 11
43
+ startup_timeout = 22
44
+ app_files = ["a.py", "b.py"]
45
+ app_files_ignore = [r"\\.venv/"]
46
+ app_files_context_dir = "."
47
+ min_concurrency = 2
48
+ max_concurrency = 3
49
+ concurrency_buffer = 4
50
+ concurrency_buffer_perc = 50
51
+ max_multiplexing = 7
52
+
31
53
  hk = VarsApp.host_kwargs
32
54
  assert hk["request_timeout"] == 11
33
55
  assert hk["startup_timeout"] == 22
@@ -39,8 +61,6 @@ def test_app_classvars_propagate_to_host_kwargs():
39
61
  assert hk["concurrency_buffer"] == 4
40
62
  assert hk["concurrency_buffer_perc"] == 50
41
63
  assert hk["max_multiplexing"] == 7
42
- assert hk["kind"] == "container"
43
- assert isinstance(hk["image"], ContainerImage)
44
64
 
45
65
 
46
66
  def test_app_kwargs_merge_into_host_kwargs_and_override_defaults():
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes