fal 1.27.0__tar.gz → 1.28.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 (186) hide show
  1. {fal-1.27.0/fal.egg-info → fal-1.28.0}/PKG-INFO +1 -1
  2. {fal-1.27.0 → fal-1.28.0/fal.egg-info}/PKG-INFO +1 -1
  3. {fal-1.27.0 → fal-1.28.0}/src/fal/_fal_version.py +2 -2
  4. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/_utils.py +10 -3
  5. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/deploy.py +16 -11
  6. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/profile.py +9 -4
  7. {fal-1.27.0 → fal-1.28.0}/src/fal/config.py +3 -1
  8. {fal-1.27.0 → fal-1.28.0}/src/fal/exceptions/auth.py +1 -1
  9. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/utils/download_utils.py +26 -2
  10. {fal-1.27.0 → fal-1.28.0}/tests/cli/test_deploy.py +12 -13
  11. {fal-1.27.0 → fal-1.28.0}/.gitignore +0 -0
  12. {fal-1.27.0 → fal-1.28.0}/Makefile +0 -0
  13. {fal-1.27.0 → fal-1.28.0}/README.md +0 -0
  14. {fal-1.27.0 → fal-1.28.0}/docs/conf.py +0 -0
  15. {fal-1.27.0 → fal-1.28.0}/docs/index.rst +0 -0
  16. {fal-1.27.0 → fal-1.28.0}/fal.egg-info/SOURCES.txt +0 -0
  17. {fal-1.27.0 → fal-1.28.0}/fal.egg-info/dependency_links.txt +0 -0
  18. {fal-1.27.0 → fal-1.28.0}/fal.egg-info/entry_points.txt +0 -0
  19. {fal-1.27.0 → fal-1.28.0}/fal.egg-info/requires.txt +0 -0
  20. {fal-1.27.0 → fal-1.28.0}/fal.egg-info/top_level.txt +0 -0
  21. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/README.md +0 -0
  22. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
  23. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
  24. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
  25. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
  26. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
  27. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
  28. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
  29. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
  30. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
  31. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
  32. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
  33. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
  34. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
  35. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
  36. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
  37. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
  38. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
  39. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
  40. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
  41. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
  42. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
  43. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
  44. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
  45. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
  46. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
  47. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
  48. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
  49. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
  50. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
  51. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
  52. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
  53. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
  54. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
  55. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
  56. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
  57. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
  58. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
  59. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
  60. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
  61. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
  62. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
  63. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
  64. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
  65. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
  66. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
  67. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
  68. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
  69. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
  70. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
  71. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
  72. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
  73. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
  74. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
  75. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
  76. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
  77. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
  78. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
  79. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
  80. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
  81. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
  82. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
  83. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
  84. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
  85. {fal-1.27.0 → fal-1.28.0}/openapi-fal-rest/pyproject.toml +0 -0
  86. {fal-1.27.0 → fal-1.28.0}/openapi_rest.config.yaml +0 -0
  87. {fal-1.27.0 → fal-1.28.0}/pyproject.toml +0 -0
  88. {fal-1.27.0 → fal-1.28.0}/setup.cfg +0 -0
  89. {fal-1.27.0 → fal-1.28.0}/src/fal/__init__.py +0 -0
  90. {fal-1.27.0 → fal-1.28.0}/src/fal/__main__.py +0 -0
  91. {fal-1.27.0 → fal-1.28.0}/src/fal/_serialization.py +0 -0
  92. {fal-1.27.0 → fal-1.28.0}/src/fal/_version.py +0 -0
  93. {fal-1.27.0 → fal-1.28.0}/src/fal/api.py +0 -0
  94. {fal-1.27.0 → fal-1.28.0}/src/fal/app.py +0 -0
  95. {fal-1.27.0 → fal-1.28.0}/src/fal/apps.py +0 -0
  96. {fal-1.27.0 → fal-1.28.0}/src/fal/auth/__init__.py +0 -0
  97. {fal-1.27.0 → fal-1.28.0}/src/fal/auth/auth0.py +0 -0
  98. {fal-1.27.0 → fal-1.28.0}/src/fal/auth/local.py +0 -0
  99. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/__init__.py +0 -0
  100. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/api.py +0 -0
  101. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/apps.py +0 -0
  102. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/auth.py +0 -0
  103. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/cli_nested_json.py +0 -0
  104. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/create.py +0 -0
  105. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/debug.py +0 -0
  106. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/doctor.py +0 -0
  107. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/files.py +0 -0
  108. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/keys.py +0 -0
  109. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/main.py +0 -0
  110. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/parser.py +0 -0
  111. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/run.py +0 -0
  112. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/runners.py +0 -0
  113. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/secrets.py +0 -0
  114. {fal-1.27.0 → fal-1.28.0}/src/fal/cli/teams.py +0 -0
  115. {fal-1.27.0 → fal-1.28.0}/src/fal/console/__init__.py +0 -0
  116. {fal-1.27.0 → fal-1.28.0}/src/fal/console/icons.py +0 -0
  117. {fal-1.27.0 → fal-1.28.0}/src/fal/console/ux.py +0 -0
  118. {fal-1.27.0 → fal-1.28.0}/src/fal/container.py +0 -0
  119. {fal-1.27.0 → fal-1.28.0}/src/fal/exceptions/__init__.py +0 -0
  120. {fal-1.27.0 → fal-1.28.0}/src/fal/exceptions/_base.py +0 -0
  121. {fal-1.27.0 → fal-1.28.0}/src/fal/exceptions/_cuda.py +0 -0
  122. {fal-1.27.0 → fal-1.28.0}/src/fal/files.py +0 -0
  123. {fal-1.27.0 → fal-1.28.0}/src/fal/flags.py +0 -0
  124. {fal-1.27.0 → fal-1.28.0}/src/fal/logging/__init__.py +0 -0
  125. {fal-1.27.0 → fal-1.28.0}/src/fal/logging/isolate.py +0 -0
  126. {fal-1.27.0 → fal-1.28.0}/src/fal/logging/style.py +0 -0
  127. {fal-1.27.0 → fal-1.28.0}/src/fal/logging/trace.py +0 -0
  128. {fal-1.27.0 → fal-1.28.0}/src/fal/logging/user.py +0 -0
  129. {fal-1.27.0 → fal-1.28.0}/src/fal/project.py +0 -0
  130. {fal-1.27.0 → fal-1.28.0}/src/fal/py.typed +0 -0
  131. {fal-1.27.0 → fal-1.28.0}/src/fal/rest_client.py +0 -0
  132. {fal-1.27.0 → fal-1.28.0}/src/fal/sdk.py +0 -0
  133. {fal-1.27.0 → fal-1.28.0}/src/fal/sync.py +0 -0
  134. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/__init__.py +0 -0
  135. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/audio/__init__.py +0 -0
  136. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/audio/audio.py +0 -0
  137. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/exceptions.py +0 -0
  138. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/file/__init__.py +0 -0
  139. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/file/file.py +0 -0
  140. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/file/providers/fal.py +0 -0
  141. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/file/providers/gcp.py +0 -0
  142. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/file/providers/r2.py +0 -0
  143. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/file/providers/s3.py +0 -0
  144. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/file/types.py +0 -0
  145. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/__init__.py +0 -0
  146. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/image.py +0 -0
  147. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
  148. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
  149. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
  150. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
  151. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
  152. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/image/safety_checker.py +0 -0
  153. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/kv.py +0 -0
  154. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/optimize.py +0 -0
  155. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/types.py +0 -0
  156. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/utils/__init__.py +0 -0
  157. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/utils/endpoint.py +0 -0
  158. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/utils/retry.py +0 -0
  159. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/video/__init__.py +0 -0
  160. {fal-1.27.0 → fal-1.28.0}/src/fal/toolkit/video/video.py +0 -0
  161. {fal-1.27.0 → fal-1.28.0}/src/fal/utils.py +0 -0
  162. {fal-1.27.0 → fal-1.28.0}/src/fal/workflows.py +0 -0
  163. {fal-1.27.0 → fal-1.28.0}/tests/__init__.py +0 -0
  164. {fal-1.27.0 → fal-1.28.0}/tests/assets/cat.png +0 -0
  165. {fal-1.27.0 → fal-1.28.0}/tests/cli/__init__.py +0 -0
  166. {fal-1.27.0 → fal-1.28.0}/tests/cli/test_apps.py +0 -0
  167. {fal-1.27.0 → fal-1.28.0}/tests/cli/test_auth.py +0 -0
  168. {fal-1.27.0 → fal-1.28.0}/tests/cli/test_keys.py +0 -0
  169. {fal-1.27.0 → fal-1.28.0}/tests/cli/test_run.py +0 -0
  170. {fal-1.27.0 → fal-1.28.0}/tests/cli/test_secrets.py +0 -0
  171. {fal-1.27.0 → fal-1.28.0}/tests/conftest.py +0 -0
  172. {fal-1.27.0 → fal-1.28.0}/tests/integration_test.py +0 -0
  173. {fal-1.27.0 → fal-1.28.0}/tests/mainify_package/__init__.py +0 -0
  174. {fal-1.27.0 → fal-1.28.0}/tests/mainify_package/impl.py +0 -0
  175. {fal-1.27.0 → fal-1.28.0}/tests/mainify_package/utils.py +0 -0
  176. {fal-1.27.0 → fal-1.28.0}/tests/mainify_target.py +0 -0
  177. {fal-1.27.0 → fal-1.28.0}/tests/test_apps.py +0 -0
  178. {fal-1.27.0 → fal-1.28.0}/tests/test_files.py +0 -0
  179. {fal-1.27.0 → fal-1.28.0}/tests/test_kv.py +0 -0
  180. {fal-1.27.0 → fal-1.28.0}/tests/test_stability.py +0 -0
  181. {fal-1.27.0 → fal-1.28.0}/tests/toolkit/file/providers/test_fal_retry.py +0 -0
  182. {fal-1.27.0 → fal-1.28.0}/tests/toolkit/file_test.py +0 -0
  183. {fal-1.27.0 → fal-1.28.0}/tests/toolkit/image_test.py +0 -0
  184. {fal-1.27.0 → fal-1.28.0}/tests/toolkit/test_types.py +0 -0
  185. {fal-1.27.0 → fal-1.28.0}/tests/toolkit/utils/retry.py +0 -0
  186. {fal-1.27.0 → fal-1.28.0}/tools/demo_script.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.27.0
