fal 1.9.1__tar.gz → 1.9.3__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 (173) hide show
  1. {fal-1.9.1/fal.egg-info → fal-1.9.3}/PKG-INFO +4 -3
  2. {fal-1.9.1 → fal-1.9.3/fal.egg-info}/PKG-INFO +4 -3
  3. {fal-1.9.1 → fal-1.9.3}/fal.egg-info/SOURCES.txt +1 -0
  4. {fal-1.9.1 → fal-1.9.3}/fal.egg-info/requires.txt +3 -2
  5. {fal-1.9.1 → fal-1.9.3}/pyproject.toml +3 -2
  6. {fal-1.9.1 → fal-1.9.3}/src/fal/_fal_version.py +9 -4
  7. {fal-1.9.1 → fal-1.9.3}/src/fal/api.py +1 -0
  8. {fal-1.9.1 → fal-1.9.3}/src/fal/app.py +19 -18
  9. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/apps.py +18 -5
  10. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/main.py +13 -2
  11. fal-1.9.3/src/fal/cli/profile.py +129 -0
  12. fal-1.9.3/src/fal/config.py +85 -0
  13. {fal-1.9.1 → fal-1.9.3}/src/fal/logging/isolate.py +2 -2
  14. {fal-1.9.1 → fal-1.9.3}/src/fal/sdk.py +13 -6
  15. fal-1.9.1/src/fal/config.py +0 -23
  16. {fal-1.9.1 → fal-1.9.3}/.gitignore +0 -0
  17. {fal-1.9.1 → fal-1.9.3}/Makefile +0 -0
  18. {fal-1.9.1 → fal-1.9.3}/README.md +0 -0
  19. {fal-1.9.1 → fal-1.9.3}/docs/conf.py +0 -0
  20. {fal-1.9.1 → fal-1.9.3}/docs/index.rst +0 -0
  21. {fal-1.9.1 → fal-1.9.3}/fal.egg-info/dependency_links.txt +0 -0
  22. {fal-1.9.1 → fal-1.9.3}/fal.egg-info/entry_points.txt +0 -0
  23. {fal-1.9.1 → fal-1.9.3}/fal.egg-info/top_level.txt +0 -0
  24. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/README.md +0 -0
  25. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
  26. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
  27. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
  28. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
  29. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
  30. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
  31. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
  32. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
  33. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
  34. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
  35. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
  36. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
  37. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
  38. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
  39. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
  40. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
  41. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
  42. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
  43. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
  44. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
  45. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
  46. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
  47. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
  48. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
  49. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
  50. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
  51. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
  52. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
  53. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
  54. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
  55. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
  56. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
  57. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
  58. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
  59. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
  60. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
  61. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
  62. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
  63. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
  64. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
  65. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
  66. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
  67. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
  68. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
  69. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
  70. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
  71. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
  72. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
  73. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
  74. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
  75. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
  76. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
  77. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
  78. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
  79. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
  80. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
  81. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
  82. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
  83. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
  84. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
  85. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
  86. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
  87. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
  88. {fal-1.9.1 → fal-1.9.3}/openapi-fal-rest/pyproject.toml +0 -0
  89. {fal-1.9.1 → fal-1.9.3}/openapi_rest.config.yaml +0 -0
  90. {fal-1.9.1 → fal-1.9.3}/setup.cfg +0 -0
  91. {fal-1.9.1 → fal-1.9.3}/src/fal/__init__.py +0 -0
  92. {fal-1.9.1 → fal-1.9.3}/src/fal/__main__.py +0 -0
  93. {fal-1.9.1 → fal-1.9.3}/src/fal/_serialization.py +0 -0
  94. {fal-1.9.1 → fal-1.9.3}/src/fal/_version.py +0 -0
  95. {fal-1.9.1 → fal-1.9.3}/src/fal/apps.py +0 -0
  96. {fal-1.9.1 → fal-1.9.3}/src/fal/auth/__init__.py +0 -0
  97. {fal-1.9.1 → fal-1.9.3}/src/fal/auth/auth0.py +0 -0
  98. {fal-1.9.1 → fal-1.9.3}/src/fal/auth/local.py +0 -0
  99. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/__init__.py +0 -0
  100. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/_utils.py +0 -0
  101. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/auth.py +0 -0
  102. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/create.py +0 -0
  103. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/debug.py +0 -0
  104. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/deploy.py +0 -0
  105. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/doctor.py +0 -0
  106. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/keys.py +0 -0
  107. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/parser.py +0 -0
  108. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/run.py +0 -0
  109. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/runners.py +0 -0
  110. {fal-1.9.1 → fal-1.9.3}/src/fal/cli/secrets.py +0 -0
  111. {fal-1.9.1 → fal-1.9.3}/src/fal/console/__init__.py +0 -0
  112. {fal-1.9.1 → fal-1.9.3}/src/fal/console/icons.py +0 -0
  113. {fal-1.9.1 → fal-1.9.3}/src/fal/console/ux.py +0 -0
  114. {fal-1.9.1 → fal-1.9.3}/src/fal/container.py +0 -0
  115. {fal-1.9.1 → fal-1.9.3}/src/fal/exceptions/__init__.py +0 -0
  116. {fal-1.9.1 → fal-1.9.3}/src/fal/exceptions/_base.py +0 -0
  117. {fal-1.9.1 → fal-1.9.3}/src/fal/exceptions/_cuda.py +0 -0
  118. {fal-1.9.1 → fal-1.9.3}/src/fal/exceptions/auth.py +0 -0
  119. {fal-1.9.1 → fal-1.9.3}/src/fal/files.py +0 -0
  120. {fal-1.9.1 → fal-1.9.3}/src/fal/flags.py +0 -0
  121. {fal-1.9.1 → fal-1.9.3}/src/fal/logging/__init__.py +0 -0
  122. {fal-1.9.1 → fal-1.9.3}/src/fal/logging/style.py +0 -0
  123. {fal-1.9.1 → fal-1.9.3}/src/fal/logging/trace.py +0 -0
  124. {fal-1.9.1 → fal-1.9.3}/src/fal/logging/user.py +0 -0
  125. {fal-1.9.1 → fal-1.9.3}/src/fal/py.typed +0 -0
  126. {fal-1.9.1 → fal-1.9.3}/src/fal/rest_client.py +0 -0
  127. {fal-1.9.1 → fal-1.9.3}/src/fal/sync.py +0 -0
  128. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/__init__.py +0 -0
  129. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/exceptions.py +0 -0
  130. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/file/__init__.py +0 -0
  131. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/file/file.py +0 -0
  132. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/file/providers/fal.py +0 -0
  133. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/file/providers/gcp.py +0 -0
  134. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/file/providers/r2.py +0 -0
  135. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/file/providers/s3.py +0 -0
  136. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/file/types.py +0 -0
  137. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/__init__.py +0 -0
  138. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/image.py +0 -0
  139. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
  140. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
  141. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
  142. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
  143. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
  144. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/image/safety_checker.py +0 -0
  145. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/optimize.py +0 -0
  146. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/types.py +0 -0
  147. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/utils/__init__.py +0 -0
  148. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/utils/download_utils.py +0 -0
  149. {fal-1.9.1 → fal-1.9.3}/src/fal/toolkit/utils/retry.py +0 -0
  150. {fal-1.9.1 → fal-1.9.3}/src/fal/utils.py +0 -0
  151. {fal-1.9.1 → fal-1.9.3}/src/fal/workflows.py +0 -0
  152. {fal-1.9.1 → fal-1.9.3}/tests/__init__.py +0 -0
  153. {fal-1.9.1 → fal-1.9.3}/tests/assets/cat.png +0 -0
  154. {fal-1.9.1 → fal-1.9.3}/tests/cli/__init__.py +0 -0
  155. {fal-1.9.1 → fal-1.9.3}/tests/cli/test_apps.py +0 -0
  156. {fal-1.9.1 → fal-1.9.3}/tests/cli/test_auth.py +0 -0
  157. {fal-1.9.1 → fal-1.9.3}/tests/cli/test_deploy.py +0 -0
  158. {fal-1.9.1 → fal-1.9.3}/tests/cli/test_keys.py +0 -0
  159. {fal-1.9.1 → fal-1.9.3}/tests/cli/test_run.py +0 -0
  160. {fal-1.9.1 → fal-1.9.3}/tests/cli/test_secrets.py +0 -0
  161. {fal-1.9.1 → fal-1.9.3}/tests/conftest.py +0 -0
  162. {fal-1.9.1 → fal-1.9.3}/tests/integration_test.py +0 -0
  163. {fal-1.9.1 → fal-1.9.3}/tests/mainify_package/__init__.py +0 -0
  164. {fal-1.9.1 → fal-1.9.3}/tests/mainify_package/impl.py +0 -0
  165. {fal-1.9.1 → fal-1.9.3}/tests/mainify_package/utils.py +0 -0
  166. {fal-1.9.1 → fal-1.9.3}/tests/mainify_target.py +0 -0
  167. {fal-1.9.1 → fal-1.9.3}/tests/test_apps.py +0 -0
  168. {fal-1.9.1 → fal-1.9.3}/tests/test_stability.py +0 -0
  169. {fal-1.9.1 → fal-1.9.3}/tests/toolkit/file_test.py +0 -0
  170. {fal-1.9.1 → fal-1.9.3}/tests/toolkit/image_test.py +0 -0
  171. {fal-1.9.1 → fal-1.9.3}/tests/toolkit/test_types.py +0 -0
  172. {fal-1.9.1 → fal-1.9.3}/tests/toolkit/utils/retry.py +0 -0
  173. {fal-1.9.1 → fal-1.9.3}/tools/demo_script.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fal
