modal 1.0.3.dev24__py3-none-any.whl → 1.0.3.dev26__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/client.pyi +2 -2
- modal/parallel_map.py +47 -23
- {modal-1.0.3.dev24.dist-info → modal-1.0.3.dev26.dist-info}/METADATA +1 -1
- {modal-1.0.3.dev24.dist-info → modal-1.0.3.dev26.dist-info}/RECORD +9 -9
- modal_version/__init__.py +1 -1
- {modal-1.0.3.dev24.dist-info → modal-1.0.3.dev26.dist-info}/WHEEL +0 -0
- {modal-1.0.3.dev24.dist-info → modal-1.0.3.dev26.dist-info}/entry_points.txt +0 -0
- {modal-1.0.3.dev24.dist-info → modal-1.0.3.dev26.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.3.dev24.dist-info → modal-1.0.3.dev26.dist-info}/top_level.txt +0 -0
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.3.
|
34
|
+
version: str = "1.0.3.dev26",
|
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.3.
|
97
|
+
version: str = "1.0.3.dev26",
|
98
98
|
): ...
|
99
99
|
def is_closed(self) -> bool: ...
|
100
100
|
@property
|
modal/parallel_map.py
CHANGED
@@ -3,6 +3,7 @@ import asyncio
|
|
3
3
|
import enum
|
4
4
|
import time
|
5
5
|
import typing
|
6
|
+
from asyncio import FIRST_COMPLETED
|
6
7
|
from dataclasses import dataclass
|
7
8
|
from typing import Any, Callable, Optional
|
8
9
|
|
@@ -110,6 +111,7 @@ async def _map_invocation(
|
|
110
111
|
max_inputs_outstanding = response.max_inputs_outstanding or MAX_INPUTS_OUTSTANDING_DEFAULT
|
111
112
|
|
112
113
|
have_all_inputs = False
|
114
|
+
map_done_event = asyncio.Event()
|
113
115
|
inputs_created = 0
|
114
116
|
inputs_sent = 0
|
115
117
|
inputs_retried = 0
|
@@ -122,10 +124,6 @@ async def _map_invocation(
|
|
122
124
|
stale_retry_duplicates = 0
|
123
125
|
no_context_duplicates = 0
|
124
126
|
|
125
|
-
def count_update():
|
126
|
-
if count_update_callback is not None:
|
127
|
-
count_update_callback(outputs_completed, inputs_created)
|
128
|
-
|
129
127
|
retry_queue = TimestampPriorityQueue()
|
130
128
|
completed_outputs: set[str] = set() # Set of input_ids whose outputs are complete (expecting no more values)
|
131
129
|
input_queue: asyncio.Queue[api_pb2.FunctionPutInputsItem | None] = asyncio.Queue()
|
@@ -134,9 +132,8 @@ async def _map_invocation(
|
|
134
132
|
)
|
135
133
|
|
136
134
|
async def create_input(argskwargs):
|
137
|
-
nonlocal inputs_created
|
138
135
|
idx = inputs_created
|
139
|
-
inputs_created
|
136
|
+
update_state(set_inputs_created=inputs_created + 1)
|
140
137
|
(args, kwargs) = argskwargs
|
141
138
|
return await _create_input(args, kwargs, client.stub, idx=idx, method_name=function._use_method_name)
|
142
139
|
|
@@ -147,9 +144,27 @@ async def _map_invocation(
|
|
147
144
|
break
|
148
145
|
yield raw_input # args, kwargs
|
149
146
|
|
150
|
-
|
151
|
-
nonlocal
|
147
|
+
def update_state(set_have_all_inputs=None, set_inputs_created=None, set_outputs_completed=None):
|
148
|
+
# This should be the only method that needs nonlocal of the following vars
|
149
|
+
nonlocal have_all_inputs, inputs_created, outputs_completed
|
150
|
+
assert set_have_all_inputs is not False # not allowed
|
151
|
+
assert set_inputs_created is None or set_inputs_created > inputs_created
|
152
|
+
assert set_outputs_completed is None or set_outputs_completed > outputs_completed
|
153
|
+
if set_have_all_inputs is not None:
|
154
|
+
have_all_inputs = set_have_all_inputs
|
155
|
+
if set_inputs_created is not None:
|
156
|
+
inputs_created = set_inputs_created
|
157
|
+
if set_outputs_completed is not None:
|
158
|
+
outputs_completed = set_outputs_completed
|
159
|
+
|
160
|
+
if count_update_callback is not None:
|
161
|
+
count_update_callback(outputs_completed, inputs_created)
|
162
|
+
|
163
|
+
if have_all_inputs and outputs_completed >= inputs_created:
|
164
|
+
# map is done
|
165
|
+
map_done_event.set()
|
152
166
|
|
167
|
+
async def drain_input_generator():
|
153
168
|
# Parallelize uploading blobs
|
154
169
|
async with aclosing(
|
155
170
|
async_map_ordered(input_iter(), create_input, concurrency=BLOB_MAX_PARALLELISM)
|
@@ -159,12 +174,12 @@ async def _map_invocation(
|
|
159
174
|
|
160
175
|
# close queue iterator
|
161
176
|
await input_queue.put(None)
|
162
|
-
|
177
|
+
update_state(set_have_all_inputs=True)
|
163
178
|
yield
|
164
179
|
|
165
180
|
async def pump_inputs():
|
166
181
|
assert client.stub
|
167
|
-
nonlocal
|
182
|
+
nonlocal inputs_sent
|
168
183
|
async for items in queue_batch_iterator(input_queue, max_batch_size=MAP_INVOCATION_CHUNK_SIZE):
|
169
184
|
# Add items to the manager. Their state will be SENDING.
|
170
185
|
await map_items_manager.add_items(items)
|
@@ -178,7 +193,6 @@ async def _map_invocation(
|
|
178
193
|
)
|
179
194
|
|
180
195
|
resp = await send_inputs(client.stub.FunctionPutInputs, request)
|
181
|
-
count_update()
|
182
196
|
inputs_sent += len(items)
|
183
197
|
# Change item state to WAITING_FOR_OUTPUT, and set the input_id and input_jwt which are in the response.
|
184
198
|
map_items_manager.handle_put_inputs_response(resp.inputs)
|
@@ -231,11 +245,8 @@ async def _map_invocation(
|
|
231
245
|
async def get_all_outputs():
|
232
246
|
assert client.stub
|
233
247
|
nonlocal \
|
234
|
-
inputs_created, \
|
235
248
|
successful_completions, \
|
236
249
|
failed_completions, \
|
237
|
-
outputs_completed, \
|
238
|
-
have_all_inputs, \
|
239
250
|
outputs_received, \
|
240
251
|
already_complete_duplicates, \
|
241
252
|
no_context_duplicates, \
|
@@ -244,7 +255,7 @@ async def _map_invocation(
|
|
244
255
|
|
245
256
|
last_entry_id = "0-0"
|
246
257
|
|
247
|
-
while not
|
258
|
+
while not map_done_event.is_set():
|
248
259
|
logger.debug(f"Requesting outputs. Have {outputs_completed} outputs, {inputs_created} inputs.")
|
249
260
|
# Get input_jwts of all items in the WAITING_FOR_OUTPUT state.
|
250
261
|
# The server uses these to track for lost inputs.
|
@@ -258,12 +269,26 @@ async def _map_invocation(
|
|
258
269
|
requested_at=time.time(),
|
259
270
|
input_jwts=input_jwts,
|
260
271
|
)
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
272
|
+
get_response_task = asyncio.create_task(
|
273
|
+
retry_transient_errors(
|
274
|
+
client.stub.FunctionGetOutputs,
|
275
|
+
request,
|
276
|
+
max_retries=20,
|
277
|
+
attempt_timeout=OUTPUTS_TIMEOUT + ATTEMPT_TIMEOUT_GRACE_PERIOD,
|
278
|
+
)
|
266
279
|
)
|
280
|
+
map_done_task = asyncio.create_task(map_done_event.wait())
|
281
|
+
done, pending = await asyncio.wait([get_response_task, map_done_task], return_when=FIRST_COMPLETED)
|
282
|
+
if get_response_task in done:
|
283
|
+
map_done_task.cancel()
|
284
|
+
response = get_response_task.result()
|
285
|
+
else:
|
286
|
+
assert map_done_event.is_set()
|
287
|
+
# map is done, cancel the pending call
|
288
|
+
get_response_task.cancel()
|
289
|
+
# not strictly necessary - don't leave dangling task
|
290
|
+
await asyncio.gather(get_response_task, return_exceptions=True)
|
291
|
+
return
|
267
292
|
|
268
293
|
last_entry_id = response.last_entry_id
|
269
294
|
now_seconds = int(time.time())
|
@@ -288,7 +313,7 @@ async def _map_invocation(
|
|
288
313
|
|
289
314
|
if output_type == _OutputType.SUCCESSFUL_COMPLETION or output_type == _OutputType.FAILED_COMPLETION:
|
290
315
|
completed_outputs.add(item.input_id)
|
291
|
-
outputs_completed
|
316
|
+
update_state(set_outputs_completed=outputs_completed + 1)
|
292
317
|
yield item
|
293
318
|
|
294
319
|
async def get_all_outputs_and_clean_up():
|
@@ -328,7 +353,6 @@ async def _map_invocation(
|
|
328
353
|
async_map_ordered(get_all_outputs_and_clean_up(), fetch_output, concurrency=BLOB_MAX_PARALLELISM)
|
329
354
|
) as streamer:
|
330
355
|
async for idx, output in streamer:
|
331
|
-
count_update()
|
332
356
|
if not order_outputs:
|
333
357
|
yield _OutputValue(output)
|
334
358
|
else:
|
@@ -401,7 +425,7 @@ async def _map_helper(
|
|
401
425
|
"""
|
402
426
|
|
403
427
|
raw_input_queue: Any = SynchronizedQueue() # type: ignore
|
404
|
-
raw_input_queue.init()
|
428
|
+
await raw_input_queue.init.aio()
|
405
429
|
|
406
430
|
async def feed_queue():
|
407
431
|
async with aclosing(async_input_gen) as streamer:
|
@@ -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=wad4VLK22aPQB63PENKOOxITmZsc_mA2xgk8q3JPaJg,8459
|
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
|
@@ -52,7 +52,7 @@ modal/network_file_system.pyi,sha256=58DiUqHGlARmI3cz-Yo7IFObKKFIiGh5UIU5JxGNFfc
|
|
52
52
|
modal/object.py,sha256=bTeskuY8JFrESjU4_UL_nTwYlBQdOLmVaOX3X6EMxsg,164
|
53
53
|
modal/object.pyi,sha256=UkR8NQ1jCIaw3hBUPxBRc6vvrOqtV37G_hsW2O5-4wE,5378
|
54
54
|
modal/output.py,sha256=q4T9uHduunj4NwY-YSwkHGgjZlCXMuJbfQ5UFaAGRAc,1968
|
55
|
-
modal/parallel_map.py,sha256=
|
55
|
+
modal/parallel_map.py,sha256=zlJTh3NuqlrmxkcZMSXerM2dKytYX3Pr737vBLr9AX4,37428
|
56
56
|
modal/parallel_map.pyi,sha256=mhYGQmufQEJbjNrX7vNhBS2gUdfBrpmuWNUHth_Dz6U,6140
|
57
57
|
modal/partial_function.py,sha256=SwuAAj2wj4SO6F6nkSnwNZrczEmm9w9YdlQTHh6hr04,1195
|
58
58
|
modal/partial_function.pyi,sha256=NFWz1aCAs2B3-GnPf1cTatWRZOLnYpFKCnjP_X9iNRs,6411
|
@@ -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.3.
|
150
|
+
modal-1.0.3.dev26.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=GIYda175HQtvkJCOUV4zp0tKpdnHT76NUXHNTm_B2kY,121
|
174
174
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
175
|
-
modal-1.0.3.
|
176
|
-
modal-1.0.3.
|
177
|
-
modal-1.0.3.
|
178
|
-
modal-1.0.3.
|
179
|
-
modal-1.0.3.
|
175
|
+
modal-1.0.3.dev26.dist-info/METADATA,sha256=IyUCFOSBhrLE8Rnpt1buHnoZCL627KE3CQSHrNgwOxA,2455
|
176
|
+
modal-1.0.3.dev26.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
177
|
+
modal-1.0.3.dev26.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
178
|
+
modal-1.0.3.dev26.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
|
179
|
+
modal-1.0.3.dev26.dist-info/RECORD,,
|
modal_version/__init__.py
CHANGED
File without changes
|
File without changes
|
File without changes
|
File without changes
|