3
+ Version: 1.28.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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.27.0
3
+ Version: 1.28.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
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.27.0'
21
- __version_tuple__ = version_tuple = (1, 27, 0)
20
+ __version__ = version = '1.28.0'
21
+ __version_tuple__ = version_tuple = (1, 28, 0)
@@ -12,7 +12,7 @@ def get_client(host: str, team: str | None = None):
12
12
 
13
13
  def is_app_name(app_ref: tuple[str, str | None]) -> bool:
14
14
  is_single_file = app_ref[1] is None
15
- is_python_file = app_ref[0].endswith(".py")
15
+ is_python_file = app_ref[0] is None or app_ref[0].endswith(".py")
16
16
 
17
17
  return is_single_file and not is_python_file
18
18
 
@@ -42,9 +42,16 @@ def get_app_data_from_toml(app_name):
42
42
 
43
43
  app_auth = app_data.pop("auth", "private")
44
44
  app_deployment_strategy = app_data.pop("deployment_strategy", "recreate")
45
- app_no_scale = app_data.pop("no_scale", False)
45
+
46
+ if "no_scale" in app_data:
47
+ # Deprecated
48
+ app_no_scale = app_data.pop("no_scale")
49
+ print("[WARNING] no_scale is deprecated, use app_scale_settings instead")
50
+ app_reset_scale = not app_no_scale
51
+ else:
52
+ app_reset_scale = app_data.pop("app_scale_settings", False)
46
53
 
