fal 1.37.0__tar.gz → 1.38.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 (187) hide show
  1. {fal-1.37.0/fal.egg-info → fal-1.38.0}/PKG-INFO +4 -2
  2. {fal-1.37.0 → fal-1.38.0/fal.egg-info}/PKG-INFO +4 -2
  3. {fal-1.37.0 → fal-1.38.0}/fal.egg-info/requires.txt +3 -1
  4. {fal-1.37.0 → fal-1.38.0}/pyproject.toml +3 -1
  5. {fal-1.37.0 → fal-1.38.0}/src/fal/_fal_version.py +2 -2
  6. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/apps.py +27 -2
  7. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/parser.py +57 -0
  8. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/runners.py +41 -5
  9. {fal-1.37.0 → fal-1.38.0}/src/fal/sdk.py +23 -4
  10. {fal-1.37.0 → fal-1.38.0}/.gitignore +0 -0
  11. {fal-1.37.0 → fal-1.38.0}/Makefile +0 -0
  12. {fal-1.37.0 → fal-1.38.0}/README.md +0 -0
  13. {fal-1.37.0 → fal-1.38.0}/docs/conf.py +0 -0
  14. {fal-1.37.0 → fal-1.38.0}/docs/index.rst +0 -0
  15. {fal-1.37.0 → fal-1.38.0}/fal.egg-info/SOURCES.txt +0 -0
  16. {fal-1.37.0 → fal-1.38.0}/fal.egg-info/dependency_links.txt +0 -0
  17. {fal-1.37.0 → fal-1.38.0}/fal.egg-info/entry_points.txt +0 -0
  18. {fal-1.37.0 → fal-1.38.0}/fal.egg-info/top_level.txt +0 -0
  19. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/README.md +0 -0
  20. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
  21. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
  22. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
  23. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
  24. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
  25. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
  26. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
  27. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
  28. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
  29. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
  30. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
  31. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
  32. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
  33. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
  34. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
  35. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
  36. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
  37. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
  38. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
  39. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
  40. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
  41. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
  42. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
  43. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
  44. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
  45. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
  46. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
  47. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
  48. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
  49. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
  50. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
  51. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
  52. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
  53. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
  54. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
  55. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
  56. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
  57. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
  58. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
  59. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
  60. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
  61. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
  62. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
  63. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
  64. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
  65. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
  66. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
  67. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
  68. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
  69. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
  70. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
  71. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
  72. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
  73. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
  74. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
  75. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
  76. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
  77. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
  78. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
  79. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
  80. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
  81. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
  82. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
  83. {fal-1.37.0 → fal-1.38.0}/openapi-fal-rest/pyproject.toml +0 -0
  84. {fal-1.37.0 → fal-1.38.0}/openapi_rest.config.yaml +0 -0
  85. {fal-1.37.0 → fal-1.38.0}/setup.cfg +0 -0
  86. {fal-1.37.0 → fal-1.38.0}/src/fal/__init__.py +0 -0
  87. {fal-1.37.0 → fal-1.38.0}/src/fal/__main__.py +0 -0
  88. {fal-1.37.0 → fal-1.38.0}/src/fal/_serialization.py +0 -0
  89. {fal-1.37.0 → fal-1.38.0}/src/fal/_version.py +0 -0
  90. {fal-1.37.0 → fal-1.38.0}/src/fal/api.py +0 -0
  91. {fal-1.37.0 → fal-1.38.0}/src/fal/app.py +0 -0
  92. {fal-1.37.0 → fal-1.38.0}/src/fal/apps.py +0 -0
  93. {fal-1.37.0 → fal-1.38.0}/src/fal/auth/__init__.py +0 -0
  94. {fal-1.37.0 → fal-1.38.0}/src/fal/auth/auth0.py +0 -0
  95. {fal-1.37.0 → fal-1.38.0}/src/fal/auth/local.py +0 -0
  96. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/__init__.py +0 -0
  97. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/_utils.py +0 -0
  98. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/api.py +0 -0
  99. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/auth.py +0 -0
  100. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/cli_nested_json.py +0 -0
  101. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/create.py +0 -0
  102. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/debug.py +0 -0
  103. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/deploy.py +0 -0
  104. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/doctor.py +0 -0
  105. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/files.py +0 -0
  106. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/keys.py +0 -0
  107. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/main.py +0 -0
  108. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/profile.py +0 -0
  109. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/run.py +0 -0
  110. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/secrets.py +0 -0
  111. {fal-1.37.0 → fal-1.38.0}/src/fal/cli/teams.py +0 -0
  112. {fal-1.37.0 → fal-1.38.0}/src/fal/config.py +0 -0
  113. {fal-1.37.0 → fal-1.38.0}/src/fal/console/__init__.py +0 -0
  114. {fal-1.37.0 → fal-1.38.0}/src/fal/console/icons.py +0 -0
  115. {fal-1.37.0 → fal-1.38.0}/src/fal/console/ux.py +0 -0
  116. {fal-1.37.0 → fal-1.38.0}/src/fal/container.py +0 -0
  117. {fal-1.37.0 → fal-1.38.0}/src/fal/exceptions/__init__.py +0 -0
  118. {fal-1.37.0 → fal-1.38.0}/src/fal/exceptions/_base.py +0 -0
  119. {fal-1.37.0 → fal-1.38.0}/src/fal/exceptions/_cuda.py +0 -0
  120. {fal-1.37.0 → fal-1.38.0}/src/fal/exceptions/auth.py +0 -0
  121. {fal-1.37.0 → fal-1.38.0}/src/fal/files.py +0 -0
  122. {fal-1.37.0 → fal-1.38.0}/src/fal/flags.py +0 -0
  123. {fal-1.37.0 → fal-1.38.0}/src/fal/logging/__init__.py +0 -0
  124. {fal-1.37.0 → fal-1.38.0}/src/fal/logging/isolate.py +0 -0
  125. {fal-1.37.0 → fal-1.38.0}/src/fal/logging/style.py +0 -0
  126. {fal-1.37.0 → fal-1.38.0}/src/fal/logging/trace.py +0 -0
  127. {fal-1.37.0 → fal-1.38.0}/src/fal/logging/user.py +0 -0
  128. {fal-1.37.0 → fal-1.38.0}/src/fal/project.py +0 -0
  129. {fal-1.37.0 → fal-1.38.0}/src/fal/py.typed +0 -0
  130. {fal-1.37.0 → fal-1.38.0}/src/fal/rest_client.py +0 -0
  131. {fal-1.37.0 → fal-1.38.0}/src/fal/sync.py +0 -0
  132. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/__init__.py +0 -0
  133. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/audio/__init__.py +0 -0
  134. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/audio/audio.py +0 -0
  135. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/exceptions.py +0 -0
  136. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/file/__init__.py +0 -0
  137. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/file/file.py +0 -0
  138. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/file/providers/fal.py +0 -0
  139. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/file/providers/gcp.py +0 -0
  140. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/file/providers/r2.py +0 -0
  141. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/file/providers/s3.py +0 -0
  142. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/file/types.py +0 -0
  143. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/__init__.py +0 -0
  144. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/image.py +0 -0
  145. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
  146. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
  147. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
  148. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
  149. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
  150. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/image/safety_checker.py +0 -0
  151. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/kv.py +0 -0
  152. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/optimize.py +0 -0
  153. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/types.py +0 -0
  154. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/utils/__init__.py +0 -0
  155. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/utils/download_utils.py +0 -0
  156. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/utils/endpoint.py +0 -0
  157. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/utils/retry.py +0 -0
  158. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/utils/setup_utils.py +0 -0
  159. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/video/__init__.py +0 -0
  160. {fal-1.37.0 → fal-1.38.0}/src/fal/toolkit/video/video.py +0 -0
  161. {fal-1.37.0 → fal-1.38.0}/src/fal/utils.py +0 -0
  162. {fal-1.37.0 → fal-1.38.0}/src/fal/workflows.py +0 -0
  163. {fal-1.37.0 → fal-1.38.0}/tests/__init__.py +0 -0
  164. {fal-1.37.0 → fal-1.38.0}/tests/assets/cat.png +0 -0
  165. {fal-1.37.0 → fal-1.38.0}/tests/cli/__init__.py +0 -0
  166. {fal-1.37.0 → fal-1.38.0}/tests/cli/test_apps.py +0 -0
  167. {fal-1.37.0 → fal-1.38.0}/tests/cli/test_auth.py +0 -0
  168. {fal-1.37.0 → fal-1.38.0}/tests/cli/test_deploy.py +0 -0
  169. {fal-1.37.0 → fal-1.38.0}/tests/cli/test_keys.py +0 -0
  170. {fal-1.37.0 → fal-1.38.0}/tests/cli/test_run.py +0 -0
  171. {fal-1.37.0 → fal-1.38.0}/tests/cli/test_secrets.py +0 -0
  172. {fal-1.37.0 → fal-1.38.0}/tests/conftest.py +0 -0
  173. {fal-1.37.0 → fal-1.38.0}/tests/integration_test.py +0 -0
  174. {fal-1.37.0 → fal-1.38.0}/tests/mainify_package/__init__.py +0 -0
  175. {fal-1.37.0 → fal-1.38.0}/tests/mainify_package/impl.py +0 -0
  176. {fal-1.37.0 → fal-1.38.0}/tests/mainify_package/utils.py +0 -0
  177. {fal-1.37.0 → fal-1.38.0}/tests/mainify_target.py +0 -0
  178. {fal-1.37.0 → fal-1.38.0}/tests/test_apps.py +0 -0
  179. {fal-1.37.0 → fal-1.38.0}/tests/test_files.py +0 -0
  180. {fal-1.37.0 → fal-1.38.0}/tests/test_kv.py +0 -0
  181. {fal-1.37.0 → fal-1.38.0}/tests/test_stability.py +0 -0
  182. {fal-1.37.0 → fal-1.38.0}/tests/toolkit/file/providers/test_fal_retry.py +0 -0
  183. {fal-1.37.0 → fal-1.38.0}/tests/toolkit/file_test.py +0 -0
  184. {fal-1.37.0 → fal-1.38.0}/tests/toolkit/image_test.py +0 -0
  185. {fal-1.37.0 → fal-1.38.0}/tests/toolkit/test_types.py +0 -0
  186. {fal-1.37.0 → fal-1.38.0}/tests/toolkit/utils/retry.py +0 -0
  187. {fal-1.37.0 → fal-1.38.0}/tools/demo_script.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.37.0
