modal 0.73.169__py3-none-any.whl → 0.73.171__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/cli/run.py +24 -18
- modal/client.pyi +2 -2
- modal/functions.pyi +6 -6
- modal/sandbox.py +0 -9
- {modal-0.73.169.dist-info → modal-0.73.171.dist-info}/METADATA +1 -1
- {modal-0.73.169.dist-info → modal-0.73.171.dist-info}/RECORD +11 -11
- modal_version/_version_generated.py +1 -1
- {modal-0.73.169.dist-info → modal-0.73.171.dist-info}/WHEEL +0 -0
- {modal-0.73.169.dist-info → modal-0.73.171.dist-info}/entry_points.txt +0 -0
- {modal-0.73.169.dist-info → modal-0.73.171.dist-info}/licenses/LICENSE +0 -0
- {modal-0.73.169.dist-info → modal-0.73.171.dist-info}/top_level.txt +0 -0
modal/cli/run.py
CHANGED
@@ -7,9 +7,10 @@ import re
|
|
7
7
|
import shlex
|
8
8
|
import sys
|
9
9
|
import time
|
10
|
+
import typing
|
10
11
|
from dataclasses import dataclass
|
11
12
|
from functools import partial
|
12
|
-
from typing import Any, Callable, Optional
|
13
|
+
from typing import Any, Callable, Optional
|
13
14
|
|
14
15
|
import click
|
15
16
|
import typer
|
@@ -18,6 +19,7 @@ from typing_extensions import TypedDict
|
|
18
19
|
|
19
20
|
from .._functions import _FunctionSpec
|
20
21
|
from ..app import App, LocalEntrypoint
|
22
|
+
from ..cls import _get_class_constructor_signature
|
21
23
|
from ..config import config
|
22
24
|
from ..environments import ensure_env
|
23
25
|
from ..exception import ExecutionError, InvalidError, _CliUserExecutionError
|
@@ -42,7 +44,7 @@ class ParameterMetadata(TypedDict):
|
|
42
44
|
name: str
|
43
45
|
default: Any
|
44
46
|
annotation: Any
|
45
|
-
type_hint: Any
|
47
|
+
type_hint: Any # same as annotation but evaluated by typing.get_type_hints
|
46
48
|
kind: Any
|
47
49
|
|
48
50
|
|
@@ -68,27 +70,24 @@ class NoParserAvailable(InvalidError):
|
|
68
70
|
|
69
71
|
|
70
72
|
@dataclass
|
71
|
-
class
|
73
|
+
class CliRunnableSignature:
|
72
74
|
parameters: dict[str, ParameterMetadata]
|
73
75
|
has_variadic_args: bool
|
74
76
|
|
75
77
|
|
76
|
-
def
|
78
|
+
def safe_get_type_hints(func_or_cls: typing.Union[Callable[..., Any], type]) -> dict[str, type]:
|
77
79
|
try:
|
78
|
-
|
80
|
+
return typing.get_type_hints(func_or_cls)
|
79
81
|
except Exception as exc:
|
80
82
|
# E.g., if entrypoint type hints cannot be evaluated by local Python runtime
|
81
|
-
msg = "Unable to generate command line interface for app entrypoint
|
83
|
+
msg = "Unable to generate command line interface for app entrypoint due to unparseable type hints:\n" + str(exc)
|
82
84
|
raise ExecutionError(msg) from exc
|
83
85
|
|
84
|
-
has_variadic_args = False
|
85
|
-
|
86
|
-
if is_method:
|
87
|
-
self = None # Dummy, doesn't matter
|
88
|
-
f = functools.partial(f, self)
|
89
86
|
|
87
|
+
def _get_cli_runnable_signature(sig: inspect.Signature, type_hints: dict[str, type]) -> CliRunnableSignature:
|
88
|
+
has_variadic_args = False
|
90
89
|
signature: dict[str, ParameterMetadata] = {}
|
91
|
-
for param in
|
90
|
+
for param in sig.parameters.values():
|
92
91
|
if param.kind == inspect.Parameter.VAR_POSITIONAL:
|
93
92
|
has_variadic_args = True
|
94
93
|
else:
|
@@ -103,7 +102,7 @@ def _get_signature(f: Callable[..., Any], is_method: bool = False) -> FnSignatur
|
|
103
102
|
if has_variadic_args and len(signature) > 0:
|
104
103
|
raise InvalidError("Functions with variable-length positional arguments (*args) cannot have other parameters.")
|
105
104
|
|
106
|
-
return
|
105
|
+
return CliRunnableSignature(signature, has_variadic_args)
|
107
106
|
|
108
107
|
|
109
108
|
def _get_param_type_as_str(annot: Any) -> str:
|
@@ -172,7 +171,7 @@ def _write_local_result(result_path: str, res: Any):
|
|
172
171
|
fid.write(res)
|
173
172
|
|
174
173
|
|
175
|
-
def _make_click_function(app, signature:
|
174
|
+
def _make_click_function(app, signature: CliRunnableSignature, inner: Callable[[tuple[str, ...], dict[str, Any]], Any]):
|
176
175
|
@click.pass_context
|
177
176
|
def f(ctx, **kwargs):
|
178
177
|
if signature.has_variadic_args:
|
@@ -201,7 +200,9 @@ def _get_click_command_for_function(app: App, function: Function):
|
|
201
200
|
if function.is_generator:
|
202
201
|
raise InvalidError("`modal run` is not supported for generator functions")
|
203
202
|
|
204
|
-
|
203
|
+
sig: inspect.Signature = inspect.signature(function.info.raw_f)
|
204
|
+
type_hints = safe_get_type_hints(function.info.raw_f)
|
205
|
+
signature: CliRunnableSignature = _get_cli_runnable_signature(sig, type_hints)
|
205
206
|
|
206
207
|
def _inner(args, click_kwargs):
|
207
208
|
return function.remote(*args, **click_kwargs)
|
@@ -223,7 +224,10 @@ def _get_click_command_for_cls(app: App, method_ref: MethodReference):
|
|
223
224
|
cls = method_ref.cls
|
224
225
|
method_name = method_ref.method_name
|
225
226
|
|
226
|
-
|
227
|
+
user_cls = cls._get_user_cls()
|
228
|
+
type_hints = safe_get_type_hints(user_cls)
|
229
|
+
sig: inspect.Signature = _get_class_constructor_signature(user_cls)
|
230
|
+
cls_signature: CliRunnableSignature = _get_cli_runnable_signature(sig, type_hints)
|
227
231
|
|
228
232
|
if cls_signature.has_variadic_args:
|
229
233
|
raise InvalidError("Modal classes cannot have variable-length positional arguments (*args).")
|
@@ -241,7 +245,9 @@ def _get_click_command_for_cls(app: App, method_ref: MethodReference):
|
|
241
245
|
)
|
242
246
|
|
243
247
|
partial_function = partial_functions[method_name]
|
244
|
-
|
248
|
+
raw_f = partial_function._get_raw_f()
|
249
|
+
sig_without_self = inspect.signature(functools.partial(raw_f, None))
|
250
|
+
fun_signature = _get_cli_runnable_signature(sig_without_self, safe_get_type_hints(raw_f))
|
245
251
|
|
246
252
|
# TODO(erikbern): assert there's no overlap?
|
247
253
|
parameters = dict(**cls_signature.parameters, **fun_signature.parameters) # Pool all arguments
|
@@ -271,7 +277,7 @@ def _get_click_command_for_local_entrypoint(app: App, entrypoint: LocalEntrypoin
|
|
271
277
|
func = entrypoint.info.raw_f
|
272
278
|
isasync = inspect.iscoroutinefunction(func)
|
273
279
|
|
274
|
-
signature =
|
280
|
+
signature = _get_cli_runnable_signature(inspect.signature(func), safe_get_type_hints(func))
|
275
281
|
|
276
282
|
@click.pass_context
|
277
283
|
def f(ctx, *args, **kwargs):
|
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 = "0.73.
|
34
|
+
version: str = "0.73.171",
|
35
35
|
): ...
|
36
36
|
def is_closed(self) -> bool: ...
|
37
37
|
@property
|
@@ -93,7 +93,7 @@ class Client:
|
|
93
93
|
server_url: str,
|
94
94
|
client_type: int,
|
95
95
|
credentials: typing.Optional[tuple[str, str]],
|
96
|
-
version: str = "0.73.
|
96
|
+
version: str = "0.73.171",
|
97
97
|
): ...
|
98
98
|
def is_closed(self) -> bool: ...
|
99
99
|
@property
|
modal/functions.pyi
CHANGED
@@ -200,11 +200,11 @@ class Function(
|
|
200
200
|
|
201
201
|
_call_generator_nowait: ___call_generator_nowait_spec[typing_extensions.Self]
|
202
202
|
|
203
|
-
class __remote_spec(typing_extensions.Protocol[
|
203
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
204
204
|
def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
205
205
|
async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
|
206
206
|
|
207
|
-
remote: __remote_spec[modal._functions.
|
207
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
208
208
|
|
209
209
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
210
210
|
def __call__(self, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
|
@@ -219,19 +219,19 @@ class Function(
|
|
219
219
|
self, *args: modal._functions.P.args, **kwargs: modal._functions.P.kwargs
|
220
220
|
) -> modal._functions.OriginalReturnType: ...
|
221
221
|
|
222
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
222
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
223
223
|
def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
224
224
|
async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
225
225
|
|
226
226
|
_experimental_spawn: ___experimental_spawn_spec[
|
227
|
-
modal._functions.
|
227
|
+
modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
|
228
228
|
]
|
229
229
|
|
230
|
-
class __spawn_spec(typing_extensions.Protocol[
|
230
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
231
231
|
def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
232
232
|
async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
|
233
233
|
|
234
|
-
spawn: __spawn_spec[modal._functions.
|
234
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
235
235
|
|
236
236
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]: ...
|
237
237
|
|
modal/sandbox.py
CHANGED
@@ -108,9 +108,6 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
108
108
|
) -> "_Sandbox":
|
109
109
|
"""mdmd:hidden"""
|
110
110
|
|
111
|
-
if len(entrypoint_args) == 0:
|
112
|
-
raise InvalidError("entrypoint_args must not be empty")
|
113
|
-
|
114
111
|
validated_network_file_systems = validate_network_file_systems(network_file_systems)
|
115
112
|
|
116
113
|
scheduler_placement: Optional[SchedulerPlacement] = _experimental_scheduler_placement
|
@@ -260,12 +257,6 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
260
257
|
|
261
258
|
environment_name = _get_environment_name(environment_name)
|
262
259
|
|
263
|
-
# If there are no entrypoint args, we'll sleep forever so that the sandbox will stay
|
264
|
-
# alive long enough for the user to interact with it.
|
265
|
-
if len(entrypoint_args) == 0:
|
266
|
-
max_sleep_time = 60 * 60 * 24 * 2 # 2 days is plenty since workers roll every 24h
|
267
|
-
entrypoint_args = ("sleep", str(max_sleep_time))
|
268
|
-
|
269
260
|
_validate_exec_args(entrypoint_args)
|
270
261
|
|
271
262
|
# TODO(erikbern): Get rid of the `_new` method and create an already-hydrated object
|
@@ -22,7 +22,7 @@ modal/app.py,sha256=bJp7W3liuVG2VwWkG31tMFogDh84EKppzP8YJFWl3eQ,48140
|
|
22
22
|
modal/app.pyi,sha256=SkqXNrdnGIZ4MmNNvpGtzNLoUdyuvi9IjQQR_DRiRHk,26968
|
23
23
|
modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
|
24
24
|
modal/client.py,sha256=U-YKSw0n7J1ZLREt9cbEJCtmHe5YoPKFxl0xlkan2yc,15565
|
25
|
-
modal/client.pyi,sha256=
|
25
|
+
modal/client.pyi,sha256=fIlYvk4weOmKH7jNlgfefTnQ-7gPjfUnSTntpLuIxRo,7661
|
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=x3CUDPC-QK7pa9E2eiFsiCS2ULvVi8UzNZQw1i9drsU,32945
|
@@ -39,7 +39,7 @@ modal/file_io.py,sha256=lcMs_E9Xfm0YX1t9U2wNIBPnqHRxmImqjLW1GHqVmyg,20945
|
|
39
39
|
modal/file_io.pyi,sha256=NTRft1tbPSWf9TlWVeZmTlgB5AZ_Zhu2srWIrWr7brk,9445
|
40
40
|
modal/file_pattern_matcher.py,sha256=trosX-Bp7dOubudN1bLLhRAoidWy1TcoaR4Pv8CedWw,6497
|
41
41
|
modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
|
42
|
-
modal/functions.pyi,sha256=
|
42
|
+
modal/functions.pyi,sha256=m1PL2pwO-lnGV0uZDVCmzZ_v7Mu8ISRtxmxS15aEIAQ,14785
|
43
43
|
modal/gpu.py,sha256=Kbhs_u49FaC2Zi0TjCdrpstpRtT5eZgecynmQi5IZVE,6752
|
44
44
|
modal/image.py,sha256=I-9_YZL0SSfnuGPywa3-4PlxDmJ-53p7ce3gP74SrOA,92877
|
45
45
|
modal/image.pyi,sha256=89zv12C1sFrJs7Es9SnX23_m208ASAdeNGCVTrhjzHI,25632
|
@@ -65,7 +65,7 @@ modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
|
|
65
65
|
modal/runner.py,sha256=V17Fb9OtTGplvILc4ogT-waHYjxyCnjf0PP4aYy_0ho,25036
|
66
66
|
modal/runner.pyi,sha256=HW2pvC_PLwg1Es_EkrfQgMZsktIr9zzVEtmjOVFG6Dw,5351
|
67
67
|
modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
|
68
|
-
modal/sandbox.py,sha256=
|
68
|
+
modal/sandbox.py,sha256=CX42Rrso7a_Gz6fWEEu-OYzFsWanWOyBy9iQ4nAfAkg,32162
|
69
69
|
modal/sandbox.pyi,sha256=cLmSwI1ab-2DgEuXNf6S1PiK63wfUR9dHtxlZtSOuX8,22719
|
70
70
|
modal/schedule.py,sha256=0ZFpKs1bOxeo5n3HZjoL7OE2ktsb-_oGtq-WJEPO4tY,2615
|
71
71
|
modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
|
@@ -128,7 +128,7 @@ modal/cli/launch.py,sha256=0_sBu6bv2xJEPWi-rbGS6Ri9ggnkWQvrGlgpYSUBMyY,3097
|
|
128
128
|
modal/cli/network_file_system.py,sha256=eq3JnwjbfFNsJodIyANHL06ByYc3BSavzdmu8C96cHA,7948
|
129
129
|
modal/cli/profile.py,sha256=0TYhgRSGUvQZ5LH9nkl6iZllEvAjDniES264dE57wOM,3201
|
130
130
|
modal/cli/queues.py,sha256=6gTu76dzBtPN5eQVsLrvQpuru5jI9ZCWK5Eh8J8XhaM,4498
|
131
|
-
modal/cli/run.py,sha256=
|
131
|
+
modal/cli/run.py,sha256=NX2wWwj8HD6XUhnZRF808Qy9eeouv8KnvyOP57HqIXI,23637
|
132
132
|
modal/cli/secret.py,sha256=WB_c-LE9-eDqleLpJxsJ9rZw62Eeza8ZFQFR10vNMEk,4197
|
133
133
|
modal/cli/token.py,sha256=mxSgOWakXG6N71hQb1ko61XAR9ZGkTMZD-Txn7gmTac,1924
|
134
134
|
modal/cli/utils.py,sha256=hZmjyzcPjDnQSkLvycZD2LhGdcsfdZshs_rOU78EpvI,3717
|
@@ -145,7 +145,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
|
|
145
145
|
modal/requirements/PREVIEW.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddRo,296
|
146
146
|
modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
|
147
147
|
modal/requirements/base-images.json,sha256=57vMSqzMbLBxw5tFWSaMiIkkVEps4JfX5PAtXGnkS4U,740
|
148
|
-
modal-0.73.
|
148
|
+
modal-0.73.171.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
149
149
|
modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
|
150
150
|
modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
|
151
151
|
modal_docs/gen_reference_docs.py,sha256=cvTgltucqYLLIX84QxAwf51Z5Vc2n6cLxS8VcrxNCAo,6401
|
@@ -170,9 +170,9 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
|
|
170
170
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
171
171
|
modal_version/__init__.py,sha256=wiJQ53c-OMs0Xf1UeXOxQ7FwlV1VzIjnX6o-pRYZ_Pk,470
|
172
172
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
173
|
-
modal_version/_version_generated.py,sha256=
|
174
|
-
modal-0.73.
|
175
|
-
modal-0.73.
|
176
|
-
modal-0.73.
|
177
|
-
modal-0.73.
|
178
|
-
modal-0.73.
|
173
|
+
modal_version/_version_generated.py,sha256=N0MMQdbQDFg-yfKvz_fuP7qeoaoC4EJqAQ2K7kyrYlU,150
|
174
|
+
modal-0.73.171.dist-info/METADATA,sha256=QaWuVkPGz8xGGcuVXHQLnMjSTFw8TcWwvco-P1RJzuU,2475
|
175
|
+
modal-0.73.171.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
176
|
+
modal-0.73.171.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
177
|
+
modal-0.73.171.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
|
178
|
+
modal-0.73.171.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|