modAL 1.5.3.dev12__py3-none-any.whl → 1.5.3.dev13__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.
Files changed (40) hide show
  1. modal/_environments.py +1 -1
  2. modal/_grpc_client.py +1 -1
  3. modal/_object.py +5 -4
  4. modal/_output/rich.py +3 -3
  5. modal/_resources.py +4 -4
  6. modal/_runtime/user_code_imports.py +2 -1
  7. modal/_traceback.py +1 -1
  8. modal/_utils/async_utils.py +5 -0
  9. modal/_utils/blob_utils.py +1 -0
  10. modal/_utils/bytes_io_segment_payload.py +2 -1
  11. modal/_utils/pattern_utils.py +2 -2
  12. modal/_utils/time_utils.py +3 -1
  13. modal/app.py +3 -1
  14. modal/app.pyi +4 -0
  15. modal/cli/cluster.py +1 -1
  16. modal/cli/dashboard.py +1 -1
  17. modal/cli/endpoint.py +2 -2
  18. modal/cli/environment.py +1 -1
  19. modal/cli/launch.py +1 -1
  20. modal/cli/network_file_system.py +1 -1
  21. modal/cli/profile.py +3 -3
  22. modal/cli/shell.py +2 -2
  23. modal/client.pyi +2 -2
  24. modal/cloud_bucket_mount.py +3 -2
  25. modal/experimental/__init__.py +2 -0
  26. modal/file_pattern_matcher.py +1 -1
  27. modal/functions.pyi +6 -6
  28. modal/mount.py +89 -31
  29. modal/mount.pyi +18 -6
  30. modal/secret.py +2 -2
  31. modal/serving.py +3 -3
  32. {modal-1.5.3.dev12.dist-info → modal-1.5.3.dev13.dist-info}/METADATA +1 -1
  33. {modal-1.5.3.dev12.dist-info → modal-1.5.3.dev13.dist-info}/RECORD +40 -40
  34. modal_proto/task_command_router_pb2.py +32 -32
  35. modal_proto/task_command_router_pb2.pyi +5 -1
  36. modal_version/__init__.py +1 -1
  37. {modal-1.5.3.dev12.dist-info → modal-1.5.3.dev13.dist-info}/WHEEL +0 -0
  38. {modal-1.5.3.dev12.dist-info → modal-1.5.3.dev13.dist-info}/entry_points.txt +0 -0
  39. {modal-1.5.3.dev12.dist-info → modal-1.5.3.dev13.dist-info}/licenses/LICENSE +0 -0
  40. {modal-1.5.3.dev12.dist-info → modal-1.5.3.dev13.dist-info}/top_level.txt +0 -0
modal/_environments.py CHANGED
@@ -591,4 +591,4 @@ def ensure_env(environment_name: str | None = None) -> str:
591
591
  if environment_name is not None:
592
592
  config.override_locally("environment", environment_name)
593
593
 
594
- return config.get("environment")
594
+ return config.get("environment") or ""
modal/_grpc_client.py CHANGED
@@ -54,7 +54,7 @@ class grpc_error_converter:
54
54
  with suppress_tb_frame():
55
55
  if isinstance(exc, GRPCError):
56
56
  modal_exc = _STATUS_TO_EXCEPTION[exc.status](exc.message)
57
- modal_exc._grpc_message = exc.message
57
+ modal_exc._grpc_message = exc.message or ""
58
58
  modal_exc._grpc_status = exc.status
59
59
  modal_exc._grpc_details = exc.details
60
60
  if use_full_traceback:
modal/_object.py CHANGED
@@ -23,19 +23,20 @@ EPHEMERAL_OBJECT_HEARTBEAT_SLEEP: int = 300
23
23
 
24
24
  def _get_environment_name(
25
25
  environment_name: str | None = None,
26
- ) -> str | None:
26
+ ) -> str:
27
27
  """Get environment name from various sources.
28
28
 
29
29
  Args:
30
- environment_name: Explicitly provided environment name (highest priority)
30
+ environment_name: Explicitly provided environment name (highest priority).
31
31
 
32
32
  Returns:
33
- Environment name from first available source, or config default
33
+ Environment name from as passed in, from config, or as a null string
34
+ (which implies workspace-level default).
34
35
  """
35
36
  if environment_name:
36
37
  return environment_name
37
38
  else:
38
- return config.get("environment")
39
+ return config.get("environment") or ""
39
40
 
40
41
 
41
42
  def live_method(method):
modal/_output/rich.py CHANGED
@@ -81,11 +81,11 @@ class FunctionQueuingColumn(ProgressColumn):
81
81
  super().__init__()
82
82
 
83
83
  def render(self, task) -> Text:
84
- self.lag = max(task.completed - task.elapsed, self.lag)
84
+ self.lag = max(task.completed - (task.elapsed or 0), self.lag)
85
85
  if task.finished:
86
- elapsed = max(task.finished_time, task.completed)
86
+ elapsed = max(task.finished_time or 0, task.completed)
87
87
  else:
88
- elapsed = task.elapsed + self.lag
88
+ elapsed = (task.elapsed or 0) + self.lag
89
89
  delta = timedelta(seconds=int(elapsed))
90
90
  return Text(str(delta), style="progress.elapsed")
91
91
 