3
+ Version: 1.38.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.20.0,>=0.18.0
9
- Requires-Dist: isolate-proto<0.15.0,>=0.14.1
9
+ Requires-Dist: isolate-proto<0.17.0,>=0.16.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
@@ -28,6 +28,8 @@ Requires-Dist: httpx>=0.15.4
28
28
  Requires-Dist: attrs>=21.3.0
29
29
  Requires-Dist: python-dateutil<3,>=2.8.0
30
30
  Requires-Dist: types-python-dateutil<3,>=2.8.0
31
+ Requires-Dist: dateparser<2,>=1.2.0
32
+ Requires-Dist: types-dateparser<2,>=1.2.0
31
33
  Requires-Dist: importlib-metadata>=4.4; python_version < "3.10"
32
34
  Requires-Dist: msgpack<2,>=1.0.7
33
35
  Requires-Dist: websockets>=12.0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.37.0
3
+ Version: 1.38.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.20.0,>=0.18.0
9
- Requires-Dist: isolate-proto<0.15.0,>=0.14.1
9
+ Requires-Dist: isolate-proto<0.17.0,>=0.16.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
@@ -28,6 +28,8 @@ Requires-Dist: httpx>=0.15.4
28
28
  Requires-Dist: attrs>=21.3.0
29
29
  Requires-Dist: python-dateutil<3,>=2.8.0
