modal 0.73.57__py3-none-any.whl → 0.73.58__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
modal/cli/entry_point.py CHANGED
@@ -84,7 +84,7 @@ async def setup(profile: Optional[str] = None):
84
84
 
85
85
 
86
86
  # Commands
87
- entrypoint_cli_typer.command("deploy", help="Deploy a Modal application.", no_args_is_help=True)(run.deploy)
87
+ entrypoint_cli_typer.command("deploy", no_args_is_help=True)(run.deploy)
88
88
  entrypoint_cli_typer.command("serve", no_args_is_help=True)(run.serve)
89
89
  entrypoint_cli_typer.command("shell")(run.shell)
90
90
  entrypoint_cli_typer.add_typer(launch_cli)
modal/cli/import_refs.py CHANGED
@@ -22,6 +22,7 @@ import click
22
22
  from rich.console import Console
23
23
  from rich.markdown import Markdown
24
24
 
25
+ from modal._utils.deprecation import deprecation_warning
25
26
  from modal.app import App, LocalEntrypoint
26
27
  from modal.cls import Cls
27
28
  from modal.exception import InvalidError, _CliUserExecutionError
@@ -31,16 +32,17 @@ from modal.functions import Function
31
32
  @dataclasses.dataclass
32
33
  class ImportRef:
33
34
  file_or_module: str
35
+ use_module_mode: bool # i.e. using the -m flag
34
36
 
35
37
  # object_path is a .-delimited path to the object to execute, or a parent from which to infer the object
36
38
  # e.g.
37
39
  # function or local_entrypoint in module scope
38
40
  # app in module scope [+ method name]
39
41
  # app [+ function/entrypoint on that app]
40
- object_path: str
42
+ object_path: str = dataclasses.field(default="")
41
43
 
42
44
 
43
- def parse_import_ref(object_ref: str) -> ImportRef:
45
+ def parse_import_ref(object_ref: str, use_module_mode: bool = False) -> ImportRef:
44
46
  if object_ref.find("::") > 1:
45
47
  file_or_module, object_path = object_ref.split("::", 1)
46
48
  elif object_ref.find(":") > 1:
@@ -48,23 +50,36 @@ def parse_import_ref(object_ref: str) -> ImportRef:
48
50
  else:
49
51
  file_or_module, object_path = object_ref, ""
50
52
 
51
- return ImportRef(file_or_module, object_path)
53
+ return ImportRef(file_or_module, use_module_mode, object_path)
52
54
 
53
55
 
54
56
  DEFAULT_APP_NAME = "app"
55
57
 
56
58
 
57
- def import_file_or_module(file_or_module: str):
59
+ def import_file_or_module(import_ref: ImportRef, base_cmd: str = ""):
58
60
  if "" not in sys.path:
59
61
  # When running from a CLI like `modal run`
60
62
  # the current working directory isn't added to sys.path
61
63
  # so we add it in order to make module path specification possible
62
64
  sys.path.insert(0, "") # "" means the current working directory
63
65
 
64
- if file_or_module.endswith(".py"):
66
+ if not import_ref.file_or_module.endswith(".py") or import_ref.use_module_mode:
67
+ if not import_ref.use_module_mode:
68
+ deprecation_warning(
69
+ (2025, 2, 6),
70
+ f"Using Python module paths will require using the -m flag in a future version of Modal.\n"
71
+ f"Use `{base_cmd} -m {import_ref.file_or_module}` instead.",
72
+ pending=True,
73
+ show_source=False,
74
+ )
75
+ try:
76
+ module = importlib.import_module(import_ref.file_or_module)
77
+ except Exception as exc:
78
+ raise _CliUserExecutionError(import_ref.file_or_module) from exc
79
+ else:
65
80
  # when using a script path, that scripts directory should also be on the path as it is
66
81
  # with `python some/script.py`
67
- full_path = Path(file_or_module).resolve()
82
+ full_path = Path(import_ref.file_or_module).resolve()
68
83
  if "." in full_path.name.removesuffix(".py"):
69
84
  raise InvalidError(
70
85
  f"Invalid Modal source filename: {full_path.name!r}."
@@ -72,10 +87,10 @@ def import_file_or_module(file_or_module: str):
72
87
  )
73
88
  sys.path.insert(0, str(full_path.parent))
74
89
 
