modal 0.73.146__py3-none-any.whl → 0.73.148__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.
@@ -150,8 +150,8 @@ class ImportedClass(Service):
150
150
  # Check this property before we turn it into a method (overriden by webhooks)
151
151
  is_async = get_is_async(user_func)
152
152
  # Use the function definition for whether this is a generator (overriden by webhooks)
153
- is_generator = partial.is_generator
154
- webhook_config = partial.webhook_config
153
+ is_generator = partial.params.is_generator
154
+ webhook_config = partial.params.webhook_config
155
155
 
156
156
  bound_func = user_func.__get__(self.user_cls_instance)
157
157
 
modal/app.py CHANGED
@@ -652,7 +652,7 @@ class _App:
652
652
 
653
653
  if isinstance(f, _PartialFunction):
654
654
  # typically for @function-wrapped @web_endpoint, @asgi_app, or @batched
655
- f.wrapped = True
655
+ f.registered = True
656
656
 
657
657
  # but we don't support @app.function wrapping a method.
658
658
  if is_method_fn(f.raw_f.__qualname__):
@@ -670,17 +670,17 @@ class _App:
670
670
  "```\n"
671
671
  )
672
672
  i6pn_enabled = i6pn or (f.flags & _PartialFunctionFlags.CLUSTERED)
673
- cluster_size = f.cluster_size # Experimental: Clustered functions
673
+ cluster_size = f.params.cluster_size # Experimental: Clustered functions
674
674
 
675
675
  info = FunctionInfo(f.raw_f, serialized=serialized, name_override=name)
676
676
  raw_f = f.raw_f
677
- webhook_config = f.webhook_config
678
- is_generator = f.is_generator
679
- batch_max_size = f.batch_max_size
680
- batch_wait_ms = f.batch_wait_ms
681
- if f.max_concurrent_inputs: # Using @modal.concurrent()
682
- max_concurrent_inputs = f.max_concurrent_inputs
683
- target_concurrent_inputs = f.target_concurrent_inputs
677
+ webhook_config = f.params.webhook_config
678
+ is_generator = f.params.is_generator
679
+ batch_max_size = f.params.batch_max_size
680
+ batch_wait_ms = f.params.batch_wait_ms
681
+ if f.flags & _PartialFunctionFlags.CONCURRENT:
682
+ max_concurrent_inputs = f.params.max_concurrent_inputs
683
+ target_concurrent_inputs = f.params.target_concurrent_inputs
684
684
  else:
685
685
  max_concurrent_inputs = allow_concurrent_inputs
686
686
  target_concurrent_inputs = None
@@ -857,11 +857,11 @@ class _App:
857
857
  def wrapper(wrapped_cls: Union[CLS_T, _PartialFunction]) -> CLS_T:
858
858
  # Check if the decorated object is a class
859
859
  if isinstance(wrapped_cls, _PartialFunction):
860
- wrapped_cls.wrapped = True
861
- user_cls = wrapped_cls.raw_f
862
- if wrapped_cls.max_concurrent_inputs: # Using @modal.concurrent()
863
- max_concurrent_inputs = wrapped_cls.max_concurrent_inputs
864
- target_concurrent_inputs = wrapped_cls.target_concurrent_inputs
860
+ wrapped_cls.registered = True
861
+ user_cls = wrapped_cls.user_cls
862
+ if wrapped_cls.flags & _PartialFunctionFlags.CONCURRENT:
863
+ max_concurrent_inputs = wrapped_cls.params.max_concurrent_inputs
864
+ target_concurrent_inputs = wrapped_cls.params.target_concurrent_inputs
865
865
  else:
866
866
  max_concurrent_inputs = allow_concurrent_inputs
867
867
  target_concurrent_inputs = None
@@ -876,13 +876,13 @@ class _App:
876
876
  if batch_functions:
877
877
  if len(batch_functions) > 1:
878
878
  raise InvalidError(f"Modal class {user_cls.__name__} can only have one batched function.")
879
- if len(_find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.FUNCTION)) > 1:
879
+ if len(_find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.interface_flags())) > 1:
880
880
  raise InvalidError(
881
881
  f"Modal class {user_cls.__name__} with a modal batched function cannot have other modal methods." # noqa
882
882
  )
883
883
  batch_function = next(iter(batch_functions.values()))
