fal 1.13.5__tar.gz → 1.14.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.
- {fal-1.13.5/fal.egg-info → fal-1.14.0}/PKG-INFO +2 -2
- {fal-1.13.5 → fal-1.14.0/fal.egg-info}/PKG-INFO +2 -2
- {fal-1.13.5 → fal-1.14.0}/fal.egg-info/SOURCES.txt +1 -0
- {fal-1.13.5 → fal-1.14.0}/fal.egg-info/requires.txt +1 -1
- {fal-1.13.5 → fal-1.14.0}/pyproject.toml +1 -1
- {fal-1.13.5 → fal-1.14.0}/src/fal/_fal_version.py +2 -2
- {fal-1.13.5 → fal-1.14.0}/src/fal/auth/__init__.py +20 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/_utils.py +1 -1
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/apps.py +6 -1
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/auth.py +30 -24
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/profile.py +7 -4
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/teams.py +2 -9
- {fal-1.13.5 → fal-1.14.0}/src/fal/config.py +17 -4
- {fal-1.13.5 → fal-1.14.0}/src/fal/container.py +3 -4
- fal-1.14.0/src/fal/project.py +81 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/sdk.py +16 -4
- {fal-1.13.5 → fal-1.14.0}/tests/test_apps.py +22 -28
- {fal-1.13.5 → fal-1.14.0}/.gitignore +0 -0
- {fal-1.13.5 → fal-1.14.0}/Makefile +0 -0
- {fal-1.13.5 → fal-1.14.0}/README.md +0 -0
- {fal-1.13.5 → fal-1.14.0}/docs/conf.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/docs/index.rst +0 -0
- {fal-1.13.5 → fal-1.14.0}/fal.egg-info/dependency_links.txt +0 -0
- {fal-1.13.5 → fal-1.14.0}/fal.egg-info/entry_points.txt +0 -0
- {fal-1.13.5 → fal-1.14.0}/fal.egg-info/top_level.txt +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/README.md +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/pyproject.toml +0 -0
- {fal-1.13.5 → fal-1.14.0}/openapi_rest.config.yaml +0 -0
- {fal-1.13.5 → fal-1.14.0}/setup.cfg +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/__main__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/_serialization.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/_version.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/api.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/app.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/apps.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/auth/auth0.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/auth/local.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/api.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/cli_nested_json.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/create.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/debug.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/deploy.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/doctor.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/keys.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/main.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/parser.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/run.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/runners.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/cli/secrets.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/console/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/console/icons.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/console/ux.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/exceptions/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/exceptions/_base.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/exceptions/_cuda.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/exceptions/auth.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/files.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/flags.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/logging/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/logging/isolate.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/logging/style.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/logging/trace.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/logging/user.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/py.typed +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/rest_client.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/sync.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/exceptions.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/file/file.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/file/providers/fal.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/file/providers/s3.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/file/types.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/image.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/image/safety_checker.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/optimize.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/types.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/utils/download_utils.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/toolkit/utils/retry.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/utils.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/src/fal/workflows.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/assets/cat.png +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/cli/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/cli/test_apps.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/cli/test_auth.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/cli/test_deploy.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/cli/test_keys.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/cli/test_run.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/cli/test_secrets.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/conftest.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/integration_test.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/mainify_package/__init__.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/mainify_package/impl.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/mainify_package/utils.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/mainify_target.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/test_stability.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/toolkit/file_test.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/toolkit/image_test.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/toolkit/test_types.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tests/toolkit/utils/retry.py +0 -0
- {fal-1.13.5 → fal-1.14.0}/tools/demo_script.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.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.17.0,>=0.16.2
|
|
9
|
-
Requires-Dist: isolate-proto<0.
|
|
9
|
+
Requires-Dist: isolate-proto<0.9.0,>=0.8.1
|
|
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.4
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.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.17.0,>=0.16.2
|
|
9
|
-
Requires-Dist: isolate-proto<0.
|
|
9
|
+
Requires-Dist: isolate-proto<0.9.0,>=0.8.1
|
|
10
10
|
Requires-Dist: grpcio==1.64.0
|
|
11
11
|
Requires-Dist: dill==0.3.7
|
|
12
12
|
Requires-Dist: cloudpickle==3.0.0
|
|
@@ -125,6 +125,26 @@ def _fetch_teams(bearer_token: str) -> list[dict]:
|
|
|
125
125
|
raise FalServerlessException("Failed to fetch teams") from exc
|
|
126
126
|
|
|
127
127
|
|
|
128
|
+
def current_user_info(headers: dict[str, str]) -> dict:
|
|
129
|
+
import json
|
|
130
|
+
from urllib.error import HTTPError
|
|
131
|
+
from urllib.request import Request, urlopen
|
|
132
|
+
|
|
133
|
+
from fal.exceptions import FalServerlessException
|
|
134
|
+
from fal.flags import REST_URL
|
|
135
|
+
|
|
136
|
+
request = Request(
|
|
137
|
+
method="GET",
|
|
138
|
+
url=f"{REST_URL}/users/current",
|
|
139
|
+
headers=headers,
|
|
140
|
+
)
|
|
141
|
+
try:
|
|
142
|
+
with urlopen(request) as response:
|
|
143
|
+
return json.load(response)
|
|
144
|
+
except HTTPError as exc:
|
|
145
|
+
raise FalServerlessException("Failed to fetch user info") from exc
|
|
146
|
+
|
|
147
|
+
|
|
128
148
|
def login(console):
|
|
129
149
|
token_data = auth0.login(console)
|
|
130
150
|
with local.lock_token():
|
|
@@ -123,7 +123,7 @@ def _app_rev_table(revs: list[ApplicationInfo]):
|
|
|
123
123
|
def _list_rev(args):
|
|
124
124
|
client = get_client(args.host, args.team)
|
|
125
125
|
with client.connect() as connection:
|
|
126
|
-
revs = connection.list_applications()
|
|
126
|
+
revs = connection.list_applications(args.app_name)
|
|
127
127
|
table = _app_rev_table(revs)
|
|
128
128
|
|
|
129
129
|
args.console.print(table)
|
|
@@ -137,6 +137,11 @@ def _add_list_rev_parser(subparsers, parents):
|
|
|
137
137
|
help=list_help,
|
|
138
138
|
parents=parents,
|
|
139
139
|
)
|
|
140
|
+
parser.add_argument(
|
|
141
|
+
"app_name",
|
|
142
|
+
nargs="?",
|
|
143
|
+
help="Application name.",
|
|
144
|
+
)
|
|
140
145
|
parser.set_defaults(func=_list_rev)
|
|
141
146
|
|
|
142
147
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
from fal.auth import current_user_info
|
|
2
|
+
from fal.cli import profile
|
|
3
|
+
from fal.sdk import get_default_credentials
|
|
4
|
+
|
|
5
|
+
|
|
1
6
|
def _login(args):
|
|
2
7
|
from fal.auth import login
|
|
3
|
-
from fal.config import Config
|
|
4
8
|
from fal.console.icons import CHECK_ICON, CROSS_ICON
|
|
5
9
|
from fal.exceptions import FalServerlessException
|
|
6
10
|
|
|
@@ -11,15 +15,12 @@ def _login(args):
|
|
|
11
15
|
args.console.print(f"{CROSS_ICON} {e}")
|
|
12
16
|
return
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
config.unset("team")
|
|
16
|
-
|
|
18
|
+
_unset_account(args)
|
|
17
19
|
_set_account(args)
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
def _logout(args):
|
|
21
23
|
from fal.auth import logout
|
|
22
|
-
from fal.config import Config
|
|
23
24
|
from fal.console.icons import CHECK_ICON, CROSS_ICON
|
|
24
25
|
from fal.exceptions import FalServerlessException
|
|
25
26
|
|
|
@@ -30,8 +31,7 @@ def _logout(args):
|
|
|
30
31
|
args.console.print(f"{CROSS_ICON} {e}")
|
|
31
32
|
return
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
config.unset("team")
|
|
34
|
+
_unset_account(args)
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def _list_accounts(args):
|
|
@@ -43,7 +43,7 @@ def _list_accounts(args):
|
|
|
43
43
|
|
|
44
44
|
user_access = UserAccess()
|
|
45
45
|
config = Config()
|
|
46
|
-
|
|
46
|
+
current_account_name = config.get_internal("team") or user_access.info["nickname"]
|
|
47
47
|
|
|
48
48
|
table = Table(border_style=Style(frame=False), show_header=False)
|
|
49
49
|
table.add_column("#")
|
|
@@ -51,7 +51,7 @@ def _list_accounts(args):
|
|
|
51
51
|
table.add_column("Type")
|
|
52
52
|
|
|
53
53
|
for idx, account in enumerate(user_access.accounts):
|
|
54
|
-
selected = account["nickname"] ==
|
|
54
|
+
selected = account["nickname"] == current_account_name
|
|
55
55
|
color = "bold yellow" if selected else None
|
|
56
56
|
|
|
57
57
|
table.add_row(
|
|
@@ -64,6 +64,13 @@ def _list_accounts(args):
|
|
|
64
64
|
args.console.print(table)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
def _unset_account(args):
|
|
68
|
+
from fal.config import Config
|
|
69
|
+
|
|
70
|
+
with Config().edit() as config:
|
|
71
|
+
config.unset_internal("team")
|
|
72
|
+
|
|
73
|
+
|
|
67
74
|
def _set_account(args):
|
|
68
75
|
from rich.prompt import Prompt
|
|
69
76
|
|
|
@@ -105,25 +112,24 @@ def _set_account(args):
|
|
|
105
112
|
)
|
|
106
113
|
|
|
107
114
|
with Config().edit() as config:
|
|
108
|
-
config.
|
|
109
|
-
|
|
115
|
+
config.set_internal("team", account["nickname"])
|
|
110
116
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
# Unset the profile if set
|
|
118
|
+
if current_profile := config.get_internal("profile"):
|
|
119
|
+
args.console.print(
|
|
120
|
+
f"\n[yellow]Unsetting profile [cyan]{current_profile}[/] "
|
|
121
|
+
"to make team selection effective.[/]"
|
|
122
|
+
)
|
|
123
|
+
profile._unset(args, config=config)
|
|
114
124
|
|
|
115
|
-
user_access = UserAccess()
|
|
116
|
-
config = Config()
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
else:
|
|
122
|
-
account = user_access.get_account(user_access.info["nickname"])
|
|
126
|
+
def _whoami(args):
|
|
127
|
+
creds = get_default_credentials()
|
|
128
|
+
user_info = current_user_info(creds.to_headers())
|
|
123
129
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
user_id =
|
|
130
|
+
full_name = user_info["full_name"]
|
|
131
|
+
nickname = user_info["nickname"]
|
|
132
|
+
user_id = user_info["user_id"]
|
|
127
133
|
|
|
128
134
|
args.console.print(f"Hello, {full_name}: {nickname!r} - {user_id!r}")
|
|
129
135
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from rich.table import Table
|
|
2
4
|
|
|
3
5
|
from fal.config import Config
|
|
@@ -31,11 +33,12 @@ def _set(args):
|
|
|
31
33
|
)
|
|
32
34
|
|
|
33
35
|
|
|
34
|
-
def _unset(args):
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
def _unset(args, config: Config | None = None):
|
|
37
|
+
config = config or Config()
|
|
38
|
+
|
|
39
|
+
with config.edit() as config:
|
|
38
40
|
config.profile = None
|
|
41
|
+
args.console.print("Default profile unset.")
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
def _key_set(args):
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
from fal.cli.auth import _list_accounts, _set_account
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def _unset(args):
|
|
5
|
-
from fal.config import Config
|
|
6
|
-
|
|
7
|
-
with Config().edit() as config:
|
|
8
|
-
config.unset("team")
|
|
1
|
+
from fal.cli.auth import _list_accounts, _set_account, _unset_account
|
|
9
2
|
|
|
10
3
|
|
|
11
4
|
def add_parser(main_subparsers, parents):
|
|
@@ -51,4 +44,4 @@ def add_parser(main_subparsers, parents):
|
|
|
51
44
|
help=unset_help,
|
|
52
45
|
parents=parents,
|
|
53
46
|
)
|
|
54
|
-
unset_parser.set_defaults(func=
|
|
47
|
+
unset_parser.set_defaults(func=_unset_account)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import os
|
|
2
4
|
from contextlib import contextmanager
|
|
3
|
-
from typing import Dict, List, Optional
|
|
5
|
+
from typing import Dict, Iterator, List, Optional
|
|
4
6
|
|
|
5
7
|
SETTINGS_SECTION = "__internal__" # legacy
|
|
6
8
|
DEFAULT_PROFILE = "default"
|
|
@@ -9,6 +11,7 @@ DEFAULT_PROFILE = "default"
|
|
|
9
11
|
class Config:
|
|
10
12
|
_config: Dict[str, Dict[str, str]]
|
|
11
13
|
_profile: Optional[str]
|
|
14
|
+
_editing: bool = False
|
|
12
15
|
|
|
13
16
|
DEFAULT_CONFIG_PATH = "~/.fal/config.toml"
|
|
14
17
|
|
|
@@ -38,7 +41,11 @@ class Config:
|
|
|
38
41
|
@profile.setter
|
|
39
42
|
def profile(self, value: Optional[str]) -> None:
|
|
40
43
|
if value and value not in self._config:
|
|
44
|
+
# Make sure the section exists
|
|
41
45
|
self._config[value] = {}
|
|
46
|
+
self.set_internal("profile", value)
|
|
47
|
+
elif not value:
|
|
48
|
+
self.unset_internal("profile")
|
|
42
49
|
|
|
43
50
|
self._profile = value
|
|
44
51
|
|
|
@@ -96,6 +103,12 @@ class Config:
|
|
|
96
103
|
del self._config[profile]
|
|
97
104
|
|
|
98
105
|
@contextmanager
|
|
99
|
-
def edit(self):
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
def edit(self) -> Iterator[Config]:
|
|
107
|
+
if self._editing:
|
|
108
|
+
# no-op
|
|
109
|
+
yield self
|
|
110
|
+
else:
|
|
111
|
+
self._editing = True
|
|
112
|
+
yield self
|
|
113
|
+
self.save()
|
|
114
|
+
self._editing = False
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
-
from typing import Dict, Literal
|
|
2
|
+
from typing import Dict, Literal, Optional
|
|
3
3
|
|
|
4
4
|
Builder = Literal["depot", "service", "worker"]
|
|
5
5
|
BUILDERS = {"depot", "service", "worker"}
|
|
6
|
-
DEFAULT_BUILDER: Builder = "depot"
|
|
7
6
|
DEFAULT_COMPRESSION: str = "gzip"
|
|
8
7
|
DEFAULT_FORCE_COMPRESSION: bool = False
|
|
9
8
|
|
|
@@ -17,7 +16,7 @@ class ContainerImage:
|
|
|
17
16
|
dockerfile_str: str
|
|
18
17
|
build_args: Dict[str, str] = field(default_factory=dict)
|
|
19
18
|
registries: Dict[str, Dict[str, str]] = field(default_factory=dict)
|
|
20
|
-
builder: Builder = field(default=
|
|
19
|
+
builder: Optional[Builder] = field(default=None)
|
|
21
20
|
compression: str = DEFAULT_COMPRESSION
|
|
22
21
|
force_compression: bool = DEFAULT_FORCE_COMPRESSION
|
|
23
22
|
|
|
@@ -30,7 +29,7 @@ class ContainerImage:
|
|
|
30
29
|
"Username and password are required for each registry"
|
|
31
30
|
)
|
|
32
31
|
|
|
33
|
-
if self.builder not in BUILDERS:
|
|
32
|
+
if self.builder and self.builder not in BUILDERS:
|
|
34
33
|
raise ValueError(
|
|
35
34
|
f"Invalid builder: {self.builder}, must be one of {BUILDERS}"
|
|
36
35
|
)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from functools import lru_cache
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Dict, Optional, Sequence, Tuple, Union
|
|
4
|
+
|
|
5
|
+
import tomli
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@lru_cache
|
|
9
|
+
def _load_toml(path: Union[Path, str]) -> Dict[str, Any]:
|
|
10
|
+
with open(path, "rb") as f:
|
|
11
|
+
return tomli.load(f)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@lru_cache
|
|
15
|
+
def _cached_resolve(path: Path) -> Path:
|
|
16
|
+
return path.resolve()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@lru_cache
|
|
20
|
+
def find_project_root(srcs: Optional[Sequence[str]]) -> Tuple[Path, str]:
|
|
21
|
+
"""Return a directory containing .git, or pyproject.toml.
|
|
22
|
+
|
|
23
|
+
That directory will be a common parent of all files and directories
|
|
24
|
+
passed in `srcs`.
|
|
25
|
+
|
|
26
|
+
If no directory in the tree contains a marker that would specify it's the
|
|
27
|
+
project root, the root of the file system is returned.
|
|
28
|
+
|
|
29
|
+
Returns a two-tuple with the first element as the project root path and
|
|
30
|
+
the second element as a string describing the method by which the
|
|
31
|
+
project root was discovered.
|
|
32
|
+
"""
|
|
33
|
+
if not srcs:
|
|
34
|
+
srcs = [str(_cached_resolve(Path.cwd()))]
|
|
35
|
+
|
|
36
|
+
path_srcs = [_cached_resolve(Path(Path.cwd(), src)) for src in srcs]
|
|
37
|
+
|
|
38
|
+
# A list of lists of parents for each 'src'. 'src' is included as a
|
|
39
|
+
# "parent" of itself if it is a directory
|
|
40
|
+
src_parents = [
|
|
41
|
+
list(path.parents) + ([path] if path.is_dir() else []) for path in path_srcs
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
common_base = max(
|
|
45
|
+
set.intersection(*(set(parents) for parents in src_parents)),
|
|
46
|
+
key=lambda path: path.parts,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
for directory in (common_base, *common_base.parents):
|
|
50
|
+
if (directory / ".git").exists():
|
|
51
|
+
return directory, ".git directory"
|
|
52
|
+
|
|
53
|
+
if (directory / "pyproject.toml").is_file():
|
|
54
|
+
pyproject_toml = _load_toml(directory / "pyproject.toml")
|
|
55
|
+
if "fal" in pyproject_toml.get("tool", {}):
|
|
56
|
+
return directory, "pyproject.toml"
|
|
57
|
+
|
|
58
|
+
return directory, "file system root"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def find_pyproject_toml(
|
|
62
|
+
path_search_start: Optional[Tuple[str, ...]] = None,
|
|
63
|
+
) -> Optional[str]:
|
|
64
|
+
"""Find the absolute filepath to a pyproject.toml if it exists"""
|
|
65
|
+
path_project_root, _ = find_project_root(path_search_start)
|
|
66
|
+
path_pyproject_toml = path_project_root / "pyproject.toml"
|
|
67
|
+
|
|
68
|
+
if path_pyproject_toml.is_file():
|
|
69
|
+
return str(path_pyproject_toml)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def parse_pyproject_toml(path_config: str) -> Dict[str, Any]:
|
|
73
|
+
"""Parse a pyproject toml file, pulling out relevant parts for fal.
|
|
74
|
+
|
|
75
|
+
If parsing fails, will raise a tomli.TOMLDecodeError.
|
|
76
|
+
"""
|
|
77
|
+
pyproject_toml = _load_toml(path_config)
|
|
78
|
+
config: Dict[str, Any] = pyproject_toml.get("tool", {}).get("fal", {})
|
|
79
|
+
config = {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
|
|
80
|
+
|
|
81
|
+
return config
|
|
@@ -157,7 +157,15 @@ class AuthenticatedCredentials(Credentials):
|
|
|
157
157
|
|
|
158
158
|
def to_headers(self) -> dict[str, str]:
|
|
159
159
|
token = self.user.bearer_token
|
|
160
|
-
|
|
160
|
+
headers = {
|
|
161
|
+
"Authorization": token,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if self.team:
|
|
165
|
+
team_id = self.user.get_account(self.team)["user_id"]
|
|
166
|
+
headers["X-Fal-User-Id"] = team_id
|
|
167
|
+
|
|
168
|
+
return headers
|
|
161
169
|
|
|
162
170
|
|
|
163
171
|
@dataclass
|
|
@@ -193,7 +201,7 @@ def get_default_credentials(team: str | None = None) -> Credentials:
|
|
|
193
201
|
return FalServerlessKeyCredentials(key_creds[0], key_creds[1])
|
|
194
202
|
else:
|
|
195
203
|
config = Config()
|
|
196
|
-
team = team or config.
|
|
204
|
+
team = team or config.get_internal("team")
|
|
197
205
|
return AuthenticatedCredentials(team=team)
|
|
198
206
|
|
|
199
207
|
|
|
@@ -650,8 +658,12 @@ class FalServerlessConnection:
|
|
|
650
658
|
)
|
|
651
659
|
return from_grpc(res.alias_info)
|
|
652
660
|
|
|
653
|
-
def list_applications(
|
|
654
|
-
|
|
661
|
+
def list_applications(
|
|
662
|
+
self, application_name: str | None = None
|
|
663
|
+
) -> list[ApplicationInfo]:
|
|
664
|
+
request = isolate_proto.ListApplicationsRequest(
|
|
665
|
+
application_name=application_name
|
|
666
|
+
)
|
|
655
667
|
res: isolate_proto.ListApplicationsResult = self.stub.ListApplications(request)
|
|
656
668
|
return [from_grpc(app) for app in res.applications]
|
|
657
669
|
|
|
@@ -332,55 +332,51 @@ def register_app(host: api.FalServerlessHost, app: fal.App, suffix: str = ""):
|
|
|
332
332
|
def base_app(host: api.FalServerlessHost):
|
|
333
333
|
# running apps without aliases is no longer supported
|
|
334
334
|
# so we need to create an alias for the app
|
|
335
|
-
with register_app(host, addition_app) as (app_alias, app_revision):
|
|
335
|
+
with register_app(host, addition_app, "base") as (app_alias, app_revision):
|
|
336
336
|
yield app_alias, app_revision
|
|
337
337
|
|
|
338
338
|
|
|
339
339
|
@pytest.fixture(scope="module")
|
|
340
|
-
def
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
@pytest.fixture(scope="module")
|
|
345
|
-
def test_app(base_app: Tuple[str, str, str], user: User):
|
|
346
|
-
yield f"{user.username}/{base_app[1]}"
|
|
340
|
+
def test_app(host: api.FalServerlessHost, user: User):
|
|
341
|
+
with register_app(host, addition_app, "addition") as (app_alias, _):
|
|
342
|
+
yield f"{user.username}/{app_alias}"
|
|
347
343
|
|
|
348
344
|
|
|
349
345
|
@pytest.fixture(scope="module")
|
|
350
346
|
def test_nomad_app(host: api.FalServerlessHost, user: User):
|
|
351
|
-
with register_app(host, nomad_addition_app) as (app_alias,
|
|
347
|
+
with register_app(host, nomad_addition_app, "nomad") as (app_alias, _):
|
|
352
348
|
yield f"{user.username}/{app_alias}"
|
|
353
349
|
|
|
354
350
|
|
|
355
351
|
@pytest.fixture(scope="module")
|
|
356
352
|
def test_container_app(host: api.FalServerlessHost, user: User):
|
|
357
|
-
with register_app(host, container_addition_app) as (app_alias,
|
|
353
|
+
with register_app(host, container_addition_app, "container") as (app_alias, _):
|
|
358
354
|
yield f"{user.username}/{app_alias}"
|
|
359
355
|
|
|
360
356
|
|
|
361
357
|
@pytest.fixture(scope="module")
|
|
362
358
|
def test_container_build_args_app(host: api.FalServerlessHost, user: User):
|
|
363
|
-
with register_app(host, container_build_args_app) as (app_alias,
|
|
359
|
+
with register_app(host, container_build_args_app, "build-args") as (app_alias, _):
|
|
364
360
|
yield f"{user.username}/{app_alias}"
|
|
365
361
|
|
|
366
362
|
|
|
367
363
|
@pytest.fixture(scope="module")
|
|
368
364
|
def test_fastapi_app(host: api.FalServerlessHost, user: User):
|
|
369
|
-
with register_app(host, calculator_app) as (app_alias,
|
|
365
|
+
with register_app(host, calculator_app, "fastapi") as (app_alias, _):
|
|
370
366
|
yield f"{user.username}/{app_alias}"
|
|
371
367
|
|
|
372
368
|
|
|
373
369
|
@pytest.fixture(scope="module")
|
|
374
370
|
def test_stateful_app(host: api.FalServerlessHost, user: User):
|
|
375
371
|
stateful_app = fal.wrap_app(StatefulAdditionApp)
|
|
376
|
-
with register_app(host, stateful_app) as (app_alias,
|
|
372
|
+
with register_app(host, stateful_app, "stateful") as (app_alias, _):
|
|
377
373
|
yield f"{user.username}/{app_alias}"
|
|
378
374
|
|
|
379
375
|
|
|
380
376
|
@pytest.fixture(scope="module")
|
|
381
377
|
def test_cancellable_app(host: api.FalServerlessHost, user: User):
|
|
382
378
|
cancellable_app = fal.wrap_app(CancellableApp)
|
|
383
|
-
with register_app(host, cancellable_app) as (app_alias,
|
|
379
|
+
with register_app(host, cancellable_app, "cancellable") as (app_alias, _):
|
|
384
380
|
yield f"{user.username}/{app_alias}"
|
|
385
381
|
|
|
386
382
|
|
|
@@ -393,14 +389,14 @@ def test_exception_app():
|
|
|
393
389
|
@pytest.fixture(scope="module")
|
|
394
390
|
def test_sleep_app(host: api.FalServerlessHost, user: User):
|
|
395
391
|
sleep_app = fal.wrap_app(SleepApp)
|
|
396
|
-
with register_app(host, sleep_app) as (app_alias,
|
|
392
|
+
with register_app(host, sleep_app, "sleep") as (app_alias, _):
|
|
397
393
|
yield f"{user.username}/{app_alias}"
|
|
398
394
|
|
|
399
395
|
|
|
400
396
|
@pytest.fixture(scope="module")
|
|
401
397
|
def test_realtime_app(host: api.FalServerlessHost, user: User):
|
|
402
398
|
realtime_app = fal.wrap_app(RealtimeApp)
|
|
403
|
-
with register_app(host, realtime_app) as (app_alias,
|
|
399
|
+
with register_app(host, realtime_app, "realtime") as (app_alias, _):
|
|
404
400
|
yield f"{user.username}/{app_alias}"
|
|
405
401
|
|
|
406
402
|
|
|
@@ -585,14 +581,14 @@ def test_traceback_logs(test_exception_app: AppClient):
|
|
|
585
581
|
), "Logs should contain the traceback message"
|
|
586
582
|
|
|
587
583
|
|
|
588
|
-
def test_app_openapi_spec_metadata(
|
|
589
|
-
|
|
584
|
+
def test_app_openapi_spec_metadata(base_app: Tuple[str, str], user: User):
|
|
585
|
+
app_alias, _ = base_app
|
|
590
586
|
res = app_metadata.sync_detailed(
|
|
591
|
-
app_alias_or_id=
|
|
587
|
+
app_alias_or_id=app_alias, app_user_id=user.user_id, client=REST_CLIENT
|
|
592
588
|
)
|
|
593
589
|
|
|
594
|
-
assert res.status_code == 200, f"Failed to fetch metadata for app {
|
|
595
|
-
assert res.parsed, f"Failed to parse metadata for app {
|
|
590
|
+
assert res.status_code == 200, f"Failed to fetch metadata for app {app_alias}"
|
|
591
|
+
assert res.parsed, f"Failed to parse metadata for app {app_alias}"
|
|
596
592
|
|
|
597
593
|
metadata = res.parsed.to_dict()
|
|
598
594
|
assert "openapi" in metadata, f"openapi key missing from metadata {metadata}"
|
|
@@ -601,9 +597,7 @@ def test_app_openapi_spec_metadata(test_app: str, request: pytest.FixtureRequest
|
|
|
601
597
|
assert key in openapi_spec, f"{key} key missing from openapi {openapi_spec}"
|
|
602
598
|
|
|
603
599
|
|
|
604
|
-
def test_app_no_serve_spec_metadata(
|
|
605
|
-
test_fastapi_app: str, request: pytest.FixtureRequest
|
|
606
|
-
):
|
|
600
|
+
def test_app_no_serve_spec_metadata(test_fastapi_app: str):
|
|
607
601
|
# We do not store the openapi spec for apps that do not use serve=True
|
|
608
602
|
user_id, _, app_id = test_fastapi_app.partition("/")
|
|
609
603
|
res = app_metadata.sync_detailed(
|
|
@@ -680,8 +674,8 @@ def test_app_deploy_scale(host: api.FalServerlessHost):
|
|
|
680
674
|
|
|
681
675
|
# List aliases is taking long
|
|
682
676
|
@pytest.mark.timeout(600)
|
|
683
|
-
def test_app_update_app(
|
|
684
|
-
|
|
677
|
+
def test_app_update_app(base_app: Tuple[str, str]):
|
|
678
|
+
app_alias, app_revision = base_app
|
|
685
679
|
|
|
686
680
|
host: api.FalServerlessHost = addition_app.host # type: ignore
|
|
687
681
|
with host._connection as client:
|
|
@@ -732,8 +726,8 @@ def test_app_update_app(aliased_app: Tuple[str, str]):
|
|
|
732
726
|
|
|
733
727
|
# List aliases is taking long
|
|
734
728
|
@pytest.mark.timeout(600)
|
|
735
|
-
def test_app_set_delete_alias(
|
|
736
|
-
|
|
729
|
+
def test_app_set_delete_alias(base_app: Tuple[str, str]):
|
|
730
|
+
app_alias, app_revision = base_app
|
|
737
731
|
|
|
738
732
|
host: api.FalServerlessHost = addition_app.host # type: ignore
|
|
739
733
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.13.5 → fal-1.14.0}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py
RENAMED
|
File without changes
|
|
File without changes
|