modal/_resources.py CHANGED
@@ -26,10 +26,10 @@ def convert_fn_config_to_resources_config(
26
26
  raise InvalidError(f"Cannot specify a CPU limit lower than request: {milli_cpu_max} < {milli_cpu}")
27
27
  elif cpu and isinstance(cpu, (float, int)):
28
28
  milli_cpu = int(1000 * cpu)
29
- milli_cpu_max = None
29
+ milli_cpu_max = 0
30
30
  else:
31
- milli_cpu = None
32
- milli_cpu_max = None
31
+ milli_cpu = 0
32
+ milli_cpu_max = 0
33
33
 
34
34
  if memory and isinstance(memory, int):
35
35
  memory_mb = memory
@@ -47,6 +47,6 @@ def convert_fn_config_to_resources_config(
47
47
  gpu_config=parse_gpu_config(gpu),
48
48
  memory_mb=memory_mb,
49
49
  memory_mb_max=memory_mb_max,
50
- ephemeral_disk_mb=ephemeral_disk,
50
+ ephemeral_disk_mb=ephemeral_disk or 0,
51
51
  rdma=rdma or False,
52
52
  )
@@ -549,7 +549,8 @@ def _get_cls_or_user_cls(
549
549
  else:
550
550
  # Load the module dynamically for non-serialized class.
551
551
  module = importlib.import_module(function_def.module_name)
552
- qual_name: str = function_def.function_name
552
+ # Always use implementation_name to find the class, default to function_name if implementation_name not set.
553
+ qual_name: str = function_def.implementation_name or function_def.function_name
553
554
 
554
555
  if not is_global_object(qual_name):
555
556
  raise LocalFunctionError("Attempted to load a class defined in a function scope")
modal/_traceback.py CHANGED
@@ -75,7 +75,7 @@ def append_modal_tb(exc: BaseException, tb_dict: TBDictType, line_cache: LineCac
75
75
  setattr(exc, "__line_cache__", line_cache)
76
76
 
77
77
 
78
- def reduce_traceback_to_user_code(tb: TracebackType | None, user_source: str) -> TracebackType:
78
+ def reduce_traceback_to_user_code(tb: TracebackType | None, user_source: str) -> TracebackType | None:
79
79
  """Return a traceback that does not contain modal entrypoint or synchronicity frames."""
80
80
 
81
81
  # Step forward all the way through the traceback and drop any "Modal support" frames
@@ -1266,3 +1266,8 @@ def deprecate_aio_usage(deprecation_date: tuple[int, int, int], readable_sync_ca
1266
1266
  return MethodWithAio(sync_implementation, _async_proxy, synchronizer, is_classmethod=is_classmethod)
1267
1267
 
1268
1268
  return deco
1269
+
1270
+
1271
+ async def async_generator_from_sync(lst: Iterable[T]) -> AsyncGenerator[T, None]:
1272
+ for item in lst:
1273
+ yield item
@@ -444,6 +444,7 @@ class FileUploadSpec:
444
444
  mode: int # file permission bits (last 12 bits of st_mode)
445
445
  size: int
446
446
  content: bytes | None = None # Set for very small files to avoid double-read
447
+ exists_in_store: bool | None = None # set after existence check
447
448
 
448
449
  def read_content(self) -> bytes:
449
450
  """Read content from source."""
@@ -45,7 +45,8 @@ class BytesIOSegmentPayload(Payload):
45
45
  self.segment_length = segment_length
46
46
  # seek to start of file segment we are interested in, in order to make .size() evaluate correctly
47
47
  self._value.seek(self.initial_seek_pos + segment_start)
48
- assert self.segment_length <= super().size
48
+ base_size = super().size
49
+ assert base_size is not None and self.segment_length <= base_size
49
50
  self.chunk_size = chunk_size
50
51
  self.progress_report_cb = progress_report_cb or (lambda *_, **__: None)
51
52
  self.reset_state()
@@ -143,12 +143,12 @@ class Pattern:
143
143
  else:
144
144
  return False
145
145
  elif self.match_type == MatchType.REGEXP:
146
- return self.regexp.match(path) is not None
146
+ return self.regexp is not None and self.regexp.match(path) is not None
147
147
  else:
148
148
  return False
149
149
 
150
150
 
151
- def read_ignorefile(reader: TextIO) -> list[str]:
151
+ def read_ignorefile(reader: TextIO | None) -> list[str]:
152
152
  """Read an ignore file from a reader and return the list of file patterns to
153
153
  ignore, applying the following rules:
154
154
 
@@ -294,7 +294,9 @@ def relative_timestamp(dt: datetime) -> str:
294
294
 
295
295
 
296
296
  def locale_tz() -> tzinfo:
297
- return datetime.now().astimezone().tzinfo
297
+ tz = datetime.now().astimezone().tzinfo
298
+ assert tz is not None
299
+ return tz
298
300
 
299
301
 
300
302
  def as_timestamp(arg: datetime | str | None) -> float:
modal/app.py CHANGED
@@ -1295,6 +1295,7 @@ class _App:
1295
1295
  scaleup_window: int | None = None, # Stabilization window (seconds) of sustained demand before scaling up
1296
1296
  scaledown_window: int | None = None, # Max idle time before scaling down (seconds)
1297
1297
  startup_timeout: int = 30, # Maximum container startup time in seconds
1298
+ name: str | None = None, # Name of the server
1298
1299
  port: int = 8000, # Port the HTTP server listens on
1299
1300
  unauthenticated: bool = False, # Whether the endpoint requires proxy authentication, required by default.
1300
1301
  h2_enabled: bool = False, # Enable HTTP/2
@@ -1341,6 +1342,7 @@ class _App:
1341
1342
  scaleup_window: Seconds of sustained demand required before scaling up new containers.
1342
1343
  scaledown_window: Maximum duration (in seconds) idle containers wait before scaling down.
1343
1344
  startup_timeout: Maximum container startup time in seconds.
1345
+ name: Sets the Modal name of the function within the app, defaults to class name.
1344
1346
  port: Port the HTTP server listens on.
1345
1347
  unauthenticated: Whether the endpoint requires proxy authentication; required by default.
1346
1348
  h2_enabled: Enable HTTP/2.
@@ -1423,7 +1425,7 @@ class _App:
1423
1425
  local_state = self._local_state
1424
1426
 
1425
1427
  # Create the FunctionInfo for the server, note we treat FunctionInfo as a class for servers
1426
- info = FunctionInfo(None, serialized=serialized, user_cls=user_cls, name_override=user_cls.__name__)
1428
+ info = FunctionInfo(None, serialized=serialized, user_cls=user_cls, name_override=name or user_cls.__name__)
1427
1429
  # Create the service function
1428
1430
  service_function = _Function.from_local(
1429
1431
  info,
modal/app.pyi CHANGED
@@ -751,6 +751,7 @@ class _App:
751
751
  scaleup_window: typing.Optional[int] = None,
752
752
  scaledown_window: typing.Optional[int] = None,
753
753
  startup_timeout: int = 30,
754
+ name: typing.Optional[str] = None,
754
755
  port: int = 8000,
755
756
  unauthenticated: bool = False,
756
757
  h2_enabled: bool = False,
@@ -797,6 +798,7 @@ class _App:
797
798
  scaleup_window: Seconds of sustained demand required before scaling up new containers.
798
799
  scaledown_window: Maximum duration (in seconds) idle containers wait before scaling down.
799
800
  startup_timeout: Maximum container startup time in seconds.
801
+ name: Sets the Modal name of the function within the app, defaults to class name.
800
802
  port: Port the HTTP server listens on.
801
803
  unauthenticated: Whether the endpoint requires proxy authentication; required by default.
802
804
  h2_enabled: Enable HTTP/2.
@@ -1755,6 +1757,7 @@ class App:
1755
1757
  scaleup_window: typing.Optional[int] = None,
1756
1758
  scaledown_window: typing.Optional[int] = None,
1757
1759
  startup_timeout: int = 30,
1760
+ name: typing.Optional[str] = None,
1758
1761
  port: int = 8000,
1759
1762
  unauthenticated: bool = False,
1760
1763
  h2_enabled: bool = False,
@@ -1799,6 +1802,7 @@ class App:
1799
1802
  scaleup_window: Seconds of sustained demand required before scaling up new containers.
1800
1803
  scaledown_window: Maximum duration (in seconds) idle containers wait before scaling down.
1801
1804
  startup_timeout: Maximum container startup time in seconds.
1805
+ name: Sets the Modal name of the function within the app, defaults to class name.
1802
1806
  port: Port the HTTP server listens on.
1803
1807
  unauthenticated: Whether the endpoint requires proxy authentication; required by default.
1804
1808
  h2_enabled: Enable HTTP/2.
modal/cli/cluster.py CHANGED
@@ -51,7 +51,7 @@ async def list_(env: str | None = None, json: bool = False):
51
51
  [
52
52
  c.cluster_id,
53
53
  c.app_id,
54
- timestamp_to_localized_str(c.started_at, json) if c.started_at else "Pending",
54
+ timestamp_to_localized_str(c.started_at, json) or "Pending",
55
55
  str(len(c.task_ids)),
56
56
  ]
57
57
  )
modal/cli/dashboard.py CHANGED
@@ -21,7 +21,7 @@ async def dashboard(
21
21
  if object_id:
22
22
  url = f"https://modal.com/id/{object_id}"
23
23
  else:
24
- env = config.get("environment")
24
+ env = config.get("environment") or ""
25
25
  request = api_pb2.WorkspaceDashboardUrlRequest(environment_name=env)
26
26
  client = await _Client.from_env()
27
27
  response = await client.stub.WorkspaceDashboardUrlGet(request)
modal/cli/endpoint.py CHANGED
@@ -207,7 +207,7 @@ async def create(
207
207
  raise click.UsageError("--custom-volume-path requires --custom-volume-name.")
208
208
 
209
209
  env_name = ensure_env(env)
210
- environment_name = _get_environment_name(env_name) or ""
210
+ environment_name = _get_environment_name(env_name)
211
211
  client = await _Client.from_env()
212
212
 
213
213
  compute_region_spec = api_pb2.EndpointComputeRegionSpec()
@@ -271,7 +271,7 @@ async def create(
271
271
  async def list_(*, json: bool = False, env: Optional[str] = None):
272
272
  """List Endpoints that are provisioning or running in an environment."""
273
273
  env_name = ensure_env(env)
274
- environment_name = _get_environment_name(env_name) or ""
274
+ environment_name = _get_environment_name(env_name)
275
275
  client = await _Client.from_env()
276
276
 
277
277
  items: list[api_pb2.EndpointListItem] = []
modal/cli/environment.py CHANGED
@@ -53,7 +53,7 @@ def list_(json: bool = False):
53
53
 
54
54
  # determine which environment is currently active, prioritizing the local default
55
55
  # over the server default
56
- active_env = config.get("environment")
56
+ active_env = config.get("environment") or ""
57
57
  for env in envs:
58
58
  if env.default is True and active_env is None:
59
59
  active_env = env.name
modal/cli/launch.py CHANGED
@@ -52,7 +52,7 @@ def _launch_program(
52
52
  else:
53
53
  func()
54
54
  except Exception as exc:
55
- raise _CliUserExecutionError(inspect.getsourcefile(func)) from exc
55
+ raise _CliUserExecutionError(inspect.getsourcefile(func) or "<unknown>") from exc
56
56
 
57
57
 
58
58
  @launch_cli.command("jupyter", help="Start Jupyter Lab on Modal.")
@@ -29,7 +29,7 @@ nfs_cli = ModalGroup(name="nfs", help="Read and edit `modal.NetworkFileSystem` f
29
29
  @env_option
30
30
  @click.option("--json", is_flag=True, default=False)
31
31
  @synchronizer.create_blocking
32
- async def list_(env: str | None = None, json: bool | None = False):
32
+ async def list_(env: str | None = None, json: bool = False):
33
33
  env = ensure_env(env)
34
34
 
35
35
  client = await _Client.from_env()
modal/cli/profile.py CHANGED
@@ -71,7 +71,7 @@ async def list_(json: bool | None = False):
71
71
  # Catch-all for other exceptions, like incorrect server url
72
72
  workspace = "Unknown (profile misconfigured)"
73
73
  else:
74
- assert hasattr(resp, "username")
74
+ assert not isinstance(resp, BaseException)
75
75
  workspace = resp.username
76
76
  content = ["•" if active else "", profile, workspace]
77
77
  rows.append((active, content))
@@ -81,8 +81,8 @@ async def list_(json: bool | None = False):
81
81
  try:
82
82
  env_based_resp = await _lookup_workspace(
83
83
  config.get("server_url", profile=_profile),
84
- os.environ.get("MODAL_TOKEN_ID"),
85
- os.environ.get("MODAL_TOKEN_SECRET"),
84
+ os.environ["MODAL_TOKEN_ID"],
85
+ os.environ.get("MODAL_TOKEN_SECRET", ""),
86
86
  )
87
87
  env_based_workspace = env_based_resp.username
88
88
  except AuthError:
modal/cli/shell.py CHANGED
@@ -48,7 +48,7 @@ def _passed_forbidden_args(
48
48
  passed_forbidden: list[str] = []
49
49
  for param in params:
50
50
  name = param.name
51
- if name is None or allowed(name):
51
+ if not name or allowed(name):
52
52
  continue
53
53
  default = param.process_value(ctx, param.get_default(ctx))
54
54
  if passed_args.get(name) != default:
@@ -150,7 +150,7 @@ def _start_shell_in_running_container(ref: str, cmd: str, pty: bool) -> None:
150
150
 
151
151
  assert _is_valid_modal_id(ref, "ta-")
152
152
  try:
153
- _exec_impl(container_id=ref, command=shlex.split(cmd), pty=pty, object_id_for_v2=object_id_for_v2)
153
+ _ = _exec_impl(container_id=ref, command=tuple(shlex.split(cmd)), pty=pty, object_id_for_v2=object_id_for_v2)
154
154
  except NotFoundError:
155
155
  raise ClickException(f"Container '{ref}' not found (is it still running?)")
156
156
  except Exception as e:
modal/client.pyi CHANGED
@@ -37,7 +37,7 @@ class _Client:
37
37
  server_url: str,
38
38
  client_type: int,
39
39
  credentials: typing.Optional[tuple[str, str]],
40
- version: str = "1.5.3.dev12",
40
+ version: str = "1.5.3.dev13",
41
41
  ):
42
42
  """mdmd:hidden
43
43
  The Modal client object is not intended to be instantiated directly by users.
@@ -207,7 +207,7 @@ class Client:
207
207
  server_url: str,
208
208
  client_type: int,
209
209
  credentials: typing.Optional[tuple[str, str]],
210
- version: str = "1.5.3.dev12",
210
+ version: str = "1.5.3.dev13",
211
211
  ):
212
212
  """mdmd:hidden
213
213
  The Modal client object is not intended to be instantiated directly by users.
@@ -134,9 +134,10 @@ def cloud_bucket_mounts_to_proto(
134
134
  # crude mapping from mount arguments to type.
135
135
  if mount.bucket_endpoint_url:
136
136
  parse_result = urlparse(mount.bucket_endpoint_url)
137
- if parse_result.hostname.endswith("r2.cloudflarestorage.com"):
137
+ hostname = parse_result.hostname or ""
138
+ if hostname.endswith("r2.cloudflarestorage.com"):
138
139
  bucket_type = api_pb2.CloudBucketMount.BucketType.R2
139
- elif parse_result.hostname.endswith("storage.googleapis.com"):
140
+ elif hostname.endswith("storage.googleapis.com"):
140
141
  bucket_type = api_pb2.CloudBucketMount.BucketType.GCP
141
142
  else:
142
143
  logger.info(
@@ -141,6 +141,7 @@ async def stop_app(name: str, *, environment_name: str | None = None, client: _C
141
141
  """
142
142
  client_ = client or await _Client.from_env()
143
143
  app = await _App.lookup(name, environment_name=environment_name, client=client_)
144
+ assert app.app_id
144
145
  req = api_pb2.AppStopRequest(app_id=app.app_id, source=api_pb2.APP_STOP_SOURCE_PYTHON_CLIENT)
145
146
  await client_.stub.AppStop(req)
146
147
 
@@ -174,6 +175,7 @@ async def get_app_objects(
174
175
  client = await _Client.from_env()
175
176
 
176
177
  app = await _App.lookup(app_name, environment_name=environment_name, client=client)
178
+ assert app.app_id
177
179
  req = api_pb2.AppGetLayoutRequest(app_id=app.app_id)
178
180
  app_layout_resp = await client.stub.AppGetLayout(req)
179
181
 
@@ -201,7 +201,7 @@ class FilePatternMatcher(_AbstractPatternMatcher):
201
201
  pattern_strings = Path(self._file_path).read_text("utf8").splitlines()
202
202
  else:
203
203
  # Use patterns provided in __init__
204
- pattern_strings = list(self._pattern_strings)
204
+ pattern_strings = list(self._pattern_strings or [])
205
205
 
206
206
  return self._parse_patterns(pattern_strings)
207
207
 
modal/functions.pyi CHANGED
@@ -516,7 +516,7 @@ class Function(
516
516
 
517
517
  _call_generator: ___call_generator_spec
518
518
 
519
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
519
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
520
520
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
521
521
  """Calls the function remotely, executing it with the given arguments and returning the execution's result.
522
522
 
@@ -541,7 +541,7 @@ class Function(
541
541
  """
542
542
  ...
543
543
 
544
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
544
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
545
545
 
546
546
  class __remote_gen_spec(typing_extensions.Protocol):
547
547
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -591,7 +591,7 @@ class Function(
591
591
  """
592
592
  ...
593
593
 
594
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
594
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
595
595
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
596
596
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
597
597
 
@@ -624,7 +624,7 @@ class Function(
624
624
  """
625
625
  ...
626
626
 
627
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
627
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
628
628
 
629
629
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
630
630
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -632,7 +632,7 @@ class Function(
632
632
 
633
633
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
634
634
 
635
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
635
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
636
636
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
637
637
  """Calls the function with the given arguments, without waiting for the results.
638
638
 
@@ -665,7 +665,7 @@ class Function(
665
665
  """
666
666
  ...
667
667
 
668
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
668
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
669
669
 
670
670
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
671
671
  """Return the inner Python object wrapped by this Modal Function.
modal/mount.py CHANGED
@@ -21,7 +21,7 @@ from modal_version import __version__
21
21
  from ._load_context import LoadContext
22
22
  from ._object import _Object
23
23
  from ._resolver import Resolver
24
- from ._utils.async_utils import TaskContext, aclosing, async_map, synchronize_api
24
+ from ._utils.async_utils import TaskContext, aclosing, async_generator_from_sync, async_map, synchronize_api
25
25
  from ._utils.blob_utils import (
26
26
  FileUploadSpec,
27
27
  blob_upload_file,
@@ -464,38 +464,79 @@ class _Mount(_Object, type_prefix="mo"):
464
464
  return ", ".join(local_contents)
465
465
 
466
466
  @staticmethod
467
- async def _get_files(entries: list[_MountEntry]) -> AsyncGenerator[FileUploadSpec, None]:
467
+ async def _batched_get_missing_files(
468
+ entries: list[_MountEntry],
469
+ client: _Client,
470
+ *,
471
+ n_concurrent_checksums: int,
472
+ batch_size: int,
473
+ ) -> AsyncGenerator[FileUploadSpec, None]:
468
474
  loop = asyncio.get_event_loop()
469
- with concurrent.futures.ThreadPoolExecutor() as exe:
470
- all_files = await loop.run_in_executor(exe, _select_files, entries)
471
- logger.debug(f"Computing checksums for {len(all_files)} files using {exe._max_workers} worker threads")
472
-
473
- # Yield FileUploadSpec objects lazily as they're consumed by async_map downstream.
474
- # async_map's concurrency limit provides natural backpressure, so we don't need
475
- # a separate semaphore here. This keeps memory bounded without creating all tasks upfront.
476
- for local_filename, remote_filename in all_files:
475
+ with concurrent.futures.ThreadPoolExecutor() as e:
476
+ all_files = await loop.run_in_executor(e, _select_files, entries)
477
+ logger.debug(f"Computing checksums for {len(all_files)} files using default max workers")
478
+
479
+ async def get_spec(work: tuple[Path, PurePosixPath]) -> FileUploadSpec | None:
480
+ local, remote = work
481
+
477
482
  try:
478
- logger.debug(f"Mounting {local_filename} as {remote_filename}")
479
- file_spec = await loop.run_in_executor(
480
- exe, get_file_upload_spec_from_path, local_filename, remote_filename
483
+ return await loop.run_in_executor(
484
+ e,
485
+ get_file_upload_spec_from_path,
486
+ local,
487
+ remote,
481
488
  )
482
- yield file_spec
483
489
  except FileNotFoundError as exc:
484
490
  # Can happen with temporary files (e.g. emacs will write temp files and delete them quickly)
485
491
  logger.info(f"Ignoring file not found: {exc}")
486
492
 
493
+ async def check_existence(batch: list[FileUploadSpec]) -> AsyncGenerator[FileUploadSpec, None]:
494
+ request = api_pb2.MountBatchedCheckExistenceRequest(
495
+ sha256_hex_hashes=[spec.sha256_hex for spec in batch]
496
+ )
497
+ response = await client.stub.MountBatchedCheckExistence(request, retry=Retry(base_delay=1))
498
+ missing_hashes = set(response.missing_sha256_hex_hashes)
499
+
500
+ for spec in batch:
501
+ spec.exists_in_store = spec.sha256_hex not in missing_hashes
502
+ yield spec
503
+
504
+ batch: list[FileUploadSpec] = []
505
+ async with aclosing(
506
+ async_map(
507
+ async_generator_from_sync(all_files),
508
+ get_spec,
509
+ n_concurrent_checksums,
510
+ )
511
+ ) as stream:
512
+ async for spec in stream:
513
+ if spec is None:
514
+ continue
515
+
516
+ batch.append(spec)
517
+ if len(batch) == batch_size:
518
+ async for checked_spec in check_existence(batch):
519
+ yield checked_spec
520
+
521
+ batch = []
522
+
523
+ if batch:
524
+ async for checked_spec in check_existence(batch):
525
+ yield checked_spec
526
+
487
527
  async def _load_mount(
488
528
  self: "_Mount",
489
529
  resolver: Resolver,
490
530
  load_context: LoadContext,
491
531
  existing_object_id: str | None,
492
532
  ):
533
+ assert self._entries is not None
534
+
493
535
  t0 = time.monotonic()
494
536
 
495
537
  # Asynchronously list and checksum files with a thread pool, then upload them concurrently.
496
538
  n_seen, n_finished = 0, 0
497
539
  total_uploads, total_bytes = 0, 0
498
- accounted_hashes: set[str] = set()
499
540
  from modal.output import OutputManager
500
541
 
501
542
  message_label = _Mount._description(self._entries)
@@ -503,10 +544,14 @@ class _Mount(_Object, type_prefix="mo"):
503
544
  output_mgr = OutputManager.get()
504
545
  status_row = output_mgr.add_status_row()
505
546
 
547
+ accounted_hashes = set()
548
+
549
+ # Assumption is that if a file_spec is provided to this function, we've checked that
550
+ # the file is not already present in blobnet upstream
506
551
  async def _put_file(file_spec: FileUploadSpec) -> api_pb2.MountFile:
507
552
  nonlocal n_seen, n_finished, total_uploads, total_bytes
508
553
  n_seen += 1
509
- status_row.message(f"Creating mount {message_label}: Uploaded {n_finished}/{n_seen} files")
554
+ status_row.message(f"Creating mount {message_label}: Uploaded {n_finished}/{n_seen} missing files")
510
555
 
511
556
  remote_filename = file_spec.mount_filename
512
557
  mount_file = api_pb2.MountFile(
@@ -515,10 +560,6 @@ class _Mount(_Object, type_prefix="mo"):
515
560
  mode=file_spec.mode,
516
561
  )
517
562
 
518
- if file_spec.sha256_hex in accounted_hashes:
519
- n_finished += 1
520
- return mount_file
521
-
522
563
  # Try to catch cases where user modified their local files (e.g. changed git branches)
523
564
  # between triggering a build and Modal actually uploading the file
524
565
  if config.get("build_validation") != "ignore" and file_spec.source_is_path:
@@ -530,50 +571,67 @@ class _Mount(_Object, type_prefix="mo"):
530
571
  elif config.get("build_validation") == "warn":
531
572
  warnings.warn(msg)
532
573
 
533
- request = api_pb2.MountPutFileRequest(sha256_hex=file_spec.sha256_hex)
534
- accounted_hashes.add(file_spec.sha256_hex)
535
- response = await load_context.client.stub.MountPutFile(request, retry=Retry(base_delay=1))
536
-
537
- if response.exists:
574
+ if file_spec.exists_in_store or file_spec.sha256_hex in accounted_hashes:
538
575
  n_finished += 1
539
576
  return mount_file
540
577
 
578
+ accounted_hashes.add(file_spec.sha256_hex)
579
+
541
580
  total_uploads += 1
542
581
  total_bytes += file_spec.size
543
582
 
544
583
  if file_spec.use_blob:
545
584
  logger.debug(f"Creating blob file for {file_spec.source_description} ({file_spec.size} bytes)")
585
+
546
586
  async with blob_upload_concurrency:
547
587
  with file_spec.source() as fp:
548
588
  blob_id = await blob_upload_file(
549
589
  fp, load_context.client.stub, sha256_hex=file_spec.sha256_hex, md5_hex=file_spec.md5_hex
550
590
  )
591
+
551
592
  logger.debug(f"Uploading blob file {file_spec.source_description} as {remote_filename}")
552
- request2 = api_pb2.MountPutFileRequest(data_blob_id=blob_id, sha256_hex=file_spec.sha256_hex)
593
+
594
+ request = api_pb2.MountPutFileRequest(data_blob_id=blob_id, sha256_hex=file_spec.sha256_hex)
553
595
  else:
554
596
  logger.debug(
555
597
  f"Uploading file {file_spec.source_description} to {remote_filename} ({file_spec.size} bytes)"
556
598
  )
599
+
557
600
  if file_spec.content is None:
558
601
  content = await asyncio.to_thread(file_spec.read_content)
559
602
  else:
560
603
  content = file_spec.content
561
- request2 = api_pb2.MountPutFileRequest(data=content, sha256_hex=file_spec.sha256_hex)
604
+
605
+ request = api_pb2.MountPutFileRequest(data=content, sha256_hex=file_spec.sha256_hex)
562
606
 
563
607
  start_time = time.monotonic()
564
608
  while time.monotonic() - start_time < MOUNT_PUT_FILE_CLIENT_TIMEOUT:
565
- response = await load_context.client.stub.MountPutFile(request2, retry=Retry(base_delay=1))
609
+ response = await load_context.client.stub.MountPutFile(request, retry=Retry(base_delay=1))
610
+
566
611
  if response.exists:
567
612
  n_finished += 1
568
613
  return mount_file
569
614
 
570
615
  raise modal.exception.MountUploadTimeoutError(f"Mounting of {file_spec.source_description} timed out")
571
616
 
572
- # Upload files, or check if they already exist.
617
+ # todo(ayush): tune these
618
+ batch_size = 64
619
+ n_concurrent_checksums = 64
573
620
  n_concurrent_uploads = 64
621
+
622
+ # Upload files, or check if they already exist.
574
623
  files: list[api_pb2.MountFile] = []
575
624
  async with aclosing(
576
- async_map(_Mount._get_files(self._entries), _put_file, concurrency=n_concurrent_uploads)
625
+ async_map(
626
+ _Mount._batched_get_missing_files(
627
+ self._entries,
628
+ load_context.client,
629
+ n_concurrent_checksums=n_concurrent_checksums,
630
+ batch_size=batch_size,
631
+ ),
632
+ _put_file,
633
+ concurrency=n_concurrent_uploads,
634
+ )
577
635
  ) as stream:
578
636
  async for file in stream:
579
637
  files.append(file)
@@ -777,7 +835,7 @@ async def _create_single_client_dependency_mount(
777
835
  ):
778
836
  import tempfile
779
837
 
780
- profile_environment = config.get("environment")
838
+ profile_environment = config.get("environment") or ""
781
839
  abi_tag = "cp" + python_version.replace(".", "")
782
840
  mount_name = f"{builder_version}-{abi_tag}-{platform}-{arch}"
783
841
 
modal/mount.pyi CHANGED
@@ -211,8 +211,8 @@ class _Mount(modal._object._Object):
211
211
  @staticmethod
212
212
  def _description(entries: list[_MountEntry]) -> str: ...
213
213
  @staticmethod
214
- def _get_files(
215
- entries: list[_MountEntry],
214
+ def _batched_get_missing_files(
215
+ entries: list[_MountEntry], client: modal.client._Client, *, n_concurrent_checksums: int, batch_size: int
216
216
  ) -> collections.abc.AsyncGenerator[modal._utils.blob_utils.FileUploadSpec, None]: ...
217
217
  async def _load_mount(
218
218
  self: _Mount,
@@ -337,15 +337,27 @@ class Mount(modal.object.Object):
337
337
  @staticmethod
338
338
  def _description(entries: list[_MountEntry]) -> str: ...
339
339
 
340
- class ___get_files_spec(typing_extensions.Protocol):
340
+ class ___batched_get_missing_files_spec(typing_extensions.Protocol):
341
341
  def __call__(
342
- self, /, entries: list[_MountEntry]
342
+ self,
343
+ /,
344
+ entries: list[_MountEntry],
345
+ client: modal.client.Client,
346
+ *,
347
+ n_concurrent_checksums: int,
348
+ batch_size: int,
343
349
  ) -> typing.Generator[modal._utils.blob_utils.FileUploadSpec, None, None]: ...
344
350
  def aio(
345
- self, /, entries: list[_MountEntry]
351
+ self,
352
+ /,
353
+ entries: list[_MountEntry],
354
+ client: modal.client.Client,
355
+ *,
356
+ n_concurrent_checksums: int,
357
+ batch_size: int,
346
358
  ) -> collections.abc.AsyncGenerator[modal._utils.blob_utils.FileUploadSpec, None]: ...
347
359
 
348
- _get_files: typing.ClassVar[___get_files_spec]
360
+ _batched_get_missing_files: typing.ClassVar[___batched_get_missing_files_spec]
349
361
 
350
362
  class ___load_mount_spec(typing_extensions.Protocol):
351
363
  def __call__(
modal/secret.py CHANGED
@@ -205,7 +205,7 @@ class _SecretManager:
205
205
  raise
206
206
  else:
207
207
  req = api_pb2.SecretDeleteRequest(secret_id=obj.object_id)
208
- await obj._client.stub.SecretDelete(req)
208
+ await obj.client.stub.SecretDelete(req)
209
209
 
210
210
 
211
211
  SecretManager = synchronize_api(_SecretManager)
@@ -511,7 +511,7 @@ class _Secret(_Object, type_prefix="st"):
511
511
  raise InvalidError(err)
512
512
  updates = [api_pb2.SecretUpdateRequest.Update(key=k, value=v) for k, v in env_dict.items()]
513
513
  req = api_pb2.SecretUpdateRequest(secret_id=self.object_id, updates=updates)
514
- await self._client.stub.SecretUpdate(req)
514
+ await self.client.stub.SecretUpdate(req)
515
515
 
516
516
 
517
517
  def _split_env_dict_and_resolvable_secrets(secrets: list[_Secret]) -> tuple[dict[str, str], list[_Secret]]:
modal/serving.py CHANGED
@@ -8,12 +8,12 @@ from typing import TYPE_CHECKING
8
8
 
9
9
  from synchronicity.async_wrap import asynccontextmanager
10
10
 
11
+ from ._object import _get_environment_name
11
12
  from ._utils.async_utils import TaskContext, asyncify, synchronize_api
12
13
  from ._utils.logger import logger
13
14
  from ._watcher import watch
14
15
  from .cli.import_refs import ImportRef, import_app_from_ref
15
16
  from .client import _Client
16
- from .config import config
17
17
  from .output import OutputManager, enable_output
18
18
  from .runner import _run_app, serve_update
19
19
 
@@ -109,8 +109,7 @@ async def _serve_app(
109
109
  _watcher: For tests only. Supplies a custom async generator of changed file paths instead of
110
110
  the default filesystem watcher.
111
111
  """
112
- if environment_name is None:
113
- environment_name = config.get("environment")
112
+ environment_name = _get_environment_name(environment_name)
114
113
 
115
114
  client = await _Client.from_env()
116
115
 
@@ -122,6 +121,7 @@ async def _serve_app(
122
121
  else:
123
122
  mounts_to_watch = app._get_watch_mounts()
124
123
  watcher = watch(mounts_to_watch)
124
+ assert app.app_id is not None
125
125
  async with TaskContext(grace=0.1) as tc:
126
126
  tc.create_task(
127
127
  _run_watch_loop(import_ref, app_id=app.app_id, watcher=watcher, environment_name=environment_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.5.3.dev12
3
+ Version: 1.5.3.dev13
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -4,10 +4,10 @@ modal/_billing.py,sha256=VEa-YKFsuKmRfWW1SPiXGiY84RzTTRvo8ILi0V10R28,3483
4
4
  modal/_clustered_functions.py,sha256=zOWouWnRA4AbYz5kUbSHghFD9mifDHwfpntxOM_c5NA,2853
5
5
  modal/_clustered_functions.pyi,sha256=akbff8aXkp5aJapn72YMXPnzeYa6OFAfuakcy7Jx6wk,1146
6
6
  modal/_container_entrypoint.py,sha256=AyhMFBiaApVn1mueur2yrVy7IXR9qdXdwY4IePtVv74,22760
7
- modal/_environments.py,sha256=qll8SrpXG2tThWpdaRZolVLUanunLwUqkQ-Q8h4h0bU,23551
7
+ modal/_environments.py,sha256=WCJvWCkKlRlU9TPDyNNx9GPVHKiOwk-_l0YoOcvFasA,23557
8
8
  modal/_function_variants.py,sha256=tKS1zJJCBJcj9_mKn2s5CdEWcvcskr3usaqEHKZddDg,12552
9
9
  modal/_functions.py,sha256=-P6cGdnsCK1iJXpT_UH24VMm6pio5xmIHsfQm94cSps,96897
10
- modal/_grpc_client.py,sha256=QL5btzOz6zZzTDcgSwFjI3PBy2gkaycyrlP7Jw-jkbY,6962
10
+ modal/_grpc_client.py,sha256=vgCeu1TV6pBkQenHISVE15djX3tzDt_-7IcDIjI6zQw,6968
11
11
  modal/_image.py,sha256=TW-0QiFa3Lo1w9khZcE8mgSHQgj-PJ0eChb8IkS2eqo,128738
12
12
  modal/_ipython.py,sha256=Bu9fc3hm3xt2O47qLe_d-Mu2jS81LwMsmXNJ1sawBA0,575
13
13
  modal/_load_context.py,sha256=wrDqD3KehhFepp0vBhyz_PoLWoRVD0gZHP8dlLHCTiw,4818
@@ -15,27 +15,27 @@ modal/_location.py,sha256=joiX-0ZeutEUDTrrqLF1GHXCdVLF-rHzstocbMcd_-k,366
15
15
  modal/_logs.py,sha256=JI2z_n2ivKrVRd6IIntyUfadNDetm1Wtu00GyGXBuG4,16938
16
16
  modal/_logs_manager.py,sha256=NsPI1Z1ZxhOFEbhXltU4T-dIlzl5yM44d5Sa1KOIK-o,26069
17
17
  modal/_logs_manager.pyi,sha256=FVhHA65unZWosgeQ6fwoLpwLkS0ALRnYMcEYq4dhRKc,39105
18
- modal/_object.py,sha256=8YXUBrEEvmx45lK5_nshmOX2xNKtPDXGHPzbiJ1YyAE,13503
18
+ modal/_object.py,sha256=E24RIV3ZRhq-TFnir7cURERrFJnF5HXgNGATas7Q1o4,13557
19
19
  modal/_partial_function.py,sha256=VWjYZCVmHsQpad7MvVifHUQn4ElGKm5cSsyOLxDQ9Yk,35371
20
20
  modal/_resolver.py,sha256=LLDM_84aaJfBdgMZ_50CpXJtQzTw5CNRkbLDOiLZEZ0,5309
21
- modal/_resources.py,sha256=IS6y7CulfLCjESrpdxFGZr23d5iRCLw6-YQVlE3mKQk,1731
21
+ modal/_resources.py,sha256=e4kEESPhz43IukQpwa3XV4PoiaOE_MqPh7HzlwejSPU,1727
22
22
  modal/_serialization.py,sha256=G07UlvH0SPU62twuwgx8MjD49zFX3te-Mg8bwNYfiEU,26594
23
23
  modal/_server.py,sha256=dMBRG9UbeVcvAxFkcx1P4Z5e5pqWMdwcpTJQS0AgxmE,13242
24
24
  modal/_supports_logs.py,sha256=bt4L4XBlFzzN9BdV3KY-Z8z0g2WpBDlunzgk2Dp1AUI,807
25
- modal/_traceback.py,sha256=472sH68_BsZGRsHW2vikIrmvaU1nT2TYkVvsuIYj_9Q,6231
25
+ modal/_traceback.py,sha256=AJDEWqGyJi_lNYqTS9ZOj_7pPpqT-9hNGnOJs7PQ8Bw,6238
26
26
  modal/_tunnel.py,sha256=iqx11Okxz052dpejoJYcofXEkSB6u1kPFw5DaGFjS2Q,7351
27
27
  modal/_tunnel.pyi,sha256=WVP0dkoN__mM73ZQ-r3nHKCXvYlRMmEWW8iw2xrSY6M,14698
28
28
  modal/_type_manager.py,sha256=DWjgmjYJuOagw2erin506UUbG2H5UzZCFEekS-7hmfA,9087
29
29
  modal/_watcher.py,sha256=f9kOdHga0TZ6Z6wL7h2O67sz3Oj8pDzjfoAYrNE2hik,3505
30
30
  modal/_workspace.py,sha256=K_2Xe6_vG5Ab0PR0yg1VtEdi-MwOKjRKvcDPaf-Oj2Q,18163
31
- modal/app.py,sha256=DQOTSOfei9ojVFJAKgLdxnaSlTIwbXvdKkPH1y3WN9U,71249
32
- modal/app.pyi,sha256=nATyAaVKh5WZ4O5RLuo8SpztCTX04831TKJVJ7CuZYo,85091
31
+ modal/app.py,sha256=qC1ct4rMAAqSn51vBhzvgO-AKwn46NCoBzVMfOKT6-g,71406
32
+ modal/app.pyi,sha256=cV3a-BoATtixiV4t5fYZuQrsB12Me1AAsupoV74GoUI,85365
33
33
  modal/billing.py,sha256=E1-P_P8bJFLp-bTaggYd4BaaViImPB5UdtXiY8VeAZQ,390
34
34
  modal/billing.pyi,sha256=4m7VLYNS8IiJ2I3CJx0awvrOM6BILWRVLfdeqtAYr8M,7189
35
35
  modal/call_graph.py,sha256=XGALIDn1bLchWo_goyX23bcPjzCZcfqKUo8INIfDapo,1775
36
36
  modal/client.py,sha256=NjpAL0fIKabEaN0uXJPEoI1OTjFtXSp4tSck-M-WF3k,16360
37
- modal/client.pyi,sha256=Att1p5hhwu4NxGYOxkpdmlo7g0k1roiZhUyCSdw4V38,17999
38
- modal/cloud_bucket_mount.py,sha256=dJ3CZsm7848QJhoFy5mOp62fSivZauVOyo4MJvlx2nw,6802
37
+ modal/client.pyi,sha256=Z6gDh7LtYbTKQnF4oQxl07mou9IEvUNb64tIm9LHDrw,17999
38
+ modal/cloud_bucket_mount.py,sha256=NrdNV9r9aL3QFrlt-Dhtd7_K3f8v1igrHf2FRwgJ1CI,6827
39
39
  modal/cloud_bucket_mount.pyi,sha256=0E8d53pMh2KsFa-rMh_i6LxlzW4cMV8drVmmkPHSqZk,8149
40
40
  modal/cls.py,sha256=bqfD4yuz5EV7wNHLAaGcUNFseFGK8eyJSkqpfQex-VY,40969
41
41
  modal/cls.pyi,sha256=cc5zIn_1wWC89U-Zn9Yks5MXT4yAGhTXCrDpCm-Nm-c,29397
@@ -49,15 +49,15 @@ modal/environments.pyi,sha256=nsTTKXi560DgCZJAV9g_RN2IHfiOiR7C5Wxvd6K4BBQ,20281
49
49
  modal/exception.py,sha256=_AUhVBCg6Gb-YUQPNcQaTt2bAGn5n2N3jOhGpPSn4UA,11780
50
50
  modal/file_io.py,sha256=GYTa67mrmbTTTBsYQnb51VmwGIo0YY-1qQ3YBhagkmA,21795
51
51
  modal/file_io.pyi,sha256=3181-DS07flFWLf2BKjqCOiWIjieEOolf33wx6fBp5c,15377
52
- modal/file_pattern_matcher.py,sha256=6g_awxudMy_ontBvkznybyeNnwGMj297YrmIHCbREI0,8132
52
+ modal/file_pattern_matcher.py,sha256=CpaNNj7oBlOSewX-AAUZCF8KDxH0_DmgwzfpVGbPYJ4,8138
53
53
  modal/functions.py,sha256=EZRcHFfnoYbvawUJnAHF5nIvoo9GX2Djy7mUmOCXmXc,258
54
- modal/functions.pyi,sha256=LW28ryYyzlh5FSJ54_6oqCMH1PYYJZ0tW5h1VUxfgx0,49526
54
+ modal/functions.pyi,sha256=hQIw3clt9C8X9oy189iwXwStOoCAR_tHzD6qwK0AFAc,49526
55
55
  modal/image.py,sha256=c0lUSAoU-Ip3g5DGZ0uhdCzoWSQWh1g0i-7Rxo-Sz-I,160
56
56
  modal/image.pyi,sha256=Whbfmda2YLAyzctLEF9uF4FQ5b1canwLojSksRJ4gx8,59716
57
57
  modal/io_streams.py,sha256=3fhhb7SDJ69pVUu9J3PiMLBePD9bpiIxPN05SCzf8FE,29118
58
58
  modal/io_streams.pyi,sha256=5uQAgwxN3aouY8UJbRmDnRj9vOId5psRaMrU4IpyQgw,24471
59
- modal/mount.py,sha256=n1jfXvZVG1zKcVHDG8_0ECnzS7eaZCCRsk0XCx-GESo,34632
60
- modal/mount.pyi,sha256=qxnBG-q1I9KPmXLoSaWn2KMWO_mdAff3z0nW3UlYH6c,15913
59
+ modal/mount.py,sha256=szqKHosJmE4DVbm5tCOBDadMsA1T05ZvZ4sOebWNUZk,36154
60
+ modal/mount.pyi,sha256=ZOlIMlK_oIINrhlm9Z5hRsW88VY-0oNLhwZ4ynldc9w,16357
61
61
  modal/network_file_system.py,sha256=w8iI8BJDGLT2jmWyBG9vWpWGnsdkMs8J8TE2519iU38,14030
62
62
  modal/network_file_system.pyi,sha256=MS4srjGFl-ogqgNLxYRlj6Ik1ObwZKJ0WrneYKMKk-A,17927
63
63
  modal/object.py,sha256=bTeskuY8JFrESjU4_UL_nTwYlBQdOLmVaOX3X6EMxsg,164
@@ -82,11 +82,11 @@ modal/sandbox_fs.py,sha256=GSuPlrLSdQ7fG7c_TGMd-VWs_s6RqQxMvLivdvC6s4s,27002
82
82
  modal/sandbox_fs.pyi,sha256=TJWx8h7x3yRC7KUxeF7q62_0a7w1IHufnJL7AYEojAg,45285
83
83
  modal/schedule.py,sha256=J0rpNAVcoQjCCzobYFQXHXv1BBPLYATUwGS5prCHp4c,3242
84
84
  modal/scheduler_placement.py,sha256=S2-MZQcWCt6NVwIWXUP11KsKZeRDQViJLlOngGUvjkM,1173
85
- modal/secret.py,sha256=38Ki_fPANzo5Zj64aDBJ_e_WXq3PQsy4f16m2BLfdzk,20651
85
+ modal/secret.py,sha256=yPe0oJH8ISIXDTtGFuPmh6PcENkW_GT0UXYPQ1ai17w,20649
86
86
  modal/secret.pyi,sha256=CyRMB8wss-EmqPIvMOGaxRdC-JFEe5DNCBvZmLvROXk,28454
87
87
  modal/server.py,sha256=zWoDdtwCEKsKbFfWC4l7-NkpnJJybweC284VIoCavrI,164
88
88
  modal/server.pyi,sha256=rlY-WDpPkUc_A9kLZ_0tJoMLdeL_6RXdJovOZS_-uMU,10113
89
- modal/serving.py,sha256=3nAFUMwFpr5WMHavJYloEF-QTr-7XzXTRb5kagp2nrg,4815
89
+ modal/serving.py,sha256=ag31rhoUgdFr3kmBz92eyoS2HLXa88YrhF_tWHpQZK8,4846
90
90
  modal/serving.pyi,sha256=nKgt3i2X93NpAAZzIpbj4fiR1TIJxSXnK659w4UD2sE,3962
91
91
  modal/snapshot.py,sha256=D4cOWfY8vXeHfw11dTax-5ciNT0Fo8u5fKmMSBUmDGY,3170
92
92
  modal/snapshot.pyi,sha256=bFVDBx15WyngldWHGg9H3RCQRAbkR0N8O1ZHhneEFyA,3528
@@ -101,7 +101,7 @@ modal/workspace.pyi,sha256=aB3LCYnbzD8eyaBMsEfMeMiSHOUdpTdio4rK6nsjHUU,24215
101
101
  modal/_output/__init__.py,sha256=xtGN6SPv2zvByrJ32JPao0yJKpxyCIZ-2JMTScrisuQ,28
102
102
  modal/_output/manager.py,sha256=lL9fK9_cSJHdVIOcgzjCZEJ90fgNB7_mO7ih_4sk1hI,18097
103
103
  modal/_output/pty.py,sha256=EK9e5yNUpwhvbQ4-WWmUJ5elJQnOtCCfMhe5w1zgY5c,10143
104
- modal/_output/rich.py,sha256=x3PQKzIt_HBbaHOyzsN8gbuS1QsR7eFVD3Bo3GthXss,31845
104
+ modal/_output/rich.py,sha256=6QsXXD-LK0sxd5wiLQS4-sy-pgtBKvAV92flzAmAwKo,31864
105
105
  modal/_output/status.py,sha256=c0rdvjoYKtIG7XJqq42TlcKawkYqZWtod38RmRY5IWA,4492
106
106
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
107
107
  modal/_runtime/asgi.py,sha256=eDNPsmV6SXl0CwUqgy7yrFDaPdlx4NiWTScXpCTlBFQ,22805
@@ -114,14 +114,14 @@ modal/_runtime/task_lifecycle_manager.py,sha256=NINQF_siXjeRkpd5rBXkE3sAdVxkwFXE
114
114
  modal/_runtime/task_lifecycle_manager.pyi,sha256=2r2eSBSfLQsbXrQfVvp73Gth7wZ7zpKJ0KaLgzsCdaQ,4952
115
115
  modal/_runtime/telemetry.py,sha256=T1RoAGyjBDr1swiM6pPsGRSITm7LI5FDK18oNXxY08U,5163
116
116
  modal/_runtime/user_code_event_loop.py,sha256=HwOuDyCZLOakr_DG7p2MrcscjSQNheIhBBuLgB5I3Cc,3014
117
- modal/_runtime/user_code_imports.py,sha256=rPCegb7vGZlhVVx2KzINq_1ymLsTgA50j88pZq2Snw8,29710
117
+ modal/_runtime/user_code_imports.py,sha256=5MgewJzAeZqop47FQyB-lEpHBfC50ApHgSb861ErJPA,29863
118
118
  modal/_utils/__init__.py,sha256=waLjl5c6IPDhSsdWAm9Bji4e2PVxamYABKAze6CHVXY,28
119
119
  modal/_utils/app_utils.py,sha256=88BT4TPLWfYAQwKTHcyzNQRHg8n9B-QE2UyJs96iV-0,108
120
- modal/_utils/async_utils.py,sha256=4E4i5bReO4NudEwi8zT9kTDKwZsQeuMOFC5O8Rz9_E4,45838
120
+ modal/_utils/async_utils.py,sha256=YHPrrg0JZoEld540gccpU34IkThNZ6AOT-xrYxdyKZQ,45962
121
121
  modal/_utils/auth_token_manager.py,sha256=J3EG8lMLUe2t_sHQ0gllj5qQi6j2SpStnMEh9JV4NCk,5124
122
- modal/_utils/blob_utils.py,sha256=VUYGmrRqmjdsjOEDcqIDeWONouVI4CzL-Rrcn8skNXs,26010
122
+ modal/_utils/blob_utils.py,sha256=VcTUEm7S5drBqB7KezYQxhdfdJyYTddD7xYXjztq6IE,26079
123
123
  modal/_utils/browser_utils.py,sha256=Yqq0qU4Id6oaDOdeT1JEmbCN7vj4baNJJraJhRWU8ZI,1085
124
- modal/_utils/bytes_io_segment_payload.py,sha256=MFe0hs9pSskRLL6iX0vV7bJ_oG-VwIC98oNB3EpsW2w,4272
124
+ modal/_utils/bytes_io_segment_payload.py,sha256=2OrIrjrsJR38a9D7JCITLqGvIPaiWViTQhxtcZlFn_M,4328
125
125
  modal/_utils/curl_utils.py,sha256=cZey1GZzyCRafXW4kje1rm739S0rc0TuY6CLG5U_zI8,3447
126
126
  modal/_utils/deprecation.py,sha256=X3uIAc8yThIjoHUMaS9ZfFCLAmGXaMysUdD1jEtbQvY,4574
127
127
  modal/_utils/display_utils.py,sha256=5XyCCjnMAWeLEEqF0hiLSA6XrrNp-gvXVsLcngN6vAI,317
@@ -137,13 +137,13 @@ modal/_utils/logger.py,sha256=NgbMKFT9chYYt_TU01DdIior5ByYr2gZtrWIk1SFRLc,1782
137
137
  modal/_utils/mount_utils.py,sha256=-KkLgkm30_MlsDKmp1NIEqfPhzt2ybSvZUsp1-IBqrU,4973
138
138
  modal/_utils/name_utils.py,sha256=k3BHNWjO1-zcUsUV_hF6U1s9yz0EhT4y20bJwiTb4OA,2762
139
139
  modal/_utils/package_utils.py,sha256=jYE7WFVzYWIfO0ZJhno_BYHb6Skp48uupOiw1a3yWzw,2056
140
- modal/_utils/pattern_utils.py,sha256=HOAxuYA1HpKxRHLT1AwqNTZwwNeNrlBCaCXWVcOdyCE,6701
140
+ modal/_utils/pattern_utils.py,sha256=Dtqh0jL07-RJYK2FMBKgkUzAXnN1CUtDAiKdpeJFGro,6736
141
141
  modal/_utils/proxy_support.py,sha256=hLA_XojYxzPysOiLqyUbB-SgMLmn_X8WtXTk92xh7g4,3162
142
142
  modal/_utils/rand_pb_testing.py,sha256=kwAKIros_g6XPXluiJAktQ79YPkD9SGopKGl83GQ1l0,4361
143
143
  modal/_utils/sandbox_fs_utils.py,sha256=rsfo1uDbVSoiY21XERDzsmp-DALcNmlPfJ6jn_2p5T0,15680
144
144
  modal/_utils/shell_utils.py,sha256=_2yHrlx4Crx5JWQXECLPQ51kclu8H-U3N7jOkBN7q5U,3390
145
145
  modal/_utils/task_command_router_client.py,sha256=ehH7N5XZXM9QazcGITWFoEtw5OlmdgZmqEcCAso4INk,44263
146
- modal/_utils/time_utils.py,sha256=4mlxFreYBSvyqI5uhzry0aDHluUCwsTGKfEsItqN6og,10927
146
+ modal/_utils/time_utils.py,sha256=JaFyW8y4iimzhrGT5KlQmlXH4oMZrZOGCtUBZAV-gfU,10965
147
147
  modal/_vendor/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
148
148
  modal/_vendor/a2wsgi_wsgi.py,sha256=RVLIYVJA8a8o96QxEXYT5tuog2zev2S24XOuAVTXZAs,21872
149
149
  modal/_vendor/cloudpickle.py,sha256=gs1rHS6yrerIbAL0mesN6xAmNFaJowRgncJpdAKwmes,59191
@@ -165,26 +165,26 @@ modal/cli/app.py,sha256=5cHqEXuoEYkDXBuYPyU19FuHE8UT1zkr8-epMmLsYfU,22762
165
165
  modal/cli/billing.py,sha256=EpVwS6HvsyMWtMCtPVXJ6lP7F4BvHh5Fu7WnsXQ0NfU,10024
166
166
  modal/cli/bootstrap.py,sha256=0P7GMEuDdZ-sUm_-lml_8F2YYdmzhAItoDnN4s8T9zo,5269
167
167
  modal/cli/changelog.py,sha256=l1litymo-ZH8KWVELnhcXkSYMzcsDCe40yIIUJCVgis,5799
168
- modal/cli/cluster.py,sha256=9XE-xOYgjVtNUrHLCVYju8Sbe5XSPwIpQ4m7BjTYJLg,4374
168
+ modal/cli/cluster.py,sha256=7u68L1PVlh4NqPoUHn7TrcekqhlpdUVjoVBnqE50-o8,4356
169
169
  modal/cli/config.py,sha256=4F67a07bS3h0sR1vMR7N21vE6tI7X5W0TQDwm_kXXdo,1899
170
170
  modal/cli/container.py,sha256=UHeoJFSMYlXuvE0kAxbe7Sryrb_v_Tr0KpTF9Vpy23Y,13217
171
171
  modal/cli/curl.py,sha256=e0YOuBlWYkVdH125H1v5r1mRy0oLKGRU4qgPOHOrHLA,4523
172
- modal/cli/dashboard.py,sha256=YBHkRNY8fwZg472mn83ZpKWkaWbbiHj1Rg_0vMwOT7w,910
172
+ modal/cli/dashboard.py,sha256=v3ME8R77JksAW-mlJnn8PAi1Q6_dIoTxJTJQDsYWy8c,916
173
173
  modal/cli/dict.py,sha256=20KQa1kZu5THlneed-F_2sxcZriY0vYxcfe12XYIkLk,5152
174
- modal/cli/endpoint.py,sha256=9_dgP3lMxj6TJnNtfTT8kNodzDJOszSgQYMSxTqoggw,14233
174
+ modal/cli/endpoint.py,sha256=7e2E-9Q-a30Aj2bYCMXm_zmxtKGtUt0Lg7JVNKHQgRA,14221
175
175
  modal/cli/entry_point.py,sha256=Z5f-kE2OumaNsuCZU_P_E2pfLB1JGQTL-55MAp3r1ys,5074
176
- modal/cli/environment.py,sha256=MUDWsMyc-uGuy6rgXvRq0FzxZl5dTrvpyq4dMdrWHOM,14872
176
+ modal/cli/environment.py,sha256=DrgD2qVt9ODmJnU2LPjrkmGJsKtfKq1fFLxCkXnttfg,14878
177
177
  modal/cli/image.py,sha256=tj50yttndufoqMNW3EjQu48kci-VkgWWC8-IPgCdtqs,6946
178
178
  modal/cli/import_refs.py,sha256=s3OeBuFZJNh0S8EaaEiqUnAPETRTrWdOk-jkO7yRVr4,15506
179
- modal/cli/launch.py,sha256=1cPg9y7zIETMeg6_5HBPpX3hbL4uKe-yXf49bXx8tSY,4482
179
+ modal/cli/launch.py,sha256=AJCXsRsK77EoJhiUSk6n3m5HAhgLh4AmhdINdwKgGCM,4497
180
180
  modal/cli/logo.py,sha256=plv82syvPb8j3qrR1A_nojZwp823t3VEXaDlrx1jkt0,3221
181
- modal/cli/network_file_system.py,sha256=HPuSzV0BaVurGhJbOahIV53sbfuZ0okNAdbdQZbPhrk,7687
182
- modal/cli/profile.py,sha256=uvxK76pJEF7DHXZhCm_za4-KL74HBOGUk2lSdQtkxhY,3674
181
+ modal/cli/network_file_system.py,sha256=WA54LgcF3ZJv3kQgdTm9tkbwKCxA2XXGCdC3nUPdTLY,7680
182
+ modal/cli/profile.py,sha256=b7AYNrKsSvBecaUotnRqqVxvdWMynY-Ynj69fT-kL6U,3684
183
183
  modal/cli/queues.py,sha256=eSeAUC_itVMFPQKcZJozipzUTvDaHzYJinao1_H7eXA,6620
184
184
  modal/cli/run.py,sha256=hGSKdhBATIkZATPECf8ytxZNTza5rzngqIQnN_B4Mww,22639
185
185
  modal/cli/secret.py,sha256=fg_g-iA_FkF7_0_24P_0Y3k_dCfcFbOzFo7vzIiHaLQ,8253
186
186
  modal/cli/selector.py,sha256=OJr9Ua3K_l-qu3N3-I8z8oVq8lBakws2-XgfheR5p-c,4741
187
- modal/cli/shell.py,sha256=cSDRK2PspHPgX37rV-yZeQMtxHBLGs5WH7UJaoGb9Vc,16844
187
+ modal/cli/shell.py,sha256=K7AwuH-WBIIx0-haBpA8NANZM6a_wVko-Ab6LKVmmzc,16851
188
188
  modal/cli/skills.py,sha256=oniDafrmu_ARYTlButnlXbKE9XlEU1-EFz-eO4tdnFY,11954
189
189
  modal/cli/token.py,sha256=yvCBs6L0yjATZIRc5vo-ZCWA01cnkk3yaMm2hBceUFI,4309
190
190
  modal/cli/utils.py,sha256=oAhQVoojdsj3cf5xvr4IDSptrCI4ndEJ7ZPmBlsP5Yw,6891
@@ -193,12 +193,12 @@ modal/cli/workspace.py,sha256=HJD4Kpc7QHc_jVLXkHwnMRSxTvAoDklMz8qzYxAKL-8,6964
193
193
  modal/cli/programs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
194
194
  modal/cli/programs/run_jupyter.py,sha256=IJw8nds8Cjl9j4dxBqMGxhz-bIyVX0kle7jbt8HFOhM,2688
195
195
  modal/cli/programs/vscode.py,sha256=E1aJPU7b8RWWj-JX71DifsCoLYsCAnre7lATiBJjUms,3386
196
- modal/experimental/__init__.py,sha256=H7ESdOADNvJ2coE-jn3Z2i0-d7xKTfFbP1wBhRuhgI4,8804
196
+ modal/experimental/__init__.py,sha256=1xJ_dfyOC4zTJvjp0YPikt8Vqz-FT2TA-XSHwKxanaM,8848
197
197
  modal/experimental/flash.py,sha256=GAJ1c-EGL8M3_loAkqr5gdUfySMHY3U_oc6RywfZ8-0,34245
198
198
  modal/experimental/flash.pyi,sha256=lpTqJFZRMGWscw0xpYZVdBMnAYjj16asXE4_64A6itQ,17774
199
199
  modal/experimental/ipython.py,sha256=kJ6o9wkAY_MiSb7paewI7f1MJAeqdi8TX5pBdhr_mUI,2925
200
200
  modal/skills/modal/SKILL.md,sha256=WzLjYJ1utjc_ZOf6qZTPwB6wxxwRYB5PibdvIf_FLy0,5316
201
- modal-1.5.3.dev12.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
201
+ modal-1.5.3.dev13.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
202
202
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
203
203
  modal_docs/gen_cli_docs.py,sha256=9-b8vl2EsLWD9zJqpCK8IUi5h44Bjn3i3rSdedZV4bA,6415
204
204
  modal_docs/gen_cli_docs_main.py,sha256=UPGr7O1DYTIRLwfINe2rbdh89J3cPVTU1OWL-SjxnOQ,198
@@ -218,14 +218,14 @@ modal_proto/api_pb2_grpc.pyi,sha256=-475ldsbyuJI3_nlxXQZWTpYCNyb7ZRWyCLfVrsoFtE,
218
218
  modal_proto/modal_api_grpc.py,sha256=euK3tQIa1XKkHAJsa51Q8tQAXz6fZObBqJRMJ9pI0Wc,28629
219
219
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
220
  modal_proto/task_command_router_grpc.py,sha256=UurJEgLeAc2CCdEsCOFE9DgIQy1ra6bXHXJLNBK81Mg,21284
221
- modal_proto/task_command_router_pb2.py,sha256=mq7jUxEaAfIew74jVNiK_aIkcvOJMtuKhsEpcdqx1_8,41085
222
- modal_proto/task_command_router_pb2.pyi,sha256=ly0RiPmOy8v7a_G3EXdTMHjccVF71q-DbwBvoTf0aAM,45980
221
+ modal_proto/task_command_router_pb2.py,sha256=4cyDT_uPGi54blsO663bnSzUe7aBFqi9F4iM8N1JPaU,41130
222
+ modal_proto/task_command_router_pb2.pyi,sha256=5xfhnwtTDTmJo1Nv0tPBJrYzb0aeilY2Lm92wWT_6yw,46211
223
223
  modal_proto/task_command_router_pb2_grpc.py,sha256=zuFkJgKcswB2ftjnyEgs70dp61VMA7gK0h0uzR3gYFw,42563
224
224
  modal_proto/task_command_router_pb2_grpc.pyi,sha256=UjAJFqz9DpOFXP04fVm5lB2eAyTtjOg3oKjfWei8yLU,14262
225
- modal_version/__init__.py,sha256=9KRyE7nBUW79innsV2uhRloZp7RsK-Q30sg-RTbkda8,121
225
+ modal_version/__init__.py,sha256=Um2GJBNkdlqLx4iwnG4VlmVlwyVVkXxEWmuQkl2n1OY,121
226
226
  modal_version/__main__.py,sha256=nLUbubxKx7GXNzJIkTB7M7_u8080LyLM0IS0rzFkC_c,119
227
- modal-1.5.3.dev12.dist-info/METADATA,sha256=78wD0VqR2U8Z1qvXEEcM2tegFs-hfCuKIrUVV9n4ngU,2513
228
- modal-1.5.3.dev12.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
229
- modal-1.5.3.dev12.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
230
- modal-1.5.3.dev12.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
231
- modal-1.5.3.dev12.dist-info/RECORD,,
227
+ modal-1.5.3.dev13.dist-info/METADATA,sha256=fdvWhsITojfDDd3_dZLcNeaEwamZbv7p9sXjrcC9gc0,2513
228
+ modal-1.5.3.dev13.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
229
+ modal-1.5.3.dev13.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
230
+ modal-1.5.3.dev13.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
231
+ modal-1.5.3.dev13.dist-info/RECORD,,
@@ -17,7 +17,7 @@ from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
17
17
  from modal_proto import api_pb2 as modal__proto_dot_api__pb2
18
18
 
19
19
 
20
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%modal_proto/task_command_router.proto\x12\x19modal.task_command_router\x1a\x1bgoogle/protobuf/empty.proto\x1a\x15modal_proto/api.proto\"X\n\x1aSandboxStdinWriteV2Request\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0e\n\x06offset\x18\x02 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x04 \x01(\x08\"\x1d\n\x1bSandboxStdinWriteV2Response\"\x8c\x01\n\x19SandboxStdioReadV2Request\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0e\n\x06offset\x18\x02 \x01(\x04\x12N\n\x0f\x66ile_descriptor\x18\x03 \x01(\x0e\x32\x35.modal.task_command_router.SandboxStdioFileDescriptor\"C\n\x1aSandboxStdioReadV2Response\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x17\n\x0fstarting_offset\x18\x02 \x01(\x04\"C\n\x1fSandboxWaitUntilReadyTcrRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07timeout\x18\x02 \x01(\x02\"4\n SandboxWaitUntilReadyTcrResponse\x12\x10\n\x08ready_at\x18\x01 \x01(\x01\"\x82\x03\n\x1aTaskContainerCreateRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\x12\x10\n\x08image_id\x18\x03 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x05 \x03(\t\x12K\n\x03\x65nv\x18\x06 \x03(\x0b\x32>.modal.task_command_router.TaskContainerCreateRequest.EnvEntry\x12\x0f\n\x07workdir\x18\x07 \x01(\t\x12\x12\n\nsecret_ids\x18\x08 \x03(\t\x12\x30\n\rvolume_mounts\x18\t \x03(\x0b\x32\x19.modal.client.VolumeMount\x12\x38\n\x0enetwork_access\x18\n \x01(\x0b\x32\x1b.modal.client.NetworkAccessH\x00\x88\x01\x01\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x11\n\x0f_network_access\"K\n\x1bTaskContainerCreateResponse\x12\x14\n\x0c\x63ontainer_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\"^\n\x17TaskContainerGetRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\x12\x1a\n\x12include_terminated\x18\x03 \x01(\x08\"[\n\x18TaskContainerGetResponse\x12?\n\tcontainer\x18\x01 \x01(\x0b\x32,.modal.task_command_router.TaskContainerInfo\"~\n\x11TaskContainerInfo\x12\x14\n\x0c\x63ontainer_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12+\n\x06result\x18\x04 \x01(\x0b\x32\x1b.modal.client.GenericResult\"G\n\x18TaskContainerListRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x1a\n\x12include_terminated\x18\x02 \x01(\x08\"]\n\x19TaskContainerListResponse\x12@\n\ncontainers\x18\x01 \x03(\x0b\x32,.modal.task_command_router.TaskContainerInfo\"F\n\x1dTaskContainerTerminateRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x14\n\x0c\x63ontainer_id\x18\x02 \x01(\t\" \n\x1eTaskContainerTerminateResponse\"R\n\x18TaskContainerWaitRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x14\n\x0c\x63ontainer_id\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\x02\"H\n\x19TaskContainerWaitResponse\x12+\n\x06result\x18\x01 \x01(\x0b\x32\x1b.modal.client.GenericResult\"7\n\x13TaskExecPollRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\"G\n\x14TaskExecPollResponse\x12\x0e\n\x04\x63ode\x18\x01 \x01(\x05H\x00\x12\x10\n\x06signal\x18\x02 \x01(\x05H\x00\x42\r\n\x0b\x65xit_status\"\x9b\x04\n\x14TaskExecStartRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x14\n\x0c\x63ommand_args\x18\x03 \x03(\t\x12\x46\n\rstdout_config\x18\x04 \x01(\x0e\x32/.modal.task_command_router.TaskExecStdoutConfig\x12\x46\n\rstderr_config\x18\x05 \x01(\x0e\x32/.modal.task_command_router.TaskExecStderrConfig\x12\x19\n\x0ctimeout_secs\x18\x06 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07workdir\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x12\n\nsecret_ids\x18\x08 \x03(\t\x12,\n\x08pty_info\x18\t \x01(\x0b\x32\x15.modal.client.PTYInfoH\x02\x88\x01\x01\x12\x15\n\rruntime_debug\x18\n \x01(\x08\x12\x14\n\x0c\x63ontainer_id\x18\x0b \x01(\t\x12\x45\n\x03\x65nv\x18\x0c \x03(\x0b\x32\x38.modal.task_command_router.TaskExecStartRequest.EnvEntry\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0f\n\r_timeout_secsB\n\n\x08_workdirB\x0b\n\t_pty_info\"\x17\n\x15TaskExecStartResponse\">\n\x1aTaskExecStdinStatusRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\"H\n\x1bTaskExecStdinStatusResponse\x12\x19\n\x11num_bytes_written\x18\x01 \x01(\x04\x12\x0e\n\x06\x63losed\x18\x02 \x01(\x08\"h\n\x19TaskExecStdinWriteRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x05 \x01(\x08\"\x1c\n\x1aTaskExecStdinWriteResponse\"\x1d\n\x1bTaskExecStdinWriteStreamEnd\"\xce\x01\n\x1fTaskExecStdinWriteStreamRequest\x12I\n\x05start\x18\x01 \x01(\x0b\x32\x38.modal.task_command_router.TaskExecStdinWriteStreamStartH\x00\x12\x0e\n\x04\x64\x61ta\x18\x02 \x01(\x0cH\x00\x12\x45\n\x03\x65nd\x18\x03 \x01(\x0b\x32\x36.modal.task_command_router.TaskExecStdinWriteStreamEndH\x00\x42\t\n\x07payload\"\"\n TaskExecStdinWriteStreamResponse\"Q\n\x1dTaskExecStdinWriteStreamStart\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x04\"\x9d\x01\n\x18TaskExecStdioReadRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x04\x12O\n\x0f\x66ile_descriptor\x18\x04 \x01(\x0e\x32\x36.modal.task_command_router.TaskExecStdioFileDescriptor\")\n\x19TaskExecStdioReadResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"7\n\x13TaskExecWaitRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\"G\n\x14TaskExecWaitResponse\x12\x0e\n\x04\x63ode\x18\x01 \x01(\x05H\x00\x12\x10\n\x06signal\x18\x02 \x01(\x05H\x00\x42\r\n\x0b\x65xit_status\"\xa0\x01\n\x19TaskMountDirectoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\x0c\x12\x10\n\x08image_id\x18\x03 \x01(\t\x12-\n customer_supplied_encryption_key\x18\x04 \x01(\x0cH\x00\x88\x01\x01\x42#\n!_customer_supplied_encryption_key\"+\n\x18TaskReloadVolumesRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"\x1b\n\x19TaskReloadVolumesResponse\"c\n\x1bTaskSetNetworkAccessRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x33\n\x0enetwork_access\x18\x02 \x01(\x0b\x32\x1b.modal.client.NetworkAccess\"\x1e\n\x1cTaskSetNetworkAccessResponse\"\xd0\x01\n\x1cTaskSnapshotDirectoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\x0c\x12\x13\n\x0bsnapshot_id\x18\x03 \x01(\t\x12\x18\n\x0bttl_seconds\x18\x04 \x01(\x03H\x00\x88\x01\x01\x12-\n customer_supplied_encryption_key\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_ttl_secondsB#\n!_customer_supplied_encryption_key\"1\n\x1dTaskSnapshotDirectoryResponse\x12\x10\n\x08image_id\x18\x01 \x01(\t\"\xc3\x01\n\x1dTaskSnapshotFilesystemRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x13\n\x0bsnapshot_id\x18\x02 \x01(\t\x12\x18\n\x0bttl_seconds\x18\x03 \x01(\x03H\x00\x88\x01\x01\x12-\n customer_supplied_encryption_key\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_ttl_secondsB#\n!_customer_supplied_encryption_key\"2\n\x1eTaskSnapshotFilesystemResponse\x12\x10\n\x08image_id\x18\x01 \x01(\t\"E\n\x19TaskSnapshotMemoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x17\n\x0fidempotency_key\x18\x02 \x01(\t\"1\n\x1aTaskSnapshotMemoryResponse\x12\x13\n\x0bsnapshot_id\x18\x01 \x01(\t\"<\n\x1bTaskUnmountDirectoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\x0c*p\n\x1aSandboxStdioFileDescriptor\x12(\n$SANDBOX_STDIO_FILE_DESCRIPTOR_STDOUT\x10\x00\x12(\n$SANDBOX_STDIO_FILE_DESCRIPTOR_STDERR\x10\x01*\x81\x01\n\x14TaskExecStderrConfig\x12#\n\x1fTASK_EXEC_STDERR_CONFIG_DEVNULL\x10\x00\x12 \n\x1cTASK_EXEC_STDERR_CONFIG_PIPE\x10\x01\x12\"\n\x1eTASK_EXEC_STDERR_CONFIG_STDOUT\x10\x02*u\n\x1bTaskExecStdioFileDescriptor\x12*\n&TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDOUT\x10\x00\x12*\n&TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDERR\x10\x01*]\n\x14TaskExecStdoutConfig\x12#\n\x1fTASK_EXEC_STDOUT_CONFIG_DEVNULL\x10\x00\x12 \n\x1cTASK_EXEC_STDOUT_CONFIG_PIPE\x10\x01\x32\xba\x16\n\x11TaskCommandRouter\x12\x84\x01\n\x13SandboxStdinWriteV2\x12\x35.modal.task_command_router.SandboxStdinWriteV2Request\x1a\x36.modal.task_command_router.SandboxStdinWriteV2Response\x12\x83\x01\n\x12SandboxStdioReadV2\x12\x34.modal.task_command_router.SandboxStdioReadV2Request\x1a\x35.modal.task_command_router.SandboxStdioReadV2Response0\x01\x12\x90\x01\n\x15SandboxWaitUntilReady\x12:.modal.task_command_router.SandboxWaitUntilReadyTcrRequest\x1a;.modal.task_command_router.SandboxWaitUntilReadyTcrResponse\x12\x84\x01\n\x13TaskContainerCreate\x12\x35.modal.task_command_router.TaskContainerCreateRequest\x1a\x36.modal.task_command_router.TaskContainerCreateResponse\x12{\n\x10TaskContainerGet\x12\x32.modal.task_command_router.TaskContainerGetRequest\x1a\x33.modal.task_command_router.TaskContainerGetResponse\x12~\n\x11TaskContainerList\x12\x33.modal.task_command_router.TaskContainerListRequest\x1a\x34.modal.task_command_router.TaskContainerListResponse\x12\x8d\x01\n\x16TaskContainerTerminate\x12\x38.modal.task_command_router.TaskContainerTerminateRequest\x1a\x39.modal.task_command_router.TaskContainerTerminateResponse\x12~\n\x11TaskContainerWait\x12\x33.modal.task_command_router.TaskContainerWaitRequest\x1a\x34.modal.task_command_router.TaskContainerWaitResponse\x12o\n\x0cTaskExecPoll\x12..modal.task_command_router.TaskExecPollRequest\x1a/.modal.task_command_router.TaskExecPollResponse\x12r\n\rTaskExecStart\x12/.modal.task_command_router.TaskExecStartRequest\x1a\x30.modal.task_command_router.TaskExecStartResponse\x12\x84\x01\n\x13TaskExecStdinStatus\x12\x35.modal.task_command_router.TaskExecStdinStatusRequest\x1a\x36.modal.task_command_router.TaskExecStdinStatusResponse\x12\x81\x01\n\x12TaskExecStdinWrite\x12\x34.modal.task_command_router.TaskExecStdinWriteRequest\x1a\x35.modal.task_command_router.TaskExecStdinWriteResponse\x12\x95\x01\n\x18TaskExecStdinWriteStream\x12:.modal.task_command_router.TaskExecStdinWriteStreamRequest\x1a;.modal.task_command_router.TaskExecStdinWriteStreamResponse(\x01\x12\x80\x01\n\x11TaskExecStdioRead\x12\x33.modal.task_command_router.TaskExecStdioReadRequest\x1a\x34.modal.task_command_router.TaskExecStdioReadResponse0\x01\x12o\n\x0cTaskExecWait\x12..modal.task_command_router.TaskExecWaitRequest\x1a/.modal.task_command_router.TaskExecWaitResponse\x12\x62\n\x12TaskMountDirectory\x12\x34.modal.task_command_router.TaskMountDirectoryRequest\x1a\x16.google.protobuf.Empty\x12~\n\x11TaskReloadVolumes\x12\x33.modal.task_command_router.TaskReloadVolumesRequest\x1a\x34.modal.task_command_router.TaskReloadVolumesResponse\x12\x87\x01\n\x14TaskSetNetworkAccess\x12\x36.modal.task_command_router.TaskSetNetworkAccessRequest\x1a\x37.modal.task_command_router.TaskSetNetworkAccessResponse\x12\x8a\x01\n\x15TaskSnapshotDirectory\x12\x37.modal.task_command_router.TaskSnapshotDirectoryRequest\x1a\x38.modal.task_command_router.TaskSnapshotDirectoryResponse\x12\x8d\x01\n\x16TaskSnapshotFilesystem\x12\x38.modal.task_command_router.TaskSnapshotFilesystemRequest\x1a\x39.modal.task_command_router.TaskSnapshotFilesystemResponse\x12\x81\x01\n\x12TaskSnapshotMemory\x12\x34.modal.task_command_router.TaskSnapshotMemoryRequest\x1a\x35.modal.task_command_router.TaskSnapshotMemoryResponse\x12\x66\n\x14TaskUnmountDirectory\x12\x36.modal.task_command_router.TaskUnmountDirectoryRequest\x1a\x16.google.protobuf.EmptyB&Z$github.com/modal-labs/modal/go/protob\x06proto3')
20
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%modal_proto/task_command_router.proto\x12\x19modal.task_command_router\x1a\x1bgoogle/protobuf/empty.proto\x1a\x15modal_proto/api.proto\"X\n\x1aSandboxStdinWriteV2Request\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0e\n\x06offset\x18\x02 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x04 \x01(\x08\"\x1d\n\x1bSandboxStdinWriteV2Response\"\x8c\x01\n\x19SandboxStdioReadV2Request\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0e\n\x06offset\x18\x02 \x01(\x04\x12N\n\x0f\x66ile_descriptor\x18\x03 \x01(\x0e\x32\x35.modal.task_command_router.SandboxStdioFileDescriptor\"C\n\x1aSandboxStdioReadV2Response\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x17\n\x0fstarting_offset\x18\x02 \x01(\x04\"C\n\x1fSandboxWaitUntilReadyTcrRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07timeout\x18\x02 \x01(\x02\"4\n SandboxWaitUntilReadyTcrResponse\x12\x10\n\x08ready_at\x18\x01 \x01(\x01\"\x82\x03\n\x1aTaskContainerCreateRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\x12\x10\n\x08image_id\x18\x03 \x01(\t\x12\x0c\n\x04\x61rgs\x18\x05 \x03(\t\x12K\n\x03\x65nv\x18\x06 \x03(\x0b\x32>.modal.task_command_router.TaskContainerCreateRequest.EnvEntry\x12\x0f\n\x07workdir\x18\x07 \x01(\t\x12\x12\n\nsecret_ids\x18\x08 \x03(\t\x12\x30\n\rvolume_mounts\x18\t \x03(\x0b\x32\x19.modal.client.VolumeMount\x12\x38\n\x0enetwork_access\x18\n \x01(\x0b\x32\x1b.modal.client.NetworkAccessH\x00\x88\x01\x01\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x11\n\x0f_network_access\"K\n\x1bTaskContainerCreateResponse\x12\x14\n\x0c\x63ontainer_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\"^\n\x17TaskContainerGetRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\x12\x1a\n\x12include_terminated\x18\x03 \x01(\x08\"[\n\x18TaskContainerGetResponse\x12?\n\tcontainer\x18\x01 \x01(\x0b\x32,.modal.task_command_router.TaskContainerInfo\"~\n\x11TaskContainerInfo\x12\x14\n\x0c\x63ontainer_id\x18\x01 \x01(\t\x12\x16\n\x0e\x63ontainer_name\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12+\n\x06result\x18\x04 \x01(\x0b\x32\x1b.modal.client.GenericResult\"G\n\x18TaskContainerListRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x1a\n\x12include_terminated\x18\x02 \x01(\x08\"]\n\x19TaskContainerListResponse\x12@\n\ncontainers\x18\x01 \x03(\x0b\x32,.modal.task_command_router.TaskContainerInfo\"F\n\x1dTaskContainerTerminateRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x14\n\x0c\x63ontainer_id\x18\x02 \x01(\t\" \n\x1eTaskContainerTerminateResponse\"R\n\x18TaskContainerWaitRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x14\n\x0c\x63ontainer_id\x18\x02 \x01(\t\x12\x0f\n\x07timeout\x18\x03 \x01(\x02\"H\n\x19TaskContainerWaitResponse\x12+\n\x06result\x18\x01 \x01(\x0b\x32\x1b.modal.client.GenericResult\"7\n\x13TaskExecPollRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\"G\n\x14TaskExecPollResponse\x12\x0e\n\x04\x63ode\x18\x01 \x01(\x05H\x00\x12\x10\n\x06signal\x18\x02 \x01(\x05H\x00\x42\r\n\x0b\x65xit_status\"\x9b\x04\n\x14TaskExecStartRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x14\n\x0c\x63ommand_args\x18\x03 \x03(\t\x12\x46\n\rstdout_config\x18\x04 \x01(\x0e\x32/.modal.task_command_router.TaskExecStdoutConfig\x12\x46\n\rstderr_config\x18\x05 \x01(\x0e\x32/.modal.task_command_router.TaskExecStderrConfig\x12\x19\n\x0ctimeout_secs\x18\x06 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07workdir\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x12\n\nsecret_ids\x18\x08 \x03(\t\x12,\n\x08pty_info\x18\t \x01(\x0b\x32\x15.modal.client.PTYInfoH\x02\x88\x01\x01\x12\x15\n\rruntime_debug\x18\n \x01(\x08\x12\x14\n\x0c\x63ontainer_id\x18\x0b \x01(\t\x12\x45\n\x03\x65nv\x18\x0c \x03(\x0b\x32\x38.modal.task_command_router.TaskExecStartRequest.EnvEntry\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0f\n\r_timeout_secsB\n\n\x08_workdirB\x0b\n\t_pty_info\"\x17\n\x15TaskExecStartResponse\">\n\x1aTaskExecStdinStatusRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\"H\n\x1bTaskExecStdinStatusResponse\x12\x19\n\x11num_bytes_written\x18\x01 \x01(\x04\x12\x0e\n\x06\x63losed\x18\x02 \x01(\x08\"h\n\x19TaskExecStdinWriteRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x05 \x01(\x08\"\x1c\n\x1aTaskExecStdinWriteResponse\"\x1d\n\x1bTaskExecStdinWriteStreamEnd\"\xce\x01\n\x1fTaskExecStdinWriteStreamRequest\x12I\n\x05start\x18\x01 \x01(\x0b\x32\x38.modal.task_command_router.TaskExecStdinWriteStreamStartH\x00\x12\x0e\n\x04\x64\x61ta\x18\x02 \x01(\x0cH\x00\x12\x45\n\x03\x65nd\x18\x03 \x01(\x0b\x32\x36.modal.task_command_router.TaskExecStdinWriteStreamEndH\x00\x42\t\n\x07payload\"\"\n TaskExecStdinWriteStreamResponse\"Q\n\x1dTaskExecStdinWriteStreamStart\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x04\"\x9d\x01\n\x18TaskExecStdioReadRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\x12\x0e\n\x06offset\x18\x03 \x01(\x04\x12O\n\x0f\x66ile_descriptor\x18\x04 \x01(\x0e\x32\x36.modal.task_command_router.TaskExecStdioFileDescriptor\")\n\x19TaskExecStdioReadResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"7\n\x13TaskExecWaitRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x65xec_id\x18\x02 \x01(\t\"G\n\x14TaskExecWaitResponse\x12\x0e\n\x04\x63ode\x18\x01 \x01(\x05H\x00\x12\x10\n\x06signal\x18\x02 \x01(\x05H\x00\x42\r\n\x0b\x65xit_status\"\xa0\x01\n\x19TaskMountDirectoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\x0c\x12\x10\n\x08image_id\x18\x03 \x01(\t\x12-\n customer_supplied_encryption_key\x18\x04 \x01(\x0cH\x00\x88\x01\x01\x42#\n!_customer_supplied_encryption_key\"A\n\x18TaskReloadVolumesRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x14\n\x0c\x63ontainer_id\x18\x02 \x01(\t\"\x1b\n\x19TaskReloadVolumesResponse\"c\n\x1bTaskSetNetworkAccessRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x33\n\x0enetwork_access\x18\x02 \x01(\x0b\x32\x1b.modal.client.NetworkAccess\"\x1e\n\x1cTaskSetNetworkAccessResponse\"\xd0\x01\n\x1cTaskSnapshotDirectoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\x0c\x12\x13\n\x0bsnapshot_id\x18\x03 \x01(\t\x12\x18\n\x0bttl_seconds\x18\x04 \x01(\x03H\x00\x88\x01\x01\x12-\n customer_supplied_encryption_key\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_ttl_secondsB#\n!_customer_supplied_encryption_key\"1\n\x1dTaskSnapshotDirectoryResponse\x12\x10\n\x08image_id\x18\x01 \x01(\t\"\xc3\x01\n\x1dTaskSnapshotFilesystemRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x13\n\x0bsnapshot_id\x18\x02 \x01(\t\x12\x18\n\x0bttl_seconds\x18\x03 \x01(\x03H\x00\x88\x01\x01\x12-\n customer_supplied_encryption_key\x18\x04 \x01(\x0cH\x01\x88\x01\x01\x42\x0e\n\x0c_ttl_secondsB#\n!_customer_supplied_encryption_key\"2\n\x1eTaskSnapshotFilesystemResponse\x12\x10\n\x08image_id\x18\x01 \x01(\t\"E\n\x19TaskSnapshotMemoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x17\n\x0fidempotency_key\x18\x02 \x01(\t\"1\n\x1aTaskSnapshotMemoryResponse\x12\x13\n\x0bsnapshot_id\x18\x01 \x01(\t\"<\n\x1bTaskUnmountDirectoryRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\x0c*p\n\x1aSandboxStdioFileDescriptor\x12(\n$SANDBOX_STDIO_FILE_DESCRIPTOR_STDOUT\x10\x00\x12(\n$SANDBOX_STDIO_FILE_DESCRIPTOR_STDERR\x10\x01*\x81\x01\n\x14TaskExecStderrConfig\x12#\n\x1fTASK_EXEC_STDERR_CONFIG_DEVNULL\x10\x00\x12 \n\x1cTASK_EXEC_STDERR_CONFIG_PIPE\x10\x01\x12\"\n\x1eTASK_EXEC_STDERR_CONFIG_STDOUT\x10\x02*u\n\x1bTaskExecStdioFileDescriptor\x12*\n&TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDOUT\x10\x00\x12*\n&TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDERR\x10\x01*]\n\x14TaskExecStdoutConfig\x12#\n\x1fTASK_EXEC_STDOUT_CONFIG_DEVNULL\x10\x00\x12 \n\x1cTASK_EXEC_STDOUT_CONFIG_PIPE\x10\x01\x32\xba\x16\n\x11TaskCommandRouter\x12\x84\x01\n\x13SandboxStdinWriteV2\x12\x35.modal.task_command_router.SandboxStdinWriteV2Request\x1a\x36.modal.task_command_router.SandboxStdinWriteV2Response\x12\x83\x01\n\x12SandboxStdioReadV2\x12\x34.modal.task_command_router.SandboxStdioReadV2Request\x1a\x35.modal.task_command_router.SandboxStdioReadV2Response0\x01\x12\x90\x01\n\x15SandboxWaitUntilReady\x12:.modal.task_command_router.SandboxWaitUntilReadyTcrRequest\x1a;.modal.task_command_router.SandboxWaitUntilReadyTcrResponse\x12\x84\x01\n\x13TaskContainerCreate\x12\x35.modal.task_command_router.TaskContainerCreateRequest\x1a\x36.modal.task_command_router.TaskContainerCreateResponse\x12{\n\x10TaskContainerGet\x12\x32.modal.task_command_router.TaskContainerGetRequest\x1a\x33.modal.task_command_router.TaskContainerGetResponse\x12~\n\x11TaskContainerList\x12\x33.modal.task_command_router.TaskContainerListRequest\x1a\x34.modal.task_command_router.TaskContainerListResponse\x12\x8d\x01\n\x16TaskContainerTerminate\x12\x38.modal.task_command_router.TaskContainerTerminateRequest\x1a\x39.modal.task_command_router.TaskContainerTerminateResponse\x12~\n\x11TaskContainerWait\x12\x33.modal.task_command_router.TaskContainerWaitRequest\x1a\x34.modal.task_command_router.TaskContainerWaitResponse\x12o\n\x0cTaskExecPoll\x12..modal.task_command_router.TaskExecPollRequest\x1a/.modal.task_command_router.TaskExecPollResponse\x12r\n\rTaskExecStart\x12/.modal.task_command_router.TaskExecStartRequest\x1a\x30.modal.task_command_router.TaskExecStartResponse\x12\x84\x01\n\x13TaskExecStdinStatus\x12\x35.modal.task_command_router.TaskExecStdinStatusRequest\x1a\x36.modal.task_command_router.TaskExecStdinStatusResponse\x12\x81\x01\n\x12TaskExecStdinWrite\x12\x34.modal.task_command_router.TaskExecStdinWriteRequest\x1a\x35.modal.task_command_router.TaskExecStdinWriteResponse\x12\x95\x01\n\x18TaskExecStdinWriteStream\x12:.modal.task_command_router.TaskExecStdinWriteStreamRequest\x1a;.modal.task_command_router.TaskExecStdinWriteStreamResponse(\x01\x12\x80\x01\n\x11TaskExecStdioRead\x12\x33.modal.task_command_router.TaskExecStdioReadRequest\x1a\x34.modal.task_command_router.TaskExecStdioReadResponse0\x01\x12o\n\x0cTaskExecWait\x12..modal.task_command_router.TaskExecWaitRequest\x1a/.modal.task_command_router.TaskExecWaitResponse\x12\x62\n\x12TaskMountDirectory\x12\x34.modal.task_command_router.TaskMountDirectoryRequest\x1a\x16.google.protobuf.Empty\x12~\n\x11TaskReloadVolumes\x12\x33.modal.task_command_router.TaskReloadVolumesRequest\x1a\x34.modal.task_command_router.TaskReloadVolumesResponse\x12\x87\x01\n\x14TaskSetNetworkAccess\x12\x36.modal.task_command_router.TaskSetNetworkAccessRequest\x1a\x37.modal.task_command_router.TaskSetNetworkAccessResponse\x12\x8a\x01\n\x15TaskSnapshotDirectory\x12\x37.modal.task_command_router.TaskSnapshotDirectoryRequest\x1a\x38.modal.task_command_router.TaskSnapshotDirectoryResponse\x12\x8d\x01\n\x16TaskSnapshotFilesystem\x12\x38.modal.task_command_router.TaskSnapshotFilesystemRequest\x1a\x39.modal.task_command_router.TaskSnapshotFilesystemResponse\x12\x81\x01\n\x12TaskSnapshotMemory\x12\x34.modal.task_command_router.TaskSnapshotMemoryRequest\x1a\x35.modal.task_command_router.TaskSnapshotMemoryResponse\x12\x66\n\x14TaskUnmountDirectory\x12\x36.modal.task_command_router.TaskUnmountDirectoryRequest\x1a\x16.google.protobuf.EmptyB&Z$github.com/modal-labs/modal/go/protob\x06proto3')
21
21
 
22
22
  _SANDBOXSTDIOFILEDESCRIPTOR = DESCRIPTOR.enum_types_by_name['SandboxStdioFileDescriptor']
23
23
  SandboxStdioFileDescriptor = enum_type_wrapper.EnumTypeWrapper(_SANDBOXSTDIOFILEDESCRIPTOR)
@@ -425,14 +425,14 @@ if _descriptor._USE_C_DESCRIPTORS == False:
425
425
  _TASKCONTAINERCREATEREQUEST_ENVENTRY._serialized_options = b'8\001'
426
426
  _TASKEXECSTARTREQUEST_ENVENTRY._options = None
427
427
  _TASKEXECSTARTREQUEST_ENVENTRY._serialized_options = b'8\001'
428
- _SANDBOXSTDIOFILEDESCRIPTOR._serialized_start=4520
429
- _SANDBOXSTDIOFILEDESCRIPTOR._serialized_end=4632
430
- _TASKEXECSTDERRCONFIG._serialized_start=4635
431
- _TASKEXECSTDERRCONFIG._serialized_end=4764
432
- _TASKEXECSTDIOFILEDESCRIPTOR._serialized_start=4766
433
- _TASKEXECSTDIOFILEDESCRIPTOR._serialized_end=4883
434
- _TASKEXECSTDOUTCONFIG._serialized_start=4885
435
- _TASKEXECSTDOUTCONFIG._serialized_end=4978
428
+ _SANDBOXSTDIOFILEDESCRIPTOR._serialized_start=4542
429
+ _SANDBOXSTDIOFILEDESCRIPTOR._serialized_end=4654
430
+ _TASKEXECSTDERRCONFIG._serialized_start=4657
431
+ _TASKEXECSTDERRCONFIG._serialized_end=4786
432
+ _TASKEXECSTDIOFILEDESCRIPTOR._serialized_start=4788
433
+ _TASKEXECSTDIOFILEDESCRIPTOR._serialized_end=4905
434
+ _TASKEXECSTDOUTCONFIG._serialized_start=4907
435
+ _TASKEXECSTDOUTCONFIG._serialized_end=5000
436
436
  _SANDBOXSTDINWRITEV2REQUEST._serialized_start=120
437
437
  _SANDBOXSTDINWRITEV2REQUEST._serialized_end=208
438
438
  _SANDBOXSTDINWRITEV2RESPONSE._serialized_start=210
@@ -506,27 +506,27 @@ if _descriptor._USE_C_DESCRIPTORS == False:
506
506
  _TASKMOUNTDIRECTORYREQUEST._serialized_start=3455
507
507
  _TASKMOUNTDIRECTORYREQUEST._serialized_end=3615
508
508
  _TASKRELOADVOLUMESREQUEST._serialized_start=3617
509
- _TASKRELOADVOLUMESREQUEST._serialized_end=3660
510
- _TASKRELOADVOLUMESRESPONSE._serialized_start=3662
511
- _TASKRELOADVOLUMESRESPONSE._serialized_end=3689
512
- _TASKSETNETWORKACCESSREQUEST._serialized_start=3691
513
- _TASKSETNETWORKACCESSREQUEST._serialized_end=3790
514
- _TASKSETNETWORKACCESSRESPONSE._serialized_start=3792
515
- _TASKSETNETWORKACCESSRESPONSE._serialized_end=3822
516
- _TASKSNAPSHOTDIRECTORYREQUEST._serialized_start=3825
517
- _TASKSNAPSHOTDIRECTORYREQUEST._serialized_end=4033
518
- _TASKSNAPSHOTDIRECTORYRESPONSE._serialized_start=4035
519
- _TASKSNAPSHOTDIRECTORYRESPONSE._serialized_end=4084
520
- _TASKSNAPSHOTFILESYSTEMREQUEST._serialized_start=4087
521
- _TASKSNAPSHOTFILESYSTEMREQUEST._serialized_end=4282
522
- _TASKSNAPSHOTFILESYSTEMRESPONSE._serialized_start=4284
523
- _TASKSNAPSHOTFILESYSTEMRESPONSE._serialized_end=4334
524
- _TASKSNAPSHOTMEMORYREQUEST._serialized_start=4336
525
- _TASKSNAPSHOTMEMORYREQUEST._serialized_end=4405
526
- _TASKSNAPSHOTMEMORYRESPONSE._serialized_start=4407
527
- _TASKSNAPSHOTMEMORYRESPONSE._serialized_end=4456
528
- _TASKUNMOUNTDIRECTORYREQUEST._serialized_start=4458
529
- _TASKUNMOUNTDIRECTORYREQUEST._serialized_end=4518
530
- _TASKCOMMANDROUTER._serialized_start=4981
531
- _TASKCOMMANDROUTER._serialized_end=7855
509
+ _TASKRELOADVOLUMESREQUEST._serialized_end=3682
510
+ _TASKRELOADVOLUMESRESPONSE._serialized_start=3684
511
+ _TASKRELOADVOLUMESRESPONSE._serialized_end=3711
512
+ _TASKSETNETWORKACCESSREQUEST._serialized_start=3713
513
+ _TASKSETNETWORKACCESSREQUEST._serialized_end=3812
514
+ _TASKSETNETWORKACCESSRESPONSE._serialized_start=3814
515
+ _TASKSETNETWORKACCESSRESPONSE._serialized_end=3844
516
+ _TASKSNAPSHOTDIRECTORYREQUEST._serialized_start=3847
517
+ _TASKSNAPSHOTDIRECTORYREQUEST._serialized_end=4055
518
+ _TASKSNAPSHOTDIRECTORYRESPONSE._serialized_start=4057
519
+ _TASKSNAPSHOTDIRECTORYRESPONSE._serialized_end=4106
520
+ _TASKSNAPSHOTFILESYSTEMREQUEST._serialized_start=4109
521
+ _TASKSNAPSHOTFILESYSTEMREQUEST._serialized_end=4304
522
+ _TASKSNAPSHOTFILESYSTEMRESPONSE._serialized_start=4306
523
+ _TASKSNAPSHOTFILESYSTEMRESPONSE._serialized_end=4356
524
+ _TASKSNAPSHOTMEMORYREQUEST._serialized_start=4358
525
+ _TASKSNAPSHOTMEMORYREQUEST._serialized_end=4427
526
+ _TASKSNAPSHOTMEMORYRESPONSE._serialized_start=4429
527
+ _TASKSNAPSHOTMEMORYRESPONSE._serialized_end=4478
528
+ _TASKUNMOUNTDIRECTORYREQUEST._serialized_start=4480
529
+ _TASKUNMOUNTDIRECTORYREQUEST._serialized_end=4540
530
+ _TASKCOMMANDROUTER._serialized_start=5003
531
+ _TASKCOMMANDROUTER._serialized_end=7877
532
532
  # @@protoc_insertion_point(module_scope)
@@ -855,13 +855,17 @@ class TaskReloadVolumesRequest(google.protobuf.message.Message):
855
855
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
856
856
 
857
857
  TASK_ID_FIELD_NUMBER: builtins.int
858
+ CONTAINER_ID_FIELD_NUMBER: builtins.int
858
859
  task_id: builtins.str
860
+ container_id: builtins.str
861
+ """Fully qualified target container ID. Empty targets the main container."""
859
862
  def __init__(
860
863
  self,
861
864
  *,
862
865
  task_id: builtins.str = ...,
866
+ container_id: builtins.str = ...,
863
867
  ) -> None: ...
864
- def ClearField(self, field_name: typing_extensions.Literal["task_id", b"task_id"]) -> None: ...
868
+ def ClearField(self, field_name: typing_extensions.Literal["container_id", b"container_id", "task_id", b"task_id"]) -> None: ...
865
869
 
866
870
  global___TaskReloadVolumesRequest = TaskReloadVolumesRequest
867
871
 
modal_version/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2026
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.5.3.dev12"
4
+ __version__ = "1.5.3.dev13"