884
- batch_max_size = batch_function.batch_max_size
885
- batch_wait_ms = batch_function.batch_wait_ms
884
+ batch_max_size = batch_function.params.batch_max_size
885
+ batch_wait_ms = batch_function.params.batch_wait_ms
886
886
  else:
887
887
  batch_max_size = None
888
888
  batch_wait_ms = None
@@ -893,11 +893,11 @@ class _App:
893
893
  ):
894
894
  raise InvalidError("A class must have `enable_memory_snapshot=True` to use `snap=True` on its methods.")
895
895
 
896
- for method in _find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.FUNCTION).values():
897
- if method.max_concurrent_inputs:
898
- raise InvalidError(
899
- "The `@modal.concurrent` decorator cannot be used on methods; decorate the class instead."
900
- )
896
+ for method in _find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.CONCURRENT).values():
897
+ method.registered = True # Avoid warning about not registering the method (hacky!)
898
+ raise InvalidError(
899
+ "The `@modal.concurrent` decorator cannot be used on methods; decorate the class instead."
900
+ )
901
901
 
902
902
  info = FunctionInfo(None, serialized=serialized, user_cls=user_cls)
903
903
 
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.146",
34
+ version: str = "0.73.148",
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.146",
96
+ version: str = "0.73.148",
97
97
  ): ...
98
98
  def is_closed(self) -> bool: ...
99
99
  @property
modal/cls.py CHANGED
@@ -225,7 +225,7 @@ class _Obj:
225
225
 
226
226
  # user cls instances are only created locally, so we have all partial functions available
227
227
  instance_methods = {}
228
- for method_name in _find_partial_methods_for_user_cls(self._user_cls, _PartialFunctionFlags.FUNCTION):
228
+ for method_name in _find_partial_methods_for_user_cls(self._user_cls, _PartialFunctionFlags.interface_flags()):
229
229
  instance_methods[method_name] = getattr(self, method_name)
230
230
 
231
231
  user_cls_instance._modal_functions = instance_methods
@@ -475,22 +475,26 @@ class _Cls(_Object, type_prefix="cs"):
475
475
  _Cls.validate_construction_mechanism(user_cls)
476
476
 
477
477
  method_partials: dict[str, _PartialFunction] = _find_partial_methods_for_user_cls(
478
- user_cls, _PartialFunctionFlags.FUNCTION
478
+ user_cls, _PartialFunctionFlags.interface_flags()
479
479
  )
480
480
 
481
481
  for method_name, partial_function in method_partials.items():
482
- if partial_function.webhook_config is not None:
482
+ if partial_function.params.webhook_config is not None:
483
483
  full_name = f"{user_cls.__name__}.{method_name}"
484
484
  app._web_endpoints.append(full_name)
485
- partial_function.wrapped = True
485
+ partial_function.registered = True
486
486
 
487
487
  # Disable the warning that lifecycle methods are not wrapped
488
- for partial_function in _find_partial_methods_for_user_cls(user_cls, ~_PartialFunctionFlags.FUNCTION).values():
489
- partial_function.wrapped = True
488
+ for partial_function in _find_partial_methods_for_user_cls(
489
+ user_cls, ~_PartialFunctionFlags.interface_flags()
490
+ ).values():
491
+ partial_function.registered = True
490
492
 
491
493
  # Get all callables
492
494
  callables: dict[str, Callable] = {
493
- k: pf.raw_f for k, pf in _find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.all()).items()
495
+ k: pf.raw_f
496
+ for k, pf in _find_partial_methods_for_user_cls(user_cls, _PartialFunctionFlags.all()).items()
497
+ if pf.raw_f is not None # Should be true for _find_partial_methods output, but hard to annotate
494
498
  }
495
499
 
496
500
  def _deps() -> list[_Function]:
@@ -2,16 +2,15 @@
2
2
  import os
3
3
  from dataclasses import dataclass
4
4
  from pathlib import Path
5
- from typing import Any, Callable, Literal, Optional, Union
5
+ from typing import Literal, Optional, Union
6
6
 
7
7
  from modal_proto import api_pb2
8
8
 
9
9
  from .._clustered_functions import ClusterInfo, get_cluster_info as _get_cluster_info
10
- from .._functions import _Function
11
10
  from .._object import _get_environment_name
