modal 1.2.1.dev4__tar.gz → 1.2.1.dev6__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 modal might be problematic. Click here for more details.
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/PKG-INFO +1 -1
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_partial_function.py +6 -1
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/_download.py +19 -3
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/run.py +6 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/volume.py +7 -1
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/client.pyi +2 -2
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/config.py +12 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/volume.py +21 -3
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/volume.pyi +30 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/api.proto +0 -1
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_version/__init__.py +1 -1
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/LICENSE +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/README.md +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/__main__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_billing.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_clustered_functions.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_container_entrypoint.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_functions.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_ipython.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_location.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_object.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_output.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_pty.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_resolver.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_resources.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_serialization.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_traceback.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_tunnel.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_tunnel.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_type_manager.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/blob_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/function_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/logger.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/package_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/_watcher.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/app.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/app.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/billing.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/2025.06.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/README.md +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/builder/base-images.json +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/call_graph.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/_traceback.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/app.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/cluster.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/config.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/container.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/dict.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/entry_point.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/environment.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/import_refs.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/launch.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/network_file_system.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/profile.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/queues.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/secret.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/token.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cli/utils.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/client.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cls.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/cls.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/container_process.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/container_process.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/dict.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/dict.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/environments.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/environments.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/exception.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/experimental/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/experimental/flash.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/experimental/flash.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/experimental/ipython.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/file_io.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/file_io.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/functions.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/functions.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/gpu.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/image.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/image.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/io_streams.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/io_streams.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/mount.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/mount.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/network_file_system.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/network_file_system.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/object.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/object.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/output.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/parallel_map.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/parallel_map.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/partial_function.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/partial_function.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/proxy.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/proxy.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/py.typed +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/queue.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/queue.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/retries.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/runner.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/runner.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/running_app.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/sandbox.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/sandbox.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/schedule.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/scheduler_placement.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/secret.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/secret.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/serving.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/serving.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/snapshot.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/snapshot.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/stream_type.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/token_flow.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal/token_flow.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal.egg-info/requires.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_docs/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/__init__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/api_pb2.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/py.typed +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/sandbox_router.proto +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/sandbox_router_grpc.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/sandbox_router_pb2.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/sandbox_router_pb2.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/task_command_router.proto +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/modal_version/__main__.py +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/pyproject.toml +0 -0
- {modal-1.2.1.dev4 → modal-1.2.1.dev6}/setup.cfg +0 -0
|
@@ -19,7 +19,7 @@ from ._functions import _Function
|
|
|
19
19
|
from ._utils.async_utils import synchronizer
|
|
20
20
|
from ._utils.deprecation import deprecation_warning
|
|
21
21
|
from ._utils.function_utils import callable_has_non_self_params
|
|
22
|
-
from .config import logger
|
|
22
|
+
from .config import config, logger
|
|
23
23
|
from .exception import InvalidError
|
|
24
24
|
|
|
25
25
|
MAX_MAX_BATCH_SIZE = 1000
|
|
@@ -378,6 +378,7 @@ def _fastapi_endpoint(
|
|
|
378
378
|
method=method,
|
|
379
379
|
web_endpoint_docs=docs,
|
|
380
380
|
requested_suffix=label or "",
|
|
381
|
+
ephemeral_suffix=config.get("dev_suffix"),
|
|
381
382
|
async_mode=api_pb2.WEBHOOK_ASYNC_MODE_AUTO,
|
|
382
383
|
custom_domains=_parse_custom_domains(custom_domains),
|
|
383
384
|
requires_proxy_auth=requires_proxy_auth,
|
|
@@ -446,6 +447,7 @@ def _web_endpoint(
|
|
|
446
447
|
method=method,
|
|
447
448
|
web_endpoint_docs=docs,
|
|
448
449
|
requested_suffix=label or "",
|
|
450
|
+
ephemeral_suffix=config.get("dev_suffix"),
|
|
449
451
|
async_mode=api_pb2.WEBHOOK_ASYNC_MODE_AUTO,
|
|
450
452
|
custom_domains=_parse_custom_domains(custom_domains),
|
|
451
453
|
requires_proxy_auth=requires_proxy_auth,
|
|
@@ -505,6 +507,7 @@ def _asgi_app(
|
|
|
505
507
|
webhook_config = api_pb2.WebhookConfig(
|
|
506
508
|
type=api_pb2.WEBHOOK_TYPE_ASGI_APP,
|
|
507
509
|
requested_suffix=label or "",
|
|
510
|
+
ephemeral_suffix=config.get("dev_suffix"),
|
|
508
511
|
async_mode=api_pb2.WEBHOOK_ASYNC_MODE_AUTO,
|
|
509
512
|
custom_domains=_parse_custom_domains(custom_domains),
|
|
510
513
|
requires_proxy_auth=requires_proxy_auth,
|
|
@@ -562,6 +565,7 @@ def _wsgi_app(
|
|
|
562
565
|
webhook_config = api_pb2.WebhookConfig(
|
|
563
566
|
type=api_pb2.WEBHOOK_TYPE_WSGI_APP,
|
|
564
567
|
requested_suffix=label or "",
|
|
568
|
+
ephemeral_suffix=config.get("dev_suffix"),
|
|
565
569
|
async_mode=api_pb2.WEBHOOK_ASYNC_MODE_AUTO,
|
|
566
570
|
custom_domains=_parse_custom_domains(custom_domains),
|
|
567
571
|
requires_proxy_auth=requires_proxy_auth,
|
|
@@ -623,6 +627,7 @@ def _web_server(
|
|
|
623
627
|
webhook_config = api_pb2.WebhookConfig(
|
|
624
628
|
type=api_pb2.WEBHOOK_TYPE_WEB_SERVER,
|
|
625
629
|
requested_suffix=label or "",
|
|
630
|
+
ephemeral_suffix=config.get("dev_suffix"),
|
|
626
631
|
async_mode=api_pb2.WEBHOOK_ASYNC_MODE_AUTO,
|
|
627
632
|
custom_domains=_parse_custom_domains(custom_domains),
|
|
628
633
|
web_server_port=port,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Copyright Modal Labs 2023
|
|
2
2
|
import asyncio
|
|
3
3
|
import functools
|
|
4
|
+
import multiprocessing
|
|
4
5
|
import os
|
|
5
6
|
import shutil
|
|
6
7
|
import sys
|
|
@@ -23,12 +24,22 @@ async def _volume_download(
|
|
|
23
24
|
remote_path: str,
|
|
24
25
|
local_destination: Path,
|
|
25
26
|
overwrite: bool,
|
|
26
|
-
|
|
27
|
+
concurrency: Optional[int] = None,
|
|
28
|
+
progress_cb: Optional[Callable] = None,
|
|
27
29
|
):
|
|
30
|
+
if progress_cb is None:
|
|
31
|
+
|
|
32
|
+
def progress_cb(*_, **__):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
if concurrency is None:
|
|
36
|
+
concurrency = max(128, 2 * multiprocessing.cpu_count())
|
|
37
|
+
|
|
28
38
|
is_pipe = local_destination == PIPE_PATH
|
|
29
39
|
|
|
30
40
|
q: asyncio.Queue[tuple[Optional[Path], Optional[FileEntry]]] = asyncio.Queue()
|
|
31
|
-
num_consumers = 1 if is_pipe else
|
|
41
|
+
num_consumers = 1 if is_pipe else concurrency # concurrency limit for downloading files
|
|
42
|
+
download_semaphore = asyncio.Semaphore(concurrency)
|
|
32
43
|
|
|
33
44
|
async def producer():
|
|
34
45
|
iterator: AsyncIterator[FileEntry]
|
|
@@ -86,7 +97,12 @@ async def _volume_download(
|
|
|
86
97
|
|
|
87
98
|
with output_path.open("wb") as fp:
|
|
88
99
|
if isinstance(volume, _Volume):
|
|
89
|
-
b = await volume.
|
|
100
|
+
b = await volume._read_file_into_fileobj(
|
|
101
|
+
path=entry.path,
|
|
102
|
+
fileobj=fp,
|
|
103
|
+
download_semaphore=download_semaphore,
|
|
104
|
+
progress_cb=file_progress_cb,
|
|
105
|
+
)
|
|
90
106
|
else:
|
|
91
107
|
b = 0
|
|
92
108
|
async for chunk in volume.read_file(entry.path):
|
|
@@ -496,6 +496,12 @@ def serve(
|
|
|
496
496
|
```
|
|
497
497
|
modal serve hello_world.py
|
|
498
498
|
```
|
|
499
|
+
|
|
500
|
+
Modal-generated URLs will have a `-dev` suffix appended to them when running with `modal serve`.
|
|
501
|
+
To customize this suffix (i.e., to avoid collisions with other users in your workspace who are
|
|
502
|
+
concurrently serving the App), you can set the `dev_suffix` in your `.modal.toml` file or the
|
|
503
|
+
`MODAL_DEV_SUFFIX` environment variable.
|
|
504
|
+
|
|
499
505
|
"""
|
|
500
506
|
env = ensure_env(env)
|
|
501
507
|
import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode)
|
|
@@ -96,7 +96,13 @@ async def get(
|
|
|
96
96
|
console = make_console()
|
|
97
97
|
progress_handler = ProgressHandler(type="download", console=console)
|
|
98
98
|
with progress_handler.live:
|
|
99
|
-
await _volume_download(
|
|
99
|
+
await _volume_download(
|
|
100
|
+
volume=volume,
|
|
101
|
+
remote_path=remote_path,
|
|
102
|
+
local_destination=destination,
|
|
103
|
+
overwrite=force,
|
|
104
|
+
progress_cb=progress_handler.progress,
|
|
105
|
+
)
|
|
100
106
|
console.print(OutputManager.step_completed("Finished downloading files to local!"))
|
|
101
107
|
|
|
102
108
|
|
|
@@ -33,7 +33,7 @@ class _Client:
|
|
|
33
33
|
server_url: str,
|
|
34
34
|
client_type: int,
|
|
35
35
|
credentials: typing.Optional[tuple[str, str]],
|
|
36
|
-
version: str = "1.2.1.
|
|
36
|
+
version: str = "1.2.1.dev6",
|
|
37
37
|
):
|
|
38
38
|
"""mdmd:hidden
|
|
39
39
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -164,7 +164,7 @@ class Client:
|
|
|
164
164
|
server_url: str,
|
|
165
165
|
client_type: int,
|
|
166
166
|
credentials: typing.Optional[tuple[str, str]],
|
|
167
|
-
version: str = "1.2.1.
|
|
167
|
+
version: str = "1.2.1.dev6",
|
|
168
168
|
):
|
|
169
169
|
"""mdmd:hidden
|
|
170
170
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -71,6 +71,10 @@ Other possible configuration options are:
|
|
|
71
71
|
The log formatting pattern that will be used by the modal client itself.
|
|
72
72
|
See https://docs.python.org/3/library/logging.html#logrecord-attributes for available
|
|
73
73
|
log attributes.
|
|
74
|
+
* `dev_suffix` (in the .toml file) / `MODAL_DEV_SUFFIX` (as an env var).
|
|
75
|
+
Overrides the default `-dev` suffix added to URLs generated for web endpoints
|
|
76
|
+
when the App is ephemeral (i.e., created via `modal serve`). Must be a short
|
|
77
|
+
alphanumeric string.
|
|
74
78
|
|
|
75
79
|
Meta-configuration
|
|
76
80
|
------------------
|
|
@@ -85,6 +89,7 @@ Some "meta-options" are set using environment variables only:
|
|
|
85
89
|
|
|
86
90
|
import logging
|
|
87
91
|
import os
|
|
92
|
+
import re
|
|
88
93
|
import typing
|
|
89
94
|
import warnings
|
|
90
95
|
from typing import Any, Callable, Optional
|
|
@@ -206,6 +211,12 @@ def _check_value(options: list[str]) -> Callable[[str], str]:
|
|
|
206
211
|
return checker
|
|
207
212
|
|
|
208
213
|
|
|
214
|
+
def _enforce_suffix_rules(x: str) -> str:
|
|
215
|
+
if x and not re.match(r"^[a-zA-Z0-9]{1,8}$", x):
|
|
216
|
+
raise ValueError("Suffix must be an alphanumeric string of no more than 8 characters.")
|
|
217
|
+
return x
|
|
218
|
+
|
|
219
|
+
|
|
209
220
|
class _Setting(typing.NamedTuple):
|
|
210
221
|
default: typing.Any = None
|
|
211
222
|
transform: typing.Callable[[str], typing.Any] = lambda x: x # noqa: E731
|
|
@@ -244,6 +255,7 @@ _SETTINGS = {
|
|
|
244
255
|
"pickle",
|
|
245
256
|
transform=lambda s: _check_value(["pickle", "cbor"])(s.lower()),
|
|
246
257
|
),
|
|
258
|
+
"dev_suffix": _Setting("", transform=_enforce_suffix_rules),
|
|
247
259
|
}
|
|
248
260
|
|
|
249
261
|
|
|
@@ -670,16 +670,33 @@ class _Volume(_Object, type_prefix="vo"):
|
|
|
670
670
|
|
|
671
671
|
@live_method
|
|
672
672
|
async def read_file_into_fileobj(
|
|
673
|
-
self,
|
|
673
|
+
self,
|
|
674
|
+
path: str,
|
|
675
|
+
fileobj: typing.IO[bytes],
|
|
676
|
+
progress_cb: Optional[Callable[..., Any]] = None,
|
|
674
677
|
) -> int:
|
|
675
678
|
"""mdmd:hidden
|
|
676
679
|
Read volume file into file-like IO object.
|
|
677
680
|
"""
|
|
681
|
+
return await self._read_file_into_fileobj(path, fileobj, progress_cb=progress_cb)
|
|
682
|
+
|
|
683
|
+
@live_method
|
|
684
|
+
async def _read_file_into_fileobj(
|
|
685
|
+
self,
|
|
686
|
+
path: str,
|
|
687
|
+
fileobj: typing.IO[bytes],
|
|
688
|
+
concurrency: Optional[int] = None,
|
|
689
|
+
download_semaphore: Optional[asyncio.Semaphore] = None,
|
|
690
|
+
progress_cb: Optional[Callable[..., Any]] = None,
|
|
691
|
+
) -> int:
|
|
678
692
|
if progress_cb is None:
|
|
679
693
|
|
|
680
694
|
def progress_cb(*_, **__):
|
|
681
695
|
pass
|
|
682
696
|
|
|
697
|
+
if concurrency is None:
|
|
698
|
+
concurrency = multiprocessing.cpu_count()
|
|
699
|
+
|
|
683
700
|
req = api_pb2.VolumeGetFile2Request(volume_id=self.object_id, path=path)
|
|
684
701
|
|
|
685
702
|
try:
|
|
@@ -687,8 +704,9 @@ class _Volume(_Object, type_prefix="vo"):
|
|
|
687
704
|
except modal.exception.NotFoundError as exc:
|
|
688
705
|
raise FileNotFoundError(exc.args[0])
|
|
689
706
|
|
|
690
|
-
|
|
691
|
-
|
|
707
|
+
if download_semaphore is None:
|
|
708
|
+
download_semaphore = asyncio.Semaphore(concurrency)
|
|
709
|
+
|
|
692
710
|
write_lock = asyncio.Lock()
|
|
693
711
|
start_pos = fileobj.tell()
|
|
694
712
|
|
|
@@ -626,6 +626,14 @@ class _Volume(modal._object._Object):
|
|
|
626
626
|
"""
|
|
627
627
|
...
|
|
628
628
|
|
|
629
|
+
async def _read_file_into_fileobj(
|
|
630
|
+
self,
|
|
631
|
+
path: str,
|
|
632
|
+
fileobj: typing.IO[bytes],
|
|
633
|
+
concurrency: typing.Optional[int] = None,
|
|
634
|
+
download_semaphore: typing.Optional[asyncio.locks.Semaphore] = None,
|
|
635
|
+
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
|
636
|
+
) -> int: ...
|
|
629
637
|
async def remove_file(self, path: str, recursive: bool = False) -> None:
|
|
630
638
|
"""Remove a file or directory from a volume."""
|
|
631
639
|
...
|
|
@@ -1065,6 +1073,28 @@ class Volume(modal.object.Object):
|
|
|
1065
1073
|
|
|
1066
1074
|
read_file_into_fileobj: __read_file_into_fileobj_spec[typing_extensions.Self]
|
|
1067
1075
|
|
|
1076
|
+
class ___read_file_into_fileobj_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
1077
|
+
def __call__(
|
|
1078
|
+
self,
|
|
1079
|
+
/,
|
|
1080
|
+
path: str,
|
|
1081
|
+
fileobj: typing.IO[bytes],
|
|
1082
|
+
concurrency: typing.Optional[int] = None,
|
|
1083
|
+
download_semaphore: typing.Optional[asyncio.locks.Semaphore] = None,
|
|
1084
|
+
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
|
1085
|
+
) -> int: ...
|
|
1086
|
+
async def aio(
|
|
1087
|
+
self,
|
|
1088
|
+
/,
|
|
1089
|
+
path: str,
|
|
1090
|
+
fileobj: typing.IO[bytes],
|
|
1091
|
+
concurrency: typing.Optional[int] = None,
|
|
1092
|
+
download_semaphore: typing.Optional[asyncio.locks.Semaphore] = None,
|
|
1093
|
+
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
|
1094
|
+
) -> int: ...
|
|
1095
|
+
|
|
1096
|
+
_read_file_into_fileobj: ___read_file_into_fileobj_spec[typing_extensions.Self]
|
|
1097
|
+
|
|
1068
1098
|
class __remove_file_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
1069
1099
|
def __call__(self, /, path: str, recursive: bool = False) -> None:
|
|
1070
1100
|
"""Remove a file or directory from a volume."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|