modal 1.0.4.dev10__py3-none-any.whl → 1.0.5.dev1__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/async_utils.py +1 -1
- modal/client.pyi +2 -2
- modal/cls.py +50 -9
- modal/cls.pyi +1 -0
- modal/parallel_map.py +13 -10
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dev1.dist-info}/METADATA +2 -2
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dev1.dist-info}/RECORD +15 -15
- modal_proto/api.proto +1 -0
- modal_proto/api_pb2.py +170 -170
- modal_proto/api_pb2.pyi +4 -1
- modal_version/__init__.py +1 -1
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dev1.dist-info}/WHEEL +0 -0
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dev1.dist-info}/entry_points.txt +0 -0
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dev1.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dev1.dist-info}/top_level.txt +0 -0
modal/_utils/async_utils.py
CHANGED
@@ -396,7 +396,7 @@ class _WarnIfGeneratorIsNotConsumed:
|
|
396
396
|
return await self.gen.aclose()
|
397
397
|
|
398
398
|
|
399
|
-
synchronize_api(_WarnIfGeneratorIsNotConsumed)
|
399
|
+
_BlockingWarnIfGeneratorIsNotConsumed = synchronize_api(_WarnIfGeneratorIsNotConsumed)
|
400
400
|
|
401
401
|
|
402
402
|
class _WarnIfNonWrappedGeneratorIsNotConsumed(_WarnIfGeneratorIsNotConsumed):
|
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.5.dev1",
|
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.5.dev1",
|
98
98
|
): ...
|
99
99
|
def is_closed(self) -> bool: ...
|
100
100
|
@property
|
modal/cls.py
CHANGED
@@ -75,6 +75,7 @@ def _get_class_constructor_signature(user_cls: type) -> inspect.Signature:
|
|
75
75
|
|
76
76
|
@dataclasses.dataclass()
|
77
77
|
class _ServiceOptions:
|
78
|
+
# Note that default values should always be "untruthy" so we can detect when they are not set
|
78
79
|
secrets: typing.Collection[_Secret] = ()
|
79
80
|
validated_volumes: typing.Sequence[tuple[str, _Volume]] = ()
|
80
81
|
resources: Optional[api_pb2.Resources] = None
|
@@ -88,6 +89,25 @@ class _ServiceOptions:
|
|
88
89
|
batch_max_size: Optional[int] = None
|
89
90
|
batch_wait_ms: Optional[int] = None
|
90
91
|
|
92
|
+
def merge_options(self, new_options: "_ServiceOptions") -> "_ServiceOptions":
|
93
|
+
"""Implement protobuf-like MergeFrom semantics for this dataclass.
|
94
|
+
|
95
|
+
This mostly exists to support "stacking" of `.with_options()` calls.
|
96
|
+
"""
|
97
|
+
new_options_dict = dataclasses.asdict(new_options)
|
98
|
+
|
99
|
+
# Resources needs special merge handling because individual fields are parameters in the public API
|
100
|
+
merged_resources = api_pb2.Resources()
|
101
|
+
if self.resources:
|
102
|
+
merged_resources.MergeFrom(self.resources)
|
103
|
+
if new_resources := new_options_dict.pop("resources"):
|
104
|
+
merged_resources.MergeFrom(new_resources)
|
105
|
+
self.resources = merged_resources
|
106
|
+
|
107
|
+
for key, value in new_options_dict.items():
|
108
|
+
if value: # Only overwrite data when the value was set in the new options
|
109
|
+
setattr(self, key, value)
|
110
|
+
|
91
111
|
|
92
112
|
def _bind_instance_method(cls: "_Cls", service_function: _Function, method_name: str):
|
93
113
|
"""Binds an "instance service function" to a specific method using metadata for that method
|
@@ -664,15 +684,32 @@ More information on class parameterization can be found here: https://modal.com/
|
|
664
684
|
container_idle_timeout: Optional[int] = None, # Now called `scaledown_window`
|
665
685
|
allow_concurrent_inputs: Optional[int] = None, # See `.with_concurrency`
|
666
686
|
) -> "_Cls":
|
667
|
-
"""
|
687
|
+
"""Override the static Function configuration at runtime.
|
688
|
+
|
689
|
+
This method will return a new instance of the cls that will autoscale independently of the
|
690
|
+
original instance. Note that options cannot be "unset" with this method (i.e., if a GPU
|
691
|
+
is configured in the `@app.cls()` decorator, passing `gpu=None` here will not create a
|
692
|
+
CPU-only instance).
|
668
693
|
|
669
694
|
**Usage:**
|
670
695
|
|
696
|
+
You can use this method after looking up the Cls from a deployed App or if you have a
|
697
|
+
direct reference to a Cls from another Function or local entrypoint on its App:
|
698
|
+
|
671
699
|
```python notest
|
672
700
|
Model = modal.Cls.from_name("my_app", "Model")
|
673
701
|
ModelUsingGPU = Model.with_options(gpu="A100")
|
674
|
-
ModelUsingGPU().generate.remote(
|
702
|
+
ModelUsingGPU().generate.remote(input_prompt) # Run with an A100 GPU
|
675
703
|
```
|
704
|
+
|
705
|
+
The method can be called multiple times to "stack" updates:
|
706
|
+
|
707
|
+
```python notest
|
708
|
+
Model.with_options(gpu="A100").with_options(scaledown_window=300) # Use an A100 with slow scaledown
|
709
|
+
```
|
710
|
+
|
711
|
+
Note that container arguments (i.e. `volumes` and `secrets`) passed in subsequent calls
|
712
|
+
will not be merged.
|
676
713
|
"""
|
677
714
|
retry_policy = _parse_retries(retries, f"Class {self.__name__}" if self._user_cls else "")
|
678
715
|
if gpu or cpu or memory:
|
@@ -705,21 +742,23 @@ More information on class parameterization can be found here: https://modal.com/
|
|
705
742
|
|
706
743
|
cls = _Cls._from_loader(_load_from_base, rep=f"{self._name}.with_options(...)", is_another_app=True, deps=_deps)
|
707
744
|
cls._initialize_from_other(self)
|
708
|
-
|
709
|
-
|
745
|
+
|
746
|
+
new_options = _ServiceOptions(
|
710
747
|
secrets=secrets,
|
748
|
+
validated_volumes=validate_volumes(volumes),
|
711
749
|
resources=resources,
|
712
750
|
retry_policy=retry_policy,
|
713
751
|
max_containers=max_containers,
|
714
752
|
buffer_containers=buffer_containers,
|
715
753
|
scaledown_window=scaledown_window,
|
716
754
|
timeout_secs=timeout,
|
717
|
-
validated_volumes=validate_volumes(volumes),
|
718
755
|
# Note: set both for backwards / forwards compatibility
|
719
756
|
# But going forward `.with_concurrency` is the preferred method with distinct parameterization
|
720
757
|
max_concurrent_inputs=allow_concurrent_inputs,
|
721
758
|
target_concurrent_inputs=allow_concurrent_inputs,
|
722
759
|
)
|
760
|
+
|
761
|
+
cls._options.merge_options(new_options)
|
723
762
|
return cls
|
724
763
|
|
725
764
|
def with_concurrency(self: "_Cls", *, max_inputs: int, target_inputs: Optional[int] = None) -> "_Cls":
|
@@ -746,9 +785,9 @@ More information on class parameterization can be found here: https://modal.com/
|
|
746
785
|
_load_from_base, rep=f"{self._name}.with_concurrency(...)", is_another_app=True, deps=_deps
|
747
786
|
)
|
748
787
|
cls._initialize_from_other(self)
|
749
|
-
|
750
|
-
|
751
|
-
)
|
788
|
+
|
789
|
+
concurrency_options = _ServiceOptions(max_concurrent_inputs=max_inputs, target_concurrent_inputs=target_inputs)
|
790
|
+
cls._options.merge_options(concurrency_options)
|
752
791
|
return cls
|
753
792
|
|
754
793
|
def with_batching(self: "_Cls", *, max_batch_size: int, wait_ms: int) -> "_Cls":
|
@@ -775,7 +814,9 @@ More information on class parameterization can be found here: https://modal.com/
|
|
775
814
|
_load_from_base, rep=f"{self._name}.with_concurrency(...)", is_another_app=True, deps=_deps
|
776
815
|
)
|
777
816
|
cls._initialize_from_other(self)
|
778
|
-
|
817
|
+
|
818
|
+
batching_options = _ServiceOptions(batch_max_size=max_batch_size, batch_wait_ms=wait_ms)
|
819
|
+
cls._options.merge_options(batching_options)
|
779
820
|
return cls
|
780
821
|
|
781
822
|
@staticmethod
|
modal/cls.pyi
CHANGED
@@ -37,6 +37,7 @@ class _ServiceOptions:
|
|
37
37
|
batch_max_size: typing.Optional[int]
|
38
38
|
batch_wait_ms: typing.Optional[int]
|
39
39
|
|
40
|
+
def merge_options(self, new_options: _ServiceOptions) -> _ServiceOptions: ...
|
40
41
|
def __init__(
|
41
42
|
self,
|
42
43
|
secrets: typing.Collection[modal.secret._Secret] = (),
|
modal/parallel_map.py
CHANGED
@@ -278,17 +278,19 @@ async def _map_invocation(
|
|
278
278
|
)
|
279
279
|
)
|
280
280
|
map_done_task = asyncio.create_task(map_done_event.wait())
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
281
|
+
try:
|
282
|
+
done, pending = await asyncio.wait([get_response_task, map_done_task], return_when=FIRST_COMPLETED)
|
283
|
+
if get_response_task in done:
|
284
|
+
map_done_task.cancel()
|
285
|
+
response = get_response_task.result()
|
286
|
+
else:
|
287
|
+
assert map_done_event.is_set()
|
288
|
+
# map is done - no more outputs, so return early
|
289
|
+
return
|
290
|
+
finally:
|
291
|
+
# clean up tasks, in case of cancellations etc.
|
288
292
|
get_response_task.cancel()
|
289
|
-
|
290
|
-
await asyncio.gather(get_response_task, return_exceptions=True)
|
291
|
-
return
|
293
|
+
map_done_task.cancel()
|
292
294
|
|
293
295
|
last_entry_id = response.last_entry_id
|
294
296
|
now_seconds = int(time.time())
|
@@ -716,6 +718,7 @@ class _MapItemContext:
|
|
716
718
|
Return True if input state was changed to COMPLETE, otherwise False.
|
717
719
|
"""
|
718
720
|
# If the item is already complete, this is a duplicate output and can be ignored.
|
721
|
+
|
719
722
|
if self.state == _MapItemState.COMPLETE:
|
720
723
|
logger.debug(
|
721
724
|
f"Received output for input marked as complete. Must be duplicate, so ignoring. "
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: modal
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.5.dev1
|
4
4
|
Summary: Python client library for Modal
|
5
5
|
Author-email: Modal Labs <support@modal.com>
|
6
6
|
License: Apache-2.0
|
@@ -22,7 +22,7 @@ Requires-Dist: click~=8.1.0
|
|
22
22
|
Requires-Dist: grpclib==0.4.7
|
23
23
|
Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
|
24
24
|
Requires-Dist: rich>=12.0.0
|
25
|
-
Requires-Dist: synchronicity~=0.9.
|
25
|
+
Requires-Dist: synchronicity~=0.9.15
|
26
26
|
Requires-Dist: toml
|
27
27
|
Requires-Dist: typer>=0.9
|
28
28
|
Requires-Dist: types-certifi
|
@@ -22,11 +22,11 @@ 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=mEQpk7s6oZXanSwdpeUki1HdXyxXk-Wu26jnOKGYDqY,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
|
-
modal/cls.py,sha256=
|
29
|
-
modal/cls.pyi,sha256
|
28
|
+
modal/cls.py,sha256=JjxAeVudXKMp-co9YUnsGG6COJOv91K0ylf4f3mR67o,39792
|
29
|
+
modal/cls.pyi,sha256=EL1mQuyf8nAL2AjVZVnZhDzhakUmQt1ZtOVMy_aYWJI,12742
|
30
30
|
modal/config.py,sha256=e8sQ4RgwgJ_45S302vWUWs_wqRlKyEt3tU898RiaDKE,12073
|
31
31
|
modal/container_process.py,sha256=PDvjcyZ6eeN8foKQgR0WJ66Sg3lt7OFhK7Y_Akz6k5w,5846
|
32
32
|
modal/container_process.pyi,sha256=pPIUxVV_TY4huO2jF5cSSjb6L_EN7Es4xRvuwZ5sa5M,2802
|
@@ -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=QkDxaFQwzOCU6-Vhb-Iq78eEHKqqlNnGMqjk-BdhI08,37469
|
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
|
@@ -91,7 +91,7 @@ modal/_runtime/telemetry.py,sha256=T1RoAGyjBDr1swiM6pPsGRSITm7LI5FDK18oNXxY08U,5
|
|
91
91
|
modal/_runtime/user_code_imports.py,sha256=78wJyleqY2RVibqcpbDQyfWVBVT9BjyHPeoV9WdwV5Y,17720
|
92
92
|
modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
|
93
93
|
modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
|
94
|
-
modal/_utils/async_utils.py,sha256=
|
94
|
+
modal/_utils/async_utils.py,sha256=MhSCsCL8GqIVFWoHubU_899IH-JBZAiiqadG9Wri2l4,29361
|
95
95
|
modal/_utils/blob_utils.py,sha256=IexC2Jbtqp_Tkmy62ayfgzTYte0UPCNufB_v-DO21g8,18585
|
96
96
|
modal/_utils/bytes_io_segment_payload.py,sha256=vaXPq8b52-x6G2hwE7SrjS58pg_aRm7gV3bn3yjmTzQ,4261
|
97
97
|
modal/_utils/deprecation.py,sha256=EXP1beU4pmEqEzWMLw6E3kUfNfpmNA_VOp6i0EHi93g,4856
|
@@ -147,7 +147,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
|
|
147
147
|
modal/requirements/PREVIEW.txt,sha256=KxDaVTOwatHvboDo4lorlgJ7-n-MfAwbPwxJ0zcJqrs,312
|
148
148
|
modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
|
149
149
|
modal/requirements/base-images.json,sha256=f1bwyp2UkM844eoO9Qk30gQw_xrMqKpMSeJ6MErXnEk,995
|
150
|
-
modal-1.0.
|
150
|
+
modal-1.0.5.dev1.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
|
@@ -155,10 +155,10 @@ modal_docs/mdmd/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,2
|
|
155
155
|
modal_docs/mdmd/mdmd.py,sha256=Irx49MCCTlBOP4FBdLR--JrpA3-WhsVeriq0LGgsRic,6232
|
156
156
|
modal_docs/mdmd/signatures.py,sha256=XJaZrK7Mdepk5fdX51A8uENiLFNil85Ud0d4MH8H5f0,3218
|
157
157
|
modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
|
158
|
-
modal_proto/api.proto,sha256=
|
158
|
+
modal_proto/api.proto,sha256=aBHQSEFm1Os9ciCl6N9N5bhumjdJIpl7VPSbP2Chjk4,96432
|
159
159
|
modal_proto/api_grpc.py,sha256=iY5o_Tm4VDP-Wa1JgA_NpQa_Y-4FYB_RN9wdSUExjwI,117469
|
160
|
-
modal_proto/api_pb2.py,sha256=
|
161
|
-
modal_proto/api_pb2.pyi,sha256=
|
160
|
+
modal_proto/api_pb2.py,sha256=PTGsaddASU8iqRoaTFmV5bNg-TtGGUGvf8tTVWjeR1Q,338641
|
161
|
+
modal_proto/api_pb2.pyi,sha256=hMvUMcYnpt7tR0fdkL-sDuOM-r2vistuds_rL03xY-k,463959
|
162
162
|
modal_proto/api_pb2_grpc.py,sha256=NL5prOS_hh_pA1hVvQP_ZRE1w49N-PR8iNPRZ65i6nA,254089
|
163
163
|
modal_proto/api_pb2_grpc.pyi,sha256=Xxgdcnv1mBnu5_AQxJ6fo0yz7GnqVU0HVObNfZWHVfM,59440
|
164
164
|
modal_proto/modal_api_grpc.py,sha256=0ir2lnwT3-IgPcAWw98yWMAiqZPkjvNro9UBk4u8hnk,17763
|
@@ -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=IBJQ2mcZZY6WLV44CaQFHUQqyZlvclRpvrY6CtGf5gs,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.5.dev1.dist-info/METADATA,sha256=HkVebF9LFr4MAW7KocR0W-AVfGfw5U6eUiU5gxTPPHI,2454
|
176
|
+
modal-1.0.5.dev1.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
177
|
+
modal-1.0.5.dev1.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
178
|
+
modal-1.0.5.dev1.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
|
179
|
+
modal-1.0.5.dev1.dist-info/RECORD,,
|