fal 1.5.18__tar.gz → 1.6.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.
- {fal-1.5.18/fal.egg-info → fal-1.6.1}/PKG-INFO +3 -3
- {fal-1.5.18 → fal-1.6.1/fal.egg-info}/PKG-INFO +3 -3
- {fal-1.5.18 → fal-1.6.1}/fal.egg-info/requires.txt +1 -1
- {fal-1.5.18 → fal-1.6.1}/pyproject.toml +4 -1
- {fal-1.5.18 → fal-1.6.1}/src/fal/_fal_version.py +2 -2
- {fal-1.5.18 → fal-1.6.1}/src/fal/app.py +11 -2
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/_utils.py +2 -1
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/deploy.py +7 -2
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/run.py +1 -1
- {fal-1.5.18 → fal-1.6.1}/src/fal/container.py +1 -1
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/file/file.py +3 -3
- {fal-1.5.18 → fal-1.6.1}/tests/cli/test_deploy.py +54 -0
- {fal-1.5.18 → fal-1.6.1}/tests/cli/test_run.py +1 -0
- {fal-1.5.18 → fal-1.6.1}/tests/conftest.py +7 -0
- {fal-1.5.18 → fal-1.6.1}/tests/integration_test.py +4 -3
- {fal-1.5.18 → fal-1.6.1}/tests/test_apps.py +51 -8
- {fal-1.5.18 → fal-1.6.1}/tests/test_stability.py +9 -4
- {fal-1.5.18 → fal-1.6.1}/tests/toolkit/file_test.py +1 -0
- {fal-1.5.18 → fal-1.6.1}/tests/toolkit/image_test.py +2 -1
- {fal-1.5.18 → fal-1.6.1}/tests/toolkit/utils/retry.py +1 -0
- {fal-1.5.18 → fal-1.6.1}/.gitignore +0 -0
- {fal-1.5.18 → fal-1.6.1}/Makefile +0 -0
- {fal-1.5.18 → fal-1.6.1}/README.md +0 -0
- {fal-1.5.18 → fal-1.6.1}/docs/conf.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/docs/index.rst +0 -0
- {fal-1.5.18 → fal-1.6.1}/fal.egg-info/SOURCES.txt +0 -0
- {fal-1.5.18 → fal-1.6.1}/fal.egg-info/dependency_links.txt +0 -0
- {fal-1.5.18 → fal-1.6.1}/fal.egg-info/entry_points.txt +0 -0
- {fal-1.5.18 → fal-1.6.1}/fal.egg-info/top_level.txt +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/README.md +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/pyproject.toml +0 -0
- {fal-1.5.18 → fal-1.6.1}/openapi_rest.config.yaml +0 -0
- {fal-1.5.18 → fal-1.6.1}/setup.cfg +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/__main__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/_serialization.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/_version.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/api.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/apps.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/auth/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/auth/auth0.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/auth/local.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/apps.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/auth.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/create.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/debug.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/doctor.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/keys.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/main.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/parser.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/runners.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/cli/secrets.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/console/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/console/icons.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/console/ux.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/exceptions/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/exceptions/_base.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/exceptions/_cuda.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/exceptions/auth.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/files.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/flags.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/logging/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/logging/isolate.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/logging/style.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/logging/trace.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/logging/user.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/py.typed +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/rest_client.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/sdk.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/sync.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/exceptions.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/file/providers/fal.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/file/providers/s3.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/file/types.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/image.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/image/safety_checker.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/optimize.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/utils/download_utils.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/toolkit/utils/retry.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/utils.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/src/fal/workflows.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/assets/cat.png +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/cli/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/cli/test_apps.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/cli/test_auth.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/cli/test_keys.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/cli/test_secrets.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/mainify_package/__init__.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/mainify_package/impl.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/mainify_package/utils.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tests/mainify_target.py +0 -0
- {fal-1.5.18 → fal-1.6.1}/tools/demo_script.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.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
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: isolate[build]<0.
|
|
8
|
+
Requires-Dist: isolate[build]<0.16.0,>=0.15.0
|
|
9
9
|
Requires-Dist: isolate-proto<0.7.0,>=0.6.0
|
|
10
10
|
Requires-Dist: grpcio==1.64.0
|
|
11
11
|
Requires-Dist: dill==0.3.7
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.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
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: isolate[build]<0.
|
|
8
|
+
Requires-Dist: isolate[build]<0.16.0,>=0.15.0
|
|
9
9
|
Requires-Dist: isolate-proto<0.7.0,>=0.6.0
|
|
10
10
|
Requires-Dist: grpcio==1.64.0
|
|
11
11
|
Requires-Dist: dill==0.3.7
|
|
@@ -22,7 +22,7 @@ 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.
|
|
25
|
+
"isolate[build]>=0.15.0,<0.16.0",
|
|
26
26
|
"isolate-proto>=0.6.0,<0.7.0",
|
|
27
27
|
"grpcio==1.64.0",
|
|
28
28
|
"dill==0.3.7",
|
|
@@ -87,5 +87,8 @@ target-version = "py38"
|
|
|
87
87
|
[tool.ruff.lint]
|
|
88
88
|
select = ["E", "F", "W", "PLC", "PLE", "PLW", "I", "UP"]
|
|
89
89
|
|
|
90
|
+
[tool.ruff.lint.isort]
|
|
91
|
+
known-first-party = ["fal"]
|
|
92
|
+
|
|
90
93
|
[tool.ruff.lint.pyupgrade]
|
|
91
94
|
keep-runtime-typing = true
|
|
@@ -23,7 +23,7 @@ from fal._serialization import include_modules_from
|
|
|
23
23
|
from fal.api import RouteSignature
|
|
24
24
|
from fal.exceptions import FalServerlessException, RequestCancelledException
|
|
25
25
|
from fal.logging import get_logger
|
|
26
|
-
from fal.toolkit.file import
|
|
26
|
+
from fal.toolkit.file import request_lifecycle_preference
|
|
27
27
|
from fal.toolkit.file.providers.fal import LIFECYCLE_PREFERENCE
|
|
28
28
|
|
|
29
29
|
REALTIME_APP_REQUIREMENTS = ["websockets", "msgpack"]
|
|
@@ -248,6 +248,14 @@ def _to_fal_app_name(name: str) -> str:
|
|
|
248
248
|
return "-".join(part.lower() for part in PART_FINDER_RE.findall(name))
|
|
249
249
|
|
|
250
250
|
|
|
251
|
+
def _print_python_packages() -> None:
|
|
252
|
+
from pkg_resources import working_set
|
|
253
|
+
|
|
254
|
+
packages = [f"{package.key}=={package.version}" for package in working_set]
|
|
255
|
+
|
|
256
|
+
print("[debug] Python packages installed:", ", ".join(packages))
|
|
257
|
+
|
|
258
|
+
|
|
251
259
|
class App(fal.api.BaseServable):
|
|
252
260
|
requirements: ClassVar[list[str]] = []
|
|
253
261
|
machine_type: ClassVar[str] = "S"
|
|
@@ -305,6 +313,7 @@ class App(fal.api.BaseServable):
|
|
|
305
313
|
|
|
306
314
|
@asynccontextmanager
|
|
307
315
|
async def lifespan(self, app: fastapi.FastAPI):
|
|
316
|
+
_print_python_packages()
|
|
308
317
|
await _call_any_fn(self.setup)
|
|
309
318
|
try:
|
|
310
319
|
yield
|
|
@@ -342,7 +351,7 @@ class App(fal.api.BaseServable):
|
|
|
342
351
|
@app.middleware("http")
|
|
343
352
|
async def set_global_object_preference(request, call_next):
|
|
344
353
|
try:
|
|
345
|
-
preference_dict =
|
|
354
|
+
preference_dict = request_lifecycle_preference(request)
|
|
346
355
|
if preference_dict is not None:
|
|
347
356
|
# This will not work properly for apps with multiplexing enabled
|
|
348
357
|
# we may mix up the preferences between requests
|
|
@@ -35,5 +35,6 @@ def get_app_data_from_toml(app_name):
|
|
|
35
35
|
|
|
36
36
|
app_auth = app_data.get("auth", "private")
|
|
37
37
|
app_deployment_strategy = app_data.get("deployment_strategy", "recreate")
|
|
38
|
+
app_no_scale = app_data.get("no_scale", False)
|
|
38
39
|
|
|
39
|
-
return app_ref, app_auth, app_deployment_strategy
|
|
40
|
+
return app_ref, app_auth, app_deployment_strategy, app_no_scale
|
|
@@ -68,6 +68,7 @@ def _deploy_from_reference(
|
|
|
68
68
|
args,
|
|
69
69
|
auth: Optional[Literal["public", "shared", "private"]] = None,
|
|
70
70
|
deployment_strategy: Optional[Literal["recreate", "rolling"]] = None,
|
|
71
|
+
no_scale: bool = False,
|
|
71
72
|
):
|
|
72
73
|
from fal.api import FalServerlessError, FalServerlessHost
|
|
73
74
|
from fal.utils import load_function_from
|
|
@@ -106,7 +107,7 @@ def _deploy_from_reference(
|
|
|
106
107
|
application_auth_mode=app_auth,
|
|
107
108
|
metadata=isolated_function.options.host.get("metadata", {}),
|
|
108
109
|
deployment_strategy=deployment_strategy,
|
|
109
|
-
scale=not
|
|
110
|
+
scale=not no_scale,
|
|
110
111
|
)
|
|
111
112
|
|
|
112
113
|
if app_id:
|
|
@@ -139,7 +140,9 @@ def _deploy(args):
|
|
|
139
140
|
raise ValueError("Cannot use --app-name or --auth with app name reference.")
|
|
140
141
|
|
|
141
142
|
app_name = args.app_ref[0]
|
|
142
|
-
app_ref, app_auth, app_deployment_strategy =
|
|
143
|
+
app_ref, app_auth, app_deployment_strategy, app_no_scale = (
|
|
144
|
+
get_app_data_from_toml(app_name)
|
|
145
|
+
)
|
|
143
146
|
file_path, func_name = RefAction.split_ref(app_ref)
|
|
144
147
|
|
|
145
148
|
# path/to/myfile.py::MyApp
|
|
@@ -148,6 +151,7 @@ def _deploy(args):
|
|
|
148
151
|
app_name = args.app_name
|
|
149
152
|
app_auth = args.auth
|
|
150
153
|
app_deployment_strategy = args.strategy
|
|
154
|
+
app_no_scale = args.no_scale
|
|
151
155
|
|
|
152
156
|
_deploy_from_reference(
|
|
153
157
|
(file_path, func_name),
|
|
@@ -155,6 +159,7 @@ def _deploy(args):
|
|
|
155
159
|
args,
|
|
156
160
|
app_auth,
|
|
157
161
|
app_deployment_strategy,
|
|
162
|
+
app_no_scale,
|
|
158
163
|
)
|
|
159
164
|
|
|
160
165
|
|
|
@@ -10,7 +10,7 @@ def _run(args):
|
|
|
10
10
|
|
|
11
11
|
if is_app_name(args.func_ref):
|
|
12
12
|
app_name = args.func_ref[0]
|
|
13
|
-
app_ref, _
|
|
13
|
+
app_ref, *_ = get_app_data_from_toml(app_name)
|
|
14
14
|
file_path, func_name = RefAction.split_ref(app_ref)
|
|
15
15
|
else:
|
|
16
16
|
file_path, func_name = args.func_ref
|
|
@@ -151,7 +151,7 @@ class File(BaseModel):
|
|
|
151
151
|
fdata = FileData(data, content_type, file_name)
|
|
152
152
|
|
|
153
153
|
object_lifecycle_preference = (
|
|
154
|
-
|
|
154
|
+
request_lifecycle_preference(request) or LIFECYCLE_PREFERENCE.get()
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
try:
|
|
@@ -207,7 +207,7 @@ class File(BaseModel):
|
|
|
207
207
|
|
|
208
208
|
content_type = content_type or "application/octet-stream"
|
|
209
209
|
object_lifecycle_preference = (
|
|
210
|
-
|
|
210
|
+
request_lifecycle_preference(request) or LIFECYCLE_PREFERENCE.get()
|
|
211
211
|
)
|
|
212
212
|
|
|
213
213
|
try:
|
|
@@ -293,7 +293,7 @@ class CompressedFile(File):
|
|
|
293
293
|
shutil.rmtree(self.extract_dir)
|
|
294
294
|
|
|
295
295
|
|
|
296
|
-
def
|
|
296
|
+
def request_lifecycle_preference(request: Optional[Request]) -> dict[str, str] | None:
|
|
297
297
|
import json
|
|
298
298
|
|
|
299
299
|
if request is None:
|
|
@@ -2,6 +2,7 @@ from typing import Optional, Tuple
|
|
|
2
2
|
from unittest.mock import MagicMock, patch
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
|
+
|
|
5
6
|
from fal.cli.deploy import _deploy
|
|
6
7
|
from fal.cli.main import parse_args
|
|
7
8
|
from fal.files import find_project_root
|
|
@@ -34,6 +35,7 @@ def mock_args(
|
|
|
34
35
|
app_name: Optional[str] = None,
|
|
35
36
|
auth: Optional[str] = None,
|
|
36
37
|
strategy: Optional[str] = None,
|
|
38
|
+
no_scale: bool = False,
|
|
37
39
|
):
|
|
38
40
|
args = MagicMock()
|
|
39
41
|
|
|
@@ -42,6 +44,8 @@ def mock_args(
|
|
|
42
44
|
args.auth = auth
|
|
43
45
|
args.strategy = strategy
|
|
44
46
|
|
|
47
|
+
args.no_scale = no_scale
|
|
48
|
+
|
|
45
49
|
return args
|
|
46
50
|
|
|
47
51
|
|
|
@@ -67,6 +71,7 @@ def test_deploy_with_toml_success(
|
|
|
67
71
|
args,
|
|
68
72
|
"shared",
|
|
69
73
|
"rolling",
|
|
74
|
+
False,
|
|
70
75
|
)
|
|
71
76
|
|
|
72
77
|
|
|
@@ -92,6 +97,7 @@ def test_deploy_with_toml_no_auth(
|
|
|
92
97
|
args,
|
|
93
98
|
"private",
|
|
94
99
|
"recreate",
|
|
100
|
+
False,
|
|
95
101
|
)
|
|
96
102
|
|
|
97
103
|
|
|
@@ -185,6 +191,7 @@ def test_deploy_with_toml_deployment_strategy(
|
|
|
185
191
|
args,
|
|
186
192
|
"shared",
|
|
187
193
|
"rolling",
|
|
194
|
+
False,
|
|
188
195
|
)
|
|
189
196
|
|
|
190
197
|
|
|
@@ -208,6 +215,7 @@ def test_deploy_with_toml_default_deployment_strategy(
|
|
|
208
215
|
args,
|
|
209
216
|
"private",
|
|
210
217
|
"recreate",
|
|
218
|
+
False,
|
|
211
219
|
)
|
|
212
220
|
|
|
213
221
|
|
|
@@ -229,6 +237,7 @@ def test_deploy_with_cli_auth(
|
|
|
229
237
|
args,
|
|
230
238
|
"shared",
|
|
231
239
|
None,
|
|
240
|
+
False,
|
|
232
241
|
)
|
|
233
242
|
|
|
234
243
|
|
|
@@ -250,4 +259,49 @@ def test_deploy_with_cli_deployment_strategy(
|
|
|
250
259
|
args,
|
|
251
260
|
None,
|
|
252
261
|
"rolling",
|
|
262
|
+
False,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@patch("fal.cli._utils.find_pyproject_toml", return_value="pyproject.toml")
|
|
267
|
+
@patch("fal.cli._utils.parse_pyproject_toml")
|
|
268
|
+
@patch("fal.cli.deploy._deploy_from_reference")
|
|
269
|
+
def test_deploy_with_cli_no_scale(
|
|
270
|
+
mock_deploy_ref, mock_parse_toml, mock_find_toml, mock_parse_pyproject_toml
|
|
271
|
+
):
|
|
272
|
+
mock_parse_toml.return_value = mock_parse_pyproject_toml
|
|
273
|
+
|
|
274
|
+
args = mock_args(app_ref=("src/my_app/inference.py", "MyApp"), no_scale=True)
|
|
275
|
+
|
|
276
|
+
_deploy(args)
|
|
277
|
+
|
|
278
|
+
mock_deploy_ref.assert_called_once_with(
|
|
279
|
+
("src/my_app/inference.py", "MyApp"),
|
|
280
|
+
None,
|
|
281
|
+
args,
|
|
282
|
+
None,
|
|
283
|
+
None,
|
|
284
|
+
True,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
@patch("fal.cli._utils.find_pyproject_toml", return_value="pyproject.toml")
|
|
289
|
+
@patch("fal.cli._utils.parse_pyproject_toml")
|
|
290
|
+
@patch("fal.cli.deploy._deploy_from_reference")
|
|
291
|
+
def test_deploy_with_cli_scale(
|
|
292
|
+
mock_deploy_ref, mock_parse_toml, mock_find_toml, mock_parse_pyproject_toml
|
|
293
|
+
):
|
|
294
|
+
mock_parse_toml.return_value = mock_parse_pyproject_toml
|
|
295
|
+
|
|
296
|
+
args = mock_args(app_ref=("src/my_app/inference.py", "MyApp"))
|
|
297
|
+
|
|
298
|
+
_deploy(args)
|
|
299
|
+
|
|
300
|
+
mock_deploy_ref.assert_called_once_with(
|
|
301
|
+
("src/my_app/inference.py", "MyApp"),
|
|
302
|
+
None,
|
|
303
|
+
args,
|
|
304
|
+
None,
|
|
305
|
+
None,
|
|
306
|
+
False,
|
|
253
307
|
)
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import sys
|
|
3
4
|
from functools import partial
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
7
|
+
|
|
6
8
|
from fal import function
|
|
9
|
+
from fal.flags import GRPC_HOST
|
|
10
|
+
from fal.sdk import get_default_credentials
|
|
11
|
+
|
|
12
|
+
print("TARGET:", GRPC_HOST, file=sys.stderr)
|
|
13
|
+
print("AUTH:", get_default_credentials(), file=sys.stderr)
|
|
7
14
|
|
|
8
15
|
|
|
9
16
|
@pytest.fixture(scope="function")
|
|
@@ -6,8 +6,11 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Callable
|
|
7
7
|
from uuid import uuid4
|
|
8
8
|
|
|
9
|
-
import fal
|
|
10
9
|
import pytest
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
from pydantic import __version__ as pydantic_version
|
|
12
|
+
|
|
13
|
+
import fal
|
|
11
14
|
from fal import FalServerlessHost, FalServerlessKeyCredentials, local, sync_dir
|
|
12
15
|
from fal.api import FalServerlessError, IsolatedFunction
|
|
13
16
|
from fal.toolkit import (
|
|
@@ -21,8 +24,6 @@ from fal.toolkit import (
|
|
|
21
24
|
)
|
|
22
25
|
from fal.toolkit.file.file import CompressedFile
|
|
23
26
|
from fal.toolkit.utils.download_utils import _get_git_revision_hash, _hash_url
|
|
24
|
-
from pydantic import BaseModel, Field
|
|
25
|
-
from pydantic import __version__ as pydantic_version
|
|
26
27
|
|
|
27
28
|
EXAMPLE_FILE_URL = "https://raw.githubusercontent.com/fal-ai/fal/main/projects/fal/tests/assets/cat.png"
|
|
28
29
|
|
|
@@ -7,10 +7,17 @@ from contextlib import contextmanager, suppress
|
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from typing import Generator, List, Tuple
|
|
9
9
|
|
|
10
|
-
import fal
|
|
11
|
-
import fal.api as api
|
|
12
10
|
import httpx
|
|
13
11
|
import pytest
|
|
12
|
+
from fastapi import WebSocket
|
|
13
|
+
from httpx import HTTPStatusError
|
|
14
|
+
from isolate.backends.common import active_python
|
|
15
|
+
from openapi_fal_rest.api.applications import app_metadata
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
from pydantic import __version__ as pydantic_version
|
|
18
|
+
|
|
19
|
+
import fal
|
|
20
|
+
import fal.api as api
|
|
14
21
|
from fal import apps
|
|
15
22
|
from fal.app import AppClient, AppClientError
|
|
16
23
|
from fal.cli.deploy import _get_user
|
|
@@ -19,12 +26,6 @@ from fal.exceptions import AppException, FieldException, RequestCancelledExcepti
|
|
|
19
26
|
from fal.exceptions._cuda import _CUDA_OOM_MESSAGE, _CUDA_OOM_STATUS_CODE
|
|
20
27
|
from fal.rest_client import REST_CLIENT
|
|
21
28
|
from fal.workflows import Workflow
|
|
22
|
-
from fastapi import WebSocket
|
|
23
|
-
from httpx import HTTPStatusError
|
|
24
|
-
from isolate.backends.common import active_python
|
|
25
|
-
from openapi_fal_rest.api.applications import app_metadata
|
|
26
|
-
from pydantic import BaseModel
|
|
27
|
-
from pydantic import __version__ as pydantic_version
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class Input(BaseModel):
|
|
@@ -90,6 +91,26 @@ def container_addition_app(input: Input) -> Output:
|
|
|
90
91
|
return Output(result=input.lhs + input.rhs)
|
|
91
92
|
|
|
92
93
|
|
|
94
|
+
@fal.function(
|
|
95
|
+
kind="container",
|
|
96
|
+
image=ContainerImage.from_dockerfile_str(
|
|
97
|
+
f"""FROM python:{actual_python}-slim\n# {git_revision_short_hash()}
|
|
98
|
+
ARG OUTPUT="built incorrectly"
|
|
99
|
+
ENV OUTPUT="$OUTPUT"
|
|
100
|
+
""",
|
|
101
|
+
build_args={"OUTPUT": "built with build args"},
|
|
102
|
+
),
|
|
103
|
+
keep_alive=60,
|
|
104
|
+
machine_type="S",
|
|
105
|
+
serve=True,
|
|
106
|
+
max_concurrency=1,
|
|
107
|
+
)
|
|
108
|
+
def container_build_args_app() -> str:
|
|
109
|
+
import os
|
|
110
|
+
|
|
111
|
+
return os.environ["OUTPUT"]
|
|
112
|
+
|
|
113
|
+
|
|
93
114
|
@fal.function(
|
|
94
115
|
keep_alive=300,
|
|
95
116
|
requirements=["fastapi", "uvicorn", "pydantic==1.10.18"],
|
|
@@ -321,6 +342,18 @@ def test_container_app():
|
|
|
321
342
|
yield f"{user.user_id}/{app_revision}"
|
|
322
343
|
|
|
323
344
|
|
|
345
|
+
@pytest.fixture(scope="module")
|
|
346
|
+
def test_container_build_args_app():
|
|
347
|
+
# Create a temporary app, register it, and return the ID of it.
|
|
348
|
+
|
|
349
|
+
app_revision = container_build_args_app.host.register(
|
|
350
|
+
func=container_build_args_app.func,
|
|
351
|
+
options=container_build_args_app.options,
|
|
352
|
+
)
|
|
353
|
+
user = _get_user()
|
|
354
|
+
yield f"{user.user_id}/{app_revision}"
|
|
355
|
+
|
|
356
|
+
|
|
324
357
|
@pytest.fixture(scope="module")
|
|
325
358
|
def test_fastapi_app():
|
|
326
359
|
# Create a temporary app, register it, and return the ID of it.
|
|
@@ -843,3 +876,13 @@ def test_kill_runner():
|
|
|
843
876
|
assert len(runners) == 1
|
|
844
877
|
|
|
845
878
|
client.kill_runner(runners[0].runner_id)
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
def test_container_app_client(test_container_app: str):
|
|
882
|
+
response = apps.run(test_container_app, arguments={"lhs": 1, "rhs": 2})
|
|
883
|
+
assert response["result"] == 3
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def test_container_build_args_app_client(test_container_build_args_app: str):
|
|
887
|
+
response = apps.run(test_container_build_args_app, {})
|
|
888
|
+
assert response == "built with build args"
|
|
@@ -3,13 +3,14 @@ from __future__ import annotations
|
|
|
3
3
|
import subprocess
|
|
4
4
|
from contextlib import suppress
|
|
5
5
|
|
|
6
|
-
import fal
|
|
7
6
|
import pytest
|
|
7
|
+
from isolate.backends.common import active_python
|
|
8
|
+
from pydantic import __version__ as pydantic_version
|
|
9
|
+
|
|
10
|
+
import fal
|
|
8
11
|
from fal.api import FalServerlessError, Options
|
|
9
12
|
from fal.container import ContainerImage
|
|
10
13
|
from fal.toolkit.file import File
|
|
11
|
-
from isolate.backends.common import active_python
|
|
12
|
-
from pydantic import __version__ as pydantic_version
|
|
13
14
|
|
|
14
15
|
PACKAGE_NAME = "fall"
|
|
15
16
|
|
|
@@ -87,7 +88,11 @@ def test_regular_function_in_a_container_with_custom_image(isolated_client):
|
|
|
87
88
|
@isolated_client(
|
|
88
89
|
"container",
|
|
89
90
|
image=ContainerImage.from_dockerfile_str(
|
|
90
|
-
f"
|
|
91
|
+
f"""
|
|
92
|
+
FROM python:{actual_python}-slim
|
|
93
|
+
# {git_revision_short_hash()}
|
|
94
|
+
RUN env
|
|
95
|
+
"""
|
|
91
96
|
),
|
|
92
97
|
)
|
|
93
98
|
def regular_function():
|
|
@@ -5,11 +5,12 @@ from io import BytesIO
|
|
|
5
5
|
from typing import Literal, overload
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
|
-
from fal.toolkit import Image
|
|
9
8
|
from PIL import Image as PILImage
|
|
10
9
|
from pydantic import BaseModel, Field
|
|
11
10
|
from pydantic import __version__ as pydantic_version
|
|
12
11
|
|
|
12
|
+
from fal.toolkit import Image
|
|
13
|
+
|
|
13
14
|
|
|
14
15
|
@overload
|
|
15
16
|
def get_image(as_bytes: Literal[False] = False) -> PILImage.Image: ...
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.18 → fal-1.6.1}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.5.18 → fal-1.6.1}/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.18 → fal-1.6.1}/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.18 → fal-1.6.1}/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.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py
RENAMED
|
File without changes
|
{fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py
RENAMED
|
File without changes
|
{fal-1.5.18 → fal-1.6.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.5.18 → fal-1.6.1}/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
|