modal 1.2.5.dev14__tar.gz → 1.2.5.dev16__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.
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/PKG-INFO +1 -1
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_functions.py +2 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_partial_function.py +1 -2
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/user_code_imports.py +6 -1
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/function_utils.py +7 -10
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/app.py +7 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/client.pyi +2 -2
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/experimental/flash.py +43 -4
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/experimental/flash.pyi +20 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/functions.pyi +6 -6
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_version/__init__.py +1 -1
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/LICENSE +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/README.md +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/__main__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_billing.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_clustered_functions.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_container_entrypoint.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_grpc_client.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_ipython.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_load_context.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_location.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_object.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_output.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_pty.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_resolver.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_resources.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_serialization.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_traceback.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_tunnel.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_tunnel.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_type_manager.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/blob_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/logger.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/package_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/_watcher.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/app.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/billing.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/2025.06.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/README.md +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/builder/base-images.json +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/call_graph.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/_download.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/_traceback.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/app.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/cluster.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/config.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/container.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/dict.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/entry_point.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/environment.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/import_refs.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/launch.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/network_file_system.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/profile.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/queues.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/run.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/secret.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/shell.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/token.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/utils.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cli/volume.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/client.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cls.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/cls.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/config.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/container_process.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/container_process.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/dict.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/dict.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/environments.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/environments.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/exception.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/experimental/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/experimental/ipython.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/file_io.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/file_io.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/functions.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/gpu.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/image.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/image.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/io_streams.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/io_streams.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/mount.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/mount.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/network_file_system.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/network_file_system.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/object.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/object.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/output.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/parallel_map.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/parallel_map.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/partial_function.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/partial_function.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/proxy.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/proxy.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/py.typed +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/queue.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/queue.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/retries.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/runner.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/runner.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/running_app.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/sandbox.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/sandbox.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/schedule.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/scheduler_placement.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/secret.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/secret.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/serving.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/serving.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/snapshot.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/snapshot.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/stream_type.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/token_flow.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/token_flow.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/volume.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal/volume.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal.egg-info/requires.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_docs/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/__init__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/api.proto +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/api_pb2.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/py.typed +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/sandbox_router.proto +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/sandbox_router_grpc.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/sandbox_router_pb2.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/sandbox_router_pb2.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/sandbox_router_pb2_grpc.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/sandbox_router_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/task_command_router.proto +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/modal_version/__main__.py +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/pyproject.toml +0 -0
- {modal-1.2.5.dev14 → modal-1.2.5.dev16}/setup.cfg +0 -0
|
@@ -988,6 +988,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
988
988
|
function_definition = api_pb2.Function(
|
|
989
989
|
module_name=info.module_name or "",
|
|
990
990
|
function_name=info.function_name,
|
|
991
|
+
implementation_name=info.implementation_name,
|
|
991
992
|
mount_ids=loaded_mount_ids,
|
|
992
993
|
secret_ids=[secret.object_id for secret in secrets],
|
|
993
994
|
image_id=(image.object_id if image else ""),
|
|
@@ -1054,6 +1055,7 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1054
1055
|
function_data = api_pb2.FunctionData(
|
|
1055
1056
|
module_name=function_definition.module_name,
|
|
1056
1057
|
function_name=function_definition.function_name,
|
|
1058
|
+
implementation_name=function_definition.implementation_name,
|
|
1057
1059
|
function_type=function_definition.function_type,
|
|
1058
1060
|
warm_pool_size=function_definition.warm_pool_size,
|
|
1059
1061
|
concurrency_limit=function_definition.concurrency_limit,
|
|
@@ -160,9 +160,8 @@ class _PartialFunction(typing.Generic[P, ReturnType, OriginalReturnType]):
|
|
|
160
160
|
raise InvalidError("Interface decorators cannot be combined with lifecycle decorators.")
|
|
161
161
|
|
|
162
162
|
has_web_interface = self.flags & _PartialFunctionFlags.WEB_INTERFACE
|
|
163
|
-
has_http_web_interface = self.flags & _PartialFunctionFlags.HTTP_WEB_INTERFACE
|
|
164
163
|
has_callable_interface = self.flags & _PartialFunctionFlags.CALLABLE_INTERFACE
|
|
165
|
-
if
|
|
164
|
+
if has_web_interface and has_callable_interface:
|
|
166
165
|
self.registered = True # Hacky, avoid false-positive warning
|
|
167
166
|
raise InvalidError("Callable decorators cannot be combined with web interface decorators.")
|
|
168
167
|
|
|
@@ -30,6 +30,7 @@ from modal._utils.function_utils import (
|
|
|
30
30
|
from modal.app import _App
|
|
31
31
|
from modal.config import logger
|
|
32
32
|
from modal.exception import ExecutionError, InvalidError
|
|
33
|
+
from modal.experimental.flash import _FlashContainerEntry
|
|
33
34
|
from modal_proto import api_pb2
|
|
34
35
|
|
|
35
36
|
if typing.TYPE_CHECKING:
|
|
@@ -392,18 +393,22 @@ class ImportedClass(Service):
|
|
|
392
393
|
event_loop: UserCodeEventLoop,
|
|
393
394
|
container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager",
|
|
394
395
|
):
|
|
396
|
+
flash_entry = _FlashContainerEntry(self.function_def.http_config)
|
|
395
397
|
# Identify the "enter" methods to run after resuming from a snapshot.
|
|
396
398
|
if not self.function_def.is_auto_snapshot:
|
|
397
399
|
post_snapshot_methods = _find_callables_for_obj(
|
|
398
400
|
self.user_cls_instance, _PartialFunctionFlags.ENTER_POST_SNAPSHOT
|
|
399
401
|
)
|
|
400
402
|
call_lifecycle_functions(event_loop, container_io_manager, list(post_snapshot_methods.values()))
|
|
403
|
+
flash_entry.enter()
|
|
401
404
|
try:
|
|
402
405
|
yield
|
|
403
406
|
finally:
|
|
404
407
|
if not self.function_def.is_auto_snapshot:
|
|
408
|
+
flash_entry.stop()
|
|
405
409
|
exit_methods = _find_callables_for_obj(self.user_cls_instance, _PartialFunctionFlags.EXIT)
|
|
406
410
|
call_lifecycle_functions(event_loop, container_io_manager, list(exit_methods.values()))
|
|
411
|
+
flash_entry.close()
|
|
407
412
|
|
|
408
413
|
|
|
409
414
|
def get_user_class_instance(_cls: modal.cls._Cls, args: tuple[Any, ...], kwargs: dict[str, Any]) -> typing.Any:
|
|
@@ -460,7 +465,7 @@ def import_single_function_service(
|
|
|
460
465
|
else:
|
|
461
466
|
# Load the module dynamically
|
|
462
467
|
module = importlib.import_module(function_def.module_name)
|
|
463
|
-
qual_name: str = function_def.
|
|
468
|
+
qual_name: str = function_def.implementation_name
|
|
464
469
|
|
|
465
470
|
if not is_global_object(qual_name):
|
|
466
471
|
raise LocalFunctionError("Attempted to load a function defined in a function scope")
|
|
@@ -129,6 +129,7 @@ class FunctionInfo:
|
|
|
129
129
|
|
|
130
130
|
raw_f: Optional[Callable[..., Any]] # if None - this is a "class service function"
|
|
131
131
|
function_name: str
|
|
132
|
+
implementation_name: str
|
|
132
133
|
user_cls: Optional[type[Any]]
|
|
133
134
|
module_name: Optional[str]
|
|
134
135
|
|
|
@@ -160,20 +161,16 @@ class FunctionInfo:
|
|
|
160
161
|
self.raw_f = f
|
|
161
162
|
self.user_cls = user_cls
|
|
162
163
|
|
|
163
|
-
if
|
|
164
|
-
if not serialized:
|
|
165
|
-
# We may relax this constraint in the future, but currently we don't track the distinction between
|
|
166
|
-
# the Function's name inside modal and the name of the object that we need to import in a container.
|
|
167
|
-
raise InvalidError("Setting a custom `name=` also requires setting `serialized=True`")
|
|
168
|
-
self.function_name = name_override
|
|
169
|
-
elif f is None and user_cls:
|
|
164
|
+
if f is None and user_cls:
|
|
170
165
|
# "service function" for running all methods of a class
|
|
171
|
-
self.
|
|
166
|
+
self.implementation_name = f"{user_cls.__name__}.*"
|
|
172
167
|
elif f and user_cls:
|
|
173
168
|
# Method may be defined on superclass of the wrapped class
|
|
174
|
-
self.
|
|
169
|
+
self.implementation_name = f"{user_cls.__name__}.{f.__name__}"
|
|
175
170
|
else:
|
|
176
|
-
self.
|
|
171
|
+
self.implementation_name = f.__qualname__
|
|
172
|
+
|
|
173
|
+
self.function_name = name_override or self.implementation_name
|
|
177
174
|
|
|
178
175
|
# If it's a cls, the @method could be defined in a base class in a different file.
|
|
179
176
|
if user_cls is not None:
|
|
@@ -1098,6 +1098,13 @@ class _App:
|
|
|
1098
1098
|
"The `@modal.http_server` decorator cannot be used on methods; decorate the class instead."
|
|
1099
1099
|
)
|
|
1100
1100
|
|
|
1101
|
+
if http_config is not None:
|
|
1102
|
+
for method in _find_partial_methods_for_user_cls(
|
|
1103
|
+
user_cls, _PartialFunctionFlags.CALLABLE_INTERFACE
|
|
1104
|
+
).values():
|
|
1105
|
+
method.registered = True # Avoid warning about not registering the method (hacky!)
|
|
1106
|
+
raise InvalidError("Callable decorators cannot be combined with web interface decorators.")
|
|
1107
|
+
|
|
1101
1108
|
info = FunctionInfo(None, serialized=serialized, user_cls=user_cls)
|
|
1102
1109
|
|
|
1103
1110
|
i6pn_enabled = i6pn or cluster_size is not None
|
|
@@ -32,7 +32,7 @@ class _Client:
|
|
|
32
32
|
server_url: str,
|
|
33
33
|
client_type: int,
|
|
34
34
|
credentials: typing.Optional[tuple[str, str]],
|
|
35
|
-
version: str = "1.2.5.
|
|
35
|
+
version: str = "1.2.5.dev16",
|
|
36
36
|
):
|
|
37
37
|
"""mdmd:hidden
|
|
38
38
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -163,7 +163,7 @@ class Client:
|
|
|
163
163
|
server_url: str,
|
|
164
164
|
client_type: int,
|
|
165
165
|
credentials: typing.Optional[tuple[str, str]],
|
|
166
|
-
version: str = "1.2.5.
|
|
166
|
+
version: str = "1.2.5.dev16",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -32,6 +32,7 @@ class _FlashManager:
|
|
|
32
32
|
process: Optional[subprocess.Popen] = None, # to be deprecated
|
|
33
33
|
health_check_url: Optional[str] = None,
|
|
34
34
|
startup_timeout: int = 30,
|
|
35
|
+
exit_grace_period: int = 0,
|
|
35
36
|
h2_enabled: bool = False,
|
|
36
37
|
):
|
|
37
38
|
self.client = client
|
|
@@ -40,6 +41,7 @@ class _FlashManager:
|
|
|
40
41
|
# Health check is not currently being used
|
|
41
42
|
self.health_check_url = health_check_url
|
|
42
43
|
self.startup_timeout = startup_timeout
|
|
44
|
+
self.exit_grace_period = exit_grace_period
|
|
43
45
|
self.tunnel_manager = _forward_tunnel(port, h2_enabled=h2_enabled, client=client)
|
|
44
46
|
self.stopped = False
|
|
45
47
|
self.num_failures = 0
|
|
@@ -158,9 +160,12 @@ class _FlashManager:
|
|
|
158
160
|
return self.tunnel.url
|
|
159
161
|
|
|
160
162
|
async def stop(self):
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
try:
|
|
164
|
+
self.heartbeat_task.cancel()
|
|
165
|
+
except Exception as e:
|
|
166
|
+
logger.error(f"[Modal Flash] Error stopping: {e}")
|
|
163
167
|
|
|
168
|
+
await self.client.stub.FlashContainerDeregister(api_pb2.FlashContainerDeregisterRequest())
|
|
164
169
|
self.stopped = True
|
|
165
170
|
logger.warning(f"[Modal Flash] No longer accepting new requests on {self.tunnel.url}.")
|
|
166
171
|
|
|
@@ -171,19 +176,22 @@ class _FlashManager:
|
|
|
171
176
|
if not self.stopped:
|
|
172
177
|
await self.stop()
|
|
173
178
|
|
|
179
|
+
await asyncio.sleep(self.exit_grace_period)
|
|
180
|
+
|
|
174
181
|
logger.warning(f"[Modal Flash] Closing tunnel on {self.tunnel.url}.")
|
|
175
182
|
await self.tunnel_manager.__aexit__(*sys.exc_info())
|
|
176
183
|
|
|
177
184
|
|
|
178
|
-
FlashManager = synchronize_api(_FlashManager)
|
|
185
|
+
FlashManager = synchronize_api(_FlashManager, target_module=__name__)
|
|
179
186
|
|
|
180
187
|
|
|
181
188
|
@synchronizer.create_blocking
|
|
182
189
|
async def flash_forward(
|
|
183
190
|
port: int,
|
|
184
|
-
process: Optional[subprocess.Popen] = None,
|
|
191
|
+
process: Optional[subprocess.Popen] = None, # to be deprecated
|
|
185
192
|
health_check_url: Optional[str] = None,
|
|
186
193
|
startup_timeout: int = 30,
|
|
194
|
+
exit_grace_period: int = 0,
|
|
187
195
|
h2_enabled: bool = False,
|
|
188
196
|
) -> _FlashManager:
|
|
189
197
|
"""
|
|
@@ -199,6 +207,7 @@ async def flash_forward(
|
|
|
199
207
|
process=process,
|
|
200
208
|
health_check_url=health_check_url,
|
|
201
209
|
startup_timeout=startup_timeout,
|
|
210
|
+
exit_grace_period=exit_grace_period,
|
|
202
211
|
h2_enabled=h2_enabled,
|
|
203
212
|
)
|
|
204
213
|
await manager._start()
|
|
@@ -692,3 +701,33 @@ def _http_server(
|
|
|
692
701
|
|
|
693
702
|
|
|
694
703
|
http_server = synchronize_api(_http_server, target_module=__name__)
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
class _FlashContainerEntry:
|
|
707
|
+
"""
|
|
708
|
+
A class that manages the lifecycle of Flash manager for Flash containers.
|
|
709
|
+
|
|
710
|
+
It is intentional that stop() runs before exit handlers and close().
|
|
711
|
+
This ensures the container is deregistered first, preventing new requests from being routed to it
|
|
712
|
+
while exit handlers execute and the exit grace period elapses, before finally closing the tunnel.
|
|
713
|
+
"""
|
|
714
|
+
|
|
715
|
+
def __init__(self, http_config: api_pb2.HTTPConfig):
|
|
716
|
+
self.http_config: api_pb2.HTTPConfig = http_config
|
|
717
|
+
self.flash_manager: Optional[FlashManager] = None # type: ignore
|
|
718
|
+
|
|
719
|
+
def enter(self):
|
|
720
|
+
if self.http_config != api_pb2.HTTPConfig():
|
|
721
|
+
self.flash_manager = flash_forward(
|
|
722
|
+
self.http_config.port,
|
|
723
|
+
startup_timeout=self.http_config.startup_timeout,
|
|
724
|
+
exit_grace_period=self.http_config.exit_grace_period,
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
def stop(self):
|
|
728
|
+
if self.flash_manager:
|
|
729
|
+
self.flash_manager.stop()
|
|
730
|
+
|
|
731
|
+
def close(self):
|
|
732
|
+
if self.flash_manager:
|
|
733
|
+
self.flash_manager.close()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import modal.client
|
|
2
|
+
import modal_proto.api_pb2
|
|
2
3
|
import subprocess
|
|
3
4
|
import typing
|
|
4
5
|
import typing_extensions
|
|
@@ -11,6 +12,7 @@ class _FlashManager:
|
|
|
11
12
|
process: typing.Optional[subprocess.Popen] = None,
|
|
12
13
|
health_check_url: typing.Optional[str] = None,
|
|
13
14
|
startup_timeout: int = 30,
|
|
15
|
+
exit_grace_period: int = 0,
|
|
14
16
|
h2_enabled: bool = False,
|
|
15
17
|
):
|
|
16
18
|
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
@@ -39,6 +41,7 @@ class FlashManager:
|
|
|
39
41
|
process: typing.Optional[subprocess.Popen] = None,
|
|
40
42
|
health_check_url: typing.Optional[str] = None,
|
|
41
43
|
startup_timeout: int = 30,
|
|
44
|
+
exit_grace_period: int = 0,
|
|
42
45
|
h2_enabled: bool = False,
|
|
43
46
|
): ...
|
|
44
47
|
|
|
@@ -97,6 +100,7 @@ class __flash_forward_spec(typing_extensions.Protocol):
|
|
|
97
100
|
process: typing.Optional[subprocess.Popen] = None,
|
|
98
101
|
health_check_url: typing.Optional[str] = None,
|
|
99
102
|
startup_timeout: int = 30,
|
|
103
|
+
exit_grace_period: int = 0,
|
|
100
104
|
h2_enabled: bool = False,
|
|
101
105
|
) -> FlashManager:
|
|
102
106
|
"""Forward a port to the Modal Flash service, exposing that port as a stable web endpoint.
|
|
@@ -112,6 +116,7 @@ class __flash_forward_spec(typing_extensions.Protocol):
|
|
|
112
116
|
process: typing.Optional[subprocess.Popen] = None,
|
|
113
117
|
health_check_url: typing.Optional[str] = None,
|
|
114
118
|
startup_timeout: int = 30,
|
|
119
|
+
exit_grace_period: int = 0,
|
|
115
120
|
h2_enabled: bool = False,
|
|
116
121
|
) -> FlashManager:
|
|
117
122
|
"""Forward a port to the Modal Flash service, exposing that port as a stable web endpoint.
|
|
@@ -420,3 +425,18 @@ def http_server(
|
|
|
420
425
|
exit_grace_period: The time to wait for the HTTP server to exit gracefully.
|
|
421
426
|
"""
|
|
422
427
|
...
|
|
428
|
+
|
|
429
|
+
class _FlashContainerEntry:
|
|
430
|
+
"""A class that manages the lifecycle of Flash manager for Flash containers.
|
|
431
|
+
|
|
432
|
+
It is intentional that stop() runs before exit handlers and close().
|
|
433
|
+
This ensures the container is deregistered first, preventing new requests from being routed to it
|
|
434
|
+
while exit handlers execute and the exit grace period elapses, before finally closing the tunnel.
|
|
435
|
+
"""
|
|
436
|
+
def __init__(self, http_config: modal_proto.api_pb2.HTTPConfig):
|
|
437
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
438
|
+
...
|
|
439
|
+
|
|
440
|
+
def enter(self): ...
|
|
441
|
+
def stop(self): ...
|
|
442
|
+
def close(self): ...
|
|
@@ -409,7 +409,7 @@ class Function(
|
|
|
409
409
|
|
|
410
410
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
|
411
411
|
|
|
412
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
412
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
413
413
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
414
414
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
415
415
|
...
|
|
@@ -418,7 +418,7 @@ class Function(
|
|
|
418
418
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
|
419
419
|
...
|
|
420
420
|
|
|
421
|
-
remote: __remote_spec[modal._functions.
|
|
421
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
|
422
422
|
|
|
423
423
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
|
424
424
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -445,7 +445,7 @@ class Function(
|
|
|
445
445
|
"""
|
|
446
446
|
...
|
|
447
447
|
|
|
448
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
448
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
449
449
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
450
450
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
451
451
|
|
|
@@ -469,7 +469,7 @@ class Function(
|
|
|
469
469
|
...
|
|
470
470
|
|
|
471
471
|
_experimental_spawn: ___experimental_spawn_spec[
|
|
472
|
-
modal._functions.
|
|
472
|
+
modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
|
|
473
473
|
]
|
|
474
474
|
|
|
475
475
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
|
@@ -478,7 +478,7 @@ class Function(
|
|
|
478
478
|
|
|
479
479
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
|
480
480
|
|
|
481
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
481
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
|
482
482
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
483
483
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
484
484
|
|
|
@@ -499,7 +499,7 @@ class Function(
|
|
|
499
499
|
"""
|
|
500
500
|
...
|
|
501
501
|
|
|
502
|
-
spawn: __spawn_spec[modal._functions.
|
|
502
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
|
503
503
|
|
|
504
504
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
505
505
|
"""Return the inner Python object wrapped by this Modal Function."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|