modAL 1.0.2__tar.gz → 1.0.2.dev0__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.0.2 → modal-1.0.2.dev0}/PKG-INFO +1 -1
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_functions.py +0 -6
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/bytes_io_segment_payload.py +5 -23
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/client.pyi +10 -2
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/exception.py +0 -2
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/image.py +16 -38
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/sandbox.py +1 -2
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/volume.py +15 -30
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/volume.pyi +2 -2
- {modal-1.0.2 → modal-1.0.2.dev0}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/api.proto +0 -3
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/api_pb2.py +374 -374
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/api_pb2.pyi +3 -16
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_version/__init__.py +1 -1
- {modal-1.0.2 → modal-1.0.2.dev0}/LICENSE +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/README.md +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/__main__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_clustered_functions.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_clustered_functions.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_container_entrypoint.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_ipython.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_location.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_object.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_output.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_partial_function.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_pty.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_resolver.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_resources.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/asgi.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/execution_context.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/telemetry.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_serialization.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_traceback.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_tunnel.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_tunnel.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_type_manager.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/app_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/async_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/blob_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/deprecation.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/docker_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/function_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/git_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/hash_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/http_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/logger.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/mount_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/name_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/package_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/shell_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_utils/time_utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_vendor/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_vendor/tblib.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/_watcher.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/app.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/app.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/call_graph.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/_download.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/_traceback.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/app.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/cluster.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/config.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/container.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/dict.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/entry_point.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/environment.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/import_refs.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/launch.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/network_file_system.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/profile.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/programs/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/programs/vscode.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/queues.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/run.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/secret.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/token.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/utils.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cli/volume.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/client.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cls.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/cls.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/config.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/container_process.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/container_process.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/dict.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/dict.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/environments.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/environments.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/experimental/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/experimental/ipython.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/file_io.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/file_io.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/file_pattern_matcher.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/functions.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/functions.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/gpu.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/image.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/io_streams.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/io_streams.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/mount.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/mount.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/network_file_system.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/network_file_system.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/object.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/object.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/output.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/parallel_map.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/parallel_map.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/partial_function.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/partial_function.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/proxy.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/proxy.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/py.typed +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/queue.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/queue.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/requirements/2023.12.312.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/requirements/2023.12.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/requirements/2024.04.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/requirements/2024.10.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/requirements/PREVIEW.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/requirements/README.md +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/requirements/base-images.json +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/retries.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/runner.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/runner.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/running_app.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/sandbox.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/schedule.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/scheduler_placement.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/secret.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/secret.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/serving.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/serving.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/snapshot.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/snapshot.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/stream_type.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/token_flow.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal/token_flow.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal.egg-info/requires.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal.egg-info/top_level.txt +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_docs/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/__init__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/api_grpc.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/modal_options_grpc.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/options.proto +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/options_grpc.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/options_pb2.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/options_pb2.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/options_pb2_grpc.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/options_pb2_grpc.pyi +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_proto/py.typed +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/modal_version/__main__.py +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/pyproject.toml +0 -0
- {modal-1.0.2 → modal-1.0.2.dev0}/setup.cfg +0 -0
|
@@ -815,11 +815,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
815
815
|
if app and app.name:
|
|
816
816
|
app_name = app.name
|
|
817
817
|
|
|
818
|
-
# on builder > 2024.10 we mount client dependencies at runtime
|
|
819
|
-
mount_client_dependencies = False
|
|
820
|
-
if image._metadata is not None:
|
|
821
|
-
mount_client_dependencies = image._metadata.image_builder_version > "2024.10"
|
|
822
|
-
|
|
823
818
|
# Relies on dicts being ordered (true as of Python 3.6).
|
|
824
819
|
volume_mounts = [
|
|
825
820
|
api_pb2.VolumeMount(
|
|
@@ -889,7 +884,6 @@ class _Function(typing.Generic[P, ReturnType, OriginalReturnType], _Object, type
|
|
|
889
884
|
schedule=schedule.proto_message if schedule is not None else None,
|
|
890
885
|
snapshot_debug=config.get("snapshot_debug"),
|
|
891
886
|
experimental_options=experimental_options or {},
|
|
892
|
-
mount_client_dependencies=mount_client_dependencies,
|
|
893
887
|
# ---
|
|
894
888
|
_experimental_group_size=cluster_size or 0, # Experimental: Clustered functions
|
|
895
889
|
_experimental_concurrent_cancellations=True,
|
|
@@ -8,14 +8,14 @@ from typing import BinaryIO, Callable, Optional
|
|
|
8
8
|
# Note: this module needs to import aiohttp in global scope
|
|
9
9
|
# This takes about 50ms and isn't needed in many cases for Modal execution
|
|
10
10
|
# To avoid this, we import it in local scope when needed (blob_utils.py)
|
|
11
|
-
from aiohttp import
|
|
11
|
+
from aiohttp import BytesIOPayload
|
|
12
12
|
from aiohttp.abc import AbstractStreamWriter
|
|
13
13
|
|
|
14
14
|
# read ~16MiB chunks by default
|
|
15
15
|
DEFAULT_SEGMENT_CHUNK_SIZE = 2**24
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class BytesIOSegmentPayload(
|
|
18
|
+
class BytesIOSegmentPayload(BytesIOPayload):
|
|
19
19
|
"""Modified bytes payload for concurrent sends of chunks from the same file.
|
|
20
20
|
|
|
21
21
|
Adds:
|
|
@@ -26,8 +26,6 @@ class BytesIOSegmentPayload(Payload):
|
|
|
26
26
|
Feels like this should be in some standard lib...
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
|
-
_value: BinaryIO
|
|
30
|
-
|
|
31
29
|
def __init__(
|
|
32
30
|
self,
|
|
33
31
|
bytes_io: BinaryIO, # should *not* be shared as IO position modification is not locked
|
|
@@ -38,7 +36,6 @@ class BytesIOSegmentPayload(Payload):
|
|
|
38
36
|
):
|
|
39
37
|
# not thread safe constructor!
|
|
40
38
|
super().__init__(bytes_io)
|
|
41
|
-
self._size = segment_length
|
|
42
39
|
self.initial_seek_pos = bytes_io.tell()
|
|
43
40
|
self.segment_start = segment_start
|
|
44
41
|
self.segment_length = segment_length
|
|
@@ -49,26 +46,18 @@ class BytesIOSegmentPayload(Payload):
|
|
|
49
46
|
self.progress_report_cb = progress_report_cb or (lambda *_, **__: None)
|
|
50
47
|
self.reset_state()
|
|
51
48
|
|
|
52
|
-
def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str:
|
|
53
|
-
self._value.seek(self.initial_seek_pos)
|
|
54
|
-
return self._value.read().decode(encoding, errors)
|
|
55
|
-
|
|
56
49
|
def reset_state(self):
|
|
57
50
|
self._md5_checksum = hashlib.md5()
|
|
58
51
|
self.num_bytes_read = 0
|
|
59
52
|
self._value.seek(self.initial_seek_pos)
|
|
60
53
|
|
|
61
54
|
@contextmanager
|
|
62
|
-
def reset_on_error(self
|
|
55
|
+
def reset_on_error(self):
|
|
63
56
|
try:
|
|
64
57
|
yield
|
|
65
58
|
except Exception as exc:
|
|
66
59
|
try:
|
|
67
|
-
|
|
68
|
-
negative_progress = -self.num_bytes_read
|
|
69
|
-
self.progress_report_cb(advance=negative_progress)
|
|
70
|
-
else:
|
|
71
|
-
self.progress_report_cb(reset=True)
|
|
60
|
+
self.progress_report_cb(reset=True)
|
|
72
61
|
except Exception as cb_exc:
|
|
73
62
|
raise cb_exc from exc
|
|
74
63
|
raise exc
|
|
@@ -83,21 +72,14 @@ class BytesIOSegmentPayload(Payload):
|
|
|
83
72
|
return self._md5_checksum
|
|
84
73
|
|
|
85
74
|
async def write(self, writer: "AbstractStreamWriter"):
|
|
86
|
-
# On aiohttp < 3.12.0 - this is the method that's being called on a custom payload,
|
|
87
|
-
# but on aiohttp 3.12+ `write_with_length` is called directly.
|
|
88
|
-
await self.write_with_length(writer, None)
|
|
89
|
-
|
|
90
|
-
async def write_with_length(self, writer: AbstractStreamWriter, content_length: Optional[int]):
|
|
91
75
|
loop = asyncio.get_event_loop()
|
|
92
76
|
|
|
93
77
|
async def safe_read():
|
|
94
78
|
read_start = self.initial_seek_pos + self.segment_start + self.num_bytes_read
|
|
95
79
|
self._value.seek(read_start)
|
|
96
80
|
num_bytes = min(self.chunk_size, self.remaining_bytes())
|
|
97
|
-
if content_length is not None:
|
|
98
|
-
num_bytes = min(num_bytes, content_length)
|
|
99
|
-
|
|
100
81
|
chunk = await loop.run_in_executor(None, self._value.read, num_bytes)
|
|
82
|
+
|
|
101
83
|
await loop.run_in_executor(None, self._md5_checksum.update, chunk)
|
|
102
84
|
self.num_bytes_read += len(chunk)
|
|
103
85
|
return chunk
|
|
@@ -27,7 +27,11 @@ class _Client:
|
|
|
27
27
|
_snapshotted: bool
|
|
28
28
|
|
|
29
29
|
def __init__(
|
|
30
|
-
self,
|
|
30
|
+
self,
|
|
31
|
+
server_url: str,
|
|
32
|
+
client_type: int,
|
|
33
|
+
credentials: typing.Optional[tuple[str, str]],
|
|
34
|
+
version: str = "1.0.2.dev0",
|
|
31
35
|
): ...
|
|
32
36
|
def is_closed(self) -> bool: ...
|
|
33
37
|
@property
|
|
@@ -86,7 +90,11 @@ class Client:
|
|
|
86
90
|
_snapshotted: bool
|
|
87
91
|
|
|
88
92
|
def __init__(
|
|
89
|
-
self,
|
|
93
|
+
self,
|
|
94
|
+
server_url: str,
|
|
95
|
+
client_type: int,
|
|
96
|
+
credentials: typing.Optional[tuple[str, str]],
|
|
97
|
+
version: str = "1.0.2.dev0",
|
|
90
98
|
): ...
|
|
91
99
|
def is_closed(self) -> bool: ...
|
|
92
100
|
@property
|
|
@@ -161,8 +161,6 @@ def simulate_preemption(wait_seconds: int, jitter_seconds: int = 0):
|
|
|
161
161
|
See https://modal.com/docs/guide/preemption for more details on preemption
|
|
162
162
|
handling.
|
|
163
163
|
"""
|
|
164
|
-
if wait_seconds <= 0:
|
|
165
|
-
raise ValueError("Time to wait must be greater than 0")
|
|
166
164
|
signal.signal(signal.SIGALRM, _simulate_preemption_interrupt)
|
|
167
165
|
jitter = random.randrange(0, jitter_seconds) if jitter_seconds else 0
|
|
168
166
|
signal.alarm(wait_seconds + jitter)
|
|
@@ -1442,9 +1442,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1442
1442
|
if version > "2024.10":
|
|
1443
1443
|
# for convenience when launching in a sandbox: sleep for 48h
|
|
1444
1444
|
commands.append(f'CMD ["sleep", "{48 * 3600}"]')
|
|
1445
|
-
context_files = {}
|
|
1446
|
-
if version <= "2024.10":
|
|
1447
|
-
context_files = {CONTAINER_REQUIREMENTS_PATH: _get_modal_requirements_path(version, python_version)}
|
|
1445
|
+
context_files = {CONTAINER_REQUIREMENTS_PATH: _get_modal_requirements_path(version, python_version)}
|
|
1448
1446
|
return DockerfileSpec(commands=commands, context_files=context_files)
|
|
1449
1447
|
|
|
1450
1448
|
return _Image._from_args(
|
|
@@ -1519,15 +1517,12 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1519
1517
|
|
|
1520
1518
|
# Note: this change is because we install dependencies with uv in 2024.10+
|
|
1521
1519
|
requirements_prefix = "python -m " if builder_version < "2024.10" else ""
|
|
1522
|
-
modal_requirements_commands = [
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
f"RUN {requirements_prefix}{_get_modal_requirements_command(builder_version)}",
|
|
1529
|
-
])
|
|
1530
|
-
if "2024.10" >= builder_version > "2023.12":
|
|
1520
|
+
modal_requirements_commands = [
|
|
1521
|
+
f"COPY {CONTAINER_REQUIREMENTS_PATH} {CONTAINER_REQUIREMENTS_PATH}",
|
|
1522
|
+
f"RUN python -m pip install --upgrade {_base_image_config('package_tools', builder_version)}",
|
|
1523
|
+
f"RUN {requirements_prefix}{_get_modal_requirements_command(builder_version)}",
|
|
1524
|
+
]
|
|
1525
|
+
if builder_version > "2023.12":
|
|
1531
1526
|
modal_requirements_commands.append(f"RUN rm {CONTAINER_REQUIREMENTS_PATH}")
|
|
1532
1527
|
|
|
1533
1528
|
return [
|
|
@@ -1590,9 +1585,7 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1590
1585
|
|
|
1591
1586
|
def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
|
|
1592
1587
|
commands = _Image._registry_setup_commands(tag, version, setup_dockerfile_commands, add_python)
|
|
1593
|
-
context_files = {}
|
|
1594
|
-
if version <= "2024.10":
|
|
1595
|
-
context_files = {CONTAINER_REQUIREMENTS_PATH: _get_modal_requirements_path(version, add_python)}
|
|
1588
|
+
context_files = {CONTAINER_REQUIREMENTS_PATH: _get_modal_requirements_path(version, add_python)}
|
|
1596
1589
|
return DockerfileSpec(commands=commands, context_files=context_files)
|
|
1597
1590
|
|
|
1598
1591
|
return _Image._from_args(
|
|
@@ -1799,10 +1792,8 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1799
1792
|
|
|
1800
1793
|
def build_dockerfile_python(version: ImageBuilderVersion) -> DockerfileSpec:
|
|
1801
1794
|
commands = _Image._registry_setup_commands("base", version, [], add_python)
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
requirements_path = _get_modal_requirements_path(version, add_python)
|
|
1805
|
-
context_files = {CONTAINER_REQUIREMENTS_PATH: requirements_path}
|
|
1795
|
+
requirements_path = _get_modal_requirements_path(version, add_python)
|
|
1796
|
+
context_files = {CONTAINER_REQUIREMENTS_PATH: requirements_path}
|
|
1806
1797
|
return DockerfileSpec(commands=commands, context_files=context_files)
|
|
1807
1798
|
|
|
1808
1799
|
return _Image._from_args(
|
|
@@ -1819,35 +1810,22 @@ class _Image(_Object, type_prefix="im"):
|
|
|
1819
1810
|
raise TypeError("The `python_version` argument should be a string, not a float.")
|
|
1820
1811
|
|
|
1821
1812
|
def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
requirements_path = _get_modal_requirements_path(version, python_version)
|
|
1825
|
-
context_files = {CONTAINER_REQUIREMENTS_PATH: requirements_path}
|
|
1813
|
+
requirements_path = _get_modal_requirements_path(version, python_version)
|
|
1814
|
+
context_files = {CONTAINER_REQUIREMENTS_PATH: requirements_path}
|
|
1826
1815
|
full_python_version = _dockerhub_python_version(version, python_version)
|
|
1827
1816
|
debian_codename = _base_image_config("debian", version)
|
|
1828
1817
|
|
|
1829
1818
|
commands = [
|
|
1830
1819
|
f"FROM python:{full_python_version}-slim-{debian_codename}",
|
|
1831
|
-
|
|
1832
|
-
if version <= "2024.10":
|
|
1833
|
-
commands.extend([
|
|
1834
|
-
f"COPY {CONTAINER_REQUIREMENTS_PATH} {CONTAINER_REQUIREMENTS_PATH}",
|
|
1835
|
-
])
|
|
1836
|
-
commands.extend([
|
|
1820
|
+
f"COPY {CONTAINER_REQUIREMENTS_PATH} {CONTAINER_REQUIREMENTS_PATH}",
|
|
1837
1821
|
"RUN apt-get update",
|
|
1838
1822
|
"RUN apt-get install -y gcc gfortran build-essential",
|
|
1839
1823
|
f"RUN pip install --upgrade {_base_image_config('package_tools', version)}",
|
|
1840
|
-
|
|
1841
|
-
if version <= "2024.10":
|
|
1842
|
-
# after 2024.10, modal requirements are mounted at runtime
|
|
1843
|
-
commands.extend([
|
|
1844
|
-
f"RUN {_get_modal_requirements_command(version)}",
|
|
1845
|
-
])
|
|
1846
|
-
commands.extend([
|
|
1824
|
+
f"RUN {_get_modal_requirements_command(version)}",
|
|
1847
1825
|
# Set debian front-end to non-interactive to avoid users getting stuck with input prompts.
|
|
1848
1826
|
"RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections",
|
|
1849
|
-
]
|
|
1850
|
-
if
|
|
1827
|
+
]
|
|
1828
|
+
if version > "2023.12":
|
|
1851
1829
|
commands.append(f"RUN rm {CONTAINER_REQUIREMENTS_PATH}")
|
|
1852
1830
|
if version > "2024.10":
|
|
1853
1831
|
# for convenience when launching in a sandbox: sleep for 48h
|
|
@@ -252,8 +252,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
|
252
252
|
client: Optional[_Client] = None,
|
|
253
253
|
) -> "_Sandbox":
|
|
254
254
|
"""
|
|
255
|
-
Create a new Sandbox to run untrusted, arbitrary code.
|
|
256
|
-
will be created asynchronously.
|
|
255
|
+
Create a new Sandbox to run untrusted, arbitrary code.
|
|
257
256
|
|
|
258
257
|
**Usage**
|
|
259
258
|
|
|
@@ -38,7 +38,6 @@ from ._utils.async_utils import (
|
|
|
38
38
|
async_map,
|
|
39
39
|
async_map_ordered,
|
|
40
40
|
asyncnullcontext,
|
|
41
|
-
retry,
|
|
42
41
|
synchronize_api,
|
|
43
42
|
)
|
|
44
43
|
from ._utils.blob_utils import (
|
|
@@ -376,16 +375,10 @@ class _Volume(_Object, type_prefix="vo"):
|
|
|
376
375
|
"Please remove the glob `*` suffix."
|
|
377
376
|
)
|
|
378
377
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
yield FileEntry._from_proto(entry)
|
|
384
|
-
else:
|
|
385
|
-
req = api_pb2.VolumeListFiles2Request(volume_id=self.object_id, path=path, recursive=recursive)
|
|
386
|
-
async for batch in self._client.stub.VolumeListFiles2.unary_stream(req):
|
|
387
|
-
for entry in batch.entries:
|
|
388
|
-
yield FileEntry._from_proto(entry)
|
|
378
|
+
req = api_pb2.VolumeListFilesRequest(volume_id=self.object_id, path=path, recursive=recursive)
|
|
379
|
+
async for batch in self._client.stub.VolumeListFiles.unary_stream(req):
|
|
380
|
+
for entry in batch.entries:
|
|
381
|
+
yield FileEntry._from_proto(entry)
|
|
389
382
|
|
|
390
383
|
@live_method
|
|
391
384
|
async def listdir(self, path: str, *, recursive: bool = False) -> list[FileEntry]:
|
|
@@ -506,7 +499,7 @@ class _Volume(_Object, type_prefix="vo"):
|
|
|
506
499
|
num_bytes_written = 0
|
|
507
500
|
|
|
508
501
|
async with download_semaphore, ClientSessionRegistry.get_session().get(url) as get_response:
|
|
509
|
-
async for chunk in get_response.content
|
|
502
|
+
async for chunk in get_response.content:
|
|
510
503
|
num_chunk_bytes_written = 0
|
|
511
504
|
|
|
512
505
|
while num_chunk_bytes_written < len(chunk):
|
|
@@ -533,12 +526,8 @@ class _Volume(_Object, type_prefix="vo"):
|
|
|
533
526
|
@live_method
|
|
534
527
|
async def remove_file(self, path: str, recursive: bool = False) -> None:
|
|
535
528
|
"""Remove a file or directory from a volume."""
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
await retry_transient_errors(self._client.stub.VolumeRemoveFile, req)
|
|
539
|
-
else:
|
|
540
|
-
req = api_pb2.VolumeRemoveFile2Request(volume_id=self.object_id, path=path, recursive=recursive)
|
|
541
|
-
await retry_transient_errors(self._client.stub.VolumeRemoveFile2, req)
|
|
529
|
+
req = api_pb2.VolumeRemoveFileRequest(volume_id=self.object_id, path=path, recursive=recursive)
|
|
530
|
+
await retry_transient_errors(self._client.stub.VolumeRemoveFile, req)
|
|
542
531
|
|
|
543
532
|
@live_method
|
|
544
533
|
async def copy_files(self, src_paths: Sequence[str], dst_path: str) -> None:
|
|
@@ -836,7 +825,7 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
|
|
|
836
825
|
progress_cb: Optional[Callable[..., Any]] = None,
|
|
837
826
|
force: bool = False,
|
|
838
827
|
hash_concurrency: int = multiprocessing.cpu_count(),
|
|
839
|
-
put_concurrency: int =
|
|
828
|
+
put_concurrency: int = multiprocessing.cpu_count(),
|
|
840
829
|
):
|
|
841
830
|
"""mdmd:hidden"""
|
|
842
831
|
self._volume_id = volume_id
|
|
@@ -1021,16 +1010,6 @@ async def _put_missing_blocks(
|
|
|
1021
1010
|
file_progress.pending_blocks.add(missing_block.block_index)
|
|
1022
1011
|
task_progress_cb = functools.partial(progress_cb, task_id=file_progress.task_id)
|
|
1023
1012
|
|
|
1024
|
-
@retry(n_attempts=5, base_delay=0.5, timeout=None)
|
|
1025
|
-
async def put_missing_block_attempt(payload: BytesIOSegmentPayload) -> bytes:
|
|
1026
|
-
with payload.reset_on_error(subtract_progress=True):
|
|
1027
|
-
async with ClientSessionRegistry.get_session().put(
|
|
1028
|
-
missing_block.put_url,
|
|
1029
|
-
data=payload,
|
|
1030
|
-
) as response:
|
|
1031
|
-
response.raise_for_status()
|
|
1032
|
-
return await response.content.read()
|
|
1033
|
-
|
|
1034
1013
|
async with put_semaphore:
|
|
1035
1014
|
with file_spec.source() as source_fp:
|
|
1036
1015
|
payload = BytesIOSegmentPayload(
|
|
@@ -1041,7 +1020,13 @@ async def _put_missing_blocks(
|
|
|
1041
1020
|
chunk_size=256 * 1024,
|
|
1042
1021
|
progress_report_cb=task_progress_cb,
|
|
1043
1022
|
)
|
|
1044
|
-
|
|
1023
|
+
|
|
1024
|
+
async with ClientSessionRegistry.get_session().put(
|
|
1025
|
+
missing_block.put_url,
|
|
1026
|
+
data=payload,
|
|
1027
|
+
) as response:
|
|
1028
|
+
response.raise_for_status()
|
|
1029
|
+
resp_data = await response.content.read()
|
|
1045
1030
|
|
|
1046
1031
|
file_progress.pending_blocks.remove(missing_block.block_index)
|
|
1047
1032
|
|
|
@@ -494,7 +494,7 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
|
|
|
494
494
|
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
|
495
495
|
force: bool = False,
|
|
496
496
|
hash_concurrency: int = 4,
|
|
497
|
-
put_concurrency: int =
|
|
497
|
+
put_concurrency: int = 4,
|
|
498
498
|
): ...
|
|
499
499
|
async def __aenter__(self): ...
|
|
500
500
|
async def __aexit__(self, exc_type, exc_val, exc_tb): ...
|
|
@@ -534,7 +534,7 @@ class VolumeUploadContextManager2(AbstractVolumeUploadContextManager):
|
|
|
534
534
|
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
|
535
535
|
force: bool = False,
|
|
536
536
|
hash_concurrency: int = 4,
|
|
537
|
-
put_concurrency: int =
|
|
537
|
+
put_concurrency: int = 4,
|
|
538
538
|
): ...
|
|
539
539
|
def __enter__(self): ...
|
|
540
540
|
async def __aenter__(self): ...
|
|
@@ -2153,7 +2153,6 @@ message PTYInfo {
|
|
|
2153
2153
|
message PortSpec {
|
|
2154
2154
|
uint32 port = 1;
|
|
2155
2155
|
bool unencrypted = 2;
|
|
2156
|
-
optional string tunnel_type = 3;
|
|
2157
2156
|
}
|
|
2158
2157
|
|
|
2159
2158
|
message PortSpecs {
|
|
@@ -2587,7 +2586,6 @@ message SandboxWaitResponse {
|
|
|
2587
2586
|
message Schedule {
|
|
2588
2587
|
message Cron {
|
|
2589
2588
|
string cron_string = 1;
|
|
2590
|
-
string timezone = 2;
|
|
2591
2589
|
}
|
|
2592
2590
|
message Period {
|
|
2593
2591
|
int32 years = 1;
|
|
@@ -2878,7 +2876,6 @@ message TunnelData {
|
|
|
2878
2876
|
message TunnelStartRequest {
|
|
2879
2877
|
uint32 port = 1;
|
|
2880
2878
|
bool unencrypted = 2;
|
|
2881
|
-
optional string tunnel_type = 3;
|
|
2882
2879
|
}
|
|
2883
2880
|
|
|
2884
2881
|
message TunnelStartResponse {
|