30
30
  Requires-Dist: types-python-dateutil<3,>=2.8.0
31
+ Requires-Dist: dateparser<2,>=1.2.0
32
+ Requires-Dist: types-dateparser<2,>=1.2.0
31
33
  Requires-Dist: importlib-metadata>=4.4; python_version < "3.10"
32
34
  Requires-Dist: msgpack<2,>=1.0.7
33
35
  Requires-Dist: websockets>=12.0
@@ -1,5 +1,5 @@
1
1
  isolate[build]<0.20.0,>=0.18.0
2
- isolate-proto<0.15.0,>=0.14.1
2
+ isolate-proto<0.17.0,>=0.16.0
3
3
  grpcio<2,>=1.64.0
4
4
  dill==0.3.7
5
5
  cloudpickle==3.0.0
@@ -21,6 +21,8 @@ httpx>=0.15.4
21
21
  attrs>=21.3.0
22
22
  python-dateutil<3,>=2.8.0
23
23
  types-python-dateutil<3,>=2.8.0
24
+ dateparser<2,>=1.2.0
25
+ types-dateparser<2,>=1.2.0
24
26
  msgpack<2,>=1.0.7
25
27
  websockets>=12.0
26
28
  pillow<11,>=10.2.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.20.0",
26
- "isolate-proto>=0.14.1,<0.15.0",
26
+ "isolate-proto>=0.16.0,<0.17.0",
27
27
  "grpcio>=1.64.0,<2",