3
- Version: 1.9.1
3
+ Version: 1.9.3
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.17.0,>=0.16.1
9
- Requires-Dist: isolate-proto<0.7.0,>=0.6.6
9
+ Requires-Dist: isolate-proto<0.7.0,>=0.6.7
10
10
  Requires-Dist: grpcio==1.64.0
11
11
  Requires-Dist: dill==0.3.7
12
12
  Requires-Dist: cloudpickle==3.0.0
@@ -37,7 +37,8 @@ Requires-Dist: pillow<11,>=10.2.0
37
37
  Requires-Dist: pyjwt[crypto]<3,>=2.8.0
38
38
  Requires-Dist: uvicorn<1,>=0.29.0
39
39
  Requires-Dist: cookiecutter
40
- Requires-Dist: tomli
40
+ Requires-Dist: tomli<3,>2
41
+ Requires-Dist: tomli-w<2,>=1
41
42
  Provides-Extra: docs
42
43
  Requires-Dist: sphinx<8.2.0; extra == "docs"
43
44
  Requires-Dist: sphinx-rtd-theme; extra == "docs"
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fal
3
- Version: 1.9.1
3
+ Version: 1.9.3
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.17.0,>=0.16.1
9
- Requires-Dist: isolate-proto<0.7.0,>=0.6.6
9
+ Requires-Dist: isolate-proto<0.7.0,>=0.6.7
10
10
  Requires-Dist: grpcio==1.64.0
