fal 1.22.0__tar.gz → 1.23.1__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 (185) hide show
  1. {fal-1.22.0/fal.egg-info → fal-1.23.1}/PKG-INFO +1 -1
  2. {fal-1.22.0 → fal-1.23.1/fal.egg-info}/PKG-INFO +1 -1
  3. {fal-1.22.0 → fal-1.23.1}/fal.egg-info/SOURCES.txt +2 -0
  4. {fal-1.22.0 → fal-1.23.1}/src/fal/_fal_version.py +2 -2
  5. {fal-1.22.0 → fal-1.23.1}/src/fal/container.py +2 -0
  6. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/exceptions.py +6 -0
  7. fal-1.23.1/src/fal/toolkit/kv.py +85 -0
  8. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/utils/download_utils.py +13 -4
  9. {fal-1.22.0 → fal-1.23.1}/tests/integration_test.py +3 -3
  10. fal-1.23.1/tests/test_kv.py +8 -0
  11. {fal-1.22.0 → fal-1.23.1}/.gitignore +0 -0
  12. {fal-1.22.0 → fal-1.23.1}/Makefile +0 -0
  13. {fal-1.22.0 → fal-1.23.1}/README.md +0 -0
  14. {fal-1.22.0 → fal-1.23.1}/docs/conf.py +0 -0
  15. {fal-1.22.0 → fal-1.23.1}/docs/index.rst +0 -0
  16. {fal-1.22.0 → fal-1.23.1}/fal.egg-info/dependency_links.txt +0 -0
  17. {fal-1.22.0 → fal-1.23.1}/fal.egg-info/entry_points.txt +0 -0
  18. {fal-1.22.0 → fal-1.23.1}/fal.egg-info/requires.txt +0 -0
  19. {fal-1.22.0 → fal-1.23.1}/fal.egg-info/top_level.txt +0 -0
  20. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/README.md +0 -0
  21. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
  22. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
  23. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
  24. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
  25. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
  26. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
  27. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
  28. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
  29. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
  30. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
  31. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
  32. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
  33. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
  34. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
  35. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
  36. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
  37. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
  38. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
  39. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
  40. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
  41. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
  42. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
  43. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
  44. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
  45. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
  46. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
  47. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
  48. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
  49. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
  50. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
  51. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
  52. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
  53. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
  54. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
  55. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
  56. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
  57. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
  58. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
  59. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
  60. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
  61. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
  62. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
  63. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
  64. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
  65. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
  66. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
  67. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
  68. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
  69. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
  70. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
  71. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
  72. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
  73. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
  74. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
  75. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
  76. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
  77. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
  78. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
  79. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
  80. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
  81. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
  82. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
  83. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
  84. {fal-1.22.0 → fal-1.23.1}/openapi-fal-rest/pyproject.toml +0 -0
  85. {fal-1.22.0 → fal-1.23.1}/openapi_rest.config.yaml +0 -0
  86. {fal-1.22.0 → fal-1.23.1}/pyproject.toml +0 -0
  87. {fal-1.22.0 → fal-1.23.1}/setup.cfg +0 -0
  88. {fal-1.22.0 → fal-1.23.1}/src/fal/__init__.py +0 -0
  89. {fal-1.22.0 → fal-1.23.1}/src/fal/__main__.py +0 -0
  90. {fal-1.22.0 → fal-1.23.1}/src/fal/_serialization.py +0 -0
  91. {fal-1.22.0 → fal-1.23.1}/src/fal/_version.py +0 -0
  92. {fal-1.22.0 → fal-1.23.1}/src/fal/api.py +0 -0
  93. {fal-1.22.0 → fal-1.23.1}/src/fal/app.py +0 -0
  94. {fal-1.22.0 → fal-1.23.1}/src/fal/apps.py +0 -0
  95. {fal-1.22.0 → fal-1.23.1}/src/fal/auth/__init__.py +0 -0
  96. {fal-1.22.0 → fal-1.23.1}/src/fal/auth/auth0.py +0 -0
  97. {fal-1.22.0 → fal-1.23.1}/src/fal/auth/local.py +0 -0
  98. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/__init__.py +0 -0
  99. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/_utils.py +0 -0
  100. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/api.py +0 -0
  101. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/apps.py +0 -0
  102. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/auth.py +0 -0
  103. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/cli_nested_json.py +0 -0
  104. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/create.py +0 -0
  105. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/debug.py +0 -0
  106. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/deploy.py +0 -0
  107. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/doctor.py +0 -0
  108. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/files.py +0 -0
  109. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/keys.py +0 -0
  110. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/main.py +0 -0
  111. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/parser.py +0 -0
  112. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/profile.py +0 -0
  113. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/run.py +0 -0
  114. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/runners.py +0 -0
  115. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/secrets.py +0 -0
  116. {fal-1.22.0 → fal-1.23.1}/src/fal/cli/teams.py +0 -0
  117. {fal-1.22.0 → fal-1.23.1}/src/fal/config.py +0 -0
  118. {fal-1.22.0 → fal-1.23.1}/src/fal/console/__init__.py +0 -0
  119. {fal-1.22.0 → fal-1.23.1}/src/fal/console/icons.py +0 -0
  120. {fal-1.22.0 → fal-1.23.1}/src/fal/console/ux.py +0 -0
  121. {fal-1.22.0 → fal-1.23.1}/src/fal/exceptions/__init__.py +0 -0
  122. {fal-1.22.0 → fal-1.23.1}/src/fal/exceptions/_base.py +0 -0
  123. {fal-1.22.0 → fal-1.23.1}/src/fal/exceptions/_cuda.py +0 -0
  124. {fal-1.22.0 → fal-1.23.1}/src/fal/exceptions/auth.py +0 -0
  125. {fal-1.22.0 → fal-1.23.1}/src/fal/files.py +0 -0
  126. {fal-1.22.0 → fal-1.23.1}/src/fal/flags.py +0 -0
  127. {fal-1.22.0 → fal-1.23.1}/src/fal/logging/__init__.py +0 -0
  128. {fal-1.22.0 → fal-1.23.1}/src/fal/logging/isolate.py +0 -0
  129. {fal-1.22.0 → fal-1.23.1}/src/fal/logging/style.py +0 -0
  130. {fal-1.22.0 → fal-1.23.1}/src/fal/logging/trace.py +0 -0
  131. {fal-1.22.0 → fal-1.23.1}/src/fal/logging/user.py +0 -0
  132. {fal-1.22.0 → fal-1.23.1}/src/fal/project.py +0 -0
  133. {fal-1.22.0 → fal-1.23.1}/src/fal/py.typed +0 -0
  134. {fal-1.22.0 → fal-1.23.1}/src/fal/rest_client.py +0 -0
  135. {fal-1.22.0 → fal-1.23.1}/src/fal/sdk.py +0 -0
  136. {fal-1.22.0 → fal-1.23.1}/src/fal/sync.py +0 -0
  137. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/__init__.py +0 -0
  138. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/audio/__init__.py +0 -0
  139. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/audio/audio.py +0 -0
  140. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/file/__init__.py +0 -0
  141. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/file/file.py +0 -0
  142. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/file/providers/fal.py +0 -0
  143. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/file/providers/gcp.py +0 -0
  144. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/file/providers/r2.py +0 -0
  145. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/file/providers/s3.py +0 -0
  146. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/file/types.py +0 -0
  147. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/__init__.py +0 -0
  148. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/image.py +0 -0
  149. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
  150. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
  151. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
  152. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
  153. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
  154. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/image/safety_checker.py +0 -0
  155. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/optimize.py +0 -0
  156. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/types.py +0 -0
  157. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/utils/__init__.py +0 -0
  158. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/utils/endpoint.py +0 -0
  159. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/utils/retry.py +0 -0
  160. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/video/__init__.py +0 -0
  161. {fal-1.22.0 → fal-1.23.1}/src/fal/toolkit/video/video.py +0 -0
  162. {fal-1.22.0 → fal-1.23.1}/src/fal/utils.py +0 -0
  163. {fal-1.22.0 → fal-1.23.1}/src/fal/workflows.py +0 -0
  164. {fal-1.22.0 → fal-1.23.1}/tests/__init__.py +0 -0
  165. {fal-1.22.0 → fal-1.23.1}/tests/assets/cat.png +0 -0
  166. {fal-1.22.0 → fal-1.23.1}/tests/cli/__init__.py +0 -0
  167. {fal-1.22.0 → fal-1.23.1}/tests/cli/test_apps.py +0 -0
  168. {fal-1.22.0 → fal-1.23.1}/tests/cli/test_auth.py +0 -0
  169. {fal-1.22.0 → fal-1.23.1}/tests/cli/test_deploy.py +0 -0
  170. {fal-1.22.0 → fal-1.23.1}/tests/cli/test_keys.py +0 -0
  171. {fal-1.22.0 → fal-1.23.1}/tests/cli/test_run.py +0 -0
  172. {fal-1.22.0 → fal-1.23.1}/tests/cli/test_secrets.py +0 -0
  173. {fal-1.22.0 → fal-1.23.1}/tests/conftest.py +0 -0
  174. {fal-1.22.0 → fal-1.23.1}/tests/mainify_package/__init__.py +0 -0
  175. {fal-1.22.0 → fal-1.23.1}/tests/mainify_package/impl.py +0 -0
  176. {fal-1.22.0 → fal-1.23.1}/tests/mainify_package/utils.py +0 -0
  177. {fal-1.22.0 → fal-1.23.1}/tests/mainify_target.py +0 -0
  178. {fal-1.22.0 → fal-1.23.1}/tests/test_apps.py +0 -0
  179. {fal-1.22.0 → fal-1.23.1}/tests/test_stability.py +0 -0
  180. {fal-1.22.0 → fal-1.23.1}/tests/toolkit/file/providers/test_fal_retry.py +0 -0
  181. {fal-1.22.0 → fal-1.23.1}/tests/toolkit/file_test.py +0 -0
  182. {fal-1.22.0 → fal-1.23.1}/tests/toolkit/image_test.py +0 -0
  183. {fal-1.22.0 → fal-1.23.1}/tests/toolkit/test_types.py +0 -0
  184. {fal-1.22.0 → fal-1.23.1}/tests/toolkit/utils/retry.py +0 -0
  185. {fal-1.22.0 → fal-1.23.1}/tools/demo_script.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fal
