fal 1.5.16__tar.gz → 1.5.17__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.16/fal.egg-info → fal-1.5.17}/PKG-INFO +1 -1
- {fal-1.5.16 → fal-1.5.17/fal.egg-info}/PKG-INFO +1 -1
- {fal-1.5.16 → fal-1.5.17}/src/fal/_fal_version.py +2 -2
- {fal-1.5.16 → fal-1.5.17}/src/fal/app.py +13 -10
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/file/file.py +13 -11
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/file/providers/fal.py +58 -27
- {fal-1.5.16 → fal-1.5.17}/.gitignore +0 -0
- {fal-1.5.16 → fal-1.5.17}/Makefile +0 -0
- {fal-1.5.16 → fal-1.5.17}/README.md +0 -0
- {fal-1.5.16 → fal-1.5.17}/docs/conf.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/docs/index.rst +0 -0
- {fal-1.5.16 → fal-1.5.17}/fal.egg-info/SOURCES.txt +0 -0
- {fal-1.5.16 → fal-1.5.17}/fal.egg-info/dependency_links.txt +0 -0
- {fal-1.5.16 → fal-1.5.17}/fal.egg-info/entry_points.txt +0 -0
- {fal-1.5.16 → fal-1.5.17}/fal.egg-info/requires.txt +0 -0
- {fal-1.5.16 → fal-1.5.17}/fal.egg-info/top_level.txt +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/README.md +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/pyproject.toml +0 -0
- {fal-1.5.16 → fal-1.5.17}/openapi_rest.config.yaml +0 -0
- {fal-1.5.16 → fal-1.5.17}/pyproject.toml +0 -0
- {fal-1.5.16 → fal-1.5.17}/setup.cfg +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/__main__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/_serialization.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/_version.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/api.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/apps.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/auth/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/auth/auth0.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/auth/local.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/_utils.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/apps.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/auth.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/create.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/debug.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/deploy.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/doctor.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/keys.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/machine.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/main.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/parser.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/run.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/cli/secrets.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/console/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/console/icons.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/console/ux.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/container.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/exceptions/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/exceptions/_base.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/exceptions/_cuda.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/exceptions/auth.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/files.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/flags.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/logging/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/logging/isolate.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/logging/style.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/logging/trace.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/logging/user.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/py.typed +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/rest_client.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/sdk.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/sync.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/exceptions.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/file/providers/s3.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/file/types.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/image.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/image/safety_checker.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/optimize.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/utils/download_utils.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/toolkit/utils/retry.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/utils.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/src/fal/workflows.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/assets/cat.png +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/cli/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/cli/test_apps.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/cli/test_auth.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/cli/test_deploy.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/cli/test_keys.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/cli/test_run.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/cli/test_secrets.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/conftest.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/integration_test.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/mainify_package/__init__.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/mainify_package/impl.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/mainify_package/utils.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/mainify_target.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/test_apps.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/test_stability.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/toolkit/file_test.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/toolkit/image_test.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tests/toolkit/utils/retry.py +0 -0
- {fal-1.5.16 → fal-1.5.17}/tools/demo_script.py +0 -0
|
@@ -23,8 +23,8 @@ 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
|
|
27
|
-
from fal.toolkit.file.providers.fal import
|
|
26
|
+
from fal.toolkit.file import request_lifecycle_repference
|
|
27
|
+
from fal.toolkit.file.providers.fal import LIFECYCLE_PREFERENCE
|
|
28
28
|
|
|
29
29
|
REALTIME_APP_REQUIREMENTS = ["websockets", "msgpack"]
|
|
30
30
|
REQUEST_ID_KEY = "x-fal-request-id"
|
|
@@ -342,13 +342,11 @@ class App(fal.api.BaseServable):
|
|
|
342
342
|
@app.middleware("http")
|
|
343
343
|
async def set_global_object_preference(request, call_next):
|
|
344
344
|
try:
|
|
345
|
-
preference_dict =
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
)
|
|
351
|
-
|
|
345
|
+
preference_dict = request_lifecycle_repference(request)
|
|
346
|
+
if preference_dict is not None:
|
|
347
|
+
# This will not work properly for apps with multiplexing enabled
|
|
348
|
+
# we may mix up the preferences between requests
|
|
349
|
+
LIFECYCLE_PREFERENCE.set(preference_dict)
|
|
352
350
|
except Exception:
|
|
353
351
|
from fastapi.logger import logger
|
|
354
352
|
|
|
@@ -357,7 +355,12 @@ class App(fal.api.BaseServable):
|
|
|
357
355
|
self.__class__.__name__,
|
|
358
356
|
)
|
|
359
357
|
|
|
360
|
-
|
|
358
|
+
try:
|
|
359
|
+
return await call_next(request)
|
|
360
|
+
finally:
|
|
361
|
+
# We may miss the global preference if there are operations
|
|
362
|
+
# being done in the background that go beyond the request
|
|
363
|
+
LIFECYCLE_PREFERENCE.set(None)
|
|
361
364
|
|
|
362
365
|
@app.middleware("http")
|
|
363
366
|
async def set_request_id(request, call_next):
|
|
@@ -22,6 +22,7 @@ else:
|
|
|
22
22
|
from pydantic import BaseModel, Field
|
|
23
23
|
|
|
24
24
|
from fal.toolkit.file.providers.fal import (
|
|
25
|
+
LIFECYCLE_PREFERENCE,
|
|
25
26
|
FalCDNFileRepository,
|
|
26
27
|
FalFileRepository,
|
|
27
28
|
FalFileRepositoryV2,
|
|
@@ -149,7 +150,9 @@ class File(BaseModel):
|
|
|
149
150
|
|
|
150
151
|
fdata = FileData(data, content_type, file_name)
|
|
151
152
|
|
|
152
|
-
object_lifecycle_preference =
|
|
153
|
+
object_lifecycle_preference = (
|
|
154
|
+
request_lifecycle_repference(request) or LIFECYCLE_PREFERENCE.get()
|
|
155
|
+
)
|
|
153
156
|
|
|
154
157
|
try:
|
|
155
158
|
url = repo.save(fdata, object_lifecycle_preference, **save_kwargs)
|
|
@@ -203,7 +206,9 @@ class File(BaseModel):
|
|
|
203
206
|
fallback_save_kwargs = fallback_save_kwargs or {}
|
|
204
207
|
|
|
205
208
|
content_type = content_type or "application/octet-stream"
|
|
206
|
-
object_lifecycle_preference =
|
|
209
|
+
object_lifecycle_preference = (
|
|
210
|
+
request_lifecycle_repference(request) or LIFECYCLE_PREFERENCE.get()
|
|
211
|
+
)
|
|
207
212
|
|
|
208
213
|
try:
|
|
209
214
|
url, data = repo.save_file(
|
|
@@ -288,21 +293,18 @@ class CompressedFile(File):
|
|
|
288
293
|
shutil.rmtree(self.extract_dir)
|
|
289
294
|
|
|
290
295
|
|
|
291
|
-
def
|
|
296
|
+
def request_lifecycle_repference(request: Optional[Request]) -> dict[str, str] | None:
|
|
292
297
|
import json
|
|
293
298
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
)
|
|
299
|
+
if request is None:
|
|
300
|
+
return None
|
|
301
|
+
|
|
302
|
+
preference_str = request.headers.get(OBJECT_LIFECYCLE_PREFERENCE_KEY)
|
|
299
303
|
if preference_str is None:
|
|
300
304
|
return None
|
|
301
305
|
|
|
302
|
-
object_lifecycle_preference = {}
|
|
303
306
|
try:
|
|
304
|
-
|
|
305
|
-
return object_lifecycle_preference
|
|
307
|
+
return json.loads(preference_str)
|
|
306
308
|
except Exception as e:
|
|
307
309
|
print(f"Failed to parse object lifecycle preference: {e}")
|
|
308
310
|
return None
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import dataclasses
|
|
4
3
|
import json
|
|
5
4
|
import math
|
|
6
5
|
import os
|
|
@@ -9,6 +8,7 @@ from base64 import b64encode
|
|
|
9
8
|
from dataclasses import dataclass
|
|
10
9
|
from datetime import datetime, timezone
|
|
11
10
|
from pathlib import Path
|
|
11
|
+
from typing import Generic, TypeVar
|
|
12
12
|
from urllib.error import HTTPError
|
|
13
13
|
from urllib.parse import urlparse, urlunparse
|
|
14
14
|
from urllib.request import Request, urlopen
|
|
@@ -105,14 +105,21 @@ fal_v2_token_manager = FalV2TokenManager()
|
|
|
105
105
|
fal_v3_token_manager = FalV3TokenManager()
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
VariableType = TypeVar("VariableType")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class VariableReference(Generic[VariableType]):
|
|
112
|
+
def __init__(self, value: VariableType) -> None:
|
|
113
|
+
self.set(value)
|
|
111
114
|
|
|
115
|
+
def get(self) -> VariableType:
|
|
116
|
+
return self.value
|
|
112
117
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
def set(self, value: VariableType) -> None:
|
|
119
|
+
self.value = value
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
LIFECYCLE_PREFERENCE: VariableReference[dict[str, str] | None] = VariableReference(None)
|
|
116
123
|
|
|
117
124
|
|
|
118
125
|
@dataclass
|
|
@@ -298,7 +305,7 @@ class MultipartUpload:
|
|
|
298
305
|
return self._file_url
|
|
299
306
|
|
|
300
307
|
|
|
301
|
-
class
|
|
308
|
+
class InternalMultipartUploadV3:
|
|
302
309
|
MULTIPART_THRESHOLD = 100 * 1024 * 1024
|
|
303
310
|
MULTIPART_CHUNK_SIZE = 10 * 1024 * 1024
|
|
304
311
|
MULTIPART_MAX_CONCURRENCY = 10
|
|
@@ -314,11 +321,23 @@ class MultipartUploadV3:
|
|
|
314
321
|
self.chunk_size = chunk_size or self.MULTIPART_CHUNK_SIZE
|
|
315
322
|
self.content_type = content_type or "application/octet-stream"
|
|
316
323
|
self.max_concurrency = max_concurrency or self.MULTIPART_MAX_CONCURRENCY
|
|
317
|
-
self.
|
|
318
|
-
self.
|
|
324
|
+
self._access_url: str | None = None
|
|
325
|
+
self._upload_id: str | None = None
|
|
319
326
|
|
|
320
327
|
self._parts: list[dict] = []
|
|
321
328
|
|
|
329
|
+
@property
|
|
330
|
+
def access_url(self) -> str:
|
|
331
|
+
if not self._access_url:
|
|
332
|
+
raise FileUploadException("Upload not initiated")
|
|
333
|
+
return self._access_url
|
|
334
|
+
|
|
335
|
+
@property
|
|
336
|
+
def upload_id(self) -> str:
|
|
337
|
+
if not self._upload_id:
|
|
338
|
+
raise FileUploadException("Upload not initiated")
|
|
339
|
+
return self._upload_id
|
|
340
|
+
|
|
322
341
|
@property
|
|
323
342
|
def auth_headers(self) -> dict[str, str]:
|
|
324
343
|
token = fal_v3_token_manager.get_token()
|
|
@@ -342,8 +361,9 @@ class MultipartUploadV3:
|
|
|
342
361
|
)
|
|
343
362
|
with urlopen(req) as response:
|
|
344
363
|
result = json.load(response)
|
|
345
|
-
self.
|
|
346
|
-
self.
|
|
364
|
+
self._access_url = result["access_url"]
|
|
365
|
+
self._upload_id = result["uploadId"]
|
|
366
|
+
|
|
347
367
|
except HTTPError as exc:
|
|
348
368
|
raise FileUploadException(
|
|
349
369
|
f"Error initiating upload. Status {exc.status}: {exc.reason}"
|
|
@@ -397,7 +417,7 @@ class MultipartUploadV3:
|
|
|
397
417
|
entry = future.result()
|
|
398
418
|
self._parts.append(entry)
|
|
399
419
|
|
|
400
|
-
def complete(self):
|
|
420
|
+
def complete(self) -> str:
|
|
401
421
|
url = f"{self.access_url}/multipart/{self.upload_id}/complete"
|
|
402
422
|
try:
|
|
403
423
|
req = Request(
|
|
@@ -515,6 +535,16 @@ class InMemoryRepository(FileRepository):
|
|
|
515
535
|
|
|
516
536
|
@dataclass
|
|
517
537
|
class FalCDNFileRepository(FileRepository):
|
|
538
|
+
def _object_lifecycle_headers(
|
|
539
|
+
self,
|
|
540
|
+
headers: dict[str, str],
|
|
541
|
+
object_lifecycle_preference: dict[str, str] | None,
|
|
542
|
+
):
|
|
543
|
+
if object_lifecycle_preference:
|
|
544
|
+
headers["X-Fal-Object-Lifecycle-Preference"] = json.dumps(
|
|
545
|
+
object_lifecycle_preference
|
|
546
|
+
)
|
|
547
|
+
|
|
518
548
|
@retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
|
|
519
549
|
def save(
|
|
520
550
|
self,
|
|
@@ -526,10 +556,10 @@ class FalCDNFileRepository(FileRepository):
|
|
|
526
556
|
"Accept": "application/json",
|
|
527
557
|
"Content-Type": file.content_type,
|
|
528
558
|
"X-Fal-File-Name": file.file_name,
|
|
529
|
-
"X-Fal-Object-Lifecycle-Preference": json.dumps(
|
|
530
|
-
dataclasses.asdict(GLOBAL_LIFECYCLE_PREFERENCE)
|
|
531
|
-
),
|
|
532
559
|
}
|
|
560
|
+
|
|
561
|
+
self._object_lifecycle_headers(headers, object_lifecycle_preference)
|
|
562
|
+
|
|
533
563
|
url = os.getenv("FAL_CDN_HOST", _FAL_CDN) + "/files/upload"
|
|
534
564
|
request = Request(url, headers=headers, method="POST", data=file.data)
|
|
535
565
|
try:
|
|
@@ -565,26 +595,27 @@ class InternalFalFileRepositoryV3(FileRepository):
|
|
|
565
595
|
That way it can avoid the need to refresh the token for every upload.
|
|
566
596
|
"""
|
|
567
597
|
|
|
598
|
+
def _object_lifecycle_headers(
|
|
599
|
+
self,
|
|
600
|
+
headers: dict[str, str],
|
|
601
|
+
object_lifecycle_preference: dict[str, str] | None,
|
|
602
|
+
):
|
|
603
|
+
if object_lifecycle_preference:
|
|
604
|
+
headers["X-Fal-Object-Lifecycle"] = json.dumps(object_lifecycle_preference)
|
|
605
|
+
|
|
568
606
|
@retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
|
|
569
607
|
def save(
|
|
570
608
|
self, file: FileData, object_lifecycle_preference: dict[str, str] | None
|
|
571
609
|
) -> str:
|
|
572
|
-
lifecycle = dataclasses.asdict(GLOBAL_LIFECYCLE_PREFERENCE)
|
|
573
|
-
if object_lifecycle_preference is not None:
|
|
574
|
-
lifecycle = {
|
|
575
|
-
key: object_lifecycle_preference[key]
|
|
576
|
-
if key in object_lifecycle_preference
|
|
577
|
-
else value
|
|
578
|
-
for key, value in lifecycle.items()
|
|
579
|
-
}
|
|
580
|
-
|
|
581
610
|
headers = {
|
|
582
611
|
**self.auth_headers,
|
|
583
612
|
"Accept": "application/json",
|
|
584
613
|
"Content-Type": file.content_type,
|
|
585
614
|
"X-Fal-File-Name": file.file_name,
|
|
586
|
-
"X-Fal-Object-Lifecycle-Preference": json.dumps(lifecycle),
|
|
587
615
|
}
|
|
616
|
+
|
|
617
|
+
self._object_lifecycle_headers(headers, object_lifecycle_preference)
|
|
618
|
+
|
|
588
619
|
url = os.getenv("FAL_CDN_V3_HOST", _FAL_CDN_V3) + "/files/upload"
|
|
589
620
|
request = Request(url, headers=headers, method="POST", data=file.data)
|
|
590
621
|
try:
|
|
@@ -613,7 +644,7 @@ class InternalFalFileRepositoryV3(FileRepository):
|
|
|
613
644
|
content_type: str | None = None,
|
|
614
645
|
max_concurrency: int | None = None,
|
|
615
646
|
) -> str:
|
|
616
|
-
multipart =
|
|
647
|
+
multipart = InternalMultipartUploadV3(
|
|
617
648
|
file_path,
|
|
618
649
|
chunk_size=chunk_size,
|
|
619
650
|
content_type=content_type,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.16 → fal-1.5.17}/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.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/comfy/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
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py
RENAMED
|
File without changes
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py
RENAMED
|
File without changes
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.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.5.16 → fal-1.5.17}/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.16 → fal-1.5.17}/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.16 → fal-1.5.17}/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.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py
RENAMED
|
File without changes
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py
RENAMED
|
File without changes
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.5.16 → fal-1.5.17}/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
|
{fal-1.5.16 → fal-1.5.17}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|