11
11
  Requires-Dist: dill==0.3.7
12
12
  Requires-Dist: cloudpickle==3.0.0
@@ -37,7 +37,8 @@ Requires-Dist: pillow<11,>=10.2.0
37
37
  Requires-Dist: pyjwt[crypto]<3,>=2.8.0
38
38
  Requires-Dist: uvicorn<1,>=0.29.0
39
39
  Requires-Dist: cookiecutter
40
- Requires-Dist: tomli
40
+ Requires-Dist: tomli<3,>2
41
+ Requires-Dist: tomli-w<2,>=1
41
42
  Provides-Extra: docs
42
43
  Requires-Dist: sphinx<8.2.0; extra == "docs"
43
44
  Requires-Dist: sphinx-rtd-theme; extra == "docs"
@@ -108,6 +108,7 @@ src/fal/cli/doctor.py
108
108
  src/fal/cli/keys.py
109
109
  src/fal/cli/main.py
110
110
  src/fal/cli/parser.py
111
+ src/fal/cli/profile.py
111
112
  src/fal/cli/run.py
112
113
  src/fal/cli/runners.py
113
114
  src/fal/cli/secrets.py
@@ -1,5 +1,5 @@
1
1
  isolate[build]<0.17.0,>=0.16.1
2
- isolate-proto<0.7.0,>=0.6.6
2
+ isolate-proto<0.7.0,>=0.6.7
3
3
  grpcio==1.64.0