28
28
  "dill==0.3.7",
29
29
  "cloudpickle==3.0.0",
@@ -47,6 +47,8 @@ dependencies = [
47
47
  "attrs>=21.3.0",
48
48
  "python-dateutil>=2.8.0,<3",
49
49
  "types-python-dateutil>=2.8.0,<3",
50
+ "dateparser>=1.2.0,<2",
51
+ "types-dateparser>=1.2.0,<2",
50
52
  # For 3.9 and earlier, importlib-metadata's newer versions are included in the standard library.
51
53
  'importlib-metadata>=4.4; python_version < "3.10"',
52
54
  "msgpack>=1.0.7,<2",
@@ -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.37.0'
32
- __version_tuple__ = version_tuple = (1, 37, 0)
31
+ __version__ = version = '1.38.0'
32
+ __version_tuple__ = version_tuple = (1, 38, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -8,7 +8,7 @@ import fal.cli.runners as runners
8
8
  from fal.sdk import RunnerState
9
9
 
10
10
  from ._utils import get_client
11
- from .parser import FalClientParser, get_output_parser
11
+ from .parser import FalClientParser, SinceAction, get_output_parser
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from fal.sdk import AliasInfo, ApplicationInfo
@@ -291,7 +291,14 @@ def _add_set_rev_parser(subparsers, parents):
291
291
  def _runners(args):
292
292
  client = get_client(args.host, args.team)
293
293
  with client.connect() as connection:
294
- alias_runners = connection.list_alias_runners(alias=args.app_name)
294
+ start_time = getattr(args, "since", None)
295
+ alias_runners = connection.list_alias_runners(
296
+ alias=args.app_name, start_time=start_time
297
+ )
298
+ if getattr(args, "state", None):
299
+ states = set(args.state)
300
+ if "all" not in states:
301
+ alias_runners = [r for r in alias_runners if r.state.value in states]
295
302
  if args.output == "pretty":
296
303
  runners_table = runners.runners_table(alias_runners)
297
304
  pending_runners = [
@@ -330,6 +337,24 @@ def _add_runners_parser(subparsers, parents):
330
337
  "app_name",
331
338
  help="Application name.",
332
339
  )
340
+ parser.add_argument(
341
+ "--since",
342
+ default=None,
343
+ action=SinceAction,
344
+ limit="1 day",
345
+ help=(
346
+ "Show dead runners since the given time. "
347
+ "Accepts 'now', relative like '30m', '1h', '1d', "
348
+ "or an ISO timestamp. Max 24 hours."
349
+ ),
350
+ )
351
+ parser.add_argument(
352
+ "--state",
353
+ choices=["all", "running", "pending", "setup", "dead"],
354
+ nargs="+",
355
+ default=None,
356
+ help=("Filter by runner state(s). Choose one or more, or 'all'(default)."),
357
+ )
333
358
  parser.set_defaults(func=_runners)
334
359
 
335
360
 
@@ -1,5 +1,7 @@
1
1
  import argparse
2
2
  import sys
3
+ from datetime import datetime, timedelta
4
+ from typing import Optional
3
5
 
4
6
  import rich_argparse
5
7
 
@@ -55,6 +57,61 @@ class DictAction(argparse.Action):
55
57
  setattr(args, self.dest, d)
56
58
 
57
59
 
60
+ class SinceAction(argparse.Action):
61
+ LIMIT_LEEWAY = timedelta(minutes=1)
62
+
63
+ def _parse_since(self, value: str) -> Optional[datetime]:
64
+ import dateparser
65
+
66
+ return dateparser.parse(
67
+ value,
68
+ settings={
69
+ "PREFER_DATES_FROM": "past",
70
+ },
71
+ )
72
+
73
+ def __init__(self, *args, **kwargs):
74
+ self._limit = kwargs.pop("limit", None)
75
+ if self._limit:
76
+ if not isinstance(self._limit, str):
77
+ raise ValueError(
78
+ f"Invalid 'limit' value for SinceAction: {self._limit!r}"
79
+ )
80
+
81
+ self._limit_dt = self._parse_since(self._limit)
82
+ if not self._limit_dt:
83
+ raise ValueError(
84
+ f"Invalid 'limit' value for SinceAction: {self._limit!r}"
85
+ )
86
+
87
+ super().__init__(*args, **kwargs)
88
+
89
+ def __call__(self, parser, args, values, option_string=None): # noqa: ARG002
90
+ if values is None:
91
+ setattr(args, self.dest, None)
92
+ return
93
+
94
+ dt = self._parse_since(values)
95
+ if not dt:
96
+ raise argparse.ArgumentError(
97
+ self,
98
+ (
99
+ f"Invalid since value: {values}. "
100
+ "Use 'now', relative like '15m' or '24h ago', "
101
+ "or an ISO timestamp."
102
+ ),
103
+ )
104
+
105
+ if self._limit_dt is not None:
106
+ if dt < self._limit_dt - self.LIMIT_LEEWAY:
107
+ raise argparse.ArgumentError(
108
+ self,
109
+ f"Since value is older than the allowed limit {self._limit}.",
110
+ )
111
+
112
+ setattr(args, self.dest, dt)
113
+
114
+
58
115
  def _find_parser(parser, func):
59
116
  defaults = parser._defaults
60
117
  if not func or func == defaults.get("func"):
@@ -1,12 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ from datetime import timedelta
4
5
  from typing import List
5
6
 
6
7
  from fal.sdk import RunnerInfo, RunnerState
7
8
 
8
9
  from ._utils import get_client
9
- from .parser import FalClientParser, get_output_parser
10
+ from .parser import FalClientParser, SinceAction, get_output_parser
10
11
 
11
12
 
12
13
  def runners_table(runners: List[RunnerInfo]):
@@ -42,17 +43,20 @@ def runners_table(runners: List[RunnerInfo]):
42
43
  # consistent
43
44
  in_flight = f"{in_flight} [dim]({missing_leases})[/]"
44
45
 
46
+ uptime = timedelta(
47
+ seconds=int(runner.uptime.total_seconds()),
48
+ )
45
49
  table.add_row(
46
50
  runner.alias,
47
51
  # Mark lost runners in red
48
52
  runner.runner_id if present else f"[red]{runner.runner_id}[/]",
49
53
  in_flight,
50
54
  (
51
- "N/A (active)"
55
+ "N/A"
52
56
  if runner.expiration_countdown is None
53
57
  else f"{runner.expiration_countdown}s"
54
58
  ),
55
- f"{runner.uptime} ({runner.uptime.total_seconds()}s)",
59
+ f"{uptime} ({uptime.total_seconds():.0f}s)",
56
60
  runner.revision,
57
61
  runner.state.value,
58
62
  )
@@ -111,17 +115,31 @@ def _list_json(args, runners: list[RunnerInfo]):
111
115
  def _list(args):
112
116
  client = get_client(args.host, args.team)
113
117
  with client.connect() as connection:
114
- runners = connection.list_runners()
118
+ start_time = getattr(args, "since", None)
119
+ runners = connection.list_runners(start_time=start_time)
120
+
121
+ if getattr(args, "state", None):
122
+ states = set(args.state)
123
+ if "all" not in states:
124
+ runners = [r for r in runners if r.state.value in states]
115
125
  pending_runners = [
116
126
  runner for runner in runners if runner.state == RunnerState.PENDING
117
127
  ]
118
128
  setup_runners = [
119
129
  runner for runner in runners if runner.state == RunnerState.SETUP
120
130
  ]
131
+ dead_runners = [
132
+ runner for runner in runners if runner.state == RunnerState.DEAD
133
+ ]
121
134
  if args.output == "pretty":
122
135
  args.console.print(
123
136
  "Runners: "
124
- + str(len(runners) - len(pending_runners) - len(setup_runners))
137
+ + str(
138
+ len(runners)
139
+ - len(pending_runners)
140
+ - len(setup_runners)
141
+ - len(dead_runners)
142
+ )
125
143
  )
126
144
  args.console.print(f"Runners Pending: {len(pending_runners)}")
127
145
  args.console.print(f"Runners Setting Up: {len(setup_runners)}")
@@ -159,6 +177,24 @@ def _add_list_parser(subparsers, parents):
159
177
  help=list_help,
160
178
  parents=[*parents, get_output_parser()],
161
179
  )
180
+ parser.add_argument(
181
+ "--since",
182
+ default=None,
183
+ action=SinceAction,
184
+ limit="1 day",
185
+ help=(
186
+ "Show dead runners since the given time. "
187
+ "Accepts 'now', relative like '30m', '1h', '1d', "
188
+ "or an ISO timestamp. Max 24 hours."
189
+ ),
190
+ )
191
+ parser.add_argument(
192
+ "--state",
193
+ choices=["all", "running", "pending", "setup", "dead"],
194
+ nargs="+",
195
+ default=None,
196
+ help=("Filter by runner state(s). Choose one or more, or 'all'(default)."),
197
+ )
162
198
  parser.set_defaults(func=_list)
163
199
 
164
200
 
@@ -265,6 +265,7 @@ class RunnerState(Enum):
265
265
  RUNNING = "running"
266
266
  PENDING = "pending"
267
267
  SETUP = "setup"
268
+ DEAD = "dead"
268
269
  UNKNOWN = "unknown"
269
270
 
270
271
  @staticmethod
@@ -275,6 +276,8 @@ class RunnerState(Enum):
275
276
  return RunnerState.PENDING
276
277
  elif proto is isolate_proto.RunnerInfo.State.SETUP:
277
278
  return RunnerState.SETUP
279
+ elif proto is isolate_proto.RunnerInfo.State.DEAD:
280
+ return RunnerState.DEAD
278
281
  else:
279
282
  return RunnerState.UNKNOWN
280
283
 
@@ -811,8 +814,18 @@ class FalServerlessConnection:
811
814
  response: isolate_proto.ListAliasesResult = self.stub.ListAliases(request)
812
815
  return [from_grpc(alias) for alias in response.aliases]
813
816
 
814
- def list_alias_runners(self, alias: str) -> list[RunnerInfo]:
815
- request = isolate_proto.ListAliasRunnersRequest(alias=alias, list_pending=True)
817
+ def list_alias_runners(
818
+ self,
819
+ alias: str,
820
+ *,
821
+ list_pending: bool = True,
822
+ start_time: datetime | None = None,
823
+ ) -> list[RunnerInfo]:
824
+ kwargs = {"alias": alias, "list_pending": list_pending}
825
+ if start_time:
826
+ kwargs["start_time"] = isolate_proto.timestamp_from_datetime(start_time)
827
+
828
+ request = isolate_proto.ListAliasRunnersRequest(**kwargs)
816
829
  response = self.stub.ListAliasRunners(request)
817
830
  return [from_grpc(runner) for runner in response.runners]
818
831
 
@@ -839,7 +852,13 @@ class FalServerlessConnection:
839
852
  request = isolate_proto.KillRunnerRequest(runner_id=runner_id)
840
853
  self.stub.KillRunner(request)
841
854
 
842
- def list_runners(self) -> list[RunnerInfo]:
843
- request = isolate_proto.ListRunnersRequest(list_pending=True)
855
+ def list_runners(self, start_time: datetime | None = None) -> list[RunnerInfo]:
856
+ kwargs = {
857
+ "list_pending": True,
858
+ }
859
+ if start_time:
860
+ kwargs["start_time"] = isolate_proto.timestamp_from_datetime(start_time)
861
+
862
+ request = isolate_proto.ListRunnersRequest(**kwargs)
844
863
  response = self.stub.ListRunners(request)
845
864
  return [from_grpc(runner) for runner in response.runners]
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