fal 1.45.2__tar.gz → 1.46.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.45.2/fal.egg-info → fal-1.46.1}/PKG-INFO +2 -1
- {fal-1.45.2 → fal-1.46.1/fal.egg-info}/PKG-INFO +2 -1
- {fal-1.45.2 → fal-1.46.1}/fal.egg-info/SOURCES.txt +12 -1
- {fal-1.45.2 → fal-1.46.1}/fal.egg-info/requires.txt +1 -0
- {fal-1.45.2 → fal-1.46.1}/pyproject.toml +1 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/_fal_version.py +2 -2
- fal-1.46.1/src/fal/api/__init__.py +1 -0
- fal-1.46.1/src/fal/api/apps.py +69 -0
- fal-1.46.1/src/fal/api/client.py +116 -0
- fal-1.46.1/src/fal/api/deploy.py +211 -0
- fal-1.46.1/src/fal/api/runners.py +16 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/apps.py +51 -60
- fal-1.46.1/src/fal/cli/deploy.py +124 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/queue.py +2 -2
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/runners.py +45 -47
- fal-1.46.1/src/fal/distributed/__init__.py +3 -0
- fal-1.46.1/src/fal/distributed/utils.py +420 -0
- fal-1.46.1/src/fal/distributed/worker.py +791 -0
- {fal-1.45.2 → fal-1.46.1}/tests/cli/test_deploy.py +28 -27
- {fal-1.45.2 → fal-1.46.1}/tests/test_apps.py +1 -1
- fal-1.46.1/tests/unit/distributed/test_integration.py +66 -0
- fal-1.46.1/tests/unit/distributed/test_utils.py +157 -0
- fal-1.46.1/tests/unit/distributed/test_worker.py +144 -0
- fal-1.45.2/src/fal/cli/deploy.py +0 -276
- {fal-1.45.2 → fal-1.46.1}/.gitignore +0 -0
- {fal-1.45.2 → fal-1.46.1}/Makefile +0 -0
- {fal-1.45.2 → fal-1.46.1}/README.md +0 -0
- {fal-1.45.2 → fal-1.46.1}/docs/conf.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/docs/index.rst +0 -0
- {fal-1.45.2 → fal-1.46.1}/fal.egg-info/dependency_links.txt +0 -0
- {fal-1.45.2 → fal-1.46.1}/fal.egg-info/entry_points.txt +0 -0
- {fal-1.45.2 → fal-1.46.1}/fal.egg-info/top_level.txt +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/README.md +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi-fal-rest/pyproject.toml +0 -0
- {fal-1.45.2 → fal-1.46.1}/openapi_rest.config.yaml +0 -0
- {fal-1.45.2 → fal-1.46.1}/setup.cfg +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/__main__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/_serialization.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/_version.py +0 -0
- {fal-1.45.2/src/fal → fal-1.46.1/src/fal/api}/api.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/app.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/apps.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/auth/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/auth/auth0.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/auth/local.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/_utils.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/api.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/auth.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/cli_nested_json.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/create.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/debug.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/doctor.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/files.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/keys.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/main.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/parser.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/profile.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/run.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/secrets.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/cli/teams.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/config.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/console/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/console/icons.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/console/ux.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/container.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/exceptions/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/exceptions/_base.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/exceptions/_cuda.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/exceptions/auth.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/file_sync.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/files.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/flags.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/logging/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/logging/isolate.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/logging/style.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/logging/trace.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/project.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/py.typed +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/rest_client.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/sdk.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/sync.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/audio/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/audio/audio.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/exceptions.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/file/file.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/file/providers/fal.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/file/providers/s3.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/file/types.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/image.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/image/safety_checker.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/kv.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/optimize.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/types.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/utils/download_utils.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/utils/endpoint.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/utils/retry.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/utils/setup_utils.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/video/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/toolkit/video/video.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/utils.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/src/fal/workflows.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/assets/cat.png +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/cli/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/cli/test_apps.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/cli/test_auth.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/cli/test_keys.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/cli/test_run.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/cli/test_secrets.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/conftest.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/integration_test.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/mainify_package/__init__.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/mainify_package/impl.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/mainify_package/utils.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/mainify_target.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/test_file_sync.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/test_files.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/test_kv.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/test_stability.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/toolkit/file/providers/test_fal_retry.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/toolkit/file_test.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/toolkit/image_test.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/toolkit/test_types.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/toolkit/utils/retry.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tests/unit/test_app.py +0 -0
- {fal-1.45.2 → fal-1.46.1}/tools/demo_script.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.46.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
|
|
@@ -53,6 +53,7 @@ Requires-Dist: pytest-xdist; extra == "test"
|
|
|
53
53
|
Requires-Dist: pytest-timeout; extra == "test"
|
|
54
54
|
Requires-Dist: flaky; extra == "test"
|
|
55
55
|
Requires-Dist: boto3; extra == "test"
|
|
56
|
+
Requires-Dist: numpy; extra == "test"
|
|
56
57
|
Provides-Extra: dev
|
|
57
58
|
Requires-Dist: fal[docs,test]; extra == "dev"
|
|
58
59
|
Requires-Dist: openapi-python-client<1,>=0.14.1; extra == "dev"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.46.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
|
|
@@ -53,6 +53,7 @@ Requires-Dist: pytest-xdist; extra == "test"
|
|
|
53
53
|
Requires-Dist: pytest-timeout; extra == "test"
|
|
54
54
|
Requires-Dist: flaky; extra == "test"
|
|
55
55
|
Requires-Dist: boto3; extra == "test"
|
|
56
|
+
Requires-Dist: numpy; extra == "test"
|
|
56
57
|
Provides-Extra: dev
|
|
57
58
|
Requires-Dist: fal[docs,test]; extra == "dev"
|
|
58
59
|
Requires-Dist: openapi-python-client<1,>=0.14.1; extra == "dev"
|
|
@@ -81,7 +81,6 @@ src/fal/__main__.py
|
|
|
81
81
|
src/fal/_fal_version.py
|
|
82
82
|
src/fal/_serialization.py
|
|
83
83
|
src/fal/_version.py
|
|
84
|
-
src/fal/api.py
|
|
85
84
|
src/fal/app.py
|
|
86
85
|
src/fal/apps.py
|
|
87
86
|
src/fal/config.py
|
|
@@ -96,6 +95,12 @@ src/fal/sdk.py
|
|
|
96
95
|
src/fal/sync.py
|
|
97
96
|
src/fal/utils.py
|
|
98
97
|
src/fal/workflows.py
|
|
98
|
+
src/fal/api/__init__.py
|
|
99
|
+
src/fal/api/api.py
|
|
100
|
+
src/fal/api/apps.py
|
|
101
|
+
src/fal/api/client.py
|
|
102
|
+
src/fal/api/deploy.py
|
|
103
|
+
src/fal/api/runners.py
|
|
99
104
|
src/fal/auth/__init__.py
|
|
100
105
|
src/fal/auth/auth0.py
|
|
101
106
|
src/fal/auth/local.py
|
|
@@ -122,6 +127,9 @@ src/fal/cli/teams.py
|
|
|
122
127
|
src/fal/console/__init__.py
|
|
123
128
|
src/fal/console/icons.py
|
|
124
129
|
src/fal/console/ux.py
|
|
130
|
+
src/fal/distributed/__init__.py
|
|
131
|
+
src/fal/distributed/utils.py
|
|
132
|
+
src/fal/distributed/worker.py
|
|
125
133
|
src/fal/exceptions/__init__.py
|
|
126
134
|
src/fal/exceptions/_base.py
|
|
127
135
|
src/fal/exceptions/_cuda.py
|
|
@@ -185,4 +193,7 @@ tests/toolkit/test_types.py
|
|
|
185
193
|
tests/toolkit/file/providers/test_fal_retry.py
|
|
186
194
|
tests/toolkit/utils/retry.py
|
|
187
195
|
tests/unit/test_app.py
|
|
196
|
+
tests/unit/distributed/test_integration.py
|
|
197
|
+
tests/unit/distributed/test_utils.py
|
|
198
|
+
tests/unit/distributed/test_worker.py
|
|
188
199
|
tools/demo_script.py
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.
|
|
32
|
-
__version_tuple__ = version_tuple = (1,
|
|
31
|
+
__version__ = version = '1.46.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 46, 1)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .api import * # noqa: F403
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
5
|
+
|
|
6
|
+
from fal.sdk import AliasInfo, FalServerlessClient, RunnerInfo
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from .client import SyncServerlessClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def list_apps(
|
|
13
|
+
client: SyncServerlessClient,
|
|
14
|
+
*,
|
|
15
|
+
filter: Optional[str] = None,
|
|
16
|
+
) -> List[AliasInfo]:
|
|
17
|
+
with FalServerlessClient(client._grpc_host, client._credentials).connect() as conn:
|
|
18
|
+
apps = conn.list_aliases()
|
|
19
|
+
|
|
20
|
+
if filter:
|
|
21
|
+
apps = [a for a in apps if filter in a.alias]
|
|
22
|
+
return apps
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def apps_runners(
|
|
26
|
+
client: SyncServerlessClient,
|
|
27
|
+
app_name: str,
|
|
28
|
+
*,
|
|
29
|
+
since: Optional[datetime] = None,
|
|
30
|
+
state: Optional[list[str]] = None,
|
|
31
|
+
) -> List[RunnerInfo]:
|
|
32
|
+
with FalServerlessClient(client._grpc_host, client._credentials).connect() as conn:
|
|
33
|
+
alias_runners = conn.list_alias_runners(alias=app_name, start_time=since)
|
|
34
|
+
|
|
35
|
+
if state and "all" not in set(state):
|
|
36
|
+
states = set(state)
|
|
37
|
+
alias_runners = [r for r in alias_runners if r.state.value in states]
|
|
38
|
+
return alias_runners
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def scale_app(
|
|
42
|
+
client: SyncServerlessClient,
|
|
43
|
+
app_name: str,
|
|
44
|
+
*,
|
|
45
|
+
keep_alive: int | None = None,
|
|
46
|
+
max_multiplexing: int | None = None,
|
|
47
|
+
max_concurrency: int | None = None,
|
|
48
|
+
min_concurrency: int | None = None,
|
|
49
|
+
concurrency_buffer: int | None = None,
|
|
50
|
+
concurrency_buffer_perc: int | None = None,
|
|
51
|
+
request_timeout: int | None = None,
|
|
52
|
+
startup_timeout: int | None = None,
|
|
53
|
+
machine_types: list[str] | None = None,
|
|
54
|
+
regions: list[str] | None = None,
|
|
55
|
+
) -> AliasInfo:
|
|
56
|
+
with FalServerlessClient(client._grpc_host, client._credentials).connect() as conn:
|
|
57
|
+
return conn.update_application(
|
|
58
|
+
application_name=app_name,
|
|
59
|
+
keep_alive=keep_alive,
|
|
60
|
+
max_multiplexing=max_multiplexing,
|
|
61
|
+
max_concurrency=max_concurrency,
|
|
62
|
+
min_concurrency=min_concurrency,
|
|
63
|
+
concurrency_buffer=concurrency_buffer,
|
|
64
|
+
concurrency_buffer_perc=concurrency_buffer_perc,
|
|
65
|
+
request_timeout=request_timeout,
|
|
66
|
+
startup_timeout=startup_timeout,
|
|
67
|
+
machine_types=machine_types,
|
|
68
|
+
valid_regions=regions,
|
|
69
|
+
)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
from fal.api import FAL_SERVERLESS_DEFAULT_URL
|
|
8
|
+
from fal.sdk import (
|
|
9
|
+
AliasInfo,
|
|
10
|
+
Credentials,
|
|
11
|
+
RunnerInfo,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from . import apps as apps_api
|
|
15
|
+
from . import deploy as deploy_api
|
|
16
|
+
from . import runners as runners_api
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _AppsNamespace:
|
|
20
|
+
def __init__(self, client: SyncServerlessClient):
|
|
21
|
+
self.client = client
|
|
22
|
+
|
|
23
|
+
def list(self, *, filter: str | None = None) -> List[AliasInfo]:
|
|
24
|
+
return apps_api.list_apps(self.client, filter=filter)
|
|
25
|
+
|
|
26
|
+
def runners(
|
|
27
|
+
self, app_name: str, *, since=None, state: List[str] | None = None
|
|
28
|
+
) -> List[RunnerInfo]:
|
|
29
|
+
return apps_api.apps_runners(self.client, app_name, since=since, state=state)
|
|
30
|
+
|
|
31
|
+
def scale(
|
|
32
|
+
self,
|
|
33
|
+
app_name: str,
|
|
34
|
+
*,
|
|
35
|
+
keep_alive: int | None = None,
|
|
36
|
+
max_multiplexing: int | None = None,
|
|
37
|
+
max_concurrency: int | None = None,
|
|
38
|
+
min_concurrency: int | None = None,
|
|
39
|
+
concurrency_buffer: int | None = None,
|
|
40
|
+
concurrency_buffer_perc: int | None = None,
|
|
41
|
+
request_timeout: int | None = None,
|
|
42
|
+
startup_timeout: int | None = None,
|
|
43
|
+
machine_types: List[str] | None = None,
|
|
44
|
+
regions: List[str] | None = None,
|
|
45
|
+
) -> apps_api.AliasInfo:
|
|
46
|
+
return apps_api.scale_app(
|
|
47
|
+
self.client,
|
|
48
|
+
app_name,
|
|
49
|
+
keep_alive=keep_alive,
|
|
50
|
+
max_multiplexing=max_multiplexing,
|
|
51
|
+
max_concurrency=max_concurrency,
|
|
52
|
+
min_concurrency=min_concurrency,
|
|
53
|
+
concurrency_buffer=concurrency_buffer,
|
|
54
|
+
concurrency_buffer_perc=concurrency_buffer_perc,
|
|
55
|
+
request_timeout=request_timeout,
|
|
56
|
+
startup_timeout=startup_timeout,
|
|
57
|
+
machine_types=machine_types,
|
|
58
|
+
regions=regions,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class _RunnersNamespace:
|
|
63
|
+
def __init__(self, client: SyncServerlessClient):
|
|
64
|
+
self.client = client
|
|
65
|
+
|
|
66
|
+
def list(self, *, since=None) -> List[RunnerInfo]:
|
|
67
|
+
return runners_api.list_runners(self.client, since=since)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class SyncServerlessClient:
|
|
72
|
+
host: Optional[str] = None
|
|
73
|
+
api_key: Optional[str] = None
|
|
74
|
+
profile: Optional[str] = None
|
|
75
|
+
team: Optional[str] = None
|
|
76
|
+
|
|
77
|
+
def __post_init__(self) -> None:
|
|
78
|
+
self.apps = _AppsNamespace(self)
|
|
79
|
+
self.runners = _RunnersNamespace(self)
|
|
80
|
+
|
|
81
|
+
# Top-level verbs
|
|
82
|
+
def deploy(self, *args, **kwargs):
|
|
83
|
+
return deploy_api.deploy(self, *args, **kwargs)
|
|
84
|
+
|
|
85
|
+
# Internal helpers
|
|
86
|
+
@property
|
|
87
|
+
def _grpc_host(self) -> str:
|
|
88
|
+
return self.host or FAL_SERVERLESS_DEFAULT_URL
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def _credentials(self) -> Credentials:
|
|
92
|
+
from fal.sdk import FalServerlessKeyCredentials, get_default_credentials
|
|
93
|
+
|
|
94
|
+
if self.api_key:
|
|
95
|
+
if self.team:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"Using explicit team with key credentials is not allowed"
|
|
98
|
+
)
|
|
99
|
+
try:
|
|
100
|
+
key_id, key_secret = self.api_key.split(":", 1)
|
|
101
|
+
except ValueError:
|
|
102
|
+
raise ValueError("api_key must be in 'KEY_ID:KEY_SECRET' format")
|
|
103
|
+
return FalServerlessKeyCredentials(key_id, key_secret)
|
|
104
|
+
|
|
105
|
+
if self.profile:
|
|
106
|
+
prev = os.environ.get("FAL_PROFILE")
|
|
107
|
+
os.environ["FAL_PROFILE"] = self.profile
|
|
108
|
+
try:
|
|
109
|
+
return get_default_credentials(team=self.team)
|
|
110
|
+
finally:
|
|
111
|
+
if prev is None:
|
|
112
|
+
os.environ.pop("FAL_PROFILE", None)
|
|
113
|
+
else:
|
|
114
|
+
os.environ["FAL_PROFILE"] = prev
|
|
115
|
+
|
|
116
|
+
return get_default_credentials(team=self.team)
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import TYPE_CHECKING, Optional
|
|
6
|
+
|
|
7
|
+
from fal.sdk import AuthModeLiteral, DeploymentStrategyLiteral
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from .client import SyncServerlessClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
from collections import namedtuple
|
|
15
|
+
from typing import Tuple, Union, cast
|
|
16
|
+
|
|
17
|
+
from fal.cli._utils import get_app_data_from_toml, is_app_name
|
|
18
|
+
from fal.cli.parser import RefAction
|
|
19
|
+
|
|
20
|
+
User = namedtuple("User", ["user_id", "username"])
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class DeploymentResult:
|
|
25
|
+
revision: str
|
|
26
|
+
app_name: str
|
|
27
|
+
urls: dict[str, dict[str, str]]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _remove_http_and_port_from_url(url):
|
|
31
|
+
# Remove http://
|
|
32
|
+
if "http://" in url:
|
|
33
|
+
url = url.replace("http://", "")
|
|
34
|
+
|
|
35
|
+
# Remove https://
|
|
36
|
+
if "https://" in url:
|
|
37
|
+
url = url.replace("https://", "")
|
|
38
|
+
|
|
39
|
+
# Remove port information
|
|
40
|
+
url_parts = url.split(":")
|
|
41
|
+
if len(url_parts) > 1:
|
|
42
|
+
url = url_parts[0]
|
|
43
|
+
|
|
44
|
+
return url
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _get_user() -> User:
|
|
48
|
+
from http import HTTPStatus
|
|
49
|
+
|
|
50
|
+
import openapi_fal_rest.api.users.get_current_user as get_current_user
|
|
51
|
+
|
|
52
|
+
from fal.api import FalServerlessError
|
|
53
|
+
from fal.rest_client import REST_CLIENT
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
user_details_response = get_current_user.sync_detailed(
|
|
57
|
+
client=REST_CLIENT,
|
|
58
|
+
)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
raise FalServerlessError(f"Error fetching user details: {str(e)}")
|
|
61
|
+
|
|
62
|
+
if user_details_response.status_code != HTTPStatus.OK:
|
|
63
|
+
try:
|
|
64
|
+
content = json.loads(user_details_response.content.decode("utf8"))
|
|
65
|
+
except Exception:
|
|
66
|
+
raise FalServerlessError(
|
|
67
|
+
f"Error fetching user details: {user_details_response}"
|
|
68
|
+
)
|
|
69
|
+
else:
|
|
70
|
+
raise FalServerlessError(content["detail"])
|
|
71
|
+
try:
|
|
72
|
+
full_user_id = user_details_response.parsed.user_id
|
|
73
|
+
_provider, _, user_id = full_user_id.partition("|")
|
|
74
|
+
if not user_id:
|
|
75
|
+
user_id = full_user_id
|
|
76
|
+
|
|
77
|
+
return User(user_id=user_id, username=user_details_response.parsed.nickname)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
raise FalServerlessError(f"Could not parse the user data: {e}")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _deploy_from_reference(
|
|
83
|
+
client: SyncServerlessClient,
|
|
84
|
+
app_ref: Tuple[Optional[Union[Path, str]], ...],
|
|
85
|
+
app_name: str,
|
|
86
|
+
auth: Optional[AuthModeLiteral],
|
|
87
|
+
strategy: Optional[DeploymentStrategyLiteral],
|
|
88
|
+
scale: bool,
|
|
89
|
+
) -> DeploymentResult:
|
|
90
|
+
from fal.api import FalServerlessError, FalServerlessHost
|
|
91
|
+
from fal.utils import load_function_from
|
|
92
|
+
|
|
93
|
+
file_path, func_name = app_ref
|
|
94
|
+
if file_path is None:
|
|
95
|
+
# Try to find a python file in the current directory
|
|
96
|
+
options = list(Path(".").glob("*.py"))
|
|
97
|
+
if len(options) == 0:
|
|
98
|
+
raise FalServerlessError("No python files found in the current directory")
|
|
99
|
+
elif len(options) > 1:
|
|
100
|
+
raise FalServerlessError(
|
|
101
|
+
"Multiple python files found in the current directory. "
|
|
102
|
+
"Please specify the file path of the app you want to deploy."
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
[file_path] = options
|
|
106
|
+
file_path = str(file_path) # type: ignore
|
|
107
|
+
|
|
108
|
+
user = _get_user()
|
|
109
|
+
host = FalServerlessHost(client._grpc_host, local_file_path=str(file_path))
|
|
110
|
+
loaded = load_function_from(
|
|
111
|
+
host,
|
|
112
|
+
file_path, # type: ignore
|
|
113
|
+
func_name, # type: ignore
|
|
114
|
+
)
|
|
115
|
+
isolated_function = loaded.function
|
|
116
|
+
app_name = app_name or loaded.app_name # type: ignore
|
|
117
|
+
app_auth = auth or loaded.app_auth
|
|
118
|
+
strategy = strategy or "rolling"
|
|
119
|
+
|
|
120
|
+
app_id = host.register(
|
|
121
|
+
func=isolated_function.func,
|
|
122
|
+
options=isolated_function.options,
|
|
123
|
+
application_name=app_name,
|
|
124
|
+
application_auth_mode=app_auth, # type: ignore
|
|
125
|
+
metadata=isolated_function.options.host.get("metadata", {}),
|
|
126
|
+
deployment_strategy=strategy,
|
|
127
|
+
scale=scale,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
assert app_id
|
|
131
|
+
env_host = _remove_http_and_port_from_url(host.url)
|
|
132
|
+
env_host = env_host.replace("api.", "").replace("alpha.", "")
|
|
133
|
+
|
|
134
|
+
env_host_parts = env_host.split(".")
|
|
135
|
+
|
|
136
|
+
# keep the last 3 parts
|
|
137
|
+
playground_host = ".".join(env_host_parts[-3:])
|
|
138
|
+
|
|
139
|
+
# just replace .ai for .run
|
|
140
|
+
endpoint_host = env_host.replace(".ai", ".run")
|
|
141
|
+
|
|
142
|
+
urls: dict[str, dict[str, str]] = {
|
|
143
|
+
"playground": {},
|
|
144
|
+
"sync": {},
|
|
145
|
+
"async": {},
|
|
146
|
+
}
|
|
147
|
+
for endpoint in loaded.endpoints:
|
|
148
|
+
urls["playground"][endpoint] = (
|
|
149
|
+
f"https://{playground_host}/models/{user.username}/{app_name}{endpoint}"
|
|
150
|
+
)
|
|
151
|
+
urls["sync"][endpoint] = (
|
|
152
|
+
f"https://{endpoint_host}/{user.username}/{app_name}{endpoint}"
|
|
153
|
+
)
|
|
154
|
+
urls["async"][endpoint] = (
|
|
155
|
+
f"https://queue.{endpoint_host}/{user.username}/{app_name}{endpoint}"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
return DeploymentResult(
|
|
159
|
+
revision=app_id,
|
|
160
|
+
app_name=app_name,
|
|
161
|
+
urls=urls,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def deploy(
|
|
166
|
+
client: SyncServerlessClient,
|
|
167
|
+
app_ref: str | tuple[str, str] | None = None,
|
|
168
|
+
*,
|
|
169
|
+
app_name: str | None = None,
|
|
170
|
+
auth: AuthModeLiteral | None = None,
|
|
171
|
+
strategy: DeploymentStrategyLiteral = "rolling",
|
|
172
|
+
reset_scale: bool = False,
|
|
173
|
+
) -> DeploymentResult:
|
|
174
|
+
if isinstance(app_ref, tuple):
|
|
175
|
+
app_ref_tuple = app_ref
|
|
176
|
+
elif app_ref:
|
|
177
|
+
app_ref_tuple = RefAction.split_ref(app_ref)
|
|
178
|
+
else:
|
|
179
|
+
raise ValueError("Invalid app reference")
|
|
180
|
+
|
|
181
|
+
# my-app
|
|
182
|
+
if is_app_name(app_ref_tuple):
|
|
183
|
+
# we do not allow --app-name and --auth to be used with app name
|
|
184
|
+
if app_name or auth:
|
|
185
|
+
raise ValueError("Cannot use --app-name or --auth with app name reference.")
|
|
186
|
+
|
|
187
|
+
app_name = app_ref_tuple[0]
|
|
188
|
+
app_ref, app_auth, app_strategy, app_scale_settings = get_app_data_from_toml(
|
|
189
|
+
app_name
|
|
190
|
+
)
|
|
191
|
+
file_path, func_name = RefAction.split_ref(app_ref)
|
|
192
|
+
|
|
193
|
+
# path/to/myfile.py::MyApp
|
|
194
|
+
else:
|
|
195
|
+
file_path, func_name = app_ref_tuple
|
|
196
|
+
app_name = cast(str, app_name)
|
|
197
|
+
# default to be set in the backend
|
|
198
|
+
app_auth = cast(Optional[AuthModeLiteral], auth)
|
|
199
|
+
# default comes from the CLI
|
|
200
|
+
app_strategy = cast(DeploymentStrategyLiteral, strategy)
|
|
201
|
+
app_scale_settings = cast(bool, reset_scale)
|
|
202
|
+
file_path = str(Path(file_path).absolute())
|
|
203
|
+
|
|
204
|
+
return _deploy_from_reference(
|
|
205
|
+
client,
|
|
206
|
+
(file_path, func_name),
|
|
207
|
+
app_name, # type: ignore
|
|
208
|
+
app_auth,
|
|
209
|
+
strategy=app_strategy,
|
|
210
|
+
scale=app_scale_settings,
|
|
211
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import TYPE_CHECKING, List, Optional
|
|
5
|
+
|
|
6
|
+
from fal.sdk import FalServerlessClient, RunnerInfo
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from .client import SyncServerlessClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def list_runners(
|
|
13
|
+
client: SyncServerlessClient, *, since: Optional[datetime] = None
|
|
14
|
+
) -> List[RunnerInfo]:
|
|
15
|
+
with FalServerlessClient(client._grpc_host, client._credentials).connect() as conn:
|
|
16
|
+
return conn.list_runners(start_time=since)
|
|
@@ -5,6 +5,7 @@ from dataclasses import asdict
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
import fal.cli.runners as runners
|
|
8
|
+
from fal.api.client import SyncServerlessClient
|
|
8
9
|
from fal.sdk import RunnerState
|
|
9
10
|
|
|
10
11
|
from ._utils import get_client
|
|
@@ -60,27 +61,23 @@ def _apps_table(apps: list[AliasInfo]):
|
|
|
60
61
|
|
|
61
62
|
|
|
62
63
|
def _list(args):
|
|
63
|
-
client =
|
|
64
|
-
|
|
65
|
-
apps = connection.list_aliases()
|
|
64
|
+
client = SyncServerlessClient(host=args.host, team=args.team)
|
|
65
|
+
apps = client.apps.list(filter=args.filter)
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
if args.sort_by_runners:
|
|
68
|
+
apps.sort(key=lambda x: x.active_runners)
|
|
69
|
+
else:
|
|
70
|
+
apps.sort(key=lambda x: x.alias)
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
apps_as_dicts = [asdict(a) for a in apps]
|
|
80
|
-
res = json.dumps({"apps": apps_as_dicts})
|
|
81
|
-
args.console.print(res)
|
|
82
|
-
else:
|
|
83
|
-
raise AssertionError(f"Invalid output format: {args.output}")
|
|
72
|
+
if args.output == "pretty":
|
|
73
|
+
table = _apps_table(apps)
|
|
74
|
+
args.console.print(table)
|
|
75
|
+
elif args.output == "json":
|
|
76
|
+
apps_as_dicts = [asdict(a) for a in apps]
|
|
77
|
+
json_res = json.dumps({"apps": apps_as_dicts})
|
|
78
|
+
args.console.print(json_res)
|
|
79
|
+
else:
|
|
80
|
+
raise AssertionError(f"Invalid output format: {args.output}")
|
|
84
81
|
|
|
85
82
|
|
|
86
83
|
def _add_list_parser(subparsers, parents):
|
|
@@ -164,37 +161,36 @@ def _add_list_rev_parser(subparsers, parents):
|
|
|
164
161
|
|
|
165
162
|
|
|
166
163
|
def _scale(args):
|
|
167
|
-
client =
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
table = _apps_table([alias_info])
|
|
164
|
+
client = SyncServerlessClient(host=args.host, team=args.team)
|
|
165
|
+
if (
|
|
166
|
+
args.keep_alive is None
|
|
167
|
+
and args.max_multiplexing is None
|
|
168
|
+
and args.max_concurrency is None
|
|
169
|
+
and args.min_concurrency is None
|
|
170
|
+
and args.concurrency_buffer is None
|
|
171
|
+
and args.concurrency_buffer_perc is None
|
|
172
|
+
and args.request_timeout is None
|
|
173
|
+
and args.startup_timeout is None
|
|
174
|
+
and args.machine_types is None
|
|
175
|
+
and args.regions is None
|
|
176
|
+
):
|
|
177
|
+
args.console.log("No parameters for update were provided, ignoring.")
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
app_info = client.apps.scale(
|
|
181
|
+
args.app_name,
|
|
182
|
+
keep_alive=args.keep_alive,
|
|
183
|
+
max_multiplexing=args.max_multiplexing,
|
|
184
|
+
max_concurrency=args.max_concurrency,
|
|
185
|
+
min_concurrency=args.min_concurrency,
|
|
186
|
+
concurrency_buffer=args.concurrency_buffer,
|
|
187
|
+
concurrency_buffer_perc=args.concurrency_buffer_perc,
|
|
188
|
+
request_timeout=args.request_timeout,
|
|
189
|
+
startup_timeout=args.startup_timeout,
|
|
190
|
+
machine_types=args.machine_types,
|
|
191
|
+
regions=args.regions,
|
|
192
|
+
)
|
|
193
|
+
table = _apps_table([app_info])
|
|
198
194
|
|
|
199
195
|
args.console.print(table)
|
|
200
196
|
|
|
@@ -303,16 +299,11 @@ def _add_set_rev_parser(subparsers, parents):
|
|
|
303
299
|
|
|
304
300
|
|
|
305
301
|
def _runners(args):
|
|
306
|
-
client =
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
)
|
|
312
|
-
if getattr(args, "state", None):
|
|
313
|
-
states = set(args.state)
|
|
314
|
-
if "all" not in states:
|
|
315
|
-
alias_runners = [r for r in alias_runners if r.state.value in states]
|
|
302
|
+
client = SyncServerlessClient(host=args.host, team=args.team)
|
|
303
|
+
start_time = args.since
|
|
304
|
+
alias_runners = client.apps.runners(
|
|
305
|
+
args.app_name, since=start_time, state=args.state
|
|
306
|
+
)
|
|
316
307
|
if args.output == "pretty":
|
|
317
308
|
runners_table = runners.runners_table(alias_runners)
|
|
318
309
|
pending_runners = [
|