4
4
  dill==0.3.7
5
5
  cloudpickle==3.0.0
@@ -29,7 +29,8 @@ pillow<11,>=10.2.0
29
29
  pyjwt[crypto]<3,>=2.8.0
30
30
  uvicorn<1,>=0.29.0
31
31
  cookiecutter
32
- tomli
32
+ tomli<3,>2
33
+ tomli-w<2,>=1
33
34
 
34
35
  [:python_version < "3.10"]
35
36
  importlib-metadata>=4.4
@@ -23,7 +23,7 @@ readme = "README.md"
23
23
  requires-python = ">=3.8"
24
24
  dependencies = [
25
25
  "isolate[build]>=0.16.1,<0.17.0",
26
- "isolate-proto>=0.6.6,<0.7.0",
26
+ "isolate-proto>=0.6.7,<0.7.0",
27
27
  "grpcio==1.64.0",
28
28
  "dill==0.3.7",
29
29
  "cloudpickle==3.0.0",
@@ -57,7 +57,8 @@ dependencies = [
57
57
  "pyjwt[crypto]>=2.8.0,<3",
58
58
  "uvicorn>=0.29.0,<1",
59
59
  "cookiecutter",
60
- "tomli"
60
+ "tomli>2,<3",
61
+ "tomli-w>=1,<2",
61
62
  ]
62
63
 
63
64
  [project.optional-dependencies]
@@ -1,8 +1,13 @@
1
- # file generated by setuptools_scm
1
+ # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
3
6
  TYPE_CHECKING = False
4
7
  if TYPE_CHECKING:
5
- from typing import Tuple, Union
8
+ from typing import Tuple
9
+ from typing import Union
10
+
6
11
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
12
  else:
8
13
  VERSION_TUPLE = object
@@ -12,5 +17,5 @@ __version__: str
12
17
  __version_tuple__: VERSION_TUPLE
13
18
  version_tuple: VERSION_TUPLE
14
19
 
15
- __version__ = version = '1.9.1'
16
- __version_tuple__ = version_tuple = (1, 9, 1)
20
+ __version__ = version = '1.9.3'
21
+ __version_tuple__ = version_tuple = (1, 9, 3)
@@ -78,6 +78,7 @@ SERVE_REQUIREMENTS = [
78
78
  "starlette_exporter",
79
79
  "structlog",
80
80
  "tomli",
81
+ "tomli-w",
81
82
  ]
82
83
 
83
84
 
@@ -9,7 +9,7 @@ import re
9
9
  import threading
10
10
  import time
11
11
  import typing
12
- from contextlib import AsyncExitStack, asynccontextmanager, contextmanager
12
+ from contextlib import asynccontextmanager, contextmanager
13
13
  from dataclasses import dataclass
14
14
  from typing import Any, Callable, ClassVar, Literal, TypeVar
15
15
 
@@ -40,27 +40,26 @@ async def _call_any_fn(fn, *args, **kwargs):
40
40
  return fn(*args, **kwargs)
41
41
 
42
42
 
43
- async def open_isolate_channel(address: str) -> async_grpc.Channel:
44
- _stack = AsyncExitStack()
45
- channel = await _stack.enter_async_context(
46
- async_grpc.insecure_channel(
47
- address,
48
- options=[
49
- ("grpc.max_send_message_length", -1),
50
- ("grpc.max_receive_message_length", -1),
51
- ("grpc.min_reconnect_backoff_ms", 0),
52
- ("grpc.max_reconnect_backoff_ms", 100),
53
- ("grpc.dns_min_time_between_resolutions_ms", 100),
54
- ],
55
- )
43
+ async def open_isolate_channel(address: str) -> async_grpc.Channel | None:
44
+ channel = async_grpc.insecure_channel(
45
+ address,
46
+ options=[
47
+ ("grpc.max_send_message_length", -1),
48
+ ("grpc.max_receive_message_length", -1),
49
+ ("grpc.min_reconnect_backoff_ms", 0),
50
+ ("grpc.max_reconnect_backoff_ms", 100),
51
+ ("grpc.dns_min_time_between_resolutions_ms", 100),
52
+ ],
56
53
  )
57
54
 
58
- channel_status = channel.channel_ready()
59
55
  try:
56
+ channel_status = channel.channel_ready()
57
+
60
58
  await asyncio.wait_for(channel_status, timeout=1)
61
59
  except asyncio.TimeoutError:
62
- await _stack.aclose()
63
- raise Exception("Timed out trying to connect to local isolate")
60
+ await channel.close(None)
61
+ print("[DEBUG] Timed out trying to connect to local isolate")
62
+ return None
64
63
 
65
64
  return channel
66
65
 
@@ -390,9 +389,11 @@ class App(fal.api.BaseServable):
390
389
  f"localhost:{grpc_port}"
391
390
  )
392
391
 
392
+ if self.isolate_channel is None:
393
+ return await call_next(request)
394
+
393
395
  request_id = request.headers.get(REQUEST_ID_KEY)
394
396
  if request_id is None:
395
- # Cut it short
396
397
  return await call_next(request)
397
398
 
398
399
  await _set_logger_labels(
@@ -22,7 +22,8 @@ def _apps_table(apps: list[AliasInfo]):
22
22
  table.add_column("Request Timeout")
23
23
  table.add_column("Startup Timeout")
24
24
  table.add_column("Machine Type")
25
- table.add_column("Active Workers")
25
+ table.add_column("Runners")
26
+ table.add_column("Regions")
26
27
 
27
28
  for app in apps:
28
29
  table.add_row(
@@ -37,6 +38,7 @@ def _apps_table(apps: list[AliasInfo]):
37
38
  str(app.startup_timeout),
38
39
  " ".join(app.machine_types),
39
40
  str(app.active_runners),
41
+ " ".join(app.valid_regions),
40
42
  )
41
43
 
42
44
  return table
@@ -76,7 +78,8 @@ def _app_rev_table(revs: list[ApplicationInfo]):
76
78
  table.add_column("Request Timeout")
77
79
  table.add_column("Startup Timeout")
78
80
  table.add_column("Machine Type")
79
- table.add_column("Active Workers")
81
+ table.add_column("Runners")
82
+ table.add_column("Regions")
80
83
 
81
84
  for rev in revs:
82
85
  table.add_row(
@@ -89,6 +92,7 @@ def _app_rev_table(revs: list[ApplicationInfo]):
89
92
  str(rev.startup_timeout),
90
93
  " ".join(rev.machine_types),
91
94
  str(rev.active_runners),
95
+ " ".join(rev.valid_regions),
92
96
  )
93
97
 
94
98
  return table
@@ -129,6 +133,7 @@ def _scale(args):
129
133
  and args.request_timeout is None
130
134
  and args.startup_timeout is None
131
135
  and args.machine_types is None
136
+ and args.regions is None
132
137
  ):
133
138
  args.console.log("No parameters for update were provided, ignoring.")
134
139
  return
@@ -142,6 +147,7 @@ def _scale(args):
142
147
  request_timeout=args.request_timeout,
143
148
  startup_timeout=args.startup_timeout,
144
149
  machine_types=args.machine_types,
150
+ valid_regions=args.regions,
145
151
  )