47
54
  if len(app_data) > 0:
48
55
  raise ValueError(f"Found unexpected keys in pyproject.toml: {app_data}")
49
56
 
50
- return app_ref, app_auth, app_deployment_strategy, app_no_scale
57
+ return app_ref, app_auth, app_deployment_strategy, app_reset_scale
@@ -66,9 +66,9 @@ def _deploy_from_reference(
66
66
  app_ref: Tuple[Optional[Union[Path, str]], ...],
67
67
  app_name: str,
68
68
  args,
69
- auth: Optional[Literal["public", "shared", "private"]] = None,
70
- deployment_strategy: Optional[Literal["recreate", "rolling"]] = None,
71
- scale: bool = True,
69
+ auth: Optional[Literal["public", "shared", "private"]],
70
+ deployment_strategy: Optional[Literal["recreate", "rolling"]],
71
+ scale: bool,
72
72
  ):
73
73
  from fal.api import FalServerlessError, FalServerlessHost
74
74
  from fal.utils import load_function_from
@@ -146,7 +146,7 @@ def _deploy(args):
146
146
  raise ValueError("Cannot use --app-name or --auth with app name reference.")
147
147
 
148
148
  app_name = args.app_ref[0]
149
- app_ref, app_auth, app_deployment_strategy, app_no_scale = (
149
+ app_ref, app_auth, app_deployment_strategy, app_scale_settings = (
150
150
  get_app_data_from_toml(app_name)
151
151
  )
152
152
  file_path, func_name = RefAction.split_ref(app_ref)
@@ -157,7 +157,7 @@ def _deploy(args):
157
157
  app_name = args.app_name
158
158
  app_auth = args.auth
159
159
  app_deployment_strategy = args.strategy
160
- app_no_scale = args.no_scale
160
+ app_scale_settings = args.app_scale_settings
161
161
 
162
162
  _deploy_from_reference(
163
163
  (file_path, func_name),
@@ -165,7 +165,7 @@ def _deploy(args):
165
165
  args,
166
166
  app_auth,
167
167
  app_deployment_strategy,
168
- scale=not app_no_scale,
168
+ scale=app_scale_settings,
169
169
  )
170
170
 
171
171
 
@@ -233,12 +233,17 @@ def add_parser(main_subparsers, parents):
233
233
  )