12
- from .._partial_function import _PartialFunction, _PartialFunctionFlags
11
+ from .._partial_function import _clustered
13
12
  from .._runtime.container_io_manager import _ContainerIOManager
14
- from .._utils.async_utils import synchronizer
13
+ from .._utils.async_utils import synchronize_api, synchronizer
15
14
  from ..client import _Client
16
15
  from ..exception import InvalidError
17
16
  from ..image import DockerfileSpec, ImageBuilderVersion, _Image, _ImageRegistryConfig
@@ -38,41 +37,13 @@ def set_local_input_concurrency(concurrency: int):
38
37
  _ContainerIOManager.set_input_concurrency(concurrency)
39
38
 
40
39
 
41
- def clustered(size: int, broadcast: bool = True):
42
- """Provision clusters of colocated and networked containers for the Function.
43
-
44
- Parameters:
45
- size: int
46
- Number of containers spun up to handle each input.
47
- broadcast: bool = True
48
- If True, inputs will be sent simultaneously to each container. Otherwise,
49
- inputs will be sent only to the rank-0 container, which is responsible for
50
- delegating to the workers.
51
- """
52
-
53
- assert broadcast, "broadcast=False has not been implemented yet!"
54
-
55
- if size <= 0:
56
- raise ValueError("cluster size must be greater than 0")
57
-
58
- def wrapper(raw_f: Callable[..., Any]) -> _PartialFunction:
59
- if isinstance(raw_f, _Function):
60
- raw_f = raw_f.get_raw_f()
61
- raise InvalidError(
62
- f"Applying decorators for {raw_f} in the wrong order!\nUsage:\n\n"
63
- "@app.function()\n@modal.clustered()\ndef clustered_function():\n ..."
64
- )
65
- return _PartialFunction(
66
- raw_f, _PartialFunctionFlags.FUNCTION | _PartialFunctionFlags.CLUSTERED, cluster_size=size
67
- )
68
-
69
- return wrapper
70
-
71
-
72
40
  def get_cluster_info() -> ClusterInfo:
73
41
  return _get_cluster_info()
74
42
 
75
43
 
44
+ clustered = synchronize_api(_clustered, target_module=__name__)
45
+
46
+
76
47
  @dataclass
77
48
  class AppInfo:
78
49
  app_id: str
modal/partial_function.py CHANGED
@@ -1,5 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
- from modal._utils.async_utils import synchronize_api
3
2
 
4
3
  from ._partial_function import (
5
4
  _asgi_app,
@@ -15,6 +14,7 @@ from ._partial_function import (
15
14
  _web_server,
16
15
  _wsgi_app,
17
16
  )
17
+ from ._utils.async_utils import synchronize_api
18
18
 
19
19
  # The only reason these are wrapped is to get translated type stubs, they
20
20
  # don't actually run any async code as of 2025-02-04:
@@ -1,41 +1,37 @@
1
1
  import collections.abc
2
2
  import modal._partial_function
3
3
  import modal.functions
4
- import modal_proto.api_pb2
5
4
  import typing
5
+ import typing_extensions
6
6
 
7
7
  class PartialFunction(
8
8
  typing.Generic[
9
9
  modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.OriginalReturnType
10
10
  ]
11
11
  ):
12
- raw_f: collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType]
12
+ raw_f: typing.Optional[collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType]]
13
+ user_cls: typing.Optional[type]
13
14
  flags: modal._partial_function._PartialFunctionFlags
14
- webhook_config: typing.Optional[modal_proto.api_pb2.WebhookConfig]
15
- is_generator: bool
16
- batch_max_size: typing.Optional[int]
17
- batch_wait_ms: typing.Optional[int]
18
- force_build: bool
19
- cluster_size: typing.Optional[int]
20
- build_timeout: typing.Optional[int]
21
- max_concurrent_inputs: typing.Optional[int]
22
- target_concurrent_inputs: typing.Optional[int]
15
+ params: modal._partial_function._PartialFunctionParams
16
+ registered: bool
23
17
 
24
18
  def __init__(
25
19
  self,
26
- raw_f: collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType],
20
+ obj: typing.Union[
21
+ collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType], type
22
+ ],
27
23
  flags: modal._partial_function._PartialFunctionFlags,