146
152
  table = _apps_table([alias_info])
147
153
 
@@ -191,11 +197,16 @@ def _add_scale_parser(subparsers, parents):
191
197
  help="Startup timeout (seconds).",
192
198
  )
193
199
  parser.add_argument(
194
- "--machine-type",
200
+ "--machine-types",
195
201
  type=str,
196
- action="append",
202
+ nargs="+",
197
203
  dest="machine_types",
198
- help="Machine type.",
204
+ help="Machine types (pass several items to set multiple).",
205
+ )
206
+ parser.add_argument(
207
+ "--regions",
208
+ nargs="+",
209
+ help="Valid regions (pass several items to set multiple).",
199
210
  )
200
211
  parser.set_defaults(func=_scale)
201
212
 
@@ -262,6 +273,7 @@ def _runners(args):
262
273
  f"{runner.uptime} ({runner.uptime.total_seconds()}s)",
263
274
  )
264
275
 
276
+ args.console.print(f"Runners: {len(runners)}")
265
277
  args.console.print(table)
266
278
 
267
279
  requests_table = Table()
@@ -280,6 +292,7 @@ def _runners(args):
280
292
  lease.get("caller_user_id") or "",
281
293
  )
282
294
 
295
+ args.console.print(f"Requests: {len(requests_table.rows)}")
283
296
  args.console.print(requests_table)
