modal 0.73.46__py3-none-any.whl → 0.73.47__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/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.46"
30
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.47"
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.46"
88
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.73.47"
89
89
  ): ...
90
90
  def is_closed(self) -> bool: ...
91
91
  @property
modal/functions.pyi CHANGED
@@ -200,11 +200,11 @@ class Function(
200
200
 
201
201
  _call_generator_nowait: ___call_generator_nowait_spec[typing_extensions.Self]
202
202
 
203
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
203
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
204
204
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
205
205
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER: ...
206
206
 
207
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
207
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
208
208
 
209
209
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
210
210
  def __call__(self, *args, **kwargs) -> typing.Generator[typing.Any, None, None]: ...
@@ -219,19 +219,19 @@ class Function(
219
219
  self, *args: modal._functions.P.args, **kwargs: modal._functions.P.kwargs
220
220
  ) -> modal._functions.OriginalReturnType: ...
221
221
 
222
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
222
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
223
223
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
224
224
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
225
225
 
226
226
  _experimental_spawn: ___experimental_spawn_spec[
227
- modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
227
+ modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
228
228
  ]
229
229
 
230
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
230
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
231
231
  def __call__(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
232
232
  async def aio(self, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]: ...
233
233
 
234
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
234
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
235
235
 
236
236
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]: ...
237
237
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: modal
3
- Version: 0.73.46
3
+ Version: 0.73.47
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=rCOPD51gVyow8muyaqMuV65qfTnAZKf_w1OCZdSF_6o,44636
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=O1FkvafYE0HPYhNlOAfgFPBfi1-ZQ00hbjPGOtk2PAk,7593
25
+ modal/client.pyi,sha256=5qG22FLFyDb4OjKfcnpVlfFwBYCVD6O_SzR9Rh2llaA,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=nJhJr-YuttOmdNWxtMHcBV-q6iQmY5qXkEy9yO43clY,31130
@@ -41,7 +41,7 @@ modal/file_io.py,sha256=lcMs_E9Xfm0YX1t9U2wNIBPnqHRxmImqjLW1GHqVmyg,20945
41
41
  modal/file_io.pyi,sha256=NTRft1tbPSWf9TlWVeZmTlgB5AZ_Zhu2srWIrWr7brk,9445
42
42
  modal/file_pattern_matcher.py,sha256=trosX-Bp7dOubudN1bLLhRAoidWy1TcoaR4Pv8CedWw,6497
43
43
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
44
- modal/functions.pyi,sha256=R_I4Foho4htNCFhYc0YKhWoS_jLqZNOrNfTrAA-Clew,14395
44
+ modal/functions.pyi,sha256=Qx5RDsB-Ta9lixUz2kWZYzUBD0ZGDxQenzHFyq0DJr8,14395
45
45
  modal/gpu.py,sha256=Kbhs_u49FaC2Zi0TjCdrpstpRtT5eZgecynmQi5IZVE,6752
46
46
  modal/image.py,sha256=EtYt7_Rjgi71gt_SutqF8KSjnzWgP5P1Z7XsV-eIoFw,91470
47
47
  modal/image.pyi,sha256=Oc2ndYHSdQTcRpZKHSfTdj-m_2oQAsnc2EWTthbNn-s,26380
@@ -144,6 +144,9 @@ modal/requirements/2024.04.txt,sha256=6NnrbIE-mflwMyKyQ0tsWeY8XFE1kSW9oE8DVDoD8Q
144
144
  modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddRo,296
145
145
  modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
146
146
  modal/requirements/base-images.json,sha256=kLNo5Sqmnhp9H6Hr9IcaGJFrRaRg1yfuepUWkm-y8iQ,571
147
+ modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
148
+ modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
149
+ modal_docs/gen_reference_docs.py,sha256=aDcUSSDtAAZ4eeFWyroeIg2TOzyRoYcic-d9Zh9TdLY,6656
147
150
  modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
148
151
  modal_proto/api.proto,sha256=hM-iLwpYycp-wGyvoAieAEM_km42yI0jZTigPQLGPC0,86712
149
152
  modal_proto/api_grpc.py,sha256=FYGqDegM_w_qxdtlxum8k31mDibKoMvmNxv_p9cKdKs,109056
@@ -162,10 +165,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
162
165
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
163
166
  modal_version/__init__.py,sha256=wiJQ53c-OMs0Xf1UeXOxQ7FwlV1VzIjnX6o-pRYZ_Pk,470
164
167
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
165
- modal_version/_version_generated.py,sha256=8fsq1Mwk_oc-cRzDa1hVjelGQTPb2sWXcU1-oVbyluE,149
166
- modal-0.73.46.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
167
- modal-0.73.46.dist-info/METADATA,sha256=cRFzas4CsmfLqOAtoQuAAfiB1dKGnRUifH9e0hUWVwg,2452
168
- modal-0.73.46.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
169
- modal-0.73.46.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
170
- modal-0.73.46.dist-info/top_level.txt,sha256=UkI9BtusWSFRKv6hePUkcXTROTUz7xo7rKGg_IHjuBM,32
171
- modal-0.73.46.dist-info/RECORD,,
168
+ modal_version/_version_generated.py,sha256=5cj8cqKxfu-44XR4MQVL7vocSJ_677tLG2jtW72Zc7U,149
169
+ modal-0.73.47.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
170
+ modal-0.73.47.dist-info/METADATA,sha256=JSgSze5rgpMBFjrdIbIjQqqlzvFPjddyU-bPzU206I4,2452
171
+ modal-0.73.47.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
172
+ modal-0.73.47.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
173
+ modal-0.73.47.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
174
+ modal-0.73.47.dist-info/RECORD,,
@@ -1,3 +1,4 @@
1
1
  modal
2
+ modal_docs
2
3
  modal_proto
3
4
  modal_version
modal_docs/__init__.py ADDED
@@ -0,0 +1 @@
1
+ # Copyright Modal Labs 2023
@@ -0,0 +1,117 @@
1
+ # Copyright Modal Labs 2023
2
+ import inspect
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Optional, cast
6
+
7
+ from click import Command, Context, Group
8
+
9
+ from modal.cli.entry_point import entrypoint_cli
10
+
11
+
12
+ # Adapted from typer_cli, since it's incompatible with the latest version of typer
13
+ # (see https://github.com/tiangolo/typer-cli/issues/50)
14
+ def get_docs_for_click(
15
+ obj: Command,
16
+ ctx: Context,
17
+ *,
18
+ indent: int = 0,
19
+ name: str = "",
20
+ call_prefix: str = "",
21
+ ) -> str:
22
+ docs = "#" * (1 + indent)
23
+ command_name = name or obj.name
24
+ if call_prefix:
25
+ command_name = f"{call_prefix} {command_name}"
26
+ title = f"`{command_name}`" if command_name else "CLI"
27
+ docs += f" {title}\n\n"
28
+ if obj.help:
29
+ docs += f"{inspect.cleandoc(obj.help)}\n\n"
30
+ usage_pieces = obj.collect_usage_pieces(ctx)
31
+ if usage_pieces:
32
+ docs += "**Usage**:\n\n"
33
+ docs += "```shell\n"
34
+ if command_name:
35
+ docs += f"{command_name} "
36
+ docs += f"{' '.join(usage_pieces)}\n"
37
+ docs += "```\n\n"
38
+ args = []
39
+ opts = []
40
+ for param in obj.get_params(ctx):
41
+ rv = param.get_help_record(ctx)
42
+ if rv is not None:
43
+ if getattr(param, "hidden", False):
44
+ continue
45
+ if param.param_type_name == "argument":
46
+ args.append(rv)
47
+ elif param.param_type_name == "option":
48
+ opts.append(rv)
49
+ if args:
50
+ docs += "**Arguments**:\n\n"
51
+ for arg_name, arg_help in args:
52
+ docs += f"* `{arg_name}`"
53
+ if arg_help:
54
+ docs += f": {arg_help}"
55
+ docs += "\n"
56
+ docs += "\n"
57
+ if opts:
58
+ docs += "**Options**:\n\n"
59
+ for opt_name, opt_help in opts:
60
+ docs += f"* `{opt_name}`"
61
+ if opt_help:
62
+ docs += f": {opt_help}"
63
+ docs += "\n"
64
+ docs += "\n"
65
+ if obj.epilog:
66
+ docs += f"{obj.epilog}\n\n"
67
+ if isinstance(obj, Group):
68
+ group: Group = cast(Group, obj)
69
+ commands = group.list_commands(ctx)
70
+ if commands:
71
+ docs += "**Commands**:\n\n"
72
+ for command in commands:
73
+ command_obj = group.get_command(ctx, command)
74
+ assert command_obj
75
+ if command_obj.hidden:
76
+ continue
77
+ docs += f"* `{command_obj.name}`"
78
+ command_help = command_obj.get_short_help_str(limit=250)
79
+ if command_help:
80
+ docs += f": {command_help}"
81
+ docs += "\n"
82
+ docs += "\n"
83
+ for command in commands:
84
+ command_obj = group.get_command(ctx, command)
85
+ if command_obj.hidden:
86
+ continue
87
+ assert command_obj
88
+ use_prefix = ""
89
+ if command_name:
90
+ use_prefix += f"{command_name}"
91
+ docs += get_docs_for_click(obj=command_obj, ctx=ctx, indent=indent + 1, call_prefix=use_prefix)
92
+ return docs
93
+
94
+
95
+ def run(output_dirname: Optional[str]) -> None:
96
+ entrypoint: Group = cast(Group, entrypoint_cli)
97
+ ctx = Context(entrypoint)
98
+ commands = entrypoint.list_commands(ctx)
99
+
100
+ for command in commands:
101
+ command_obj = entrypoint.get_command(ctx, command)
102
+ if command_obj.hidden:
103
+ continue
104
+ docs = get_docs_for_click(obj=command_obj, ctx=ctx, call_prefix="modal")
105
+
106
+ if output_dirname:
107
+ output_dir = Path(output_dirname)
108
+ output_dir.mkdir(parents=True, exist_ok=True)
109
+ output_file = output_dir / f"{command}.md"
110
+ print("Writing to", output_file)
111
+ output_file.write_text(docs)
112
+ else:
113
+ print(docs)
114
+
115
+
116
+ if __name__ == "__main__":
117
+ run(None if len(sys.argv) <= 1 else sys.argv[1])
@@ -0,0 +1,193 @@
1
+ # Copyright Modal Labs 2023
2
+ import importlib
3
+ import inspect
4
+ import json
5
+ import os
6
+ import sys
7
+ import warnings
8
+ from typing import NamedTuple
9
+
10
+ from synchronicity.synchronizer import FunctionWithAio
11
+
12
+ from .mdmd.mdmd import (
13
+ Category,
14
+ class_str,
15
+ default_filter,
16
+ function_str,
17
+ module_items,
18
+ module_str,
19
+ object_is_private,
20
+ package_filter,
21
+ )
22
+
23
+
24
+ class DocItem(NamedTuple):
25
+ label: str
26
+ category: Category
27
+ document: str
28
+ in_sidebar: bool = True
29
+
30
+
31
+ def validate_doc_item(docitem: DocItem) -> DocItem:
32
+ # Check that unwanted strings aren't leaking into our docs.
33
+ bad_strings = [
34
+ # Presence of a to-do inside a `DocItem` usually indicates it's been
35
+ # placed inside a function signature definition or right underneath it, before the body.
36
+ # Fix by moving the to-do into the body or above the signature.
37
+ "TODO:"
38
+ ]
39
+ for line in docitem.document.splitlines():
40
+ for bad_str in bad_strings:
41
+ if bad_str in line:
42
+ msg = f"Found unwanted string '{bad_str}' in content for item '{docitem.label}'. Problem line: {line}"
43
+ raise ValueError(msg)
44
+ return docitem
45
+
46
+
47
+ def run(output_dir: str = None):
48
+ """Generate Modal docs."""
49
+ import modal
50
+
51
+ ordered_doc_items: list[DocItem] = []
52
+ documented_items = set()
53
+
54
+ def filter_non_aio(module, name):
55
+ return not name.lower().startswith("aio")
56
+
57
+ def filter_already_documented(module, name):
58
+ item = getattr(module, name)
59
+ try:
60
+ if item in documented_items:
61
+ return False
62
+ except TypeError: # unhashable stuff
63
+ print(f"Warning: could not document item {name}: {item}:")
64
+ return False
65
+ documented_items.add(item)
66
+ return True
67
+
68
+ def modal_default_filter(module, name):
69
+ return default_filter(module, name) and filter_non_aio(module, name) and filter_already_documented(module, name)
70
+
71
+ def top_level_filter(module, name):
72
+ item = getattr(module, name)
73
+ if object_is_private(name, item) or inspect.ismodule(item):
74
+ return False
75
+ return package_filter("modal") and filter_already_documented(module, name) and filter_non_aio(module, name)
76
+
77
+ base_title_level = "#"
78
+ forced_module_docs = [
79
+ ("modal.Function", "modal.functions"),
80
+ ("modal.Secret", "modal.secret"),
81
+ ("modal.Dict", "modal.dict"),
82
+ ("modal.Queue", "modal.queue"),
83
+ ("modal.call_graph", "modal.call_graph"),
84
+ ("modal.gpu", "modal.gpu"),
85
+ ("modal.runner", "modal.runner"),
86
+ ("modal.Sandbox", "modal.sandbox"),
87
+ ("modal.ContainerProcess", "modal.container_process"),
88
+ ("modal.io_streams", "modal.io_streams"),
89
+ ("modal.FileIO", "modal.file_io"),
90
+ ]
91
+ # These aren't defined in `modal`, but should still be documented as top-level entries.
92
+ forced_members = {"web_endpoint", "asgi_app", "method", "wsgi_app", "forward"}
93
+ # These are excluded from the sidebar, typically to 'soft release' some documentation.
94
+ sidebar_excluded: set[str] = set()
95
+
96
+ for title, modulepath in forced_module_docs:
97
+ module = importlib.import_module(modulepath)
98
+ document = module_str(modulepath, module, title_level=base_title_level, filter_items=modal_default_filter)
99
+ if document:
100
+ ordered_doc_items.append(
101
+ validate_doc_item(
102
+ DocItem(
103
+ label=title,
104
+ category=Category.MODULE,
105
+ document=document,
106
+ in_sidebar=title not in sidebar_excluded,
107
+ )
108
+ )
109
+ )
110
+
111
+ def f(module, member_name):
112
+ return top_level_filter(module, member_name) or (member_name in forced_members)
113
+
114
+ # now add all remaining top level modal.X entries
115
+ for qual_name, item_name, item in module_items(modal, filter_items=f):
116
+ if object_is_private(item_name, item):
117
+ continue # skip stuff that's part of explicit `handle_objects` above
118
+
119
+ title = f"modal.{item_name}"
120
+ if inspect.isclass(item):
121
+ content = f"{base_title_level} {qual_name}\n\n" + class_str(item_name, item, base_title_level)
122
+ category = Category.CLASS
123
+ elif inspect.isroutine(item) or isinstance(item, FunctionWithAio):
124
+ content = f"{base_title_level} {qual_name}\n\n" + function_str(item_name, item)
125
+ category = Category.FUNCTION
126
+ elif inspect.ismodule(item):
127
+ continue # skipping imported modules
128
+ else:
129
+ warnings.warn(f"Not sure how to document: {item_name} ({item})")
130
+ continue
131
+ ordered_doc_items.append(
132
+ validate_doc_item(
133
+ DocItem(
134
+ label=title,
135
+ category=category,
136
+ document=content,
137
+ in_sidebar=title not in sidebar_excluded,
138
+ )
139
+ )
140
+ )
141
+ ordered_doc_items.sort()
142
+
143
+ for modulepath in ["modal.exception", "modal.config"]:
144
+ module = importlib.import_module(modulepath)
145
+ document = module_str(modulepath, module, title_level=base_title_level, filter_items=modal_default_filter)
146
+ ordered_doc_items.append(
147
+ DocItem(
148
+ label=modulepath,
149
+ category=Category.MODULE,
150
+ document=document,
151
+ )
152
+ )
153
+
154
+ # TODO: add some way of documenting our .aio sub-methods
155
+
156
+ make_markdown_docs(
157
+ ordered_doc_items,
158
+ output_dir,
159
+ )
160
+
161
+
162
+ def make_markdown_docs(items: list[DocItem], output_dir: str = None):
163
+ def _write_file(rel_path: str, data: str):
164
+ if output_dir is None:
165
+ print(f"<<< {rel_path}")
166
+ print(data)
167
+ print(f">>> {rel_path}")
168
+ return
169
+
170
+ filename = os.path.join(output_dir, rel_path)
171
+ print("Writing to", filename)
172
+ os.makedirs(os.path.dirname(filename), exist_ok=True)
173
+ with open(filename, "w") as fp:
174
+ fp.write(data)
175
+
176
+ sidebar_items = []
177
+ for item in items:
178
+ if item.in_sidebar:
179
+ sidebar_items.append(
180
+ {
181
+ "label": item.label,
182
+ "category": item.category.value,
183
+ }
184
+ )
185
+ _write_file(f"{item.label}.md", item.document)
186
+
187
+ sidebar_data = {"items": sidebar_items}
188
+ _write_file("sidebar.json", json.dumps(sidebar_data))
189
+
190
+
191
+ if __name__ == "__main__":
192
+ # running this module outputs docs to stdout for inspection, useful for debugging
193
+ run(None if len(sys.argv) <= 1 else sys.argv[1])
@@ -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 = 46 # git: 8736584
4
+ build_number = 47 # git: 985591d