modal 1.4.4.dev17__tar.gz → 1.4.4.dev19__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.4.4.dev17 → modal-1.4.4.dev19}/PKG-INFO +1 -1
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_container_entrypoint.py +10 -12
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_function_variants.py +43 -1
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_functions.py +10 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_image.py +102 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/user_code_imports.py +2 -4
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/sandbox_fs_utils.py +47 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/billing.py +5 -1
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/client.pyi +2 -2
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/file_io.py +4 -19
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/file_io.pyi +9 -34
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/functions.pyi +6 -6
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/image.pyi +71 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/sandbox.py +15 -8
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/sandbox.pyi +21 -15
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/sandbox_fs.py +141 -1
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/sandbox_fs.pyi +196 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/api_grpc.py +32 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/api_pb2.py +621 -581
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/api_pb2.pyi +74 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/api_pb2_grpc.py +66 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/api_pb2_grpc.pyi +20 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/modal_api_grpc.py +2 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_version/__init__.py +1 -1
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/LICENSE +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/README.md +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/__main__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_billing.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_clustered_functions.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_clustered_functions.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_environments.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_grpc_client.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_ipython.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_load_context.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_location.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_logs.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_object.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_output/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_output/manager.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_output/pty.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_output/rich.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_output/status.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_partial_function.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_resolver.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_resources.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/asgi.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/execution_context.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/telemetry.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_serialization.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_server.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_traceback.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_tunnel.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_tunnel.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_type_manager.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/app_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/async_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/blob_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/browser_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/deprecation.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/docker_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/function_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/git_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/hash_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/http_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/logger.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/mount_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/name_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/package_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/shell_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_utils/time_utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_vendor/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_vendor/tblib.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_vendor/version.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_watcher.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/_workspace.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/app.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/app.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/2023.12.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/2024.04.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/2024.10.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/2025.06.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/README.md +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/builder/base-images.json +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/call_graph.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/_download.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/_help.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/_traceback.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/app.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/billing.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/bootstrap.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/changelog.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/cluster.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/config.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/container.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/dashboard.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/dict.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/entry_point.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/environment.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/import_refs.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/launch.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/logo.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/network_file_system.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/profile.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/programs/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/programs/vscode.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/queues.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/run.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/secret.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/selector.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/shell.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/skills.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/token.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/utils.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cli/volume.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/client.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cls.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/cls.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/config.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/container_process.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/container_process.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/dict.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/dict.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/environments.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/environments.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/exception.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/experimental/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/experimental/flash.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/experimental/flash.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/experimental/ipython.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/file_pattern_matcher.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/functions.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/image.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/io_streams.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/io_streams.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/mount.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/mount.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/network_file_system.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/network_file_system.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/object.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/object.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/output.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/parallel_map.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/parallel_map.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/partial_function.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/partial_function.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/proxy.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/proxy.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/py.typed +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/queue.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/queue.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/retries.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/runner.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/runner.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/running_app.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/schedule.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/scheduler_placement.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/secret.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/secret.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/server.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/server.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/serving.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/serving.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/skills/modal/SKILL.md +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/snapshot.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/snapshot.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/stream_type.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/token_flow.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/token_flow.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/volume.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/volume.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/workspace.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal/workspace.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal.egg-info/requires.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal.egg-info/top_level.txt +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_docs/mdmd/types.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/__init__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/py.typed +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/modal_version/__main__.py +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/pyproject.toml +0 -0
- {modal-1.4.4.dev17 → modal-1.4.4.dev19}/setup.cfg +0 -0
|
@@ -28,7 +28,7 @@ from modal._clustered_functions import initialize_clustered_function
|
|
|
28
28
|
from modal._runtime.user_code_event_loop import UserCodeEventLoop
|
|
29
29
|
from modal._serialization import deserialize, deserialize_params
|
|
30
30
|
from modal._utils.async_utils import TaskContext, aclosing, synchronizer
|
|
31
|
-
from modal.app import
|
|
31
|
+
from modal.app import _App
|
|
32
32
|
from modal.client import Client, _Client
|
|
33
33
|
from modal.config import logger
|
|
34
34
|
from modal.exception import ExecutionError, InputCancellation
|
|
@@ -288,7 +288,7 @@ def get_serialized_user_class_and_function(
|
|
|
288
288
|
|
|
289
289
|
|
|
290
290
|
def get_server_service(
|
|
291
|
-
container_args: api_pb2.ContainerArguments, function_def: api_pb2.Function, _client: _Client
|
|
291
|
+
container_args: api_pb2.ContainerArguments, function_def: api_pb2.Function, _client: _Client
|
|
292
292
|
) -> Service:
|
|
293
293
|
ser_usr_cls, ser_fun = get_serialized_user_class_and_function(function_def, _client)
|
|
294
294
|
service_base_function_id = container_args.app_layout.function_ids[function_def.function_name]
|
|
@@ -298,14 +298,14 @@ def get_server_service(
|
|
|
298
298
|
service = import_server_service(
|
|
299
299
|
function_def,
|
|
300
300
|
service_function_hydration_data,
|
|
301
|
-
|
|
301
|
+
_client,
|
|
302
302
|
ser_usr_cls,
|
|
303
303
|
)
|
|
304
304
|
return service
|
|
305
305
|
|
|
306
306
|
|
|
307
307
|
def get_class_service(
|
|
308
|
-
container_args: api_pb2.ContainerArguments, function_def: api_pb2.Function, _client: _Client
|
|
308
|
+
container_args: api_pb2.ContainerArguments, function_def: api_pb2.Function, _client: _Client
|
|
309
309
|
) -> Service:
|
|
310
310
|
ser_usr_cls, ser_fun = get_serialized_user_class_and_function(function_def, _client)
|
|
311
311
|
if container_args.serialized_params:
|
|
@@ -326,7 +326,7 @@ def get_class_service(
|
|
|
326
326
|
function_def,
|
|
327
327
|
service_function_hydration_data,
|
|
328
328
|
class_id,
|
|
329
|
-
|
|
329
|
+
_client,
|
|
330
330
|
ser_usr_cls,
|
|
331
331
|
param_args,
|
|
332
332
|
param_kwargs,
|
|
@@ -349,16 +349,15 @@ def hydrate_function(
|
|
|
349
349
|
task_lifecycle_manager: TaskLifecycleManager,
|
|
350
350
|
function_def: api_pb2.Function,
|
|
351
351
|
_client: _Client,
|
|
352
|
-
client: Client,
|
|
353
352
|
) -> Service:
|
|
354
353
|
active_app: _App
|
|
355
354
|
service: Service
|
|
356
355
|
with task_lifecycle_manager.handle_task_lifecycle_exception():
|
|
357
356
|
with execution_context._import_context():
|
|
358
357
|
if function_def.is_server:
|
|
359
|
-
service = get_server_service(container_args, function_def, _client
|
|
358
|
+
service = get_server_service(container_args, function_def, _client)
|
|
360
359
|
elif function_def.is_class:
|
|
361
|
-
service = get_class_service(container_args, function_def, _client
|
|
360
|
+
service = get_class_service(container_args, function_def, _client)
|
|
362
361
|
else:
|
|
363
362
|
service = get_function_service(function_def, _client)
|
|
364
363
|
|
|
@@ -369,8 +368,7 @@ def hydrate_function(
|
|
|
369
368
|
|
|
370
369
|
# Initialize objects on the app.
|
|
371
370
|
# This is basically only functions and classes - anything else is deprecated and will be unsupported soon
|
|
372
|
-
|
|
373
|
-
app._init_container(client, container_app)
|
|
371
|
+
active_app._init_container(_client, container_app)
|
|
374
372
|
|
|
375
373
|
# Hydrate all function dependencies.
|
|
376
374
|
# TODO(erikbern): we an remove this once we
|
|
@@ -406,7 +404,7 @@ def run_server(container_args: api_pb2.ContainerArguments, client: Client):
|
|
|
406
404
|
client,
|
|
407
405
|
)
|
|
408
406
|
|
|
409
|
-
service: Service = hydrate_function(container_args, task_lifecycle_manager, function_def, _client
|
|
407
|
+
service: Service = hydrate_function(container_args, task_lifecycle_manager, function_def, _client)
|
|
410
408
|
# Initialize clustered functions.
|
|
411
409
|
if function_def._experimental_group_size > 0:
|
|
412
410
|
initialize_clustered_function(
|
|
@@ -442,7 +440,7 @@ def run_function(container_args: api_pb2.ContainerArguments, client: Client):
|
|
|
442
440
|
with container_io_manager.heartbeats(is_snapshotting_function), UserCodeEventLoop() as event_loop:
|
|
443
441
|
# Initialize the function, importing user code.
|
|
444
442
|
service: Service = hydrate_function(
|
|
445
|
-
container_args, container_io_manager.get_task_lifecycle_manager(), function_def, _client
|
|
443
|
+
container_args, container_io_manager.get_task_lifecycle_manager(), function_def, _client
|
|
446
444
|
)
|
|
447
445
|
if function_def.pty_info.pty_type == api_pb2.PTYInfo.PTY_TYPE_SHELL:
|
|
448
446
|
# Concurrency and batching doesn't apply for `modal shell`.
|
|
@@ -185,6 +185,48 @@ class _FunctionOptions:
|
|
|
185
185
|
)
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
async def _function_bind_params_cached(
|
|
189
|
+
base_function: "_Function",
|
|
190
|
+
req: api_pb2.FunctionBindParamsRequest,
|
|
191
|
+
) -> api_pb2.FunctionBindParamsResponse:
|
|
192
|
+
"""Cache layer for FunctionBindParams RPCs, scoped to a base Function handle.
|
|
193
|
+
|
|
194
|
+
We have this because users probably do not realize that Function invocations structured as
|
|
195
|
+
|
|
196
|
+
res = f.with_options(...).remote(...)
|
|
197
|
+
|
|
198
|
+
would always need to do two sequential RPCs (bind params / call function variant).
|
|
199
|
+
|
|
200
|
+
The bound Function ID from FunctionBindParams is deterministic with respect to the full request,
|
|
201
|
+
so we can avoid the unnecessary call and hydrate the new instance from a cached response.
|
|
202
|
+
|
|
203
|
+
The cache is stored on the base Function handle so that the variant cache behaves similarly to
|
|
204
|
+
the local reference to the base Function metadata.
|
|
205
|
+
|
|
206
|
+
"""
|
|
207
|
+
cache = base_function._bind_params_cache
|
|
208
|
+
cache_key = req.SerializeToString(deterministic=True)
|
|
209
|
+
|
|
210
|
+
cached_response = cache.get(cache_key)
|
|
211
|
+
if cached_response is not None:
|
|
212
|
+
cache.move_to_end(cache_key)
|
|
213
|
+
response = api_pb2.FunctionBindParamsResponse()
|
|
214
|
+
response.ParseFromString(cached_response)
|
|
215
|
+
return response
|
|
216
|
+
|
|
217
|
+
assert base_function._client and base_function._client.stub
|
|
218
|
+
response = await base_function._client.stub.FunctionBindParams(req)
|
|
219
|
+
|
|
220
|
+
cache[cache_key] = response.SerializeToString(deterministic=True)
|
|
221
|
+
cache.move_to_end(cache_key)
|
|
222
|
+
|
|
223
|
+
max_cache_size = 32
|
|
224
|
+
while len(cache) > max_cache_size:
|
|
225
|
+
cache.popitem(last=False)
|
|
226
|
+
|
|
227
|
+
return response
|
|
228
|
+
|
|
229
|
+
|
|
188
230
|
def _make_function_variant(
|
|
189
231
|
base_function: "_Function",
|
|
190
232
|
options: _FunctionOptions | None,
|
|
@@ -229,7 +271,7 @@ def _make_function_variant(
|
|
|
229
271
|
or "", # TODO: investigate shouldn't environment name always be specified here?
|
|
230
272
|
)
|
|
231
273
|
|
|
232
|
-
response = await base_function
|
|
274
|
+
response = await _function_bind_params_cached(base_function, req)
|
|
233
275
|
function_variant._hydrate(response.bound_function_id, base_function._client, response.handle_metadata)
|
|
234
276
|
|
|
235
277
|
def _deps():
|
|
@@ -5,6 +5,7 @@ import inspect
|
|
|
5
5
|
import time
|
|
6
6
|
import typing
|
|
7
7
|
import warnings
|
|
8
|
+
from collections import OrderedDict
|
|
8
9
|
from collections.abc import AsyncGenerator, AsyncIterator, Callable, Collection, Sequence
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from pathlib import PurePosixPath
|
|
@@ -1354,6 +1355,11 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1354
1355
|
self._options = _FunctionOptions()
|
|
1355
1356
|
self._base_function = None
|
|
1356
1357
|
|
|
1358
|
+
# An OrderedDict[bytes, bytes] LRU of FunctionBindParams responses for
|
|
1359
|
+
# variants derived from this base Function. Omitted from class-level annotations because
|
|
1360
|
+
# Synchronicity doesn't understand OrderedDict as a type hint.
|
|
1361
|
+
self._bind_params_cache = OrderedDict()
|
|
1362
|
+
|
|
1357
1363
|
def _hydrate_metadata(self, metadata: Message | None):
|
|
1358
1364
|
# Overridden concrete implementation of base class method
|
|
1359
1365
|
assert metadata and isinstance(metadata, api_pb2.FunctionHandleMetadata), (
|
|
@@ -1382,6 +1388,10 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
1382
1388
|
)
|
|
1383
1389
|
self._experimental_flash_urls = metadata._experimental_flash_urls
|
|
1384
1390
|
|
|
1391
|
+
# Invalidate the Function variant cache when we load new metadata, since the base Function handle
|
|
1392
|
+
# is now in sync with the server but any previously-cached variants may be stale.
|
|
1393
|
+
self._bind_params_cache.clear()
|
|
1394
|
+
|
|
1385
1395
|
def _get_metadata(self):
|
|
1386
1396
|
# Overridden concrete implementation of base class method
|
|
1387
1397
|
assert self._function_name, f"Function name must be set before metadata can be retrieved for {self}"
|
|
@@ -40,6 +40,7 @@ from ._utils.docker_utils import (
|
|
|
40
40
|
)
|
|
41
41
|
from ._utils.function_utils import FunctionInfo, parse_gpu_config
|
|
42
42
|
from ._utils.mount_utils import validate_only_modal_volumes, validate_volumes_by_object_id
|
|
43
|
+
from ._utils.name_utils import check_object_name
|
|
43
44
|
from .client import _Client
|
|
44
45
|
from .cloud_bucket_mount import _CloudBucketMount
|
|
45
46
|
from .config import config, logger, user_config_path
|
|
@@ -103,6 +104,27 @@ See https://modal.com/docs/guide/modal-1-0-migration for more details.
|
|
|
103
104
|
P = typing_extensions.ParamSpec("P")
|
|
104
105
|
|
|
105
106
|
|
|
107
|
+
def _validate_image_name(name: str) -> None:
|
|
108
|
+
check_object_name(name, "Image")
|
|
109
|
+
# Reserve the "im-" prefix for image IDs so CLI args can be parsed
|
|
110
|
+
# unambiguously as either an image ID or an image name.
|
|
111
|
+
if name.startswith("im-"):
|
|
112
|
+
raise InvalidError("Image name cannot start with 'im-' (reserved for image IDs).")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _validate_image_tag(tag: str) -> None:
|
|
116
|
+
check_object_name(tag, "Image tag")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _parse_named_image_ref(name: str) -> str:
|
|
120
|
+
image_name, sep, tag = name.partition(":")
|
|
121
|
+
if not sep:
|
|
122
|
+
tag = "latest"
|
|
123
|
+
_validate_image_name(image_name)
|
|
124
|
+
_validate_image_tag(tag)
|
|
125
|
+
return f"{image_name}:{tag}"
|
|
126
|
+
|
|
127
|
+
|
|
106
128
|
def _validate_python_version(
|
|
107
129
|
python_version: str | None,
|
|
108
130
|
builder_version: ImageBuilderVersion,
|
|
@@ -2844,6 +2866,86 @@ class _Image(_Object, type_prefix="im"):
|
|
|
2844
2866
|
if task_log.data:
|
|
2845
2867
|
yield task_log.data
|
|
2846
2868
|
|
|
2869
|
+
@staticmethod
|
|
2870
|
+
def from_name(
|
|
2871
|
+
name: str,
|
|
2872
|
+
*,
|
|
2873
|
+
environment_name: str | None = None,
|
|
2874
|
+
client: _Client | None = None,
|
|
2875
|
+
) -> "_Image":
|
|
2876
|
+
"""Reference a named Image that was previously published with `.publish()`.
|
|
2877
|
+
|
|
2878
|
+
Names can contain an optional `:tag` part - if no tag part is included `":latest"` is used,
|
|
2879
|
+
matching Docker conventions.
|
|
2880
|
+
|
|
2881
|
+
```python notest
|
|
2882
|
+
image = modal.Image.from_name("my-image") # references my-image:latest
|
|
2883
|
+
image_v1 = modal.Image.from_name("my-image:v1")
|
|
2884
|
+
|
|
2885
|
+
@app.function(image=image)
|
|
2886
|
+
def run():
|
|
2887
|
+
...
|
|
2888
|
+
```
|
|
2889
|
+
"""
|
|
2890
|
+
tag = _parse_named_image_ref(name)
|
|
2891
|
+
|
|
2892
|
+
async def _load(self: _Image, resolver: Resolver, load_context: LoadContext, existing_object_id: str | None):
|
|
2893
|
+
req = api_pb2.ImageGetByTagRequest(
|
|
2894
|
+
tag=tag,
|
|
2895
|
+
environment_name=load_context.environment_name,
|
|
2896
|
+
)
|
|
2897
|
+
response = await load_context.client.stub.ImageGetByTag(req)
|
|
2898
|
+
self._hydrate(response.image_id, load_context.client, None)
|
|
2899
|
+
|
|
2900
|
+
rep = _Image._repr(tag, environment_name)
|
|
2901
|
+
return _Image._from_loader(
|
|
2902
|
+
_load,
|
|
2903
|
+
rep,
|
|
2904
|
+
hydrate_lazily=True,
|
|
2905
|
+
skip_reload=True,
|
|
2906
|
+
load_context_overrides=LoadContext(environment_name=environment_name, client=client),
|
|
2907
|
+
)
|
|
2908
|
+
|
|
2909
|
+
async def publish(
|
|
2910
|
+
self,
|
|
2911
|
+
name: str,
|
|
2912
|
+
*,
|
|
2913
|
+
environment_name: str | None = None,
|
|
2914
|
+
client: _Client | None = None,
|
|
2915
|
+
) -> None:
|
|
2916
|
+
"""Publish this image under the given name
|
|
2917
|
+
|
|
2918
|
+
The Image must already be created (typically by calling `image.build()` or `sandbox.snapshot_filesystem()`).
|
|
2919
|
+
|
|
2920
|
+
Image names can contain an explicit tag designation (using the `name:tag`). If no tag is included in the name,
|
|
2921
|
+
`":latest"` is used, matching Docker conventions. To publish multiple tags, call `.publish()` once per tag.
|
|
2922
|
+
|
|
2923
|
+
```python notest
|
|
2924
|
+
image = modal.Image.debian_slim().pip_install("numpy")
|
|
2925
|
+
image.build(app)
|
|
2926
|
+
image.publish("my-image-with-numpy") # my-image-with-numpy:latest
|
|
2927
|
+
image.publish("my-image-with-numpy:v1")
|
|
2928
|
+
```
|
|
2929
|
+
"""
|
|
2930
|
+
tag = _parse_named_image_ref(name)
|
|
2931
|
+
|
|
2932
|
+
if not self.is_hydrated:
|
|
2933
|
+
raise InvalidError("Cannot publish an image that has not been created yet. Call `.build()` first.")
|
|
2934
|
+
|
|
2935
|
+
_client = client or self._client
|
|
2936
|
+
assert _client is not None
|
|
2937
|
+
|
|
2938
|
+
resolved_env = environment_name or config.get("environment") or ""
|
|
2939
|
+
|
|
2940
|
+
await _client.stub.ImagePublish(
|
|
2941
|
+
api_pb2.ImagePublishRequest(
|
|
2942
|
+
image_id=self.object_id,
|
|
2943
|
+
environment_name=resolved_env,
|
|
2944
|
+
is_public=False,
|
|
2945
|
+
tag=tag,
|
|
2946
|
+
)
|
|
2947
|
+
)
|
|
2948
|
+
|
|
2847
2949
|
async def hydrate(self, client: _Client | None = None) -> Self:
|
|
2848
2950
|
"""mdmd:hidden"""
|
|
2849
2951
|
# Image inherits hydrate() from Object but can't be hydrated on demand
|
|
@@ -571,7 +571,7 @@ def import_class_service(
|
|
|
571
571
|
function_def: api_pb2.Function,
|
|
572
572
|
service_function_hydration_data: api_pb2.Object,
|
|
573
573
|
class_id: str,
|
|
574
|
-
|
|
574
|
+
_client: "modal.client._Client",
|
|
575
575
|
ser_user_cls: type | None,
|
|
576
576
|
cls_args,
|
|
577
577
|
cls_kwargs,
|
|
@@ -599,7 +599,6 @@ def import_class_service(
|
|
|
599
599
|
# Undecorated user class (serialized or local scope-decoration).
|
|
600
600
|
service_deps = None # we can't infer service deps for now
|
|
601
601
|
active_app = get_active_app_fallback(function_def)
|
|
602
|
-
_client = typing.cast("modal.client._Client", synchronizer._translate_in(client))
|
|
603
602
|
_service_function: modal._functions._Function[Any, Any, Any] = modal._functions._Function._new_hydrated(
|
|
604
603
|
service_function_hydration_data.object_id,
|
|
605
604
|
_client,
|
|
@@ -627,7 +626,7 @@ def import_class_service(
|
|
|
627
626
|
def import_server_service(
|
|
628
627
|
function_def: api_pb2.Function,
|
|
629
628
|
service_function_hydration_data: api_pb2.Object,
|
|
630
|
-
|
|
629
|
+
_client: "modal.client._Client",
|
|
631
630
|
ser_user_cls: type | None,
|
|
632
631
|
) -> Service:
|
|
633
632
|
"""
|
|
@@ -654,7 +653,6 @@ def import_server_service(
|
|
|
654
653
|
# Undecorated user class (serialized or local scope-decoration).
|
|
655
654
|
service_deps = None # we can't infer service deps for now
|
|
656
655
|
active_app = get_active_app_fallback(function_def)
|
|
657
|
-
_client = typing.cast("modal.client._Client", synchronizer._translate_in(client))
|
|
658
656
|
_service_function: modal._functions._Function[Any, Any, Any] = modal._functions._Function._new_hydrated(
|
|
659
657
|
service_function_hydration_data.object_id,
|
|
660
658
|
_client,
|
|
@@ -285,6 +285,53 @@ def make_stat_command(remote_path: str) -> str:
|
|
|
285
285
|
return json.dumps({"Stat": {"path": remote_path}})
|
|
286
286
|
|
|
287
287
|
|
|
288
|
+
def raise_watch_error(returncode: int, stderr: str | bytes, remote_path: str) -> NoReturn:
|
|
289
|
+
if payload := try_parse_error_payload(stderr):
|
|
290
|
+
logger.debug(
|
|
291
|
+
f"sandbox-fs-tools watch error: path={remote_path}, "
|
|
292
|
+
f"error_kind={payload.error_kind}, message={payload.message}, detail={payload.detail}"
|
|
293
|
+
)
|
|
294
|
+
if payload.error_kind == "NotFound":
|
|
295
|
+
raise SandboxFilesystemNotFoundError(f"{payload.message}: {remote_path}")
|
|
296
|
+
if payload.error_kind == "PermissionDenied":
|
|
297
|
+
raise SandboxFilesystemPermissionError(f"{payload.message}: {remote_path}")
|
|
298
|
+
if payload.error_kind == "NotSupported":
|
|
299
|
+
raise InvalidError(
|
|
300
|
+
f"{payload.message}: {remote_path} - this operation is not supported for CloudBucketMounts"
|
|
301
|
+
)
|
|
302
|
+
raise SandboxFilesystemError(payload.message)
|
|
303
|
+
|
|
304
|
+
if stderr_text := _stderr_to_text(stderr):
|
|
305
|
+
logger.debug(f"Unstructured modal-sandbox-fs-tools stderr: {stderr_text}")
|
|
306
|
+
raise SandboxFilesystemError(f"Operation on '{remote_path}' failed with exit code {returncode}")
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def make_watch_command(
|
|
310
|
+
remote_path: str,
|
|
311
|
+
*,
|
|
312
|
+
recursive: bool,
|
|
313
|
+
filter: list[str] | None,
|
|
314
|
+
timeout: int | None,
|
|
315
|
+
) -> str:
|
|
316
|
+
"""Build the JSON command string for a Watch operation.
|
|
317
|
+
|
|
318
|
+
The returned JSON must match the `Command` enum in the modal-sandbox-fs-tools
|
|
319
|
+
Rust crate (crates/modal-sandbox-fs-tools/src/lib.rs). Treat changes to
|
|
320
|
+
this schema like protobuf changes: fields must not be removed or renamed,
|
|
321
|
+
only added with backwards-compatible defaults.
|
|
322
|
+
"""
|
|
323
|
+
return json.dumps(
|
|
324
|
+
{
|
|
325
|
+
"Watch": {
|
|
326
|
+
"path": remote_path,
|
|
327
|
+
"recursive": recursive,
|
|
328
|
+
"filter": filter,
|
|
329
|
+
"timeout_secs": timeout,
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
288
335
|
def validate_absolute_remote_path(remote_path: str, operation: str) -> None:
|
|
289
336
|
if not PurePosixPath(remote_path).is_absolute():
|
|
290
337
|
raise InvalidError(f"Sandbox.filesystem.{operation}() currently only supports absolute remote_path values")
|
|
@@ -3,4 +3,8 @@ from ._billing import WorkspaceBillingReportItem, _workspace_billing_report
|
|
|
3
3
|
from ._utils.async_utils import synchronize_api
|
|
4
4
|
|
|
5
5
|
workspace_billing_report = synchronize_api(_workspace_billing_report)
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"workspace_billing_report",
|
|
9
|
+
"WorkspaceBillingReportItem",
|
|
10
|
+
]
|
|
@@ -35,7 +35,7 @@ class _Client:
|
|
|
35
35
|
server_url: str,
|
|
36
36
|
client_type: int,
|
|
37
37
|
credentials: typing.Optional[tuple[str, str]],
|
|
38
|
-
version: str = "1.4.4.
|
|
38
|
+
version: str = "1.4.4.dev19",
|
|
39
39
|
):
|
|
40
40
|
"""mdmd:hidden
|
|
41
41
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -205,7 +205,7 @@ class Client:
|
|
|
205
205
|
server_url: str,
|
|
206
206
|
client_type: int,
|
|
207
207
|
credentials: typing.Optional[tuple[str, str]],
|
|
208
|
-
version: str = "1.4.4.
|
|
208
|
+
version: str = "1.4.4.dev19",
|
|
209
209
|
):
|
|
210
210
|
"""mdmd:hidden
|
|
211
211
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# Copyright Modal Labs 2024
|
|
2
2
|
import asyncio
|
|
3
|
-
import enum
|
|
4
3
|
import io
|
|
5
4
|
from collections.abc import AsyncIterator, Sequence
|
|
6
|
-
from
|
|
7
|
-
from typing import TYPE_CHECKING, Generic, TypeVar, Union, cast
|
|
5
|
+
from typing import TYPE_CHECKING, Generic, Optional, TypeVar, Union, cast
|
|
8
6
|
|
|
9
7
|
if TYPE_CHECKING:
|
|
10
8
|
import _typeshed
|
|
@@ -15,6 +13,7 @@ from grpclib.exceptions import StreamTerminatedError
|
|
|
15
13
|
|
|
16
14
|
from modal._utils.async_utils import TaskContext
|
|
17
15
|
from modal.exception import ClientClosed
|
|
16
|
+
from modal.sandbox_fs import FileWatchEvent, FileWatchEventType
|
|
18
17
|
from modal_proto import api_pb2
|
|
19
18
|
|
|
20
19
|
from ._utils.async_utils import synchronize_api
|
|
@@ -60,21 +59,7 @@ async def _replace_bytes(file: "_FileIO", data: bytes, start: int | None = None,
|
|
|
60
59
|
deprecation_error((2025, 12, 3), "replace_bytes has been removed.")
|
|
61
60
|
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
Unknown = "Unknown"
|
|
65
|
-
Access = "Access"
|
|
66
|
-
Create = "Create"
|
|
67
|
-
Modify = "Modify"
|
|
68
|
-
Remove = "Remove"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@dataclass
|
|
72
|
-
class FileWatchEvent:
|
|
73
|
-
paths: list[str]
|
|
74
|
-
type: FileWatchEventType
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
async def _consume_output(client: _Client, exec_id: str) -> AsyncIterator[bytes | None | Exception]:
|
|
62
|
+
async def _consume_output(client: _Client, exec_id: str) -> AsyncIterator[Optional[bytes] | Exception]:
|
|
78
63
|
req = api_pb2.ContainerFilesystemExecGetOutputRequest(
|
|
79
64
|
exec_id=exec_id,
|
|
80
65
|
timeout=55,
|
|
@@ -424,7 +409,7 @@ class _FileIO(Generic[T]):
|
|
|
424
409
|
) -> AsyncIterator[FileWatchEvent]:
|
|
425
410
|
deprecation_warning(
|
|
426
411
|
(2026, 3, 9),
|
|
427
|
-
"`FileIO.watch()` is deprecated. Use `Sandbox.watch()` instead.",
|
|
412
|
+
"`FileIO.watch()` is deprecated. Use `Sandbox.filesystem.watch()` instead.",
|
|
428
413
|
)
|
|
429
414
|
async for event in watch(path, client, task_id, filter, recursive, timeout):
|
|
430
415
|
yield event
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import _io
|
|
2
2
|
import _typeshed
|
|
3
3
|
import collections.abc
|
|
4
|
-
import enum
|
|
5
4
|
import modal.client
|
|
5
|
+
import modal.sandbox_fs
|
|
6
6
|
import typing
|
|
7
7
|
import typing_extensions
|
|
8
8
|
|
|
@@ -22,31 +22,6 @@ async def _replace_bytes(
|
|
|
22
22
|
"""
|
|
23
23
|
...
|
|
24
24
|
|
|
25
|
-
class FileWatchEventType(enum.Enum):
|
|
26
|
-
Unknown = "Unknown"
|
|
27
|
-
Access = "Access"
|
|
28
|
-
Create = "Create"
|
|
29
|
-
Modify = "Modify"
|
|
30
|
-
Remove = "Remove"
|
|
31
|
-
|
|
32
|
-
class FileWatchEvent:
|
|
33
|
-
"""FileWatchEvent(paths: list[str], type: modal.file_io.FileWatchEventType)"""
|
|
34
|
-
|
|
35
|
-
paths: list[str]
|
|
36
|
-
type: FileWatchEventType
|
|
37
|
-
|
|
38
|
-
def __init__(self, paths: list[str], type: FileWatchEventType) -> None:
|
|
39
|
-
"""Initialize self. See help(type(self)) for accurate signature."""
|
|
40
|
-
...
|
|
41
|
-
|
|
42
|
-
def __repr__(self):
|
|
43
|
-
"""Return repr(self)."""
|
|
44
|
-
...
|
|
45
|
-
|
|
46
|
-
def __eq__(self, other):
|
|
47
|
-
"""Return self==value."""
|
|
48
|
-
...
|
|
49
|
-
|
|
50
25
|
def _consume_output(
|
|
51
26
|
client: modal.client._Client, exec_id: str
|
|
52
27
|
) -> collections.abc.AsyncIterator[typing.Union[bytes, None, Exception]]: ...
|
|
@@ -157,10 +132,10 @@ class _FileIO(typing.Generic[T]):
|
|
|
157
132
|
path: str,
|
|
158
133
|
client: modal.client._Client,
|
|
159
134
|
task_id: str,
|
|
160
|
-
filter: typing.Optional[list[FileWatchEventType]] = None,
|
|
135
|
+
filter: typing.Optional[list[modal.sandbox_fs.FileWatchEventType]] = None,
|
|
161
136
|
recursive: bool = False,
|
|
162
137
|
timeout: typing.Optional[int] = None,
|
|
163
|
-
) -> collections.abc.AsyncIterator[FileWatchEvent]: ...
|
|
138
|
+
) -> collections.abc.AsyncIterator[modal.sandbox_fs.FileWatchEvent]: ...
|
|
164
139
|
async def _close(self) -> None: ...
|
|
165
140
|
async def close(self) -> None:
|
|
166
141
|
"""Flush the buffer and close the file."""
|
|
@@ -190,10 +165,10 @@ def watch(
|
|
|
190
165
|
path: str,
|
|
191
166
|
client: modal.client._Client,
|
|
192
167
|
task_id: str,
|
|
193
|
-
filter: typing.Optional[list[FileWatchEventType]] = None,
|
|
168
|
+
filter: typing.Optional[list[modal.sandbox_fs.FileWatchEventType]] = None,
|
|
194
169
|
recursive: bool = False,
|
|
195
170
|
timeout: typing.Optional[int] = None,
|
|
196
|
-
) -> collections.abc.AsyncIterator[FileWatchEvent]:
|
|
171
|
+
) -> collections.abc.AsyncIterator[modal.sandbox_fs.FileWatchEvent]:
|
|
197
172
|
"""Watch a file or directory for changes."""
|
|
198
173
|
...
|
|
199
174
|
|
|
@@ -428,20 +403,20 @@ class FileIO(typing.Generic[T]):
|
|
|
428
403
|
path: str,
|
|
429
404
|
client: modal.client.Client,
|
|
430
405
|
task_id: str,
|
|
431
|
-
filter: typing.Optional[list[FileWatchEventType]] = None,
|
|
406
|
+
filter: typing.Optional[list[modal.sandbox_fs.FileWatchEventType]] = None,
|
|
432
407
|
recursive: bool = False,
|
|
433
408
|
timeout: typing.Optional[int] = None,
|
|
434
|
-
) -> typing.Iterator[FileWatchEvent]: ...
|
|
409
|
+
) -> typing.Iterator[modal.sandbox_fs.FileWatchEvent]: ...
|
|
435
410
|
def aio(
|
|
436
411
|
self,
|
|
437
412
|
/,
|
|
438
413
|
path: str,
|
|
439
414
|
client: modal.client.Client,
|
|
440
415
|
task_id: str,
|
|
441
|
-
filter: typing.Optional[list[FileWatchEventType]] = None,
|
|
416
|
+
filter: typing.Optional[list[modal.sandbox_fs.FileWatchEventType]] = None,
|
|
442
417
|
recursive: bool = False,
|
|
443
418
|
timeout: typing.Optional[int] = None,
|
|
444
|
-
) -> collections.abc.AsyncIterator[FileWatchEvent]: ...
|
|
419
|
+
) -> collections.abc.AsyncIterator[modal.sandbox_fs.FileWatchEvent]: ...
|
|
445
420
|
|
|
446
421
|
watch: typing.ClassVar[__watch_spec]
|
|
447
422
|
|
|
@@ -465,7 +465,7 @@ class Function(
|
|
|
465
465
|
|
|
466
466
|
_call_generator: ___call_generator_spec
|
|
467
467
|
|
|
468
|
-
class __remote_spec(typing_extensions.Protocol[
|
|
468
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
469
469
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
|
470
470
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result.
|
|
471
471
|
|
|
@@ -490,7 +490,7 @@ class Function(
|
|
|
490
490
|
"""
|
|
491
491
|
...
|
|
492
492
|
|
|
493
|
-
remote: __remote_spec[modal._functions.
|
|
493
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
|
|
494
494
|
|
|
495
495
|
class __remote_gen_spec(typing_extensions.Protocol):
|
|
496
496
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
|
@@ -540,7 +540,7 @@ class Function(
|
|
|
540
540
|
"""
|
|
541
541
|
...
|
|
542
542
|
|
|
543
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
|
543
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
544
544
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
545
545
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
|
546
546
|
|
|
@@ -573,7 +573,7 @@ class Function(
|
|
|
573
573
|
"""
|
|
574
574
|
...
|
|
575
575
|
|
|
576
|
-
_experimental_spawn: ___experimental_spawn_spec[modal._functions.
|
|
576
|
+
_experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
|
|
577
577
|
|
|
578
578
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
|
|
579
579
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
|
|
@@ -581,7 +581,7 @@ class Function(
|
|
|
581
581
|
|
|
582
582
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
|
|
583
583
|
|
|
584
|
-
class __spawn_spec(typing_extensions.Protocol[
|
|
584
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
|
|
585
585
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
|
586
586
|
"""Calls the function with the given arguments, without waiting for the results.
|
|
587
587
|
|
|
@@ -614,7 +614,7 @@ class Function(
|
|
|
614
614
|
"""
|
|
615
615
|
...
|
|
616
616
|
|
|
617
|
-
spawn: __spawn_spec[modal._functions.
|
|
617
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
|
|
618
618
|
|
|
619
619
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
|
620
620
|
"""Return the inner Python object wrapped by this Modal Function.
|