75
- module_name = inspect.getmodulename(file_or_module)
90
+ module_name = inspect.getmodulename(import_ref.file_or_module)
76
91
  assert module_name is not None
77
92
  # Import the module - see https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
78
- spec = importlib.util.spec_from_file_location(module_name, file_or_module)
93
+ spec = importlib.util.spec_from_file_location(module_name, import_ref.file_or_module)
79
94
  assert spec is not None
80
95
  module = importlib.util.module_from_spec(spec)
81
96
  sys.modules[module_name] = module
@@ -84,11 +99,6 @@ def import_file_or_module(file_or_module: str):
84
99
  spec.loader.exec_module(module)
85
100
  except Exception as exc:
86
101
  raise _CliUserExecutionError(str(full_path)) from exc
87
- else:
88
- try:
89
- module = importlib.import_module(file_or_module)
90
- except Exception as exc:
91
- raise _CliUserExecutionError(file_or_module) from exc
92
102
 
93
103
  return module
94
104
 
@@ -227,15 +237,18 @@ def filter_cli_commands(
227
237
  return res
228
238
 
229
239
 
230
- def import_app(app_ref: str) -> App:
231
- import_ref = parse_import_ref(app_ref)
240
+ def import_app(app_ref: str):
241
+ # TODO: remove when integration tests have been migrated to import_app_from_ref
242
+ return import_app_from_ref(parse_import_ref(app_ref))
243
+
232
244
 
245
+ def import_app_from_ref(import_ref: ImportRef, base_cmd: str = "") -> App:
233
246
  # TODO: default could be to just pick up any app regardless if it's called DEFAULT_APP_NAME
234
247
  # as long as there is a single app in the module?
235
248
  import_path = import_ref.file_or_module
236
249
  object_path = import_ref.object_path or DEFAULT_APP_NAME
237
250
 
238
- module = import_file_or_module(import_ref.file_or_module)
251
+ module = import_file_or_module(import_ref, base_cmd)
239
252
 
240
253
  if "." in object_path:
241
254
  raise click.UsageError(f"{object_path} is not a Modal App")
@@ -305,7 +318,7 @@ def _get_runnable_app(runnable: Runnable) -> App:
305
318
 
306
319
 
307
320
  def import_and_filter(
308
- import_ref: ImportRef, accept_local_entrypoint=True, accept_webhook=False
321
+ import_ref: ImportRef, *, base_cmd: str, accept_local_entrypoint=True, accept_webhook=False
309
322
  ) -> tuple[Optional[Runnable], list[CLICommand]]:
310
323
  """Takes a function ref string and returns a single determined "runnable" to use, and a list of all available
311
324
  runnables.
@@ -321,7 +334,7 @@ def import_and_filter(
321
334
  3. if there is a single method (within a class) that one is used
322
335
  """
323
336
  # all commands:
324
- module = import_file_or_module(import_ref.file_or_module)
337
+ module = import_file_or_module(import_ref, base_cmd)
325
338
  cli_commands = list_cli_commands(module)
326
339
 
327
340
  # all commands that satisfy local entrypoint/accept webhook limitations AND object path prefix
modal/cli/launch.py CHANGED
@@ -8,11 +8,10 @@ from typing import Any, Optional
8
8
 
9
9
  from typer import Typer
10
10
 
11
- from ..app import LocalEntrypoint
12
11
  from ..exception import _CliUserExecutionError
13
12
  from ..output import enable_output
14
13
  from ..runner import run_app
15
- from .import_refs import _get_runnable_app, import_and_filter, parse_import_ref
14
+ from .import_refs import ImportRef, _get_runnable_app, import_file_or_module
16
15
 
17
16
  launch_cli = Typer(
18
17
  name="launch",
@@ -29,14 +28,12 @@ def _launch_program(name: str, filename: str, detach: bool, args: dict[str, Any]
29
28
  os.environ["MODAL_LAUNCH_ARGS"] = json.dumps(args)
30
29
 
31
30
  program_path = str(Path(__file__).parent / "programs" / filename)
32
- entrypoint, _ = import_and_filter(
33
- parse_import_ref(program_path), accept_local_entrypoint=True, accept_webhook=False
34
- )
35
- if not isinstance(entrypoint, LocalEntrypoint):
36
- raise ValueError(f"{program_path} has no single local_entrypoint")
31
+ base_cmd = f"modal launch {name}"
32
+ module = import_file_or_module(ImportRef(program_path, use_module_mode=False), base_cmd=base_cmd)
33
+ entrypoint = module.main
37
34
 
38
35
  app = _get_runnable_app(entrypoint)
39
- app.set_description(f"modal launch {name}")
36
+ app.set_description(base_cmd)
40
37
 
41
38
  # `launch/` scripts must have a `local_entrypoint()` with no args, for simplicity here.
42
39
  func = entrypoint.info.raw_f
modal/cli/run.py CHANGED
@@ -27,7 +27,14 @@ from ..output import enable_output
27
27
  from ..runner import deploy_app, interactive_shell, run_app
28
28
  from ..serving import serve_app
29
29
  from ..volume import Volume
30
- from .import_refs import CLICommand, MethodReference, _get_runnable_app, import_and_filter, import_app, parse_import_ref
30
+ from .import_refs import (
31
+ CLICommand,
32
+ MethodReference,
33
+ _get_runnable_app,
34
+ import_and_filter,
35
+ import_app_from_ref,
36
+ parse_import_ref,
37
+ )
31
38
  from .utils import ENV_OPTION, ENV_OPTION_HELP, is_tty, stream_app_logs
32
39
 
33
40
 
@@ -324,9 +331,9 @@ class RunGroup(click.Group):
324
331
  ctx.ensure_object(dict)
325
332
  ctx.obj["env"] = ensure_env(ctx.params["env"])
326
333
 
327
- import_ref = parse_import_ref(func_ref)
334
+ import_ref = parse_import_ref(func_ref, use_module_mode=ctx.params["m"])
328
335
  runnable, all_usable_commands = import_and_filter(
329
- import_ref, accept_local_entrypoint=True, accept_webhook=False
336
+ import_ref, base_cmd="modal run", accept_local_entrypoint=True, accept_webhook=False
330
337
  )
331
338
  if not runnable:
332
339
  help_header = (
@@ -368,8 +375,9 @@ class RunGroup(click.Group):
368
375
  @click.option("-d", "--detach", is_flag=True, help="Don't stop the app if the local process dies or disconnects.")
369
376
  @click.option("-i", "--interactive", is_flag=True, help="Run the app in interactive mode.")
370
377
  @click.option("-e", "--env", help=ENV_OPTION_HELP, default=None)
378
+ @click.option("-m", is_flag=True, help="Interpret argument as a Python module path instead of a file/script path")
371
379
  @click.pass_context
372
- def run(ctx, write_result, detach, quiet, interactive, env):
380
+ def run(ctx, write_result, detach, quiet, interactive, env, m):
373
381
  """Run a Modal function or local entrypoint.
374
382
 
375
383
  `FUNC_REF` should be of the format `{file or module}::{function name}`.
@@ -385,7 +393,7 @@ def run(ctx, write_result, detach, quiet, interactive, env):
385
393
  modal run my_app.py::hello_world
386
394
  ```
387
395
 
388
- If your module only has a single app called `app` and your app has a
396
+ If your module only has a single app and your app has a
389
397
  single local entrypoint (or single function), you can omit the app and
390
398
  function parts:
391
399
 
@@ -393,10 +401,12 @@ def run(ctx, write_result, detach, quiet, interactive, env):
393
401
  modal run my_app.py
394
402
  ```
395
403
 
396
- Instead of pointing to a file, you can also use the Python module path:
404
+ Instead of pointing to a file, you can also use the Python module path, which
405
+ by default will ensure that your remote functions will use the same module
406
+ names as they do locally.
397
407
 
398
408
  ```
399
- modal run my_project.my_app
409
+ modal run -m my_project.my_app
400
410
  ```
401
411
  """
402
412
  ctx.ensure_object(dict)
@@ -407,16 +417,26 @@ def run(ctx, write_result, detach, quiet, interactive, env):
407
417
 
408
418
 
409
419
  def deploy(
410
- app_ref: str = typer.Argument(..., help="Path to a Python file with an app."),
420
+ app_ref: str = typer.Argument(..., help="Path to a Python file with an app to deploy"),
411
421
  name: str = typer.Option("", help="Name of the deployment."),
412
422
  env: str = ENV_OPTION,
413
423
  stream_logs: bool = typer.Option(False, help="Stream logs from the app upon deployment."),
414
424
  tag: str = typer.Option("", help="Tag the deployment with a version."),
425
+ use_module_mode: bool = typer.Option(
426
+ False, "-m", help="Interpret argument as a Python module path instead of a file/script path"
427
+ ),
415
428
  ):
429
+ """Deploy a Modal application.
430
+
431
+ **Usage:**
432
+ modal deploy my_script.py
433
+ modal deploy -m my_package.my_mod
434
+ """
416
435
  # this ensures that lookups without environment specification use the same env as specified
417
436
  env = ensure_env(env)
418
437
 
419
- app = import_app(app_ref)
438
+ import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode)
439
+ app = import_app_from_ref(import_ref, base_cmd="modal deploy")
420
440
 
421
441
  if name is None:
422
442
  name = app.name
@@ -432,6 +452,9 @@ def serve(
432
452
  app_ref: str = typer.Argument(..., help="Path to a Python file with an app."),
433
453
  timeout: Optional[float] = None,
434
454
  env: str = ENV_OPTION,
455
+ use_module_mode: bool = typer.Option(
456
+ False, "-m", help="Interpret argument as a Python module path instead of a file/script path"
457
+ ),
435
458
  ):
436
459
  """Run a web endpoint(s) associated with a Modal app and hot-reload code.
437
460
 
@@ -442,13 +465,13 @@ def serve(
442
465
  ```
443
466
  """
444
467
  env = ensure_env(env)
445
-
446
- app = import_app(app_ref)
468
+ import_ref = parse_import_ref(app_ref, use_module_mode=use_module_mode)
469
+ app = import_app_from_ref(import_ref, base_cmd="modal serve")
447
470
  if app.description is None:
448
471
  app.set_description(_get_clean_app_description(app_ref))
449
472
 
450
473
  with enable_output():
451
- with serve_app(app, app_ref, environment_name=env):
474
+ with serve_app(app, import_ref, environment_name=env):
452
475
  if timeout is None:
453
476
  timeout = config["serve_timeout"]
454
477
  if timeout is None:
@@ -563,7 +586,7 @@ def shell(
563
586
 
564
587
  import_ref = parse_import_ref(container_or_function)
565
588
  runnable, all_usable_commands = import_and_filter(
566
- import_ref, accept_local_entrypoint=False, accept_webhook=True
589
+ import_ref, base_cmd="modal shell", accept_local_entrypoint=False, accept_webhook=True
567
590
  )
568
591
  if not runnable:
569
592
  help_header = (
modal/client.pyi CHANGED
@@ -27,7 +27,7 @@ class _Client:
27
27
  _snapshotted: bool
28
28
 
29
29
  def __init__(
30
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.57"
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.58"
31
31
  ): ...
32
32
  def is_closed(self) -> bool: ...
33
33
  @property
@@ -85,7 +85,7 @@ class Client:
85
85
  _snapshotted: bool
86
86
 
87
87
  def __init__(
88
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.57"
88
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.58"
89
89
  ): ...
90
90
  def is_closed(self) -> bool: ...
91
91
  @property
modal/serving.py CHANGED
@@ -14,7 +14,7 @@ from ._utils.async_utils import TaskContext, asyncify, synchronize_api, synchron
14
14
  from ._utils.deprecation import deprecation_error
15
15
  from ._utils.logger import logger
16
16
  from ._watcher import watch
17
- from .cli.import_refs import import_app
17
+ from .cli.import_refs import ImportRef, import_app_from_ref
18
18
  from .client import _Client
19
19
  from .config import config
20
20
  from .output import _get_output_manager, enable_output
@@ -26,9 +26,11 @@ else:
26
26
  _App = TypeVar("_App")
27
27
 
28
28
 
29
- def _run_serve(app_ref: str, existing_app_id: str, is_ready: Event, environment_name: str, show_progress: bool):
29
+ def _run_serve(
30
+ import_ref: ImportRef, existing_app_id: str, is_ready: Event, environment_name: str, show_progress: bool
31
+ ):
30
32
  # subprocess entrypoint
31
- _app = import_app(app_ref)
33
+ _app = import_app_from_ref(import_ref, base_cmd="modal serve")
32
34
  blocking_app = synchronizer._translate_out(_app)
33
35
 
34
36
  with enable_output(show_progress=show_progress):
@@ -36,13 +38,13 @@ def _run_serve(app_ref: str, existing_app_id: str, is_ready: Event, environment_
36
38
 
37
39
 
38
40
  async def _restart_serve(
39
- app_ref: str, existing_app_id: str, environment_name: str, timeout: float = 5.0
41
+ import_ref: ImportRef, *, existing_app_id: str, environment_name: str, timeout: float = 5.0
40
42
  ) -> SpawnProcess:
41
43
  ctx = multiprocessing.get_context("spawn") # Needed to reload the interpreter
42
44
  is_ready = ctx.Event()
43
45
  output_mgr = OutputManager.get()
44
46
  show_progress = output_mgr is not None
45
- p = ctx.Process(target=_run_serve, args=(app_ref, existing_app_id, is_ready, environment_name, show_progress))
47
+ p = ctx.Process(target=_run_serve, args=(import_ref, existing_app_id, is_ready, environment_name, show_progress))
46
48
  p.start()
47
49
  await asyncify(is_ready.wait)(timeout)
48
50
  # TODO(erikbern): we don't fail if the above times out, but that's somewhat intentional, since
@@ -68,7 +70,8 @@ async def _terminate(proc: Optional[SpawnProcess], timeout: float = 5.0):
68
70
 
69
71
 
70
72
  async def _run_watch_loop(
71
- app_ref: str,
73
+ import_ref: ImportRef,
74
+ *,
72
75
  app_id: str,
73
76
  watcher: AsyncGenerator[set[str], None],
74
77
  environment_name: str,
@@ -88,7 +91,7 @@ async def _run_watch_loop(
88
91
  async for trigger_files in watcher:
89
92
  logger.debug(f"The following files triggered an app update: {', '.join(trigger_files)}")
90
93
  await _terminate(curr_proc)
91
- curr_proc = await _restart_serve(app_ref, existing_app_id=app_id, environment_name=environment_name)
94
+ curr_proc = await _restart_serve(import_ref, existing_app_id=app_id, environment_name=environment_name)
92
95
  finally:
93
96
  await _terminate(curr_proc)
94
97
 
@@ -96,7 +99,8 @@ async def _run_watch_loop(
96
99
  @asynccontextmanager
97
100
  async def _serve_app(
98
101
  app: "_App",
99
- app_ref: str,
102
+ import_ref: ImportRef,
103
+ *,
100
104
  _watcher: Optional[AsyncGenerator[set[str], None]] = None, # for testing
101
105
  environment_name: Optional[str] = None,
102
106
  ) -> AsyncGenerator["_App", None]:
@@ -112,7 +116,9 @@ async def _serve_app(
112
116
  mounts_to_watch = app._get_watch_mounts()
113
117
  watcher = watch(mounts_to_watch)
114
118
  async with TaskContext(grace=0.1) as tc:
115
- tc.create_task(_run_watch_loop(app_ref, app.app_id, watcher, environment_name))
119
+ tc.create_task(
120
+ _run_watch_loop(import_ref, app_id=app.app_id, watcher=watcher, environment_name=environment_name)
121
+ )
116
122
  yield app
117
123
 
118
124
 
modal/serving.pyi CHANGED
@@ -1,4 +1,5 @@
1
1
  import collections.abc
2
+ import modal.cli.import_refs
2
3
  import multiprocessing.context
3
4
  import multiprocessing.synchronize
4
5
  import synchronicity.combined_types
@@ -8,22 +9,27 @@ import typing_extensions
8
9
  _App = typing.TypeVar("_App")
9
10
 
10
11
  def _run_serve(
11
- app_ref: str,
12
+ import_ref: modal.cli.import_refs.ImportRef,
12
13
  existing_app_id: str,
13
14
  is_ready: multiprocessing.synchronize.Event,
14
15
  environment_name: str,
15
16
  show_progress: bool,
16
17
  ): ...
17
18
  async def _restart_serve(
18
- app_ref: str, existing_app_id: str, environment_name: str, timeout: float = 5.0
19
+ import_ref: modal.cli.import_refs.ImportRef, *, existing_app_id: str, environment_name: str, timeout: float = 5.0
19
20
  ) -> multiprocessing.context.SpawnProcess: ...
20
21
  async def _terminate(proc: typing.Optional[multiprocessing.context.SpawnProcess], timeout: float = 5.0): ...
21
22
  async def _run_watch_loop(
22
- app_ref: str, app_id: str, watcher: collections.abc.AsyncGenerator[set[str], None], environment_name: str
23
+ import_ref: modal.cli.import_refs.ImportRef,
24
+ *,
25
+ app_id: str,
26
+ watcher: collections.abc.AsyncGenerator[set[str], None],
27
+ environment_name: str,
23
28
  ): ...
24
29
  def _serve_app(
25
30
  app: _App,
26
- app_ref: str,
31
+ import_ref: modal.cli.import_refs.ImportRef,
32
+ *,
27
33
  _watcher: typing.Optional[collections.abc.AsyncGenerator[set[str], None]] = None,
28
34
  environment_name: typing.Optional[str] = None,
29
35
  ) -> typing.AsyncContextManager[_App]: ...
@@ -33,14 +39,16 @@ class __serve_app_spec(typing_extensions.Protocol):
33
39
  def __call__(
34
40
  self,
35
41
  app: _App,
36
- app_ref: str,
42
+ import_ref: modal.cli.import_refs.ImportRef,
43
+ *,
37
44
  _watcher: typing.Optional[typing.Generator[set[str], None, None]] = None,
38
45
  environment_name: typing.Optional[str] = None,
39
46
  ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[_App]: ...
40
47
  def aio(
41
48
  self,
42
49
  app: _App,
43
- app_ref: str,
50
+ import_ref: modal.cli.import_refs.ImportRef,
51
+ *,
44
52
  _watcher: typing.Optional[collections.abc.AsyncGenerator[set[str], None]] = None,
45
53
  environment_name: typing.Optional[str] = None,
46
54
  ) -> typing.AsyncContextManager[_App]: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: modal
3
- Version: 0.73.57
3
+ Version: 0.73.58
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -22,7 +22,7 @@ modal/app.py,sha256=o5mHoHtn41nkvskX_ekJkyfG6MXwj5rqerRi_nnPd0w,44725
22
22
  modal/app.pyi,sha256=0MMCgskIL4r3eq8oBcfm2lLyeao2gXjS3iXaIfmaJ-o,25959
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=8SQawr7P1PNUCq1UmJMUQXG2jIo4Nmdcs311XqrNLRE,15276
25
- modal/client.pyi,sha256=W672QLh5KjAdhs9O13OnWPiNtBdR1YDphEvqB8ECtNY,7593
25
+ modal/client.pyi,sha256=4rq2-Bl3Ru8gaL6mi3_XMTXkGvCpo83qwO7mBmg64Oo,7593
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=30T3K1a89l6wzmEJ_J9iWv9SknoGqaZDx59Xs-ZQcmk,1607
28
28
  modal/cls.py,sha256=wztMTYkhJyW9iUVqx4_Gga4bJJpUiPgGsS6iacUqy-A,30001
@@ -73,8 +73,8 @@ modal/schedule.py,sha256=0ZFpKs1bOxeo5n3HZjoL7OE2ktsb-_oGtq-WJEPO4tY,2615
73
73
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
74
74
  modal/secret.py,sha256=U2Jivqdb94eI_BrGCMVbCots8F2gDcbXLMia_gVlej0,10455
75
75
  modal/secret.pyi,sha256=W4g_BOSxafYm-K9PvFc7-li3a-rsCFNkYgHTZXr1AFA,2974
76
- modal/serving.py,sha256=MnVuTsimN05LfNPxuJZ4sr5s1_BPUkIsOP_VC-bkp78,4464
77
- modal/serving.pyi,sha256=ncV-9jY_vZYFnGs5ZnMb3ffrX8LmcLdIMHBC56xRbtE,1711
76
+ modal/serving.py,sha256=orZjhyikqk7U77My7GedbVKy65j0_CF7J7mqye86dRw,4650
77
+ modal/serving.pyi,sha256=KGSaZhg0qwygLmDkhgJedUfWeNSkXsyoOipq10vYffU,1978
78
78
  modal/snapshot.py,sha256=6rQvDP3iX9hdiAudKTy0-m0JESt4kk0q2gusXbaRA-8,1279
79
79
  modal/snapshot.pyi,sha256=Ypd4NKsjOTnnnqXyTGGLKq5lkocRrUURYjY5Pi67_qA,670
80
80
  modal/stream_type.py,sha256=A6320qoAAWhEfwOCZfGtymQTu5AfLfJXXgARqooTPvY,417
@@ -121,14 +121,14 @@ modal/cli/app.py,sha256=TmUiFKAE1yc6ll8pfl-wZ2lh9crC31Fu_8_YKCX8NJc,7818
121
121
  modal/cli/config.py,sha256=QvFsqO4eUOtI7d_pQAOAyfq_ZitjhPtav3C6GIDQcZM,1680
122
122
  modal/cli/container.py,sha256=FYwEgjf93j4NMorAjGbSV98i1wpebqdAeNU1wfrFp1k,3668
123
123
  modal/cli/dict.py,sha256=8Wq3w-UDaywk8EVNdj-ECCNV9TYHqh4kzhUqhhulatM,4593
124
- modal/cli/entry_point.py,sha256=DzFr75smEi1OSJdGXx1ZaAl-3-4b08QCDUP3tzvApKo,4225
124
+ modal/cli/entry_point.py,sha256=dOosuCwhfznwTCB4oMljUFhihq5aLUVoAz7RhcBEDnc,4189
125
125
  modal/cli/environment.py,sha256=Ayddkiq9jdj3XYDJ8ZmUqFpPPH8xajYlbexRkzGtUcg,4334
126
- modal/cli/import_refs.py,sha256=YYseLJ6cU_wln7DjVWfKPgEhv77hxfA0klWAkTK_1HA,12672
127
- modal/cli/launch.py,sha256=pzQt2QlcrbIUU0MVzWWPAvMQ6MCyqsHZ0X9JcV-sY04,3242
126
+ modal/cli/import_refs.py,sha256=kbjWZxSyLc6Bp6UxtB7iJ7qp10DG5j7i4bbbA1bSIXQ,13529
127
+ modal/cli/launch.py,sha256=0_sBu6bv2xJEPWi-rbGS6Ri9ggnkWQvrGlgpYSUBMyY,3097
128
128
  modal/cli/network_file_system.py,sha256=eq3JnwjbfFNsJodIyANHL06ByYc3BSavzdmu8C96cHA,7948
129
129
  modal/cli/profile.py,sha256=rLXfjJObfPNjaZvNfHGIKqs7y9bGYyGe-K7V0w-Ni0M,3110
130
130
  modal/cli/queues.py,sha256=6gTu76dzBtPN5eQVsLrvQpuru5jI9ZCWK5Eh8J8XhaM,4498
131
- modal/cli/run.py,sha256=Wu5P4ERjB4iZ_d4J8nP7KB58qIjL595KnFQkw_pWDik,21761
131
+ modal/cli/run.py,sha256=rCd-lB6p-l2vd0OrvXcioVN6wn_1EkCiRQLJRC3Z7J4,22764
132
132
  modal/cli/secret.py,sha256=iDsaFUJBq3333ZBVzKPcqyey68w0j82PNddGhRgP2pA,4206
133
133
  modal/cli/token.py,sha256=mxSgOWakXG6N71hQb1ko61XAR9ZGkTMZD-Txn7gmTac,1924
134
134
  modal/cli/utils.py,sha256=hZmjyzcPjDnQSkLvycZD2LhGdcsfdZshs_rOU78EpvI,3717
@@ -168,10 +168,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
168
168
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
169
  modal_version/__init__.py,sha256=wiJQ53c-OMs0Xf1UeXOxQ7FwlV1VzIjnX6o-pRYZ_Pk,470
170
170
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
171
- modal_version/_version_generated.py,sha256=WH9Vy1kofy1Ic8RJwi4vmJgQ4b76chh14d4FehkqkYY,149
172
- modal-0.73.57.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
173
- modal-0.73.57.dist-info/METADATA,sha256=58VX1PaTnh9Wcx2TDfYXKSqcG9ZrI8jCjeUYSFaf83c,2452
174
- modal-0.73.57.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
175
- modal-0.73.57.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
176
- modal-0.73.57.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
177
- modal-0.73.57.dist-info/RECORD,,
171
+ modal_version/_version_generated.py,sha256=G5__kr5AhSAVmt7cklLxZHp3OMEHBXH7Bvr-Gj7d5rI,149
172
+ modal-0.73.58.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
173
+ modal-0.73.58.dist-info/METADATA,sha256=hYo8IB8JpTwI-uVd-OvMmxAD2Kfig-qLQmsawgeZcaQ,2452
174
+ modal-0.73.58.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
175
+ modal-0.73.58.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
176
+ modal-0.73.58.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
177
+ modal-0.73.58.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
 
3
3
  # Note: Reset this value to -1 whenever you make a minor `0.X` release of the client.
4
- build_number = 57 # git: 0890d83
4
+ build_number = 58 # git: 0fe73d2