modal 0.73.157__py3-none-any.whl → 0.73.159__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.
@@ -2,7 +2,12 @@
2
2
  # ruff: noqa: E402
3
3
  import os
4
4
 
5
- from modal._runtime.user_code_imports import Service, import_class_service, import_single_function_service
5
+ from modal._runtime.user_code_imports import (
6
+ Service,
7
+ get_active_app_fallback,
8
+ import_class_service,
9
+ import_single_function_service,
10
+ )
6
11
 
7
12
  telemetry_socket = os.environ.get("MODAL_TELEMETRY_SOCKET")
8
13
  if telemetry_socket:
@@ -349,32 +354,6 @@ def call_function(
349
354
  signal.signal(signal.SIGUSR1, usr1_handler) # reset signal handler
350
355
 
351
356
 
352
- def get_active_app_fallback(function_def: api_pb2.Function) -> _App:
353
- # This branch is reached in the special case that the imported function/class is:
354
- # 1) not serialized, and
355
- # 2) isn't a FunctionHandle - i.e, not decorated at definition time
356
- # Look at all instantiated apps - if there is only one with the indicated name, use that one
357
- app_name: Optional[str] = function_def.app_name or None # coalesce protobuf field to None
358
- matching_apps = _App._all_apps.get(app_name, [])
359
- if len(matching_apps) == 1:
360
- active_app: _App = matching_apps[0]
361
- return active_app
362
-
363
- if len(matching_apps) > 1:
364
- if app_name is not None:
365
- warning_sub_message = f"app with the same name ('{app_name}')"
366
- else:
367
- warning_sub_message = "unnamed app"
368
- logger.warning(
369
- f"You have more than one {warning_sub_message}. "
370
- "It's recommended to name all your Apps uniquely when using multiple apps"
371
- )
372
-
373
- # If we don't have an active app, create one on the fly
374
- # The app object is used to carry the app layout etc
375
- return _App()
376
-
377
-
378
357
  def call_lifecycle_functions(
379
358
  event_loop: UserCodeEventLoop,
380
359
  container_io_manager, #: ContainerIOManager, TODO: this type is generated at runtime
@@ -416,9 +395,9 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
416
395
  with container_io_manager.heartbeats(is_snapshotting_function), UserCodeEventLoop() as event_loop:
417
396
  # If this is a serialized function, fetch the definition from the server
418
397
  if function_def.definition_type == api_pb2.Function.DEFINITION_TYPE_SERIALIZED:
419
- ser_cls, ser_fun = container_io_manager.get_serialized_function()
398
+ ser_usr_cls, ser_fun = container_io_manager.get_serialized_function()
420
399
  else:
421
- ser_cls, ser_fun = None, None
400
+ ser_usr_cls, ser_fun = None, None
422
401
 
423
402
  # Initialize the function, importing user code.
424
403
  with container_io_manager.handle_user_exception():
@@ -429,16 +408,28 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
429
408
  param_kwargs = {}
430
409
 
431
410
  if function_def.is_class:
411
+ # this is a bit ugly - match the function and class based on function name to get metadata
412
+ # This metadata is required in order to hydrate the class in case it's not globally
413
+ # decorated (or serialized)
414
+ service_base_function_id = container_args.app_layout.function_ids[function_def.function_name]
415
+ service_function_hydration_data = [
416
+ o for o in container_args.app_layout.objects if o.object_id == service_base_function_id
417
+ ][0]
418
+ class_id = container_args.app_layout.class_ids[function_def.function_name.removesuffix(".*")]
419
+
432
420
  service = import_class_service(
433
421
  function_def,
434
- ser_cls,
422
+ service_function_hydration_data,
423
+ class_id,
424
+ client,
425
+ ser_usr_cls,
435
426
  param_args,
436
427
  param_kwargs,
437
428
  )
438
429
  else:
439
430
  service = import_single_function_service(
440
431
  function_def,
441
- ser_cls,
432
+ ser_usr_cls,
442
433
  ser_fun,
443
434
  param_args,
444
435
  param_kwargs,
@@ -10,9 +10,10 @@ import modal._runtime.container_io_manager
10
10
  import modal.cls
11
11
  from modal import Function
12
12
  from modal._functions import _Function
13
- from modal._partial_function import _find_partial_methods_for_user_cls, _PartialFunctionFlags
14
13
  from modal._utils.async_utils import synchronizer
15
14
  from modal._utils.function_utils import LocalFunctionError, is_async as get_is_async, is_global_object
15
+ from modal.app import _App
16
+ from modal.config import logger
16
17
  from modal.exception import ExecutionError, InvalidError
17
18
  from modal_proto import api_pb2
18
19
 
@@ -144,14 +145,13 @@ class ImportedClass(Service):
144
145
  self, fun_def: api_pb2.Function, container_io_manager: "modal._runtime.container_io_manager.ContainerIOManager"
145
146
  ) -> dict[str, "FinalizedFunction"]:
146
147
  finalized_functions = {}
147
- for method_name, partial in self._partial_functions.items():
148
- partial = synchronizer._translate_in(partial) # ugly
149
- user_func = partial.raw_f
148
+ for method_name, _partial in self._partial_functions.items():
149
+ user_func = _partial.raw_f
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.params.is_generator
154
- webhook_config = partial.params.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
 
@@ -178,22 +178,20 @@ class ImportedClass(Service):
178
178
  return finalized_functions
179
179
 
180
180
 
181
- def get_user_class_instance(cls: typing.Union[type, modal.cls.Cls], args: tuple, kwargs: dict[str, Any]) -> typing.Any:
181
+ def get_user_class_instance(_cls: modal.cls._Cls, args: tuple, kwargs: dict[str, Any]) -> typing.Any:
182
182
  """Returns instance of the underlying class to be used as the `self`
183
183
 
184
- The input `cls` can either be the raw Python class the user has declared ("user class"),
185
- or an @app.cls-decorated version of it which is a modal.Cls-instance wrapping the user class.
186
- """
187
- if isinstance(cls, modal.cls.Cls):
188
- # globally @app.cls-decorated class
189
- modal_obj: modal.cls.Obj = cls(*args, **kwargs)
190
- modal_obj._entered = True # ugly but prevents .local() from triggering additional enter-logic
191
- # TODO: unify lifecycle logic between .local() and container_entrypoint
192
- user_cls_instance = modal_obj._cached_user_cls_instance()
193
- else:
194
- # undecorated class (non-global decoration or serialized)
195
- user_cls_instance = cls(*args, **kwargs)
184
+ For the time being, this is an instance of the underlying user defined type, with
185
+ some extra attributes like parameter values and _modal_functions set, allowing
186
+ its methods to be used as modal Function objects with .remote() and .local() etc.
196
187
 
188
+ TODO: Could possibly change this to use an Obj to clean up the data model? would invalidate isinstance checks though
189
+ """
190
+ cls = synchronizer._translate_out(_cls) # ugly
191
+ modal_obj: modal.cls.Obj = cls(*args, **kwargs)
192
+ modal_obj._entered = True # ugly but prevents .local() from triggering additional enter-logic
193
+ # TODO: unify lifecycle logic between .local() and container_entrypoint
194
+ user_cls_instance = modal_obj._cached_user_cls_instance()
197
195
  return user_cls_instance
198
196
 
199
197
 
@@ -293,7 +291,10 @@ def import_single_function_service(
293
291
 
294
292
  def import_class_service(
295
293
  function_def: api_pb2.Function,
296
- ser_cls,
294
+ service_function_hydration_data: api_pb2.Object,
295
+ class_id: str,
296
+ client: "modal.client.Client",
297
+ ser_user_cls: Optional[type],
297
298
  cls_args,
298
299
  cls_kwargs,
299
300
  ) -> Service:
@@ -304,11 +305,11 @@ def import_class_service(
304
305
  """
305
306
  active_app: Optional["modal.app._App"]
306
307
  service_deps: Optional[Sequence["modal._object._Object"]]
307
- cls: typing.Union[type, modal.cls.Cls]
308
+ cls_or_user_cls: typing.Union[type, modal.cls.Cls]
308
309
 
309
310
  if function_def.definition_type == api_pb2.Function.DEFINITION_TYPE_SERIALIZED:
310
- assert ser_cls is not None
311
- cls = ser_cls
311
+ assert ser_user_cls is not None
312
+ cls_or_user_cls = ser_user_cls
312
313
  else:
313
314
  # Load the module dynamically
314
315
  module = importlib.import_module(function_def.module_name)
@@ -327,22 +328,31 @@ def import_class_service(
327
328
 
328
329
  assert not function_def.use_method_name # new "placeholder methods" should not be invoked directly!
329
330
  cls_name = parts[0]
330
- cls = getattr(module, cls_name)
331
-
332
- if isinstance(cls, modal.cls.Cls):
333
- # The cls decorator is in global scope
334
- _cls = synchronizer._translate_in(cls)
335
- method_partials = _cls._get_partial_functions()
336
- service_function: _Function = _cls._class_service_function
337
- service_deps = service_function.deps(only_explicit_mounts=True)
338
- active_app = service_function.app
331
+ cls_or_user_cls = getattr(module, cls_name)
332
+
333
+ if isinstance(cls_or_user_cls, modal.cls.Cls):
334
+ _cls = synchronizer._translate_in(cls_or_user_cls)
335
+ class_service_function: _Function = _cls._get_class_service_function()
336
+ service_deps = class_service_function.deps(only_explicit_mounts=True)
337
+ active_app = class_service_function.app
339
338
  else:
340
- # Undecorated user class - find all methods
341
- method_partials = _find_partial_methods_for_user_cls(cls, _PartialFunctionFlags.all())
342
- service_deps = None
343
- active_app = None
339
+ # Undecorated user class (serialized or local scope-decoration).
340
+ service_deps = None # we can't infer service deps for now
341
+ active_app = get_active_app_fallback(function_def)
342
+ _client: "modal.client._Client" = synchronizer._translate_in(client)
343
+ _service_function: modal._functions._Function[Any, Any, Any] = modal._functions._Function._new_hydrated(
344
+ service_function_hydration_data.object_id,
345
+ _client,
346
+ service_function_hydration_data.function_handle_metadata,
347
+ is_another_app=True, # this skips re-loading the function, which is required since it doesn't have a loader
348
+ )
349
+ _cls = modal.cls._Cls.from_local(cls_or_user_cls, active_app, _service_function)
350
+ # hydration of the class itself - just sets the id and triggers some side effects
351
+ # that transfers metadata from the service function to the class. TODO: cleanup!
352
+ _cls._hydrate(class_id, _client, api_pb2.ClassHandleMetadata())
344
353
 
345
- user_cls_instance = get_user_class_instance(cls, cls_args, cls_kwargs)
354
+ method_partials: dict[str, "modal._partial_function._PartialFunction"] = _cls._get_partial_functions()
355
+ user_cls_instance = get_user_class_instance(_cls, cls_args, cls_kwargs)
346
356
 
347
357
  return ImportedClass(
348
358
  user_cls_instance,
@@ -351,3 +361,29 @@ def import_class_service(
351
361
  # TODO (elias/deven): instead of using method_partials here we should use a set of api_pb2.MethodDefinition
352
362
  method_partials,
353
363
  )
364
+
365
+
366
+ def get_active_app_fallback(function_def: api_pb2.Function) -> _App:
367
+ # This branch is reached in the special case that the imported function/class is:
368
+ # 1) not serialized, and
369
+ # 2) isn't a FunctionHandle - i.e, not decorated at definition time
370
+ # Look at all instantiated apps - if there is only one with the indicated name, use that one
371
+ app_name: Optional[str] = function_def.app_name or None # coalesce protobuf field to None
372
+ matching_apps = _App._all_apps.get(app_name, [])
373
+ if len(matching_apps) == 1:
374
+ active_app: _App = matching_apps[0]
375
+ return active_app
376
+
377
+ if len(matching_apps) > 1:
378
+ if app_name is not None:
379
+ warning_sub_message = f"app with the same name ('{app_name}')"
380
+ else:
381
+ warning_sub_message = "unnamed app"
382
+ logger.warning(
383
+ f"You have more than one {warning_sub_message}. "
384
+ "It's recommended to name all your Apps uniquely when using multiple apps"
385
+ )
386
+
387
+ # If we don't have an active app, create one on the fly
388
+ # The app object is used to carry the app layout etc
389
+ return _App()
modal/_serialization.py CHANGED
@@ -501,20 +501,20 @@ def _signature_parameter_to_spec(
501
501
  has_default=has_default,
502
502
  )
503
503
  if include_legacy_parameter_fields:
504
+ # Specific to *class parameters*:
504
505
  # add the .{type}_default and `.type` values as required by legacy clients
505
506
  # looking at class parameter specs
506
- if full_proto_type.base_type == api_pb2.PARAM_TYPE_INT:
507
- if has_default:
507
+ field_spec.type = field_spec.full_type.base_type
508
+
509
+ if has_default:
510
+ if full_proto_type.base_type == api_pb2.PARAM_TYPE_INT:
508
511
  field_spec.int_default = python_signature_parameter.default
509
- field_spec.type = api_pb2.PARAM_TYPE_INT
510
- elif full_proto_type.base_type == api_pb2.PARAM_TYPE_STRING:
511
- if has_default:
512
+ elif full_proto_type.base_type == api_pb2.PARAM_TYPE_STRING:
512
513
  field_spec.string_default = python_signature_parameter.default
513
- field_spec.type = api_pb2.PARAM_TYPE_STRING
514
- elif full_proto_type.base_type == api_pb2.PARAM_TYPE_BYTES:
515
- if has_default:
514
+ elif full_proto_type.base_type == api_pb2.PARAM_TYPE_BYTES:
516
515
  field_spec.bytes_default = python_signature_parameter.default
517
- field_spec.type = api_pb2.PARAM_TYPE_BYTES
516
+ elif full_proto_type.base_type == api_pb2.PARAM_TYPE_BOOL:
517
+ field_spec.bool_default = python_signature_parameter.default
518
518
 
519
519
  return field_spec
520
520
 
modal/_type_manager.py CHANGED
@@ -143,6 +143,23 @@ class BytesParameter:
143
143
  raise TypeError(f"Expected bytes, got {type(python_value).__name__}")
144
144
 
145
145
 
146
+ @parameter_serde_registry.register_encoder(bool)
147
+ @parameter_serde_registry.register_decoder(api_pb2.PARAM_TYPE_BOOL)
148
+ class BoolParameter:
149
+ @staticmethod
150
+ def encode(value: Any) -> api_pb2.ClassParameterValue:
151
+ return api_pb2.ClassParameterValue(type=api_pb2.PARAM_TYPE_BOOL, bool_value=value)
152
+
153
+ @staticmethod
154
+ def decode(proto_value: api_pb2.ClassParameterValue) -> bool:
155
+ return proto_value.bool_value
156
+
157
+ @staticmethod
158
+ def validate(python_value: Any):
159
+ if not isinstance(python_value, bool):
160
+ raise TypeError(f"Expected bool, got {type(python_value).__name__}")
161
+
162
+
146
163
  SCHEMA_FACTORY_TYPE = typing.Callable[[type], api_pb2.GenericPayloadType]
147
164
 
148
165
 
@@ -205,6 +222,13 @@ def str_schema(full_python_type: type) -> api_pb2.GenericPayloadType:
205
222
  )
206
223
 
207
224
 
225
+ @schema_registry.add(bool)
226
+ def bool_schema(full_python_type: type) -> api_pb2.GenericPayloadType:
227
+ return api_pb2.GenericPayloadType(
228
+ base_type=api_pb2.PARAM_TYPE_BOOL,
229
+ )
230
+
231
+
208
232
  @schema_registry.add(type(None))
209
233
  def none_type_schema(declared_python_type: type) -> api_pb2.GenericPayloadType:
210
234
  return api_pb2.GenericPayloadType(base_type=api_pb2.PARAM_TYPE_NONE)
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.157",
34
+ version: str = "0.73.159",
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.157",
96
+ version: str = "0.73.159",
97
97
  ): ...
98
98
  def is_closed(self) -> bool: ...
99
99
  @property
modal/cls.py CHANGED
@@ -139,7 +139,7 @@ def _bind_instance_method(cls: "_Cls", service_function: _Function, method_name:
139
139
  # ugly - needed for .local() TODO (elias): Clean up!
140
140
  partial_function.raw_f,
141
141
  user_cls=cls._user_cls,
142
- serialized=service_function.info.is_serialized(),
142
+ serialized=True, # service_function.info.is_serialized(),
143
143
  )
144
144
 
145
145
  fun._obj = service_function._obj
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: modal
3
- Version: 0.73.157
3
+ Version: 0.73.159
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -2,7 +2,7 @@ modal/__init__.py,sha256=7wz1AT_bpWJJEzXsAo3QMb7i87y7UGXwfneb0bGDhRg,2502
2
2
  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
- modal/_container_entrypoint.py,sha256=XyqJPvzX0YMqviIIz-9bsD6HMrPsboU4A1yfgTloTSA,29302
5
+ modal/_container_entrypoint.py,sha256=Dhv6YV2ejwluaWi3pHTxIja8U7IXtgD1vsCeH9wHCKM,29002
6
6
  modal/_functions.py,sha256=M94gzMA9xfW9086djoG2yYFVihcslKnsleacmNbVrG0,74996
7
7
  modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
8
8
  modal/_location.py,sha256=joiX-0ZeutEUDTrrqLF1GHXCdVLF-rHzstocbMcd_-k,366
@@ -13,20 +13,20 @@ 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
15
15
  modal/_resources.py,sha256=5qmcirXUI8dSH926nwkUaeX9H25mqYu9mXD_KuT79-o,1733
16
- modal/_serialization.py,sha256=kkLmQ6jnPlbLT3FfuyigocHKG7H1HDJ0i24IxYFbgs8,22927
16
+ modal/_serialization.py,sha256=wAgaALThfr-DBV9LMhM4qY_PCH7SRhA9xgoHL2bapBk,22963
17
17
  modal/_traceback.py,sha256=IZQzB3fVlUfMHOSyKUgw0H6qv4yHnpyq-XVCNZKfUdA,5023
18
18
  modal/_tunnel.py,sha256=zTBxBiuH1O22tS1OliAJdIsSmaZS8PlnifS_6S5z-mk,6320
19
19
  modal/_tunnel.pyi,sha256=JmmDYAy9F1FpgJ_hWx0xkom2nTOFQjn4mTPYlU3PFo4,1245
20
- modal/_type_manager.py,sha256=SvDvX9JK1jLp8TA_psLd-hNYPALlG9KtSOmlbHqdtQE,8284
20
+ modal/_type_manager.py,sha256=DWjgmjYJuOagw2erin506UUbG2H5UzZCFEekS-7hmfA,9087
21
21
  modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
22
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=U-YKSw0n7J1ZLREt9cbEJCtmHe5YoPKFxl0xlkan2yc,15565
26
- modal/client.pyi,sha256=2r_RawoavNS1KIGw_fAUQHoOIYkZni6yaea8_qedhHE,7661
26
+ modal/client.pyi,sha256=TE65rR-JEWtJhkSxNOsl0fr1IqDYd21AjD2aa5_xOtA,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=jlQE7qEwGG49FCSqqzYkcedi619G3K4PNnJCtPO8y_w,32954
29
+ modal/cls.py,sha256=8tvSw7QFTS1FnX2MXaxagu3KwuR6y_DMwhqHv3MZ0Nk,32963
30
30
  modal/cls.pyi,sha256=pTYO9JsRENmsa5pDgzfoRJGm_NpCvEjEx--vs-jJkj8,10902
31
31
  modal/config.py,sha256=FlqVyh6LVukMahhmEGQVTwWtwtfoPfHqEo3GDn13EOA,11687
32
32
  modal/container_process.py,sha256=vvyK3DVPUMsuqvkKdUiQ49cDLF9JawGrxpglLk5vfgI,6208
@@ -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=Q3EXhRObBvBWwUrrXI3wfVPSlGqNr5UtchFjMWeoVS0,14828
92
+ modal/_runtime/user_code_imports.py,sha256=kAv37Pl1TmGKduv0Kozum0xNTD42bDLloSIsT7zf84o,16884
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
@@ -153,10 +153,10 @@ modal_docs/mdmd/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,2
153
153
  modal_docs/mdmd/mdmd.py,sha256=Irx49MCCTlBOP4FBdLR--JrpA3-WhsVeriq0LGgsRic,6232
154
154
  modal_docs/mdmd/signatures.py,sha256=XJaZrK7Mdepk5fdX51A8uENiLFNil85Ud0d4MH8H5f0,3218
155
155
  modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
156
- modal_proto/api.proto,sha256=id2Ep7N4h09b-TWSk8sBEJ7jDxnqTJR1EDzDQw_idtY,91357
156
+ modal_proto/api.proto,sha256=VwW2t0kpo9FMrYq1jHQpL4pvLbes2oCUxw7EXKAplpA,91432
157
157
  modal_proto/api_grpc.py,sha256=9Rs0JyHcz_DSjVKhdtMbDuNt6qDkrE2718KsyA3QL4c,110702
158
- modal_proto/api_pb2.py,sha256=2PaWyzRrd5TIHN2imLlsiAaBpzqqHM1UXaj_t0h9k5A,321857
159
- modal_proto/api_pb2.pyi,sha256=S2p4cY5k8Uw4nxncuTzVLDftKldmnhCUsQtgA4MICKo,438482
158
+ modal_proto/api_pb2.py,sha256=JXOC0c4UtDJkNfpwTJTB-rkVoeW1pMHTxr6iAb9ckQI,322009
159
+ modal_proto/api_pb2.pyi,sha256=iJH5M3mh9TGO2nZV2Te0vfLawharrzxBsIndsoF9pWs,438965
160
160
  modal_proto/api_pb2_grpc.py,sha256=olXvs6OQvy7pqvHP9bkSWC_DdIv0iO38xRlmkLo-ai8,239213
161
161
  modal_proto/api_pb2_grpc.pyi,sha256=ybhcN2nwFBIPd4Z4kkMOv-M8Ejidz93Bl4zScLpYcK0,55706
162
162
  modal_proto/modal_api_grpc.py,sha256=43ujbC_a8YAjuhtEvS-O-5lNpkG5d0K0ZIlryJ4weT4,14766
@@ -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=8z1dZXLk13pbLXOUQfQfB2qHzbM_QT3SY6V9WVjVZAk,150
174
- modal-0.73.157.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
175
- modal-0.73.157.dist-info/METADATA,sha256=GUT8XtlnOYHmpHyo6u1Q5XlsoEOPQGyuJB-UVeLDm6w,2453
176
- modal-0.73.157.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
177
- modal-0.73.157.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
- modal-0.73.157.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
- modal-0.73.157.dist-info/RECORD,,
173
+ modal_version/_version_generated.py,sha256=G2ne8nDuU_4SoCtLuOAJRnbZo3wKwxhaEnQrw0W6Efw,150
174
+ modal-0.73.159.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
175
+ modal-0.73.159.dist-info/METADATA,sha256=MraIsGfyaQsXi1lj19eWqdlSeIz3LFAvA0mcxNdUW-U,2453
176
+ modal-0.73.159.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
177
+ modal-0.73.159.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-0.73.159.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-0.73.159.dist-info/RECORD,,
modal_proto/api.proto CHANGED
@@ -176,6 +176,7 @@ enum ParameterType {
176
176
  PARAM_TYPE_LIST = 6;
177
177
  PARAM_TYPE_DICT = 7;
178
178
  PARAM_TYPE_NONE = 8;
179
+ PARAM_TYPE_BOOL = 9;
179
180
  }
180
181
 
181
182
  enum ProgressType {
@@ -710,6 +711,7 @@ message ClassParameterSpec { // TODO: rename into NamedPayloadType or similar
710
711
  int64 int_default = 5;
711
712
  bytes pickle_default = 6;
712
713
  bytes bytes_default = 7;
714
+ bool bool_default = 9;
713
715
  }
714
716
  GenericPayloadType full_type = 8; // supersedes `type`
715
717
  }
@@ -726,6 +728,7 @@ message ClassParameterValue { // TODO: rename into NamedPayloadValue
726
728
  int64 int_value = 4;
727
729
  bytes pickle_value = 5;
728
730
  bytes bytes_value = 6;
731
+ bool bool_value = 7;
729
732
  }
730
733
  }
731
734