fal 1.5.7__tar.gz → 1.5.9__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.
- {fal-1.5.7/fal.egg-info → fal-1.5.9}/PKG-INFO +3 -3
- {fal-1.5.7 → fal-1.5.9/fal.egg-info}/PKG-INFO +3 -3
- {fal-1.5.7 → fal-1.5.9}/fal.egg-info/SOURCES.txt +1 -0
- {fal-1.5.7 → fal-1.5.9}/fal.egg-info/requires.txt +2 -2
- {fal-1.5.7 → fal-1.5.9}/pyproject.toml +2 -2
- {fal-1.5.7 → fal-1.5.9}/src/fal/_fal_version.py +2 -2
- {fal-1.5.7 → fal-1.5.9}/src/fal/api.py +6 -4
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/apps.py +1 -1
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/deploy.py +10 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/sdk.py +7 -3
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/file/file.py +16 -2
- fal-1.5.9/src/fal/toolkit/file/providers/s3.py +80 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/__init__.py +3 -3
- {fal-1.5.7 → fal-1.5.9}/tests/test_apps.py +42 -0
- {fal-1.5.7 → fal-1.5.9}/.gitignore +0 -0
- {fal-1.5.7 → fal-1.5.9}/Makefile +0 -0
- {fal-1.5.7 → fal-1.5.9}/README.md +0 -0
- {fal-1.5.7 → fal-1.5.9}/docs/conf.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/docs/index.rst +0 -0
- {fal-1.5.7 → fal-1.5.9}/fal.egg-info/dependency_links.txt +0 -0
- {fal-1.5.7 → fal-1.5.9}/fal.egg-info/entry_points.txt +0 -0
- {fal-1.5.7 → fal-1.5.9}/fal.egg-info/top_level.txt +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/README.md +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/pyproject.toml +0 -0
- {fal-1.5.7 → fal-1.5.9}/openapi_rest.config.yaml +0 -0
- {fal-1.5.7 → fal-1.5.9}/setup.cfg +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/__main__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/_serialization.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/_version.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/app.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/apps.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/auth/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/auth/auth0.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/auth/local.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/_utils.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/auth.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/create.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/debug.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/doctor.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/keys.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/main.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/parser.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/run.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/cli/secrets.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/console/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/console/icons.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/console/ux.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/container.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/exceptions/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/exceptions/_base.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/exceptions/_cuda.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/exceptions/auth.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/files.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/flags.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/logging/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/logging/isolate.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/logging/style.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/logging/trace.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/logging/user.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/py.typed +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/rest_client.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/sync.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/exceptions.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/file/providers/fal.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/file/types.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/image.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/image/safety_checker.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/optimize.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/utils/download_utils.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/toolkit/utils/retry.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/utils.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/src/fal/workflows.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/assets/cat.png +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/cli/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/cli/test_apps.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/cli/test_auth.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/cli/test_deploy.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/cli/test_keys.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/cli/test_run.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/cli/test_secrets.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/conftest.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/integration_test.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/mainify_package/__init__.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/mainify_package/impl.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/mainify_package/utils.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/mainify_target.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/test_stability.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/toolkit/file_test.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/toolkit/image_test.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tests/toolkit/utils/retry.py +0 -0
- {fal-1.5.7 → fal-1.5.9}/tools/demo_script.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.9
|
|
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
|
-
Requires-Dist: isolate[build]<
|
|
9
|
-
Requires-Dist: isolate-proto==0.5.
|
|
8
|
+
Requires-Dist: isolate[build]<0.15.0,>=0.14.2
|
|
9
|
+
Requires-Dist: isolate-proto==0.5.5
|
|
10
10
|
Requires-Dist: grpcio==1.64.0
|
|
11
11
|
Requires-Dist: dill==0.3.7
|
|
12
12
|
Requires-Dist: cloudpickle==3.0.0
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.9
|
|
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
|
-
Requires-Dist: isolate[build]<
|
|
9
|
-
Requires-Dist: isolate-proto==0.5.
|
|
8
|
+
Requires-Dist: isolate[build]<0.15.0,>=0.14.2
|
|
9
|
+
Requires-Dist: isolate-proto==0.5.5
|
|
10
10
|
Requires-Dist: grpcio==1.64.0
|
|
11
11
|
Requires-Dist: dill==0.3.7
|
|
12
12
|
Requires-Dist: cloudpickle==3.0.0
|
|
@@ -130,6 +130,7 @@ src/fal/toolkit/file/types.py
|
|
|
130
130
|
src/fal/toolkit/file/providers/fal.py
|
|
131
131
|
src/fal/toolkit/file/providers/gcp.py
|
|
132
132
|
src/fal/toolkit/file/providers/r2.py
|
|
133
|
+
src/fal/toolkit/file/providers/s3.py
|
|
133
134
|
src/fal/toolkit/image/__init__.py
|
|
134
135
|
src/fal/toolkit/image/image.py
|
|
135
136
|
src/fal/toolkit/image/safety_checker.py
|
|
@@ -22,8 +22,8 @@ authors = [{ name = "Features & Labels <support@fal.ai>"}]
|
|
|
22
22
|
readme = "README.md"
|
|
23
23
|
requires-python = ">=3.8"
|
|
24
24
|
dependencies = [
|
|
25
|
-
"isolate[build]>=0.
|
|
26
|
-
"isolate-proto==0.5.
|
|
25
|
+
"isolate[build]>=0.14.2,<0.15.0",
|
|
26
|
+
"isolate-proto==0.5.5",
|
|
27
27
|
"grpcio==1.64.0",
|
|
28
28
|
"dill==0.3.7",
|
|
29
29
|
"cloudpickle==3.0.0",
|
|
@@ -171,6 +171,7 @@ class Host(Generic[ArgsT, ReturnT]):
|
|
|
171
171
|
application_name: str | None = None,
|
|
172
172
|
application_auth_mode: Literal["public", "shared", "private"] | None = None,
|
|
173
173
|
metadata: dict[str, Any] | None = None,
|
|
174
|
+
scale: bool = True,
|
|
174
175
|
) -> str | None:
|
|
175
176
|
"""Register the given function on the host for API call execution."""
|
|
176
177
|
raise NotImplementedError
|
|
@@ -430,6 +431,7 @@ class FalServerlessHost(Host):
|
|
|
430
431
|
application_auth_mode: Literal["public", "shared", "private"] | None = None,
|
|
431
432
|
metadata: dict[str, Any] | None = None,
|
|
432
433
|
deployment_strategy: Literal["recreate", "rolling"] = "recreate",
|
|
434
|
+
scale: bool = True,
|
|
433
435
|
) -> str | None:
|
|
434
436
|
environment_options = options.environment.copy()
|
|
435
437
|
environment_options.setdefault("python_version", active_python())
|
|
@@ -439,15 +441,14 @@ class FalServerlessHost(Host):
|
|
|
439
441
|
"machine_type", FAL_SERVERLESS_DEFAULT_MACHINE_TYPE
|
|
440
442
|
)
|
|
441
443
|
keep_alive = options.host.get("keep_alive", FAL_SERVERLESS_DEFAULT_KEEP_ALIVE)
|
|
442
|
-
max_concurrency = options.host.get("max_concurrency")
|
|
443
|
-
min_concurrency = options.host.get("min_concurrency")
|
|
444
|
-
max_multiplexing = options.host.get("max_multiplexing")
|
|
445
444
|
base_image = options.host.get("_base_image", None)
|
|
446
445
|
scheduler = options.host.get("_scheduler", None)
|
|
447
446
|
scheduler_options = options.host.get("_scheduler_options", None)
|
|
447
|
+
max_concurrency = options.host.get("max_concurrency")
|
|
448
|
+
min_concurrency = options.host.get("min_concurrency")
|
|
449
|
+
max_multiplexing = options.host.get("max_multiplexing")
|
|
448
450
|
exposed_port = options.get_exposed_port()
|
|
449
451
|
request_timeout = options.host.get("request_timeout")
|
|
450
|
-
|
|
451
452
|
machine_requirements = MachineRequirements(
|
|
452
453
|
machine_types=machine_type, # type: ignore
|
|
453
454
|
num_gpus=options.host.get("num_gpus"),
|
|
@@ -486,6 +487,7 @@ class FalServerlessHost(Host):
|
|
|
486
487
|
machine_requirements=machine_requirements,
|
|
487
488
|
metadata=metadata,
|
|
488
489
|
deployment_strategy=deployment_strategy,
|
|
490
|
+
scale=scale,
|
|
489
491
|
):
|
|
490
492
|
for log in partial_result.logs:
|
|
491
493
|
self._log_printer.print(log)
|
|
@@ -221,7 +221,7 @@ def _runners(args):
|
|
|
221
221
|
str(runner.in_flight_requests),
|
|
222
222
|
(
|
|
223
223
|
"N/A (active)"
|
|
224
|
-
if
|
|
224
|
+
if runner.expiration_countdown is None
|
|
225
225
|
else f"{runner.expiration_countdown}s"
|
|
226
226
|
),
|
|
227
227
|
f"{runner.uptime} ({runner.uptime.total_seconds()}s)",
|
|
@@ -106,6 +106,7 @@ def _deploy_from_reference(
|
|
|
106
106
|
application_auth_mode=app_auth,
|
|
107
107
|
metadata=isolated_function.options.host.get("metadata", {}),
|
|
108
108
|
deployment_strategy=deployment_strategy,
|
|
109
|
+
scale=not args.no_scale,
|
|
109
110
|
)
|
|
110
111
|
|
|
111
112
|
if app_id:
|
|
@@ -219,5 +220,14 @@ def add_parser(main_subparsers, parents):
|
|
|
219
220
|
help="Deployment strategy.",
|
|
220
221
|
default="recreate",
|
|
221
222
|
)
|
|
223
|
+
parser.add_argument(
|
|
224
|
+
"--no-scale",
|
|
225
|
+
action="store_true",
|
|
226
|
+
help=(
|
|
227
|
+
"Use min_concurrency/max_concurrency/max_multiplexing from previous "
|
|
228
|
+
"deployment of application with this name, if exists. Otherwise will "
|
|
229
|
+
"use the values from the application code."
|
|
230
|
+
),
|
|
231
|
+
)
|
|
222
232
|
|
|
223
233
|
parser.set_defaults(func=_deploy)
|
|
@@ -5,7 +5,7 @@ from contextlib import ExitStack
|
|
|
5
5
|
from dataclasses import dataclass, field
|
|
6
6
|
from datetime import datetime, timedelta
|
|
7
7
|
from enum import Enum
|
|
8
|
-
from typing import Any, Callable, Generic, Iterator, Literal, TypeVar
|
|
8
|
+
from typing import Any, Callable, Generic, Iterator, Literal, Optional, TypeVar
|
|
9
9
|
|
|
10
10
|
import grpc
|
|
11
11
|
import isolate_proto
|
|
@@ -214,7 +214,7 @@ class AliasInfo:
|
|
|
214
214
|
class RunnerInfo:
|
|
215
215
|
runner_id: str
|
|
216
216
|
in_flight_requests: int
|
|
217
|
-
expiration_countdown: int
|
|
217
|
+
expiration_countdown: Optional[int]
|
|
218
218
|
uptime: timedelta
|
|
219
219
|
|
|
220
220
|
|
|
@@ -344,7 +344,9 @@ def _from_grpc_runner_info(message: isolate_proto.RunnerInfo) -> RunnerInfo:
|
|
|
344
344
|
return RunnerInfo(
|
|
345
345
|
runner_id=message.runner_id,
|
|
346
346
|
in_flight_requests=message.in_flight_requests,
|
|
347
|
-
expiration_countdown=message.expiration_countdown
|
|
347
|
+
expiration_countdown=message.expiration_countdown
|
|
348
|
+
if message.HasField("expiration_countdown")
|
|
349
|
+
else None,
|
|
348
350
|
uptime=timedelta(seconds=message.uptime),
|
|
349
351
|
)
|
|
350
352
|
|
|
@@ -497,6 +499,7 @@ class FalServerlessConnection:
|
|
|
497
499
|
machine_requirements: MachineRequirements | None = None,
|
|
498
500
|
metadata: dict[str, Any] | None = None,
|
|
499
501
|
deployment_strategy: Literal["recreate", "rolling"] = "recreate",
|
|
502
|
+
scale: bool = True,
|
|
500
503
|
) -> Iterator[isolate_proto.RegisterApplicationResult]:
|
|
501
504
|
wrapped_function = to_serialized_object(function, serialization_method)
|
|
502
505
|
if machine_requirements:
|
|
@@ -544,6 +547,7 @@ class FalServerlessConnection:
|
|
|
544
547
|
auth_mode=auth_mode,
|
|
545
548
|
metadata=struct_metadata,
|
|
546
549
|
deployment_strategy=deployment_strategy_proto,
|
|
550
|
+
scale=scale,
|
|
547
551
|
)
|
|
548
552
|
for partial_result in self.stub.RegisterApplication(request):
|
|
549
553
|
yield from_grpc(partial_result)
|
|
@@ -135,6 +135,8 @@ class File(BaseModel):
|
|
|
135
135
|
FileRepository | RepositoryId
|
|
136
136
|
] = FALLBACK_REPOSITORY,
|
|
137
137
|
request: Optional[Request] = None,
|
|
138
|
+
save_kwargs: Optional[dict] = None,
|
|
139
|
+
fallback_save_kwargs: Optional[dict] = None,
|
|
138
140
|
) -> File:
|
|
139
141
|
repo = (
|
|
140
142
|
repository
|
|
@@ -142,12 +144,15 @@ class File(BaseModel):
|
|
|
142
144
|
else get_builtin_repository(repository)
|
|
143
145
|
)
|
|
144
146
|
|
|
147
|
+
save_kwargs = save_kwargs or {}
|
|
148
|
+
fallback_save_kwargs = fallback_save_kwargs or {}
|
|
149
|
+
|
|
145
150
|
fdata = FileData(data, content_type, file_name)
|
|
146
151
|
|
|
147
152
|
object_lifecycle_preference = get_lifecycle_preference(request)
|
|
148
153
|
|
|
149
154
|
try:
|
|
150
|
-
url = repo.save(fdata, object_lifecycle_preference)
|
|
155
|
+
url = repo.save(fdata, object_lifecycle_preference, **save_kwargs)
|
|
151
156
|
except Exception:
|
|
152
157
|
if not fallback_repository:
|
|
153
158
|
raise
|
|
@@ -158,7 +163,9 @@ class File(BaseModel):
|
|
|
158
163
|
else get_builtin_repository(fallback_repository)
|
|
159
164
|
)
|
|
160
165
|
|
|
161
|
-
url = fallback_repo.save(
|
|
166
|
+
url = fallback_repo.save(
|
|
167
|
+
fdata, object_lifecycle_preference, **fallback_save_kwargs
|
|
168
|
+
)
|
|
162
169
|
|
|
163
170
|
return cls(
|
|
164
171
|
url=url,
|
|
@@ -179,6 +186,8 @@ class File(BaseModel):
|
|
|
179
186
|
FileRepository | RepositoryId
|
|
180
187
|
] = FALLBACK_REPOSITORY,
|
|
181
188
|
request: Optional[Request] = None,
|
|
189
|
+
save_kwargs: Optional[dict] = None,
|
|
190
|
+
fallback_save_kwargs: Optional[dict] = None,
|
|
182
191
|
) -> File:
|
|
183
192
|
file_path = Path(path)
|
|
184
193
|
if not file_path.exists():
|
|
@@ -190,6 +199,9 @@ class File(BaseModel):
|
|
|
190
199
|
else get_builtin_repository(repository)
|
|
191
200
|
)
|
|
192
201
|
|
|
202
|
+
save_kwargs = save_kwargs or {}
|
|
203
|
+
fallback_save_kwargs = fallback_save_kwargs or {}
|
|
204
|
+
|
|
193
205
|
content_type = content_type or "application/octet-stream"
|
|
194
206
|
object_lifecycle_preference = get_lifecycle_preference(request)
|
|
195
207
|
|
|
@@ -199,6 +211,7 @@ class File(BaseModel):
|
|
|
199
211
|
content_type=content_type,
|
|
200
212
|
multipart=multipart,
|
|
201
213
|
object_lifecycle_preference=object_lifecycle_preference,
|
|
214
|
+
**save_kwargs,
|
|
202
215
|
)
|
|
203
216
|
except Exception:
|
|
204
217
|
if not fallback_repository:
|
|
@@ -215,6 +228,7 @@ class File(BaseModel):
|
|
|
215
228
|
content_type=content_type,
|
|
216
229
|
multipart=multipart,
|
|
217
230
|
object_lifecycle_preference=object_lifecycle_preference,
|
|
231
|
+
**fallback_save_kwargs,
|
|
218
232
|
)
|
|
219
233
|
|
|
220
234
|
return cls(
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import posixpath
|
|
5
|
+
import uuid
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from io import BytesIO
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from fal.toolkit.file.types import FileData, FileRepository
|
|
11
|
+
from fal.toolkit.utils.retry import retry
|
|
12
|
+
|
|
13
|
+
DEFAULT_URL_TIMEOUT = 60 * 15 # 15 minutes
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class S3Repository(FileRepository):
|
|
18
|
+
bucket_name: str = "fal_file_storage"
|
|
19
|
+
url_expiration: int = DEFAULT_URL_TIMEOUT
|
|
20
|
+
aws_access_key_id: str | None = None
|
|
21
|
+
aws_secret_access_key: str | None = None
|
|
22
|
+
|
|
23
|
+
_s3_client = None
|
|
24
|
+
|
|
25
|
+
def __post_init__(self):
|
|
26
|
+
try:
|
|
27
|
+
import boto3
|
|
28
|
+
from botocore.client import Config
|
|
29
|
+
except ImportError:
|
|
30
|
+
raise Exception("boto3 is not installed")
|
|
31
|
+
|
|
32
|
+
if self.aws_access_key_id is None:
|
|
33
|
+
self.aws_access_key_id = os.environ.get("AWS_ACCESS_KEY_ID")
|
|
34
|
+
if self.aws_access_key_id is None:
|
|
35
|
+
raise Exception("AWS_ACCESS_KEY_ID environment variable is not set")
|
|
36
|
+
|
|
37
|
+
if self.aws_secret_access_key is None:
|
|
38
|
+
self.aws_secret_access_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
|
|
39
|
+
if self.aws_secret_access_key is None:
|
|
40
|
+
raise Exception("AWS_SECRET_ACCESS_KEY environment variable is not set")
|
|
41
|
+
|
|
42
|
+
self._s3_client = boto3.client(
|
|
43
|
+
"s3",
|
|
44
|
+
aws_access_key_id=self.aws_access_key_id,
|
|
45
|
+
aws_secret_access_key=self.aws_secret_access_key,
|
|
46
|
+
config=Config(signature_version="s3v4"),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def storage_client(self):
|
|
51
|
+
if self._s3_client is None:
|
|
52
|
+
raise Exception("S3 client is not initialized")
|
|
53
|
+
|
|
54
|
+
return self._s3_client
|
|
55
|
+
|
|
56
|
+
@retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
|
|
57
|
+
def save(
|
|
58
|
+
self,
|
|
59
|
+
data: FileData,
|
|
60
|
+
object_lifecycle_preference: Optional[dict[str, str]] = None,
|
|
61
|
+
key: Optional[str] = None,
|
|
62
|
+
) -> str:
|
|
63
|
+
destination_path = posixpath.join(
|
|
64
|
+
key or "",
|
|
65
|
+
f"{uuid.uuid4().hex}_{data.file_name}",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
self.storage_client.upload_fileobj(
|
|
69
|
+
BytesIO(data.data),
|
|
70
|
+
self.bucket_name,
|
|
71
|
+
destination_path,
|
|
72
|
+
ExtraArgs={"ContentType": data.content_type},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
public_url = self.storage_client.generate_presigned_url(
|
|
76
|
+
ClientMethod="get_object",
|
|
77
|
+
Params={"Bucket": self.bucket_name, "Key": destination_path},
|
|
78
|
+
ExpiresIn=self.url_expiration,
|
|
79
|
+
)
|
|
80
|
+
return public_url
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import urllib.request
|
|
3
4
|
from functools import lru_cache
|
|
4
5
|
from typing import TYPE_CHECKING
|
|
5
|
-
from urllib.request import Request, urlopen
|
|
6
6
|
|
|
7
7
|
from .image import * # noqa: F403
|
|
8
8
|
|
|
@@ -62,8 +62,8 @@ def read_image_from_url(
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
try:
|
|
65
|
-
request = Request(url, headers=TEMP_HEADERS)
|
|
66
|
-
response = urlopen(request)
|
|
65
|
+
request = urllib.request.Request(url, headers=TEMP_HEADERS)
|
|
66
|
+
response = urllib.request.urlopen(request)
|
|
67
67
|
image_pil = Image.open(response)
|
|
68
68
|
except Exception:
|
|
69
69
|
import traceback
|
|
@@ -516,6 +516,48 @@ def test_404_response(test_app: str, request: pytest.FixtureRequest):
|
|
|
516
516
|
apps.run(test_app, path="/other", arguments={"lhs": 1, "rhs": 2})
|
|
517
517
|
|
|
518
518
|
|
|
519
|
+
def test_app_deploy_scale(aliased_app: tuple[str, str]):
|
|
520
|
+
import uuid
|
|
521
|
+
from dataclasses import replace
|
|
522
|
+
|
|
523
|
+
app_alias = str(uuid.uuid4()) + "-alias"
|
|
524
|
+
app_revision = addition_app.host.register(
|
|
525
|
+
func=addition_app.func,
|
|
526
|
+
options=addition_app.options,
|
|
527
|
+
application_name=app_alias,
|
|
528
|
+
application_auth_mode="private",
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
host: api.FalServerlessHost = addition_app.host # type: ignore
|
|
532
|
+
options = replace(
|
|
533
|
+
addition_app.options, host={**addition_app.options.host, "max_multiplexing": 30}
|
|
534
|
+
)
|
|
535
|
+
kwargs = dict(
|
|
536
|
+
func=addition_app.func,
|
|
537
|
+
options=options,
|
|
538
|
+
application_name=app_alias,
|
|
539
|
+
application_auth_mode="private",
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
app_revision = addition_app.host.register(**kwargs, scale=False)
|
|
543
|
+
|
|
544
|
+
with host._connection as client:
|
|
545
|
+
res = client.list_aliases()
|
|
546
|
+
found = next(filter(lambda alias: alias.alias == app_alias, res), None)
|
|
547
|
+
assert found, f"Could not find app {app_alias} in {res}"
|
|
548
|
+
assert found.revision == app_revision
|
|
549
|
+
assert found.max_multiplexing == 1
|
|
550
|
+
|
|
551
|
+
app_revision = addition_app.host.register(**kwargs, scale=True)
|
|
552
|
+
|
|
553
|
+
with host._connection as client:
|
|
554
|
+
res = client.list_aliases()
|
|
555
|
+
found = next(filter(lambda alias: alias.alias == app_alias, res), None)
|
|
556
|
+
assert found, f"Could not find app {app_alias} in {res}"
|
|
557
|
+
assert found.revision == app_revision
|
|
558
|
+
assert found.max_multiplexing == 30
|
|
559
|
+
|
|
560
|
+
|
|
519
561
|
def test_app_update_app(aliased_app: tuple[str, str]):
|
|
520
562
|
app_revision, app_alias = aliased_app
|
|
521
563
|
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/Makefile
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py
RENAMED
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.5.7 → fal-1.5.9}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|