234
234
  parser.add_argument(
235
235
  "--no-scale",
236
+ action="store_false",
237
+ dest="app_scale_settings",
238
+ default=False,
239
+ help="Use the previous deployment of the application for scale settings. "
240
+ "This is the default behavior.",
241
+ )
242
+ parser.add_argument(
243
+ "--reset-scale",
236
244
  action="store_true",
237
- help=(
238
- "Use min_concurrency/max_concurrency/concurrency_buffer/max_multiplexing "
239
- "from previous deployment of application with this name, if exists. "
240
- "Otherwise will use the values from the application code."
241
- ),
245
+ dest="app_scale_settings",
246
+ help="Use the application code for scale settings.",
242
247
  )
243
248
 
244
249
  parser.set_defaults(func=_deploy)
@@ -68,12 +68,17 @@ def _unset(args, config: Config | None = None):
68
68
  def _key_set(args):
69
69
  config = Config(validate_profile=True)
70
70
 
71
+ args.console.print("Go to https://fal.ai/dashboard/keys to create a key.")
72
+ args.console.print(
73
+ "Enter the key in the format [cyan][bold]id:secret[/][/]. You can copy and paste it from the browser." # noqa: E501
74
+ )
75
+
71
76
  while True:
72
77
  key = input("Enter the key: ")
73
78
  if ":" in key:
74
79
  break
