modal 1.1.2.dev26__tar.gz → 1.1.2.dev28__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.1.2.dev26 → modal-1.1.2.dev28}/PKG-INFO +1 -1
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/blob_utils.py +83 -24
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/client.pyi +2 -2
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/functions.pyi +6 -6
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/volume.py +7 -9
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/api.proto +18 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/api_grpc.py +32 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/api_pb2.py +627 -597
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/api_pb2.pyi +53 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/api_pb2_grpc.py +67 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/api_pb2_grpc.pyi +22 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/modal_api_grpc.py +2 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_version/__init__.py +1 -1
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/LICENSE +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/README.md +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/__main__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_clustered_functions.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_clustered_functions.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_container_entrypoint.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_functions.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_ipython.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_location.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_object.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_output.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_partial_function.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_pty.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_resolver.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_resources.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/asgi.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/execution_context.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/telemetry.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_serialization.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_traceback.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_tunnel.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_tunnel.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_type_manager.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/app_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/async_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/deprecation.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/docker_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/function_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/git_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/hash_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/http_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/logger.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/mount_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/name_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/package_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/shell_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_utils/time_utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_vendor/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_vendor/tblib.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/_watcher.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/app.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/app.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/2023.12.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/2024.04.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/2024.10.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/2025.06.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/README.md +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/builder/base-images.json +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/call_graph.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/_download.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/_traceback.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/app.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/cluster.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/config.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/container.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/dict.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/entry_point.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/environment.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/import_refs.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/launch.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/network_file_system.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/profile.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/programs/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/programs/vscode.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/queues.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/run.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/secret.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/token.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/utils.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cli/volume.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/client.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cls.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/cls.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/config.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/container_process.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/container_process.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/dict.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/dict.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/environments.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/environments.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/exception.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/experimental/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/experimental/flash.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/experimental/flash.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/experimental/ipython.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/file_io.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/file_io.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/file_pattern_matcher.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/functions.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/gpu.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/image.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/image.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/io_streams.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/io_streams.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/mount.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/mount.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/network_file_system.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/network_file_system.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/object.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/object.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/output.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/parallel_map.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/parallel_map.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/partial_function.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/partial_function.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/proxy.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/proxy.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/py.typed +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/queue.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/queue.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/retries.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/runner.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/runner.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/running_app.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/sandbox.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/sandbox.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/schedule.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/scheduler_placement.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/secret.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/secret.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/serving.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/serving.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/snapshot.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/snapshot.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/stream_type.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/token_flow.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/token_flow.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal/volume.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal.egg-info/requires.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal.egg-info/top_level.txt +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_docs/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/__init__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/modal_options_grpc.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/options.proto +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/options_grpc.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/options_pb2.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/options_pb2.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/options_pb2_grpc.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/options_pb2_grpc.pyi +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_proto/py.typed +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/modal_version/__main__.py +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/pyproject.toml +0 -0
- {modal-1.1.2.dev26 → modal-1.1.2.dev28}/setup.cfg +0 -0
@@ -444,14 +444,24 @@ def get_file_upload_spec_from_fileobj(fp: BinaryIO, mount_filename: PurePosixPat
|
|
444
444
|
_FileUploadSource2 = Callable[[], ContextManager[BinaryIO]]
|
445
445
|
|
446
446
|
|
447
|
+
@dataclasses.dataclass
|
448
|
+
class FileUploadBlock:
|
449
|
+
# The start (byte offset, inclusive) of the block within the file
|
450
|
+
start: int
|
451
|
+
# The end (byte offset, exclusive) of the block, after having removed any trailing zeroes
|
452
|
+
end: int
|
453
|
+
# Raw (unencoded 32 byte) SHA256 sum of the block, not including trailing zeroes
|
454
|
+
contents_sha256: bytes
|
455
|
+
|
456
|
+
|
447
457
|
@dataclasses.dataclass
|
448
458
|
class FileUploadSpec2:
|
449
459
|
source: _FileUploadSource2
|
450
460
|
source_description: Union[str, Path]
|
451
461
|
|
452
462
|
path: str
|
453
|
-
#
|
454
|
-
|
463
|
+
# 8MiB file blocks
|
464
|
+
blocks: list[FileUploadBlock]
|
455
465
|
mode: int # file permission bits (last 12 bits of st_mode)
|
456
466
|
size: int
|
457
467
|
|
@@ -522,53 +532,102 @@ class FileUploadSpec2:
|
|
522
532
|
source_fp.seek(0, os.SEEK_END)
|
523
533
|
size = source_fp.tell()
|
524
534
|
|
525
|
-
|
535
|
+
blocks = await _gather_blocks(source, size, hash_semaphore)
|
526
536
|
|
527
537
|
return FileUploadSpec2(
|
528
538
|
source=source,
|
529
539
|
source_description=source_description,
|
530
540
|
path=mount_filename.as_posix(),
|
531
|
-
|
541
|
+
blocks=blocks,
|
532
542
|
mode=mode & 0o7777,
|
533
543
|
size=size,
|
534
544
|
)
|
535
545
|
|
536
546
|
|
537
|
-
async def
|
547
|
+
async def _gather_blocks(
|
538
548
|
source: _FileUploadSource2,
|
539
549
|
size: int,
|
540
550
|
hash_semaphore: asyncio.Semaphore,
|
541
|
-
) -> list[
|
551
|
+
) -> list[FileUploadBlock]:
|
542
552
|
def ceildiv(a: int, b: int) -> int:
|
543
553
|
return -(a // -b)
|
544
554
|
|
545
555
|
num_blocks = ceildiv(size, BLOCK_SIZE)
|
546
556
|
|
547
|
-
def
|
548
|
-
|
549
|
-
|
557
|
+
async def gather_block(block_idx: int) -> FileUploadBlock:
|
558
|
+
async with hash_semaphore:
|
559
|
+
return await asyncio.to_thread(_gather_block, source, block_idx)
|
550
560
|
|
551
|
-
|
552
|
-
|
561
|
+
tasks = (gather_block(idx) for idx in range(num_blocks))
|
562
|
+
return await asyncio.gather(*tasks)
|
553
563
|
|
554
|
-
num_bytes_read = 0
|
555
|
-
while num_bytes_read < BLOCK_SIZE:
|
556
|
-
chunk = block_fp.read(BLOCK_SIZE - num_bytes_read)
|
557
564
|
|
558
|
-
|
559
|
-
|
565
|
+
def _gather_block(source: _FileUploadSource2, block_idx: int) -> FileUploadBlock:
|
566
|
+
start = block_idx * BLOCK_SIZE
|
567
|
+
end = _find_end_of_block(source, start, start + BLOCK_SIZE)
|
568
|
+
contents_sha256 = _hash_range_sha256(source, start, end)
|
569
|
+
return FileUploadBlock(start=start, end=end, contents_sha256=contents_sha256)
|
560
570
|
|
561
|
-
num_bytes_read += len(chunk)
|
562
|
-
sha256_hash.update(chunk)
|
563
571
|
|
564
|
-
|
572
|
+
def _hash_range_sha256(source: _FileUploadSource2, start, end):
|
573
|
+
sha256_hash = hashlib.sha256()
|
574
|
+
range_size = end - start
|
565
575
|
|
566
|
-
|
567
|
-
|
568
|
-
|
576
|
+
with source() as fp:
|
577
|
+
fp.seek(start)
|
578
|
+
|
579
|
+
num_bytes_read = 0
|
580
|
+
while num_bytes_read < range_size:
|
581
|
+
chunk = fp.read(range_size - num_bytes_read)
|
582
|
+
|
583
|
+
if not chunk:
|
584
|
+
break
|
585
|
+
|
586
|
+
num_bytes_read += len(chunk)
|
587
|
+
sha256_hash.update(chunk)
|
588
|
+
|
589
|
+
return sha256_hash.digest()
|
590
|
+
|
591
|
+
|
592
|
+
def _find_end_of_block(source: _FileUploadSource2, start: int, end: int) -> Optional[int]:
|
593
|
+
"""Finds the appropriate end of a block, which is the index of the byte just past the last non-zero byte in the
|
594
|
+
block.
|
595
|
+
|
596
|
+
>>> _find_end_of_block(lambda: BytesIO(b"abc123\0\0\0"), 0, 1024)
|
597
|
+
6
|
598
|
+
>>> _find_end_of_block(lambda: BytesIO(b"abc123\0\0\0"), 3, 1024)
|
599
|
+
6
|
600
|
+
>>> _find_end_of_block(lambda: BytesIO(b"abc123\0\0\0"), 0, 3)
|
601
|
+
4
|
602
|
+
>>> _find_end_of_block(lambda: BytesIO(b"abc123\0\0\0a"), 0, 9)
|
603
|
+
6
|
604
|
+
>>> _find_end_of_block(lambda: BytesIO(b"\0\0\0"), 0, 3)
|
605
|
+
0
|
606
|
+
>>> _find_end_of_block(lambda: BytesIO(b"\0\0\0\0\0\0"), 3, 6)
|
607
|
+
3
|
608
|
+
>>> _find_end_of_block(lambda: BytesIO(b""), 0, 1024)
|
609
|
+
0
|
610
|
+
"""
|
611
|
+
size = end - start
|
612
|
+
new_end = start
|
569
613
|
|
570
|
-
|
571
|
-
|
614
|
+
with source() as block_fp:
|
615
|
+
block_fp.seek(start)
|
616
|
+
|
617
|
+
num_bytes_read = 0
|
618
|
+
while num_bytes_read < size:
|
619
|
+
chunk = block_fp.read(size - num_bytes_read)
|
620
|
+
|
621
|
+
if not chunk:
|
622
|
+
break
|
623
|
+
|
624
|
+
stripped_chunk = chunk.rstrip(b"\0")
|
625
|
+
if stripped_chunk:
|
626
|
+
new_end = start + num_bytes_read + len(stripped_chunk)
|
627
|
+
|
628
|
+
num_bytes_read += len(chunk)
|
629
|
+
|
630
|
+
return new_end
|
572
631
|
|
573
632
|
|
574
633
|
def use_md5(url: str) -> bool:
|
@@ -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.1.2.
|
36
|
+
version: str = "1.1.2.dev28",
|
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.1.2.
|
167
|
+
version: str = "1.1.2.dev28",
|
168
168
|
):
|
169
169
|
"""mdmd:hidden
|
170
170
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -433,7 +433,7 @@ class Function(
|
|
433
433
|
|
434
434
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
435
435
|
|
436
|
-
class __remote_spec(typing_extensions.Protocol[
|
436
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
437
437
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
438
438
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
439
439
|
...
|
@@ -442,7 +442,7 @@ class Function(
|
|
442
442
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
443
443
|
...
|
444
444
|
|
445
|
-
remote: __remote_spec[modal._functions.
|
445
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
446
446
|
|
447
447
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
448
448
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
@@ -469,7 +469,7 @@ class Function(
|
|
469
469
|
"""
|
470
470
|
...
|
471
471
|
|
472
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
472
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
473
473
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
474
474
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
475
475
|
|
@@ -493,7 +493,7 @@ class Function(
|
|
493
493
|
...
|
494
494
|
|
495
495
|
_experimental_spawn: ___experimental_spawn_spec[
|
496
|
-
modal._functions.
|
496
|
+
modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
|
497
497
|
]
|
498
498
|
|
499
499
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
@@ -502,7 +502,7 @@ class Function(
|
|
502
502
|
|
503
503
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
504
504
|
|
505
|
-
class __spawn_spec(typing_extensions.Protocol[
|
505
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
506
506
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
507
507
|
"""Calls the function with the given arguments, without waiting for the results.
|
508
508
|
|
@@ -523,7 +523,7 @@ class Function(
|
|
523
523
|
"""
|
524
524
|
...
|
525
525
|
|
526
|
-
spawn: __spawn_spec[modal._functions.
|
526
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
527
527
|
|
528
528
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
529
529
|
"""Return the inner Python object wrapped by this Modal Function."""
|
@@ -1122,9 +1122,9 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
|
|
1122
1122
|
for file_spec in file_specs:
|
1123
1123
|
blocks = [
|
1124
1124
|
api_pb2.VolumePutFiles2Request.Block(
|
1125
|
-
contents_sha256=
|
1125
|
+
contents_sha256=block.contents_sha256, put_response=put_responses.get(block.contents_sha256)
|
1126
1126
|
)
|
1127
|
-
for
|
1127
|
+
for block in file_spec.blocks
|
1128
1128
|
]
|
1129
1129
|
files.append(
|
1130
1130
|
api_pb2.VolumePutFiles2Request.File(
|
@@ -1181,7 +1181,7 @@ async def _put_missing_blocks(
|
|
1181
1181
|
# TODO(dflemstr): Type is `api_pb2.VolumePutFiles2Response.MissingBlock` but synchronicity gets confused
|
1182
1182
|
# by the nested class (?)
|
1183
1183
|
missing_block,
|
1184
|
-
) ->
|
1184
|
+
) -> tuple[bytes, bytes]:
|
1185
1185
|
# Lazily import to keep the eager loading time of this module down
|
1186
1186
|
from ._utils.bytes_io_segment_payload import BytesIOSegmentPayload
|
1187
1187
|
|
@@ -1190,9 +1190,7 @@ async def _put_missing_blocks(
|
|
1190
1190
|
file_spec = file_specs[missing_block.file_index]
|
1191
1191
|
# TODO(dflemstr): What if the underlying file has changed here in the meantime; should we check the
|
1192
1192
|
# hash again just to be sure?
|
1193
|
-
|
1194
|
-
block_start = missing_block.block_index * BLOCK_SIZE
|
1195
|
-
block_length = min(BLOCK_SIZE, file_spec.size - block_start)
|
1193
|
+
block = file_spec.blocks[missing_block.block_index]
|
1196
1194
|
|
1197
1195
|
if file_spec.path not in file_progresses:
|
1198
1196
|
file_task_id = progress_cb(name=file_spec.path, size=file_spec.size)
|
@@ -1216,8 +1214,8 @@ async def _put_missing_blocks(
|
|
1216
1214
|
with file_spec.source() as source_fp:
|
1217
1215
|
payload = BytesIOSegmentPayload(
|
1218
1216
|
source_fp,
|
1219
|
-
|
1220
|
-
|
1217
|
+
block.start,
|
1218
|
+
block.end - block.start,
|
1221
1219
|
# limit chunk size somewhat to not keep event loop busy for too long
|
1222
1220
|
chunk_size=256 * 1024,
|
1223
1221
|
progress_report_cb=task_progress_cb,
|
@@ -1229,7 +1227,7 @@ async def _put_missing_blocks(
|
|
1229
1227
|
if len(file_progress.pending_blocks) == 0:
|
1230
1228
|
task_progress_cb(complete=True)
|
1231
1229
|
|
1232
|
-
return
|
1230
|
+
return block.contents_sha256, resp_data
|
1233
1231
|
|
1234
1232
|
tasks = [asyncio.create_task(put_missing_block(missing_block)) for missing_block in missing_blocks]
|
1235
1233
|
for task_result in asyncio.as_completed(tasks):
|
@@ -1510,6 +1510,16 @@ message FunctionCallCancelRequest {
|
|
1510
1510
|
optional string function_id = 3; // Only provided for sync input cancellation on the input plane. Async input cancellation does not provide this field this.
|
1511
1511
|
}
|
1512
1512
|
|
1513
|
+
message FunctionCallFromIdRequest {
|
1514
|
+
string function_call_id = 1;
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
// Everything you need to build a FunctionCallHandler.
|
1518
|
+
message FunctionCallFromIdResponse {
|
1519
|
+
string function_call_id = 1;
|
1520
|
+
int32 num_inputs = 2;
|
1521
|
+
}
|
1522
|
+
|
1513
1523
|
message FunctionCallGetDataRequest {
|
1514
1524
|
oneof call_info {
|
1515
1525
|
string function_call_id = 1;
|
@@ -1648,6 +1658,12 @@ message FunctionExtended {
|
|
1648
1658
|
}
|
1649
1659
|
}
|
1650
1660
|
|
1661
|
+
message FunctionFinishInputsRequest {
|
1662
|
+
string function_id = 1;
|
1663
|
+
string function_call_id = 2;
|
1664
|
+
uint32 num_inputs = 3;
|
1665
|
+
}
|
1666
|
+
|
1651
1667
|
|
1652
1668
|
message FunctionGetCallGraphRequest {
|
1653
1669
|
// TODO: use input_id once we switch client submit API to return those.
|
@@ -3494,11 +3510,13 @@ service ModalClient {
|
|
3494
3510
|
rpc FunctionAsyncInvoke(FunctionAsyncInvokeRequest) returns (FunctionAsyncInvokeResponse);
|
3495
3511
|
rpc FunctionBindParams(FunctionBindParamsRequest) returns (FunctionBindParamsResponse);
|
3496
3512
|
rpc FunctionCallCancel(FunctionCallCancelRequest) returns (google.protobuf.Empty);
|
3513
|
+
rpc FunctionCallFromId(FunctionCallFromIdRequest) returns (FunctionCallFromIdResponse);
|
3497
3514
|
rpc FunctionCallGetDataIn(FunctionCallGetDataRequest) returns (stream DataChunk);
|
3498
3515
|
rpc FunctionCallGetDataOut(FunctionCallGetDataRequest) returns (stream DataChunk);
|
3499
3516
|
rpc FunctionCallList(FunctionCallListRequest) returns (FunctionCallListResponse);
|
3500
3517
|
rpc FunctionCallPutDataOut(FunctionCallPutDataRequest) returns (google.protobuf.Empty);
|
3501
3518
|
rpc FunctionCreate(FunctionCreateRequest) returns (FunctionCreateResponse);
|
3519
|
+
rpc FunctionFinishInputs(FunctionFinishInputsRequest) returns (google.protobuf.Empty); // For map RPCs, to signal that all inputs have been sent
|
3502
3520
|
rpc FunctionGet(FunctionGetRequest) returns (FunctionGetResponse);
|
3503
3521
|
rpc FunctionGetCallGraph(FunctionGetCallGraphRequest) returns (FunctionGetCallGraphResponse);
|
3504
3522
|
rpc FunctionGetCurrentStats(FunctionGetCurrentStatsRequest) returns (FunctionStats);
|
@@ -274,6 +274,10 @@ class ModalClientBase(abc.ABC):
|
|
274
274
|
async def FunctionCallCancel(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionCallCancelRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
275
275
|
pass
|
276
276
|
|
277
|
+
@abc.abstractmethod
|
278
|
+
async def FunctionCallFromId(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionCallFromIdRequest, modal_proto.api_pb2.FunctionCallFromIdResponse]') -> None:
|
279
|
+
pass
|
280
|
+
|
277
281
|
@abc.abstractmethod
|
278
282
|
async def FunctionCallGetDataIn(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionCallGetDataRequest, modal_proto.api_pb2.DataChunk]') -> None:
|
279
283
|
pass
|
@@ -294,6 +298,10 @@ class ModalClientBase(abc.ABC):
|
|
294
298
|
async def FunctionCreate(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionCreateRequest, modal_proto.api_pb2.FunctionCreateResponse]') -> None:
|
295
299
|
pass
|
296
300
|
|
301
|
+
@abc.abstractmethod
|
302
|
+
async def FunctionFinishInputs(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionFinishInputsRequest, google.protobuf.empty_pb2.Empty]') -> None:
|
303
|
+
pass
|
304
|
+
|
297
305
|
@abc.abstractmethod
|
298
306
|
async def FunctionGet(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionGetRequest, modal_proto.api_pb2.FunctionGetResponse]') -> None:
|
299
307
|
pass
|
@@ -1060,6 +1068,12 @@ class ModalClientBase(abc.ABC):
|
|
1060
1068
|
modal_proto.api_pb2.FunctionCallCancelRequest,
|
1061
1069
|
google.protobuf.empty_pb2.Empty,
|
1062
1070
|
),
|
1071
|
+
'/modal.client.ModalClient/FunctionCallFromId': grpclib.const.Handler(
|
1072
|
+
self.FunctionCallFromId,
|
1073
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
1074
|
+
modal_proto.api_pb2.FunctionCallFromIdRequest,
|
1075
|
+
modal_proto.api_pb2.FunctionCallFromIdResponse,
|
1076
|
+
),
|
1063
1077
|
'/modal.client.ModalClient/FunctionCallGetDataIn': grpclib.const.Handler(
|
1064
1078
|
self.FunctionCallGetDataIn,
|
1065
1079
|
grpclib.const.Cardinality.UNARY_STREAM,
|
@@ -1090,6 +1104,12 @@ class ModalClientBase(abc.ABC):
|
|
1090
1104
|
modal_proto.api_pb2.FunctionCreateRequest,
|
1091
1105
|
modal_proto.api_pb2.FunctionCreateResponse,
|
1092
1106
|
),
|
1107
|
+
'/modal.client.ModalClient/FunctionFinishInputs': grpclib.const.Handler(
|
1108
|
+
self.FunctionFinishInputs,
|
1109
|
+
grpclib.const.Cardinality.UNARY_UNARY,
|
1110
|
+
modal_proto.api_pb2.FunctionFinishInputsRequest,
|
1111
|
+
google.protobuf.empty_pb2.Empty,
|
1112
|
+
),
|
1093
1113
|
'/modal.client.ModalClient/FunctionGet': grpclib.const.Handler(
|
1094
1114
|
self.FunctionGet,
|
1095
1115
|
grpclib.const.Cardinality.UNARY_UNARY,
|
@@ -2050,6 +2070,12 @@ class ModalClientStub:
|
|
2050
2070
|
modal_proto.api_pb2.FunctionCallCancelRequest,
|
2051
2071
|
google.protobuf.empty_pb2.Empty,
|
2052
2072
|
)
|
2073
|
+
self.FunctionCallFromId = grpclib.client.UnaryUnaryMethod(
|
2074
|
+
channel,
|
2075
|
+
'/modal.client.ModalClient/FunctionCallFromId',
|
2076
|
+
modal_proto.api_pb2.FunctionCallFromIdRequest,
|
2077
|
+
modal_proto.api_pb2.FunctionCallFromIdResponse,
|
2078
|
+
)
|
2053
2079
|
self.FunctionCallGetDataIn = grpclib.client.UnaryStreamMethod(
|
2054
2080
|
channel,
|
2055
2081
|
'/modal.client.ModalClient/FunctionCallGetDataIn',
|
@@ -2080,6 +2106,12 @@ class ModalClientStub:
|
|
2080
2106
|
modal_proto.api_pb2.FunctionCreateRequest,
|
2081
2107
|
modal_proto.api_pb2.FunctionCreateResponse,
|
2082
2108
|
)
|
2109
|
+
self.FunctionFinishInputs = grpclib.client.UnaryUnaryMethod(
|
2110
|
+
channel,
|
2111
|
+
'/modal.client.ModalClient/FunctionFinishInputs',
|
2112
|
+
modal_proto.api_pb2.FunctionFinishInputsRequest,
|
2113
|
+
google.protobuf.empty_pb2.Empty,
|
2114
|
+
)
|
2083
2115
|
self.FunctionGet = grpclib.client.UnaryUnaryMethod(
|
2084
2116
|
channel,
|
2085
2117
|
'/modal.client.ModalClient/FunctionGet',
|