modal 1.0.2.dev6__py3-none-any.whl → 1.0.3.dev0__py3-none-any.whl
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/_utils/bytes_io_segment_payload.py +17 -3
- modal/client.pyi +2 -2
- modal/functions.pyi +6 -6
- modal/sandbox.py +2 -1
- modal/schedule.py +17 -4
- {modal-1.0.2.dev6.dist-info → modal-1.0.3.dev0.dist-info}/METADATA +1 -1
- {modal-1.0.2.dev6.dist-info → modal-1.0.3.dev0.dist-info}/RECORD +12 -12
- modal_version/__init__.py +1 -1
- {modal-1.0.2.dev6.dist-info → modal-1.0.3.dev0.dist-info}/WHEEL +0 -0
- {modal-1.0.2.dev6.dist-info → modal-1.0.3.dev0.dist-info}/entry_points.txt +0 -0
- {modal-1.0.2.dev6.dist-info → modal-1.0.3.dev0.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.2.dev6.dist-info → modal-1.0.3.dev0.dist-info}/top_level.txt +0 -0
@@ -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 Payload
|
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(Payload):
|
19
19
|
"""Modified bytes payload for concurrent sends of chunks from the same file.
|
20
20
|
|
21
21
|
Adds:
|
@@ -26,6 +26,8 @@ class BytesIOSegmentPayload(BytesIOPayload):
|
|
26
26
|
Feels like this should be in some standard lib...
|
27
27
|
"""
|
28
28
|
|
29
|
+
_value: BinaryIO
|
30
|
+
|
29
31
|
def __init__(
|
30
32
|
self,
|
31
33
|
bytes_io: BinaryIO, # should *not* be shared as IO position modification is not locked
|
@@ -36,6 +38,7 @@ class BytesIOSegmentPayload(BytesIOPayload):
|
|
36
38
|
):
|
37
39
|
# not thread safe constructor!
|
38
40
|
super().__init__(bytes_io)
|
41
|
+
self._size = segment_length
|
39
42
|
self.initial_seek_pos = bytes_io.tell()
|
40
43
|
self.segment_start = segment_start
|
41
44
|
self.segment_length = segment_length
|
@@ -46,6 +49,10 @@ class BytesIOSegmentPayload(BytesIOPayload):
|
|
46
49
|
self.progress_report_cb = progress_report_cb or (lambda *_, **__: None)
|
47
50
|
self.reset_state()
|
48
51
|
|
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
|
+
|
49
56
|
def reset_state(self):
|
50
57
|
self._md5_checksum = hashlib.md5()
|
51
58
|
self.num_bytes_read = 0
|
@@ -76,14 +83,21 @@ class BytesIOSegmentPayload(BytesIOPayload):
|
|
76
83
|
return self._md5_checksum
|
77
84
|
|
78
85
|
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]):
|
79
91
|
loop = asyncio.get_event_loop()
|
80
92
|
|
81
93
|
async def safe_read():
|
82
94
|
read_start = self.initial_seek_pos + self.segment_start + self.num_bytes_read
|
83
95
|
self._value.seek(read_start)
|
84
96
|
num_bytes = min(self.chunk_size, self.remaining_bytes())
|
85
|
-
|
97
|
+
if content_length is not None:
|
98
|
+
num_bytes = min(num_bytes, content_length)
|
86
99
|
|
100
|
+
chunk = await loop.run_in_executor(None, self._value.read, num_bytes)
|
87
101
|
await loop.run_in_executor(None, self._md5_checksum.update, chunk)
|
88
102
|
self.num_bytes_read += len(chunk)
|
89
103
|
return chunk
|
modal/client.pyi
CHANGED
@@ -31,7 +31,7 @@ class _Client:
|
|
31
31
|
server_url: str,
|
32
32
|
client_type: int,
|
33
33
|
credentials: typing.Optional[tuple[str, str]],
|
34
|
-
version: str = "1.0.
|
34
|
+
version: str = "1.0.3.dev0",
|
35
35
|
): ...
|
36
36
|
def is_closed(self) -> bool: ...
|
37
37
|
@property
|
@@ -94,7 +94,7 @@ class Client:
|
|
94
94
|
server_url: str,
|
95
95
|
client_type: int,
|
96
96
|
credentials: typing.Optional[tuple[str, str]],
|
97
|
-
version: str = "1.0.
|
97
|
+
version: str = "1.0.3.dev0",
|
98
98
|
): ...
|
99
99
|
def is_closed(self) -> bool: ...
|
100
100
|
@property
|
modal/functions.pyi
CHANGED
@@ -227,11 +227,11 @@ class Function(
|
|
227
227
|
|
228
228
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
229
229
|
|
230
|
-
class __remote_spec(typing_extensions.Protocol[
|
230
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
231
231
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
232
232
|
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
233
233
|
|
234
|
-
remote: __remote_spec[modal._functions.
|
234
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
235
235
|
|
236
236
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
237
237
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
|
@@ -246,12 +246,12 @@ class Function(
|
|
246
246
|
self, *args: modal._functions.P.args, **kwargs: modal._functions.P.kwargs
|
247
247
|
) -> modal._functions.OriginalReturnType: ...
|
248
248
|
|
249
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
249
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
250
250
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
251
251
|
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
252
252
|
|
253
253
|
_experimental_spawn: ___experimental_spawn_spec[
|
254
|
-
modal._functions.
|
254
|
+
modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
|
255
255
|
]
|
256
256
|
|
257
257
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
@@ -260,11 +260,11 @@ class Function(
|
|
260
260
|
|
261
261
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
262
262
|
|
263
|
-
class __spawn_spec(typing_extensions.Protocol[
|
263
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
264
264
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
265
265
|
async def aio(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
266
266
|
|
267
|
-
spawn: __spawn_spec[modal._functions.
|
267
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
268
268
|
|
269
269
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]: ...
|
270
270
|
|
modal/sandbox.py
CHANGED
@@ -252,7 +252,8 @@ 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.
|
255
|
+
Create a new Sandbox to run untrusted, arbitrary code. The Sandbox's corresponding container
|
256
|
+
will be created asynchronously.
|
256
257
|
|
257
258
|
**Usage**
|
258
259
|
|
modal/schedule.py
CHANGED
@@ -30,15 +30,28 @@ class Cron(Schedule):
|
|
30
30
|
We can specify different schedules with cron strings, for example:
|
31
31
|
|
32
32
|
```python
|
33
|
-
modal.Cron("5 4 * * *") # run at 4:05am every night
|
34
|
-
modal.Cron("0 9 * * 4") # runs every Thursday 9am
|
33
|
+
modal.Cron("5 4 * * *") # run at 4:05am UTC every night
|
34
|
+
modal.Cron("0 9 * * 4") # runs every Thursday at 9am UTC
|
35
35
|
```
|
36
36
|
|
37
|
+
We can also optionally specify a timezone, for example:
|
38
|
+
|
39
|
+
```python
|
40
|
+
# Run daily at 6am New York time, regardless of whether daylight saving
|
41
|
+
# is in effect (i.e. at 11am UTC in the winter, and 10am UTC in the summer):
|
42
|
+
modal.Cron("0 6 * * *", timezone="America/New_York")
|
43
|
+
```
|
44
|
+
|
45
|
+
If no timezone is specified, the default is UTC.
|
37
46
|
"""
|
38
47
|
|
39
|
-
def __init__(
|
48
|
+
def __init__(
|
49
|
+
self,
|
50
|
+
cron_string: str,
|
51
|
+
timezone: str = "UTC",
|
52
|
+
) -> None:
|
40
53
|
"""Construct a schedule that runs according to a cron expression string."""
|
41
|
-
cron = api_pb2.Schedule.Cron(cron_string=cron_string)
|
54
|
+
cron = api_pb2.Schedule.Cron(cron_string=cron_string, timezone=timezone)
|
42
55
|
super().__init__(api_pb2.Schedule(cron=cron))
|
43
56
|
|
44
57
|
|
@@ -22,7 +22,7 @@ modal/app.py,sha256=NZ_rJ9TuMfiNiLg8-gOFgufD5flGtXWPHOZI0gdD3hE,46585
|
|
22
22
|
modal/app.pyi,sha256=4-b_vbe3lNAqQPcMRpQCEDsE1zsVkQRJGUql9B7HvbM,22659
|
23
23
|
modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
|
24
24
|
modal/client.py,sha256=OwISJvkgMb-rHm9Gc4i-7YcDgGiZgwJ7F_PzwZH7a6Q,16847
|
25
|
-
modal/client.pyi,sha256=
|
25
|
+
modal/client.pyi,sha256=WchjEazuZYhrnl4NEK8hQ7uGCStzILQX1T7vTVI05I4,8457
|
26
26
|
modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
|
27
27
|
modal/cloud_bucket_mount.pyi,sha256=30T3K1a89l6wzmEJ_J9iWv9SknoGqaZDx59Xs-ZQcmk,1607
|
28
28
|
modal/cls.py,sha256=dBbeARwOWftlKd1cwtM0cHFtQWSWkwVXwVmOV4w0SyI,37907
|
@@ -39,7 +39,7 @@ modal/file_io.py,sha256=lcMs_E9Xfm0YX1t9U2wNIBPnqHRxmImqjLW1GHqVmyg,20945
|
|
39
39
|
modal/file_io.pyi,sha256=oB7x-rKq7bmm8cA7Z7W9C9yeko7KK9m9i5GidFnkGK4,9569
|
40
40
|
modal/file_pattern_matcher.py,sha256=wov-otB5M1oTdrYDtR2_VgacYin2srdtAP4McA1Cqzw,6516
|
41
41
|
modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
|
42
|
-
modal/functions.pyi,sha256=
|
42
|
+
modal/functions.pyi,sha256=5T58OucdNU4I-LqhBdwsWSAGka-Wa8nP2GcZ5K1bOL0,16236
|
43
43
|
modal/gpu.py,sha256=Kbhs_u49FaC2Zi0TjCdrpstpRtT5eZgecynmQi5IZVE,6752
|
44
44
|
modal/image.py,sha256=-ia4ELkIh4sxOSqdYETAPV8EEb58Nue6DLdAxhM2C_Y,92687
|
45
45
|
modal/image.pyi,sha256=2xjB6XOZDtm_chDdd90UoIj8pnDt5hCg6bOmu5fNaA4,25625
|
@@ -65,9 +65,9 @@ modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
|
|
65
65
|
modal/runner.py,sha256=nvpnU7U2O5d2WqME1QUTTwu-NkSLLwblytlGk7HXPAw,24152
|
66
66
|
modal/runner.pyi,sha256=1AnEu48SUPnLWp3raQ2zJCV5lc85EGLkX2nL0bHWaB0,5162
|
67
67
|
modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
|
68
|
-
modal/sandbox.py,sha256=
|
68
|
+
modal/sandbox.py,sha256=zUldeCA98GLObLT1N9v1IILomcPYeLrQJRCRUMTtbLE,35734
|
69
69
|
modal/sandbox.pyi,sha256=stxwoLcyQNToPISj6umlU8sDUgqzeooLdMs3BwIr740,28195
|
70
|
-
modal/schedule.py,sha256=
|
70
|
+
modal/schedule.py,sha256=SdH8jk6S0zoc1bTRVblrVw0zBsNwPlSC2gNpVxMet9g,3061
|
71
71
|
modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
|
72
72
|
modal/secret.py,sha256=I2z-rgKWl_Ix107d2_Y2OWGXdFOuJ7zMOyDfIOdFI1A,10374
|
73
73
|
modal/secret.pyi,sha256=NY_dz0UjiYyn4u4LaBZwPP3Ji7SlTLpEyzrYK2sj9HQ,3103
|
@@ -93,7 +93,7 @@ modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
|
|
93
93
|
modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
|
94
94
|
modal/_utils/async_utils.py,sha256=zjdtdA54zvNL_RuREmN5NWFhhiRcNh8z0jT2rBc5RgY,28001
|
95
95
|
modal/_utils/blob_utils.py,sha256=IexC2Jbtqp_Tkmy62ayfgzTYte0UPCNufB_v-DO21g8,18585
|
96
|
-
modal/_utils/bytes_io_segment_payload.py,sha256=
|
96
|
+
modal/_utils/bytes_io_segment_payload.py,sha256=vaXPq8b52-x6G2hwE7SrjS58pg_aRm7gV3bn3yjmTzQ,4261
|
97
97
|
modal/_utils/deprecation.py,sha256=EXP1beU4pmEqEzWMLw6E3kUfNfpmNA_VOp6i0EHi93g,4856
|
98
98
|
modal/_utils/docker_utils.py,sha256=h1uETghR40mp_y3fSWuZAfbIASH1HMzuphJHghAL6DU,3722
|
99
99
|
modal/_utils/function_utils.py,sha256=bhrjyOHPPXm6fAyJx3bzI1Yh56j6xh8eeMSFKdAWrHQ,26978
|
@@ -147,7 +147,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
|
|
147
147
|
modal/requirements/PREVIEW.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddRo,296
|
148
148
|
modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
|
149
149
|
modal/requirements/base-images.json,sha256=57vMSqzMbLBxw5tFWSaMiIkkVEps4JfX5PAtXGnkS4U,740
|
150
|
-
modal-1.0.
|
150
|
+
modal-1.0.3.dev0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
151
151
|
modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
|
152
152
|
modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
|
153
153
|
modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
|
@@ -170,10 +170,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
|
|
170
170
|
modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
171
171
|
modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
|
172
172
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
173
|
-
modal_version/__init__.py,sha256=
|
173
|
+
modal_version/__init__.py,sha256=PBOcW6yepZON7eAPdHj5SjQ9s_hSBK07voJ08ugbBuI,120
|
174
174
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
175
|
-
modal-1.0.
|
176
|
-
modal-1.0.
|
177
|
-
modal-1.0.
|
178
|
-
modal-1.0.
|
179
|
-
modal-1.0.
|
175
|
+
modal-1.0.3.dev0.dist-info/METADATA,sha256=d5X9f8PR_Vz4GPggWSto0prphSlc0LF2vyOB4nVcLd8,2454
|
176
|
+
modal-1.0.3.dev0.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
177
|
+
modal-1.0.3.dev0.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
178
|
+
modal-1.0.3.dev0.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
|
179
|
+
modal-1.0.3.dev0.dist-info/RECORD,,
|
modal_version/__init__.py
CHANGED
File without changes
|
File without changes
|
File without changes
|
File without changes
|