284
297
 
285
298
 
@@ -6,7 +6,7 @@ from fal import __version__
6
6
  from fal.console import console
7
7
  from fal.console.icons import CROSS_ICON
8
8
 
9
- from . import apps, auth, create, deploy, doctor, keys, run, runners, secrets
9
+ from . import apps, auth, create, deploy, doctor, keys, profile, run, runners, secrets
10
10
  from .debug import debugtools, get_debug_parser
11
11
  from .parser import FalParser, FalParserExit
12
12
 
@@ -31,7 +31,18 @@ def _get_main_parser() -> argparse.ArgumentParser:
31
31
  required=True,
32
32
  )
33
33
 
34
- for cmd in [auth, apps, deploy, run, keys, secrets, doctor, create, runners]:
34
+ for cmd in [
35
+ auth,
36
+ apps,
37
+ deploy,
38
+ run,
39
+ keys,
40
+ profile,
41
+ secrets,
42
+ doctor,
43
+ create,
44
+ runners,
45
+ ]:
35
46
  cmd.add_parser(subparsers, parents)
36
47
 
37
48
  return parser
@@ -0,0 +1,129 @@
1
+ from rich.table import Table
2
+
3
+ from fal.config import Config
4
+
5
+
6
+ def _list(args):
7
+ config = Config()
8
+
9
+ table = Table()
10
+ table.add_column("Default")
11
+ table.add_column("Profile")
12
+ table.add_column("Settings")
13
+
14
+ for profile in config.profiles():
15
+ table.add_row(
16
+ "*" if profile == config._profile else "",
17
+ profile,
18
+ ", ".join(key for key in config._config[profile]),
19
+ )
20
+
21
+ args.console.print(table)
22
+
23
+
24
+ def _set(args):
25
+ config = Config()
26
+ config.set_internal("profile", args.PROFILE)
27
+ args.console.print(f"Default profile set to [cyan]{args.PROFILE}[/].")
28
+ config.profile = args.PROFILE
29
+ config.save()
30
+
31
+
32
+ def _unset(args):
33
+ config = Config()
34
+ config.set_internal("profile", None)
35
+ args.console.print("Default profile unset.")
36
+ config.profile = None
37
+ config.save()
38
+
39
+
40
+ def _key_set(args):
41
+ config = Config()
42
+ key_id, key_secret = args.KEY.split(":", 1)
43
+ config.set("key", f"{key_id}:{key_secret}")
44
+ args.console.print(f"Key set for profile [cyan]{config.profile}[/].")
45
+ config.save()
46
+
47
+
48
+ def _delete(args):
49
+ config = Config()
50
+ if config.profile == args.PROFILE:
51
+ config.set_internal("profile", None)
52
+
53
+ config.delete(args.PROFILE)
54
+ args.console.print(f"Profile [cyan]{args.PROFILE}[/] deleted.")
55
+ config.save()
56
+
57
+
58
+ def add_parser(main_subparsers, parents):
59
+ auth_help = "Profile management."
60
+ parser = main_subparsers.add_parser(
61
+ "profile",
62
+ description=auth_help,
63
+ help=auth_help,
64
+ parents=parents,
65
+ )
66
+
67
+ subparsers = parser.add_subparsers(
68
+ title="Commands",
69
+ metavar="command",
70
+ dest="cmd",
71
+ required=True,
72
+ )
73
+
74
+ list_help = "List all profiles."
75
+ list_parser = subparsers.add_parser(
76
+ "list",
77
+ description=list_help,
78
+ help=list_help,
79
+ parents=parents,
80
+ )
81
+ list_parser.set_defaults(func=_list)
82
+
83
+ set_help = "Set default profile."
84
+ set_parser = subparsers.add_parser(
85
+ "set",
86
+ description=set_help,
87
+ help=set_help,
88
+ parents=parents,
89
+ )
90
+ set_parser.add_argument(
91
+ "PROFILE",
92
+ help="Profile name.",
93
+ )
94
+ set_parser.set_defaults(func=_set)
95
+
96
+ unset_help = "Unset default profile."
97
+ unset_parser = subparsers.add_parser(
98
+ "unset",
99
+ description=unset_help,
100
+ help=unset_help,
101
+ parents=parents,
102
+ )
103
+ unset_parser.set_defaults(func=_unset)
104
+
105
+ key_set_help = "Set key for profile."
106
+ key_set_parser = subparsers.add_parser(
107
+ "key",
108
+ description=key_set_help,
109
+ help=key_set_help,
110
+ parents=parents,
111
+ )
112
+ key_set_parser.add_argument(
113
+ "KEY",
114
+ help="Key ID and secret separated by a colon.",
115
+ )
116
+ key_set_parser.set_defaults(func=_key_set)
117
+
118
+ delete_help = "Delete profile."
119
+ delete_parser = subparsers.add_parser(
120
+ "delete",
121
+ description=delete_help,
122
+ help=delete_help,
123
+ parents=parents,
124
+ )
125
+ delete_parser.add_argument(
126
+ "PROFILE",
127
+ help="Profile name.",
128
+ )
129
+ delete_parser.set_defaults(func=_delete)
@@ -0,0 +1,85 @@
1
+ import os
2
+ from typing import Dict, List, Optional
3
+
4
+ SETTINGS_SECTION = "__internal__"
5
+
6
+
7
+ class Config:
8
+ _config: Dict[str, Dict[str, str]]
9
+ _profile: Optional[str]
10
+
11
+ DEFAULT_CONFIG_PATH = "~/.fal/config.toml"
12
+
13
+ def __init__(self):
14
+ import tomli
15
+
16
+ self.config_path = os.path.expanduser(
17
+ os.getenv("FAL_CONFIG_PATH", self.DEFAULT_CONFIG_PATH)
18
+ )
19
+
20
+ try:
21
+ with open(self.config_path, "rb") as file:
22
+ self._config = tomli.load(file)
23
+ except FileNotFoundError:
24
+ self._config = {}
25
+
26
+ profile = os.getenv("FAL_PROFILE")
27
+ if not profile:
28
+ profile = self.get_internal("profile")
29
+
30
+ self.profile = profile
31
+
32
+ @property
33
+ def profile(self) -> Optional[str]:
34
+ return self._profile
35
+
36
+ @profile.setter
37
+ def profile(self, value: Optional[str]) -> None:
38
+ if value and value not in self._config:
39
+ self._config[value] = {}
40
+
41
+ self._profile = value
42
+
43
+ def profiles(self) -> List[str]:
44
+ keys = []
45
+ for key in self._config:
46
+ if key != SETTINGS_SECTION:
47
+ keys.append(key)
48
+
49
+ return keys
50
+
51
+ def save(self) -> None:
52
+ import tomli_w
53
+
54
+ with open(self.config_path, "wb") as file:
55
+ tomli_w.dump(self._config, file)
56
+
57
+ def get(self, key: str) -> Optional[str]:
58
+ if not self.profile:
59
+ return None
60
+
61
+ return self._config.get(self.profile, {}).get(key)
62
+
63
+ def set(self, key: str, value: str) -> None:
64
+ if not self.profile:
65
+ raise ValueError("No profile set.")
66
+
67
+ self._config[self.profile][key] = value
68
+
69
+ def get_internal(self, key: str) -> Optional[str]:
70
+ if SETTINGS_SECTION not in self._config:
71
+ self._config[SETTINGS_SECTION] = {}
72
+
73
+ return self._config[SETTINGS_SECTION].get(key)
74
+
75
+ def set_internal(self, key: str, value: Optional[str]) -> None:
76
+ if SETTINGS_SECTION not in self._config:
77
+ self._config[SETTINGS_SECTION] = {}
78
+
79
+ if value is None:
80
+ del self._config[SETTINGS_SECTION][key]
81
+ else:
82
+ self._config[SETTINGS_SECTION][key] = value
83
+
84
+ def delete(self, profile: str) -> None:
85
+ del self._config[profile]
@@ -26,8 +26,8 @@ class IsolateLogPrinter:
26
26
  return