75
80
  args.console.print(
76
- "[red]Invalid key. The key must be in the format [bold]key:value[/].[/]"
81
+ "[yellow]Invalid key. The key must be in the format:[/] [cyan][bold]id:secret[/][/]." # noqa: E501
77
82
  )
78
83
 
79
84
  with config.edit():
@@ -99,10 +104,10 @@ def _create(args):
99
104
  with config.edit() as config:
100
105
  config._config[args.PROFILE] = {}
101
106
 
102
- args.console.print(f"Profile [cyan]{args.PROFILE}[/] created.")
103
107
  args.console.print(
104
- f"Use [bold]fal profile set {args.PROFILE}[/] to set it as default."
108
+ f"Profile [cyan]{args.PROFILE}[/] created. Setting it as default profile..."
105
109
  )
110
+ _set(args)
106
111
 
107
112
 
108
113
  def _delete(args):
@@ -184,7 +189,7 @@ def add_parser(main_subparsers, parents):
184
189
  )
185
190
  host_set_parser.set_defaults(func=_host_set)
186
191
 
187
- create_help = "Create a new profile. Use 'fal profile set <name>' to set it as default after creation." # noqa: E501
192
+ create_help = "Create a new profile."
188
193
  create_parser = subparsers.add_parser(
189
194
  "create",
190
195
  description=create_help,
@@ -6,7 +6,9 @@ from typing import Dict, Iterator, List, Optional
6
6
 
7
7
  SETTINGS_SECTION = "__internal__"
8
8
 
9
- NO_PROFILE_ERROR = ValueError("No profile set.")
9
+ NO_PROFILE_ERROR = ValueError(
10
+ "No profile set. Use command [bold]fal profile set[/] to set a profile."
11
+ )
10
12
 
11
13
 
12
14
  class Config:
@@ -7,5 +7,5 @@ class UnauthenticatedException(FalServerlessException):
7
7
  def __init__(self) -> None:
8
8
  super().__init__(
9
9
  "You must be authenticated. "
10
- "Login via `fal auth login` or make sure to setup fal keys correctly."
10
+ "Use [bold]fal auth login[/] or [bold]fal profile key[/] to set your fal key." # noqa: E501
11
11
  )
@@ -6,6 +6,7 @@ import os
6
6
  import shutil
7
7
  import subprocess
8
8
  import sys
9
+ import time
9
10
  from contextlib import suppress
10
11
  from pathlib import Path, PurePath
11
12
  from tempfile import NamedTemporaryFile, TemporaryDirectory
@@ -345,6 +346,14 @@ def _stream_url_data_to_file(
345
346
  raise DownloadError("Received less data than expected from the server.")
346
347
 
347
348
 
349
+ def _mark_used_dir(dir: Path):
350
+ used_file = dir / ".fal_used"
351
+ day_ago = time.time() - 86400
352
+ if not used_file.exists() or used_file.stat().st_mtime < day_ago:
353
+ # Touch a last-used file to indicate that the weights have been used
354
+ used_file.touch()
355
+
356
+
348
357
  def download_model_weights(
349
358
  url: str, force: bool = False, request_headers: dict[str, str] | None = None
350
359
  ) -> Path:
@@ -375,19 +384,34 @@ def download_model_weights(
375
384
 
376
385
  if weights_dir.exists() and not force:
377
386
  try:
378
- weights_path = next(weights_dir.glob("*"))
387
+ # TODO: sometimes the directory can hold multiple files
388
+ # Example:
389
+ # .fal/model_weights/00155dc2d9579360d577d1a87d31b52c21135c14a5f44fcbab36fbb8352f3e0d # noqa: E501
390
+ # We need to either not allow multiple files in the directory or
391
+ # find the one that is the most recently used.
392
+ weights_path = next(
393
+ # Ignore .fal dotfiles since they are metadata files
394
+ f
395
+ for f in weights_dir.glob("*")
396
+ if not f.name.startswith(".fal")
397
+ )
398
+ _mark_used_dir(weights_dir)
379
399
  return weights_path
380
400
  # The model weights directory is empty, so we need to download the weights
381
401
  except StopIteration:
382
402
  pass
383
403
 
384
- return download_file(
404
+ path = download_file(
385
405
  url,
386
406
  target_dir=weights_dir,
387
407
  force=force,
388
408
  request_headers=request_headers,
389
409
  )
390
410
 
411
+ _mark_used_dir(weights_dir)
412
+
413
+ return path
414
+
391
415
 
392
416
  def clone_repository(
393
417
  https_url: str,
@@ -39,7 +39,7 @@ def mock_args(
39
39
  app_name: Optional[str] = None,
40
40
  auth: Optional[str] = None,
41
41
  strategy: Optional[str] = None,
42
- no_scale: bool = False,
42
+ reset_scale: bool = False,
43
43
  ):
44
44
  args = MagicMock()
45
45
 
@@ -47,8 +47,7 @@ def mock_args(
47
47
  args.app_name = app_name
48
48
  args.auth = auth
49
49
  args.strategy = strategy
50
-
51
- args.no_scale = no_scale
50
+ args.app_scale_settings = reset_scale
52
51
 
53
52
  return args
54
53
 
@@ -75,7 +74,7 @@ def test_deploy_with_toml_success(
75
74
  args,
76
75
  "shared",
77
76
  "rolling",
78
- scale=True,
77
+ scale=False,
79
78
  )
80
79
 
81
80
 
@@ -101,7 +100,7 @@ def test_deploy_with_toml_no_auth(
101
100
  args,
102
101
  "private",
103
102
  "recreate",
104
- scale=True,
103
+ scale=False,
105
104
  )
106
105
 
107
106
 
@@ -212,7 +211,7 @@ def test_deploy_with_toml_deployment_strategy(
212
211
  args,
213
212
  "shared",
214
213
  "rolling",
215
- scale=True,
214
+ scale=False,
216
215
  )
217
216
 
218
217
 
@@ -236,7 +235,7 @@ def test_deploy_with_toml_default_deployment_strategy(
236
235
  args,
237
236
  "private",
238
237
  "recreate",
239
- scale=True,
238
+ scale=False,
240
239
  )
241
240
 
242
241
 
@@ -258,7 +257,7 @@ def test_deploy_with_cli_auth(
258
257
  args,
259
258
  "shared",
260
259
  None,
261
- scale=True,
260
+ scale=False,
262
261
  )
263
262
 
264
263
 
@@ -280,19 +279,19 @@ def test_deploy_with_cli_deployment_strategy(
280
279
  args,
281
280
  None,
282
281
  "rolling",
283
- scale=True,
282
+ scale=False,
284
283
  )
285
284
 
286
285
 
287
286
  @patch("fal.cli._utils.find_pyproject_toml", return_value="pyproject.toml")
288
287
  @patch("fal.cli._utils.parse_pyproject_toml")
289
288
  @patch("fal.cli.deploy._deploy_from_reference")
290
- def test_deploy_with_cli_no_scale(
289
+ def test_deploy_with_cli_reset_scale(
291
290
  mock_deploy_ref, mock_parse_toml, mock_find_toml, mock_parse_pyproject_toml
292
291
  ):
293
292
  mock_parse_toml.return_value = mock_parse_pyproject_toml
294
293
 
295
- args = mock_args(app_ref=("src/my_app/inference.py", "MyApp"), no_scale=True)
294
+ args = mock_args(app_ref=("src/my_app/inference.py", "MyApp"), reset_scale=True)
296
295
 
297
296
  _deploy(args)
298
297
 
@@ -302,7 +301,7 @@ def test_deploy_with_cli_no_scale(
302
301
  args,
303
302
  None,
304
303
  None,
305
- scale=False,
304
+ scale=True,
306
305
  )
307
306
 
308
307
 
@@ -324,5 +323,5 @@ def test_deploy_with_cli_scale(
324
323
  args,
325
324
  None,
326
325
  None,
327
- scale=True,
326
+ scale=False,
328
327
  )
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