modal 1.2.5.dev26__tar.gz → 1.2.5.dev27__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.dev26 → modal-1.2.5.dev27}/PKG-INFO +1 -1
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/blob_utils.py +18 -5
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/client.pyi +2 -2
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/mount.py +14 -8
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/volume.py +5 -1
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_version/__init__.py +1 -1
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/LICENSE +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/README.md +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/__main__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_billing.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_clustered_functions.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_clustered_functions.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_container_entrypoint.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_functions.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_grpc_client.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_ipython.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_load_context.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_location.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_object.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_output.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_partial_function.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_pty.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_resolver.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_resources.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/asgi.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/execution_context.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/telemetry.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_serialization.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_traceback.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_tunnel.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_tunnel.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_type_manager.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/app_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/async_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/deprecation.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/docker_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/function_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/git_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/hash_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/http_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/logger.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/mount_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/name_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/package_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/shell_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/task_command_router_client.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_utils/time_utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_vendor/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_vendor/tblib.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/_watcher.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/app.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/app.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/billing.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/2023.12.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/2024.04.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/2024.10.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/2025.06.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/README.md +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/builder/base-images.json +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/call_graph.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/_download.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/_traceback.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/app.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/cluster.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/config.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/container.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/dict.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/entry_point.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/environment.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/import_refs.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/launch.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/network_file_system.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/profile.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/programs/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/programs/vscode.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/queues.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/run.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/secret.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/shell.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/token.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/utils.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cli/volume.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/client.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cls.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/cls.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/config.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/container_process.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/container_process.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/dict.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/dict.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/environments.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/environments.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/exception.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/experimental/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/experimental/flash.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/experimental/flash.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/experimental/ipython.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/file_io.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/file_io.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/file_pattern_matcher.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/functions.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/functions.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/gpu.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/image.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/image.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/io_streams.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/io_streams.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/mount.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/network_file_system.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/network_file_system.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/object.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/object.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/output.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/parallel_map.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/parallel_map.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/partial_function.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/partial_function.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/proxy.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/proxy.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/py.typed +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/queue.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/queue.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/retries.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/runner.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/runner.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/running_app.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/sandbox.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/sandbox.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/schedule.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/scheduler_placement.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/secret.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/secret.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/serving.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/serving.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/snapshot.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/snapshot.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/stream_type.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/token_flow.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/token_flow.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal/volume.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal.egg-info/requires.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal.egg-info/top_level.txt +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_docs/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/__init__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/api.proto +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/api_grpc.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/api_pb2.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/api_pb2.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/py.typed +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/task_command_router.proto +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/task_command_router_pb2.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/task_command_router_pb2.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/modal_version/__main__.py +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/pyproject.toml +0 -0
- {modal-1.2.5.dev26 → modal-1.2.5.dev27}/setup.cfg +0 -0
|
@@ -371,11 +371,17 @@ class FileUploadSpec:
|
|
|
371
371
|
mount_filename: str
|
|
372
372
|
|
|
373
373
|
use_blob: bool
|
|
374
|
-
content: Optional[bytes] # typically None if using blob, required otherwise
|
|
375
374
|
sha256_hex: str
|
|
376
375
|
md5_hex: str
|
|
377
376
|
mode: int # file permission bits (last 12 bits of st_mode)
|
|
378
377
|
size: int
|
|
378
|
+
content: Optional[bytes] = None # Set for very small files to avoid double-read
|
|
379
|
+
|
|
380
|
+
def read_content(self) -> bytes:
|
|
381
|
+
"""Read content from source."""
|
|
382
|
+
with self.source() as fp:
|
|
383
|
+
fp.seek(0)
|
|
384
|
+
return fp.read()
|
|
379
385
|
|
|
380
386
|
|
|
381
387
|
def _get_file_upload_spec(
|
|
@@ -384,6 +390,7 @@ def _get_file_upload_spec(
|
|
|
384
390
|
mount_filename: PurePosixPath,
|
|
385
391
|
mode: int,
|
|
386
392
|
) -> FileUploadSpec:
|
|
393
|
+
content = None
|
|
387
394
|
with source() as fp:
|
|
388
395
|
# Current position is ignored - we always upload from position 0
|
|
389
396
|
fp.seek(0, os.SEEK_END)
|
|
@@ -394,12 +401,18 @@ def _get_file_upload_spec(
|
|
|
394
401
|
# TODO(dano): remove the placeholder md5 once we stop requiring md5 for blobs
|
|
395
402
|
md5_hex = "baadbaadbaadbaadbaadbaadbaadbaad" if size > MULTIPART_UPLOAD_THRESHOLD else None
|
|
396
403
|
use_blob = True
|
|
397
|
-
content = None
|
|
398
404
|
hashes = get_upload_hashes(fp, md5_hex=md5_hex)
|
|
399
405
|
else:
|
|
400
406
|
use_blob = False
|
|
401
|
-
|
|
402
|
-
|
|
407
|
+
# For very small files (< 256 KiB), read content once and cache it
|
|
408
|
+
# This avoids double-read penalty while limiting memory usage
|
|
409
|
+
if size < 256 * 1024: # 256 KiB threshold
|
|
410
|
+
fp.seek(0)
|
|
411
|
+
content = fp.read()
|
|
412
|
+
hashes = get_upload_hashes(content)
|
|
413
|
+
else:
|
|
414
|
+
# For medium files (256 KiB - 4 MiB), compute hashes without caching content
|
|
415
|
+
hashes = get_upload_hashes(fp)
|
|
403
416
|
|
|
404
417
|
return FileUploadSpec(
|
|
405
418
|
source=source,
|
|
@@ -407,11 +420,11 @@ def _get_file_upload_spec(
|
|
|
407
420
|
source_is_path=isinstance(source_description, Path),
|
|
408
421
|
mount_filename=mount_filename.as_posix(),
|
|
409
422
|
use_blob=use_blob,
|
|
410
|
-
content=content,
|
|
411
423
|
sha256_hex=hashes.sha256_hex(),
|
|
412
424
|
md5_hex=hashes.md5_hex(),
|
|
413
425
|
mode=mode & 0o7777,
|
|
414
426
|
size=size,
|
|
427
|
+
content=content,
|
|
415
428
|
)
|
|
416
429
|
|
|
417
430
|
|
|
@@ -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.dev27",
|
|
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.dev27",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -466,16 +466,18 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
466
466
|
loop = asyncio.get_event_loop()
|
|
467
467
|
with concurrent.futures.ThreadPoolExecutor() as exe:
|
|
468
468
|
all_files = await loop.run_in_executor(exe, _select_files, entries)
|
|
469
|
+
logger.debug(f"Computing checksums for {len(all_files)} files using {exe._max_workers} worker threads")
|
|
469
470
|
|
|
470
|
-
|
|
471
|
+
# Yield FileUploadSpec objects lazily as they're consumed by async_map downstream.
|
|
472
|
+
# async_map's concurrency limit provides natural backpressure, so we don't need
|
|
473
|
+
# a separate semaphore here. This keeps memory bounded without creating all tasks upfront.
|
|
471
474
|
for local_filename, remote_filename in all_files:
|
|
472
|
-
logger.debug(f"Mounting {local_filename} as {remote_filename}")
|
|
473
|
-
futs.append(loop.run_in_executor(exe, get_file_upload_spec_from_path, local_filename, remote_filename))
|
|
474
|
-
|
|
475
|
-
logger.debug(f"Computing checksums for {len(futs)} files using {exe._max_workers} worker threads")
|
|
476
|
-
for fut in asyncio.as_completed(futs):
|
|
477
475
|
try:
|
|
478
|
-
|
|
476
|
+
logger.debug(f"Mounting {local_filename} as {remote_filename}")
|
|
477
|
+
file_spec = await loop.run_in_executor(
|
|
478
|
+
exe, get_file_upload_spec_from_path, local_filename, remote_filename
|
|
479
|
+
)
|
|
480
|
+
yield file_spec
|
|
479
481
|
except FileNotFoundError as exc:
|
|
480
482
|
# Can happen with temporary files (e.g. emacs will write temp files and delete them quickly)
|
|
481
483
|
logger.info(f"Ignoring file not found: {exc}")
|
|
@@ -547,7 +549,11 @@ class _Mount(_Object, type_prefix="mo"):
|
|
|
547
549
|
logger.debug(
|
|
548
550
|
f"Uploading file {file_spec.source_description} to {remote_filename} ({file_spec.size} bytes)"
|
|
549
551
|
)
|
|
550
|
-
|
|
552
|
+
if file_spec.content is None:
|
|
553
|
+
content = await asyncio.to_thread(file_spec.read_content)
|
|
554
|
+
else:
|
|
555
|
+
content = file_spec.content
|
|
556
|
+
request2 = api_pb2.MountPutFileRequest(data=content, sha256_hex=file_spec.sha256_hex)
|
|
551
557
|
|
|
552
558
|
start_time = time.monotonic()
|
|
553
559
|
while time.monotonic() - start_time < MOUNT_PUT_FILE_CLIENT_TIMEOUT:
|
|
@@ -1056,7 +1056,11 @@ class _VolumeUploadContextManager(_AbstractVolumeUploadContextManager):
|
|
|
1056
1056
|
logger.debug(
|
|
1057
1057
|
f"Uploading file {file_spec.source_description} to {remote_filename} ({file_spec.size} bytes)"
|
|
1058
1058
|
)
|
|
1059
|
-
|
|
1059
|
+
if file_spec.content is None:
|
|
1060
|
+
content = await asyncio.to_thread(file_spec.read_content)
|
|
1061
|
+
else:
|
|
1062
|
+
content = file_spec.content
|
|
1063
|
+
request2 = api_pb2.MountPutFileRequest(data=content, sha256_hex=file_spec.sha256_hex)
|
|
1060
1064
|
self._progress_cb(task_id=progress_task_id, complete=True)
|
|
1061
1065
|
|
|
1062
1066
|
while (time.monotonic() - start_time) < VOLUME_PUT_FILE_CLIENT_TIMEOUT:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|