27
27
 
28
28
  msg = {
29
- LogSource.BUILDER: "Building the environment",
30
- LogSource.BRIDGE: "Unpacking user code",
29
+ LogSource.BUILDER: "Preparing the environment",
30
+ LogSource.BRIDGE: "Setting up runtime",
31
31
  LogSource.USER: "Running",
32
32
  }.get(source)
33
33
 
@@ -200,6 +200,7 @@ class ApplicationInfo:
200
200
  machine_types: list[str]
201
201
  request_timeout: int
202
202
  startup_timeout: int
203
+ valid_regions: list[str]
203
204
 
204
205
 
205
206
  @dataclass
@@ -215,6 +216,7 @@ class AliasInfo:
215
216
  machine_types: list[str]
216
217
  request_timeout: int
217
218
  startup_timeout: int
219
+ valid_regions: list[str]
218
220
 
219
221
 
220
222
  @dataclass
@@ -321,9 +323,10 @@ def _from_grpc_application_info(
321
323
  max_multiplexing=message.max_multiplexing,
322
324
  active_runners=message.active_runners,
323
325
  min_concurrency=message.min_concurrency,
324
- machine_types=message.machine_types,
326
+ machine_types=list(message.machine_types),
325
327
  request_timeout=message.request_timeout,
326
328
  startup_timeout=message.startup_timeout,
329
+ valid_regions=list(message.valid_regions),
327
330
  )