3
- Version: 1.22.0
3
+ Version: 1.23.1
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.22.0
3
+ Version: 1.23.1
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
@@ -131,6 +131,7 @@ src/fal/logging/trace.py
131
131
  src/fal/logging/user.py
132
132
  src/fal/toolkit/__init__.py
133
133
  src/fal/toolkit/exceptions.py
134
+ src/fal/toolkit/kv.py
134
135
  src/fal/toolkit/optimize.py
135
136
  src/fal/toolkit/types.py
136
137
  src/fal/toolkit/audio/__init__.py
@@ -161,6 +162,7 @@ tests/conftest.py
161
162
  tests/integration_test.py
162
163
  tests/mainify_target.py
163
164
  tests/test_apps.py
165
+ tests/test_kv.py
164
166
  tests/test_stability.py
165
167
  tests/assets/cat.png
166
168
  tests/cli/__init__.py
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.22.0'
21
- __version_tuple__ = version_tuple = (1, 22, 0)
20
+ __version__ = version = '1.23.1'
21
+ __version_tuple__ = version_tuple = (1, 23, 1)
@@ -19,6 +19,7 @@ class ContainerImage:
19
19
  builder: Optional[Builder] = field(default=None)
20
20
  compression: str = DEFAULT_COMPRESSION
21
21
  force_compression: bool = DEFAULT_FORCE_COMPRESSION
22
+ secrets: Dict[str, str] = field(default_factory=dict)
22
23
 
23
24
  def __post_init__(self) -> None:
24
25
  if self.registries:
@@ -51,4 +52,5 @@ class ContainerImage:
51
52
  "builder": self.builder,
52
53
  "compression": self.compression,
53
54
  "force_compression": self.force_compression,
55
+ "secrets": self.secrets,
54
56
  }
@@ -8,3 +8,9 @@ class FileUploadException(FalTookitException):
8
8
  """Raised when file upload fails"""
9
9
 
10
10
  pass
11
+
12
+
13
+ class KVStoreException(FalTookitException):
14
+ """Raised when KV store operation fails"""
15
+
16
+ pass
@@ -0,0 +1,85 @@
1
+ import json
2
+ from typing import Any, Dict, Optional
3
+ from urllib.error import HTTPError
4
+ from urllib.request import Request
5
+
6
+ from fal.toolkit.exceptions import KVStoreException
7
+ from fal.toolkit.file.providers.fal import _maybe_retry_request, fal_v3_token_manager
8
+
9
+ FAL_KV_HOST = "https://kv.fal.media"
10
+
11
+
12
+ class KVStore:
13
+ """A key-value store client for interacting with the FAL KV service.
14
+
15
+ Args:
16
+ db_name: The name of the database/namespace to use for this KV store.
17
+ """
18
+
19
+ def __init__(self, db_name: str):
20
+ self.db_name = db_name
21
+
22
+ @property
23
+ def auth_headers(self) -> Dict[str, str]:
24
+ token = fal_v3_token_manager.get_token()
25
+ return {
26
+ "Authorization": f"{token.token_type} {token.token}",
27
+ "User-Agent": "fal/0.1.0",
28
+ }
29
+
30
+ def get(self, key: str) -> Optional[str]:
31
+ """Retrieve a value from the key-value store.
32
+
33
+ Args:
34
+ key: The key to retrieve the value for.
35
+
36
+ Returns:
37
+ The value associated with the key, or None if the key doesn't exist.
38
+ """
39
+ response = self._send_request(
40
+ method="GET",
41
+ path=f"/get/{self.db_name}/{key}",
42
+ )
43
+
44
+ if response is None:
45
+ return None
46
+
47
+ return response["value"]
48
+
49
+ def set(self, key: str, value: str) -> None:
50
+ """Store a value in the key-value store.
51
+
52
+ Args:
53
+ key: The key to store the value under.
54
+ value: The value to store.
55
+ """
56
+ self._send_request(
57
+ method="PUT",
58
+ path=f"/set/{self.db_name}/{key}",
59
+ data=value.encode(),
60
+ )
61
+
62
+ def _send_request(
63
+ self,
64
+ method: str,
65
+ path: str,
66
+ data: Optional[bytes] = None,
67
+ ) -> Optional[Dict[str, Any]]:
68
+ headers = {
69
+ **self.auth_headers,
70
+ "Accept": "application/json",
71
+ }
72
+
73
+ url = FAL_KV_HOST + path
74
+ request = Request(url, headers=headers, method=method, data=data)
75
+ try:
76
+ with _maybe_retry_request(request) as response:
77
+ result = json.load(response)
78
+ except HTTPError as e:
79
+ if e.status == 404:
80
+ return None
81
+ raise KVStoreException(
82
+ f"Error sending request. Status {e.status}: {e.reason}"
83
+ )
84
+
85
+ return result
@@ -427,13 +427,22 @@ def clone_repository(
427
427
  if repo_name is None:
428
428
  repo_name = Path(https_url).stem
429
429
  if commit_hash:
430
+ if len(commit_hash) < 8:
431
+ raise ValueError(f"Commit hash '{commit_hash}' is too short.")
430
432
  repo_name += f"-{commit_hash[:8]}"
431
433
 
432
434
  local_repo_path = Path(target_dir) / repo_name # type: ignore[arg-type]
433
435
 
434
436
  if local_repo_path.exists():
435
- local_repo_commit_hash = _get_git_revision_hash(local_repo_path)
436
- if local_repo_commit_hash == commit_hash and not force:
437
+ local_repo_commit_hash = _git_rev_parse(local_repo_path, "HEAD")
438
+ full_commit_hash = (
439
+ _git_rev_parse(local_repo_path, commit_hash) if commit_hash else None
440
+ )
441
+ if (
442
+ full_commit_hash
443
+ and local_repo_commit_hash == full_commit_hash
444
+ and not force
445
+ ):
437
446
  if include_to_path:
438
447
  __add_local_path_to_sys_path(local_repo_path)
439
448
  return local_repo_path
@@ -516,12 +525,12 @@ def __add_local_path_to_sys_path(local_path: Path | str):
516
525
  sys.path.insert(0, local_path_str)
517
526
 
518
527
 
519
- def _get_git_revision_hash(repo_path: Path) -> str:
528
+ def _git_rev_parse(repo_path: Path, ref: str) -> str:
520
529
  import subprocess
521
530
 
522
531
  try:
523
532
  return subprocess.check_output(
524
- ["git", "rev-parse", "HEAD"],
533
+ ["git", "rev-parse", ref],
525
534
  cwd=repo_path,
526
535
  text=True,
527
536
  stderr=subprocess.STDOUT,
@@ -23,7 +23,7 @@ from fal.toolkit import (
23
23
  Image as FalImage,
24
24
  )
25
25
  from fal.toolkit.file.file import CompressedFile
26
- from fal.toolkit.utils.download_utils import _get_git_revision_hash, _hash_url
26
+ from fal.toolkit.utils.download_utils import _git_rev_parse, _hash_url
27
27
 
28
28
  EXAMPLE_FILE_URL = "https://raw.githubusercontent.com/fal-ai/fal/main/projects/fal/tests/assets/cat.png"
29
29
 
@@ -376,13 +376,13 @@ def test_clone_repository(isolated_client, mock_fal_persistent_dirs):
376
376
  first_path = clone_repository(
377
377
  EXAMPLE_REPO_URL, commit_hash=EXAMPLE_REPO_FIRST_COMMIT
378
378
  )
379
- first_repo_hash = _get_git_revision_hash(first_path)
379
+ first_repo_hash = _git_rev_parse(first_path, "HEAD")
380
380
 
381
381
  second_path = clone_repository(
382
382
  EXAMPLE_REPO_URL, commit_hash=EXAMPLE_REPO_SECOND_COMMIT
383
383
  )
384
384
 
385
- second_repo_hash = _get_git_revision_hash(second_path)
385
+ second_repo_hash = _git_rev_parse(second_path, "HEAD")
386
386
 
387
387
  return first_path, first_repo_hash, second_path, second_repo_hash
388
388
 
@@ -0,0 +1,8 @@
1
+ from fal.toolkit.kv import KVStore
2
+
3
+
4
+ def test_kv_store():
5
+ kv = KVStore("test")
6
+ kv.set("test", "test")
7
+ assert kv.get("test") == "test"
8
+ assert kv.get("test2") is None
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