28
- *,
29
- webhook_config: typing.Optional[modal_proto.api_pb2.WebhookConfig] = None,
30
- is_generator: typing.Optional[bool] = None,
31
- batch_max_size: typing.Optional[int] = None,
32
- batch_wait_ms: typing.Optional[int] = None,
33
- cluster_size: typing.Optional[int] = None,
34
- force_build: bool = False,
35
- build_timeout: typing.Optional[int] = None,
36
- max_concurrent_inputs: typing.Optional[int] = None,
37
- target_concurrent_inputs: typing.Optional[int] = None,
24
+ params: modal._partial_function._PartialFunctionParams,
38
25
  ): ...
26
+ def stack(
27
+ self,
28
+ flags: modal._partial_function._PartialFunctionFlags,
29
+ params: modal._partial_function._PartialFunctionParams,
30
+ ) -> typing_extensions.Self: ...
31
+ def validate_flag_composition(self) -> None: ...
32
+ def validate_obj_compatibility(
33
+ self, decorator_name: str, require_sync: bool = False, require_nullary: bool = False
34
+ ) -> None: ...
39
35
  def _get_raw_f(self) -> collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType]: ...
40
36
  def _is_web_endpoint(self) -> bool: ...
41
37
  def __get__(
@@ -44,7 +40,6 @@ class PartialFunction(
44
40
  modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.OriginalReturnType
45
41
  ]: ...
46
42
  def __del__(self): ...
47
- def add_flags(self, flags) -> PartialFunction: ...
48
43
 
49
44
  def method(
50
45
  _warn_parentheses_missing=None, *, is_generator: typing.Optional[bool] = None
@@ -58,7 +53,14 @@ def web_endpoint(
58
53
  custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
59
54
  requires_proxy_auth: bool = False,
60
55
  ) -> collections.abc.Callable[
61
- [collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType]],
56
+ [
57
+ typing.Union[
58
+ PartialFunction[
59
+ modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType
60
+ ],
61
+ collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType],
62
+ ]
63
+ ],
62
64
  PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
63
65
  ]: ...
64
66
  def fastapi_endpoint(
@@ -70,7 +72,14 @@ def fastapi_endpoint(
70
72
  docs: bool = False,
71
73
  requires_proxy_auth: bool = False,
72
74
  ) -> collections.abc.Callable[
73
- [collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType]],
75
+ [
76
+ typing.Union[
77
+ PartialFunction[
78
+ modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType
79
+ ],
80
+ collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType],
81
+ ]
82
+ ],
74
83
  PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
75
84
  ]: ...
76
85
  def asgi_app(
@@ -79,14 +88,32 @@ def asgi_app(
79
88
  label: typing.Optional[str] = None,
80
89
  custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
81
90
  requires_proxy_auth: bool = False,
82
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], PartialFunction]: ...
91
+ ) -> collections.abc.Callable[
92
+ [
93
+ typing.Union[
94
+ PartialFunction,
95
+ collections.abc.Callable[[], typing.Any],
96
+ collections.abc.Callable[[typing.Any], typing.Any],
97
+ ]
98
+ ],
99
+ PartialFunction,
100
+ ]: ...
83
101
  def wsgi_app(
84
102
  _warn_parentheses_missing=None,
85
103
  *,
86
104
  label: typing.Optional[str] = None,
87
105
  custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
88
106
  requires_proxy_auth: bool = False,
89
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], PartialFunction]: ...
107
+ ) -> collections.abc.Callable[
108
+ [
109
+ typing.Union[
110
+ PartialFunction,
111
+ collections.abc.Callable[[], typing.Any],
112
+ collections.abc.Callable[[typing.Any], typing.Any],
113
+ ]
114
+ ],
115
+ PartialFunction,
116
+ ]: ...
90
117
  def web_server(
91
118
  port: int,
92
119
  *,
@@ -94,36 +121,52 @@ def web_server(
94
121
  label: typing.Optional[str] = None,
95
122
  custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
96
123
  requires_proxy_auth: bool = False,
97
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], PartialFunction]: ...
124
+ ) -> collections.abc.Callable[
125
+ [
126
+ typing.Union[
127
+ PartialFunction,
128
+ collections.abc.Callable[[], typing.Any],
129
+ collections.abc.Callable[[typing.Any], typing.Any],
130
+ ]
131
+ ],
132
+ PartialFunction,
133
+ ]: ...
98
134
  def build(
99
135
  _warn_parentheses_missing=None, *, force: bool = False, timeout: int = 86400
100
136
  ) -> collections.abc.Callable[
101
- [typing.Union[collections.abc.Callable[[typing.Any], typing.Any], PartialFunction]], PartialFunction
137
+ [typing.Union[PartialFunction, collections.abc.Callable[[typing.Any], typing.Any]]], PartialFunction
102
138
  ]: ...
103
139
  def enter(
104
140
  _warn_parentheses_missing=None, *, snap: bool = False
105
141
  ) -> collections.abc.Callable[
106
- [typing.Union[collections.abc.Callable[[typing.Any], typing.Any], PartialFunction]], PartialFunction
142
+ [typing.Union[PartialFunction, collections.abc.Callable[[typing.Any], typing.Any]]], PartialFunction
107
143
  ]: ...
108
144
  def exit(
109
145
  _warn_parentheses_missing=None,
146
+ ) -> collections.abc.Callable[[collections.abc.Callable[[typing.Any], typing.Any]], PartialFunction]: ...
147
+ def batched(
148
+ _warn_parentheses_missing=None, *, max_batch_size: int, wait_ms: int
110
149
  ) -> collections.abc.Callable[
111
150
  [
112
151
  typing.Union[
113
- collections.abc.Callable[
114
- [typing.Any, typing.Optional[type[BaseException]], typing.Optional[BaseException], typing.Any],
115
- typing.Any,
152
+ PartialFunction[
153
+ modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType
116
154
  ],
117
- collections.abc.Callable[[typing.Any], typing.Any],
155
+ collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType],
118
156
  ]
119
157
  ],
120
- PartialFunction,
158
+ PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
121
159
  ]: ...
122
- def batched(
123
- _warn_parentheses_missing=None, *, max_batch_size: int, wait_ms: int
124
- ) -> collections.abc.Callable[[collections.abc.Callable[..., typing.Any]], PartialFunction]: ...
125
160
  def concurrent(
126
161
  _warn_parentheses_missing=None, *, max_inputs: int, target_inputs: typing.Optional[int] = None
127
162
  ) -> collections.abc.Callable[
128
- [typing.Union[collections.abc.Callable[..., typing.Any], PartialFunction]], PartialFunction
163
+ [
164
+ typing.Union[
165
+ PartialFunction[
166
+ modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType
167
+ ],
168
+ collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType],
169
+ ]
170
+ ],
171
+ PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
129
172
  ]: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: modal
3
- Version: 0.73.146
3
+ Version: 0.73.148
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -3,12 +3,12 @@ modal/__main__.py,sha256=CgIjP8m1xJjjd4AXc-delmR6LdBCZclw2A_V38CFIio,2870
3
3
  modal/_clustered_functions.py,sha256=kTf-9YBXY88NutC1akI-gCbvf01RhMPCw-zoOI_YIUE,2700
4
4
  modal/_clustered_functions.pyi,sha256=vllkegc99A0jrUOWa8mdlSbdp6uz36TsHhGxysAOpaQ,771
5
5
  modal/_container_entrypoint.py,sha256=XyqJPvzX0YMqviIIz-9bsD6HMrPsboU4A1yfgTloTSA,29302
6
- modal/_functions.py,sha256=NDr7mB4pUtQ0la8Y0FyvEIifkXiJoZ49KwzJUlQLU3M,73483
6
+ modal/_functions.py,sha256=nUyiCOYcuY_jXJhY5-haHFIUQleCmjh8z6GgXgo5MRY,73556
7
7
  modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
8
8
  modal/_location.py,sha256=joiX-0ZeutEUDTrrqLF1GHXCdVLF-rHzstocbMcd_-k,366
9
9
  modal/_object.py,sha256=JBIECWdfpRKCaCxVWZbC3Q1kF5Whk_EKvY9f4Y6AFyg,11446
10
10
  modal/_output.py,sha256=Z0nngPh2mKHMQc4MQ92YjVPc3ewOLa3I4dFBlL9nvQY,25656
11
- modal/_partial_function.py,sha256=owqnPM7tGbl2b6qrdB__62W08DYF_1d4xEvS3RmayWk,33823
11
+ modal/_partial_function.py,sha256=fsHktCBncN2pj_BwSe0eqUn-fo8emZnnCg5YK5mOBuM,39570
12
12
  modal/_proxy_tunnel.py,sha256=gnKyCfmVB7x2d1A6c-JDysNIP3kEFxmXzhcXhPrzPn0,1906
13
13
  modal/_pty.py,sha256=JZfPDDpzqICZqtyPI_oMJf_9w-p_lLNuzHhwhodUXio,1329
14
14
  modal/_resolver.py,sha256=RtoXoYzSllPlFu0D1vel_FWiEmDO7RyToiC2bxeN8ZY,6917
@@ -19,14 +19,14 @@ modal/_tunnel.py,sha256=zTBxBiuH1O22tS1OliAJdIsSmaZS8PlnifS_6S5z-mk,6320
19
19
  modal/_tunnel.pyi,sha256=JmmDYAy9F1FpgJ_hWx0xkom2nTOFQjn4mTPYlU3PFo4,1245
20
20
  modal/_type_manager.py,sha256=SvDvX9JK1jLp8TA_psLd-hNYPALlG9KtSOmlbHqdtQE,8284
21
21
  modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
22
- modal/app.py,sha256=NKH7Cw1M6eyyrMXFbhWfdo3uRd28-8kv0Pcw56kPiPU,47312
22
+ modal/app.py,sha256=w00bV9cjABAsS2ExE7zb1jY6Q_snXYmdKa3xRFg8iXA,47428
23
23
  modal/app.pyi,sha256=pUEqciyGZ446sc_QoG8XcQ_oc6oU-U4dqjkxjhgOX98,26968
24
24
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
25
25
  modal/client.py,sha256=j9D3hNis1lfhnz9lVFGgJgowbH3PaGUzNKgHPWYG778,15372
26
- modal/client.pyi,sha256=bdRQ5vkT_ruyvdR7pZTK6l4qYekAEyH_AsyOXVQNDLo,7661
26
+ modal/client.pyi,sha256=mMEPgjcIyzVWg-sdPiS4Xg6JpoC5OjNBEmIbLmqn6Ok,7661
27
27
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
28
28
  modal/cloud_bucket_mount.pyi,sha256=30T3K1a89l6wzmEJ_J9iWv9SknoGqaZDx59Xs-ZQcmk,1607
29
- modal/cls.py,sha256=PJimWA9q_sbQJNLbYy7fzjZGBm_hdfXuuZ7O_pKLXdk,31586
29
+ modal/cls.py,sha256=6MZYzhOcsCG7uWKk_zv_Q7fDcn5dkmK0M4QVRrpfF3Q,31769
30
30
  modal/cls.pyi,sha256=ZJUwtRaQBGlM6tphvnv49FHBVDSgttMdD_LnYyRSKJM,10302
31
31
  modal/config.py,sha256=Zx7YsllgIJzMRKeIkaGSLLtMFV4kTUvGxpptnmqlP1U,11623
32
32
  modal/container_process.py,sha256=vvyK3DVPUMsuqvkKdUiQ49cDLF9JawGrxpglLk5vfgI,6208
@@ -55,8 +55,8 @@ modal/object.pyi,sha256=kyJkRQcVv3ct7zSAxvvXcuhBVeH914v80uSlqeS7cA4,5632
55
55
  modal/output.py,sha256=q4T9uHduunj4NwY-YSwkHGgjZlCXMuJbfQ5UFaAGRAc,1968
56
56
  modal/parallel_map.py,sha256=2d30AM43g8SazkhGbbP1t2sACa4NRqeZrw3JEAqqZDg,33867
57
57
  modal/parallel_map.pyi,sha256=mEenHruPiZDq3ucV_6RM8ctc0c_Qpqra5MBagXeHiiQ,5708
58
- modal/partial_function.py,sha256=y0h-EvlPnfvZr7nlJLOFk7NB-K-ZO41XJnsGtQTesAI,1200
59
- modal/partial_function.pyi,sha256=-xWrvFMhLT6ulx9B82u1g8kL69vt3nYAvp8pV0d__uw,5407
58
+ modal/partial_function.py,sha256=SwuAAj2wj4SO6F6nkSnwNZrczEmm9w9YdlQTHh6hr04,1195
59
+ modal/partial_function.pyi,sha256=NFWz1aCAs2B3-GnPf1cTatWRZOLnYpFKCnjP_X9iNRs,6411
60
60
  modal/proxy.py,sha256=NrOevrWxG3G7-zlyRzG6BcIvop7AWLeyahZxitbBaOk,1418
61
61
  modal/proxy.pyi,sha256=1OEKIVUyC-xb7fHMzngakQso0nTsK60TVhXtlcMj6Wk,390
62
62
  modal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -89,7 +89,7 @@ modal/_runtime/execution_context.py,sha256=E6ofm6j1POXGPxS841X3V7JU6NheVb8OkQc7J
89
89
  modal/_runtime/execution_context.pyi,sha256=wQZwMNADExkeNdB9yKX0PPojovxlFHbap3441wAsiMY,634
90
90
  modal/_runtime/gpu_memory_snapshot.py,sha256=tA3m1d1cwnmHpvpCeN_WijDd6n8byn7LWlpicbIxiOI,3144
91
91
  modal/_runtime/telemetry.py,sha256=T1RoAGyjBDr1swiM6pPsGRSITm7LI5FDK18oNXxY08U,5163
92
- modal/_runtime/user_code_imports.py,sha256=OTxf5BIwMOaHFplIxxyEAOsR-xM2f5kSiSOa9Ne2le0,14814
92
+ modal/_runtime/user_code_imports.py,sha256=Q3EXhRObBvBWwUrrXI3wfVPSlGqNr5UtchFjMWeoVS0,14828
93
93
  modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
94
94
  modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
95
95
  modal/_utils/async_utils.py,sha256=b2TJyKY1Hq7df7M-fo3qlFM95mGdo3dCuqRPPcV5hsE,27445
@@ -137,7 +137,7 @@ modal/cli/volume.py,sha256=c2IuVNO2yJVaXmZkRh3xwQmznlRTgFoJr_BIzzqtVv0,10251
137
137
  modal/cli/programs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
138
138
  modal/cli/programs/run_jupyter.py,sha256=MX6YQ6zRyRk1xo8tYZFiGam0p5KETwax81L6TpaS9I0,2778
139
139
  modal/cli/programs/vscode.py,sha256=kfvhZQ4bJwtVm3MgC1V7AlygZOlKT1a33alr_uwrewA,3473
140
- modal/experimental/__init__.py,sha256=DXXQnYEjaRPcr1b4pbKk4DckHKtQ8T8PcWTUuXG4_ug,7595
140
+ modal/experimental/__init__.py,sha256=7qlR4P4U1_sfPdiX8mhSzHR5scbS96QVxeKFnsIcpS4,6457
141
141
  modal/experimental/ipython.py,sha256=epLUZeDSdE226TH_tU3igRKCiVuQi99mUOrIJ4SemOE,2792
142
142
  modal/requirements/2023.12.312.txt,sha256=zWWUVgVQ92GXBKNYYr2-5vn9rlnXcmkqlwlX5u1eTYw,400
143
143
  modal/requirements/2023.12.txt,sha256=OjsbXFkCSdkzzryZP82Q73osr5wxQ6EUzmGcK7twfkA,502
@@ -170,10 +170,10 @@ 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=qXFivVwqk3XozQgTf5wU8Dy4T77AmnPeQjIFqesEans,150
174
- modal-0.73.146.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
175
- modal-0.73.146.dist-info/METADATA,sha256=LxtkRG1reaAqP5lbyQUMlRKFAAt-lLGO7c5V_NfZ5Co,2453
176
- modal-0.73.146.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
177
- modal-0.73.146.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
- modal-0.73.146.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
- modal-0.73.146.dist-info/RECORD,,
173
+ modal_version/_version_generated.py,sha256=nzFQHmuRs46mrfpDMjMlOZqG-WUOmD7XQgKYT_4bcSQ,150
174
+ modal-0.73.148.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
175
+ modal-0.73.148.dist-info/METADATA,sha256=7cfZ8raRL3PwJoKUpglIOKEiGcmBB0rkUu2ijhjasOo,2453
176
+ modal-0.73.148.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
177
+ modal-0.73.148.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-0.73.148.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-0.73.148.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
 
3
3
  # Note: Reset this value to -1 whenever you make a minor `0.X` release of the client.
4
- build_number = 146 # git: 868bbba
4
+ build_number = 148 # git: 7d05f36