328
331
 
329
332
 
@@ -347,9 +350,10 @@ def _from_grpc_alias_info(message: isolate_proto.AliasInfo) -> AliasInfo:
347
350
  max_multiplexing=message.max_multiplexing,
348
351
  active_runners=message.active_runners,
349
352
  min_concurrency=message.min_concurrency,
350
- machine_types=message.machine_types,
353
+ machine_types=list(message.machine_types),
351
354
  request_timeout=message.request_timeout,
352
355
  startup_timeout=message.startup_timeout,
356
+ valid_regions=list(message.valid_regions),
353
357
  )
354
358
 
355
359
 
@@ -359,9 +363,11 @@ def _from_grpc_runner_info(message: isolate_proto.RunnerInfo) -> RunnerInfo:
359
363
  return RunnerInfo(
360
364
  runner_id=message.runner_id,
361
365
  in_flight_requests=message.in_flight_requests,
362
- expiration_countdown=message.expiration_countdown
363
- if message.HasField("expiration_countdown")
364
- else None,
366
+ expiration_countdown=(
367
+ message.expiration_countdown
368
+ if message.HasField("expiration_countdown")
369
+ else None
370
+ ),
365
371
  uptime=timedelta(seconds=message.uptime),
366
372
  external_metadata=external_metadata,
367
373
  )
@@ -582,9 +588,9 @@ class FalServerlessConnection:
582
588
  min_concurrency: int | None = None,
583
589
  request_timeout: int | None = None,
584
590
  startup_timeout: int | None = None,
591
+ valid_regions: list[str] | None = None,
585
592
  machine_types: list[str] | None = None,
586
593
  ) -> AliasInfo:
587
- print(machine_types)
588
594
  request = isolate_proto.UpdateApplicationRequest(
589
595
  application_name=application_name,
590
596
  keep_alive=keep_alive,
@@ -593,6 +599,7 @@ class FalServerlessConnection:
593
599
  min_concurrency=min_concurrency,
594
600
  request_timeout=request_timeout,
595
601
  startup_timeout=startup_timeout,
602
+ valid_regions=valid_regions,
596
603
  machine_types=machine_types,
597
604
  )
598
605
  res: isolate_proto.UpdateApplicationResult = self.stub.UpdateApplication(
@@ -1,23 +0,0 @@
1
- import os
2
-
3
- import tomli
4
-
5
-
6
- class Config:
7
- DEFAULT_CONFIG_PATH = "~/.fal/config.toml"
8
- DEFAULT_PROFILE = "default"
9
-
10
- def __init__(self):
11
- self.config_path = os.path.expanduser(
12
- os.getenv("FAL_CONFIG_PATH", self.DEFAULT_CONFIG_PATH)
13
- )
14
- self.profile = os.getenv("FAL_PROFILE", self.DEFAULT_PROFILE)
15
-
16
- try:
17
- with open(self.config_path, "rb") as file:
18
- self.config = tomli.load(file)
19
- except FileNotFoundError:
20
- self.config = {}
21
-
22
- def get(self, key):
23
- return self.config.get(self.profile, {}).get(key)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes