modal 1.1.2.dev28__py3-none-any.whl → 1.1.2.dev31__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/app.py CHANGED
@@ -931,13 +931,16 @@ class _App:
931
931
 
932
932
  if wrapped_cls.flags & _PartialFunctionFlags.CLUSTERED:
933
933
  cluster_size = wrapped_cls.params.cluster_size
934
+ rdma = wrapped_cls.params.rdma
934
935
  else:
935
936
  cluster_size = None
937
+ rdma = None
936
938
  else:
937
939
  user_cls = wrapped_cls
938
940
  max_concurrent_inputs = allow_concurrent_inputs
939
941
  target_concurrent_inputs = None
940
942
  cluster_size = None
943
+ rdma = None
941
944
  if not inspect.isclass(user_cls):
942
945
  raise TypeError("The @app.cls decorator must be used on a class.")
943
946
 
@@ -1007,6 +1010,7 @@ class _App:
1007
1010
  scheduler_placement=scheduler_placement,
1008
1011
  i6pn_enabled=i6pn_enabled,
1009
1012
  cluster_size=cluster_size,
1013
+ rdma=rdma,
1010
1014
  include_source=include_source if include_source is not None else self._include_source_default,
1011
1015
  experimental_options={k: str(v) for k, v in (experimental_options or {}).items()},
1012
1016
  _experimental_proxy_ip=_experimental_proxy_ip,
modal/cli/launch.py CHANGED
@@ -123,7 +123,7 @@ def vscode(
123
123
  _launch_program("vscode", "vscode.py", detach, args)
124
124
 
125
125
 
126
- @launch_cli.command(name="machine", help="Start an instance on Modal, with direct SSH access.")
126
+ @launch_cli.command(name="machine", help="Start an instance on Modal, with direct SSH access.", hidden=True)
127
127
  def machine(
128
128
  name: str, # Name of the machine App.
129
129
  cpu: int = 8, # Reservation of CPU cores (can burst above this value).
@@ -170,7 +170,7 @@ def machine(
170
170
  )
171
171
 
172
172
 
173
- @launch_cli.command(name="marimo", help="Start a remote Marimo notebook on Modal.")
173
+ @launch_cli.command(name="marimo", help="Start a remote Marimo notebook on Modal.", hidden=True)
174
174
  def marimo(
175
175
  cpu: int = 8,
176
176
  memory: int = 32768,
modal/client.pyi CHANGED
@@ -33,7 +33,7 @@ class _Client:
33
33
  server_url: str,
34
34
  client_type: int,
35
35
  credentials: typing.Optional[tuple[str, str]],
36
- version: str = "1.1.2.dev28",
36
+ version: str = "1.1.2.dev31",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -164,7 +164,7 @@ class Client:
164
164
  server_url: str,
165
165
  client_type: int,
166
166
  credentials: typing.Optional[tuple[str, str]],
167
- version: str = "1.1.2.dev28",
167
+ version: str = "1.1.2.dev31",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
modal/dict.py CHANGED
@@ -5,7 +5,7 @@ from datetime import datetime
5
5
  from typing import Any, Optional, Union
6
6
 
7
7
  from google.protobuf.message import Message
8
- from grpclib import GRPCError
8
+ from grpclib import GRPCError, Status
9
9
  from synchronicity import classproperty
10
10
  from synchronicity.async_wrap import asynccontextmanager
11
11
 
@@ -27,7 +27,7 @@ from ._utils.name_utils import check_object_name
27
27
  from ._utils.time_utils import as_timestamp, timestamp_to_localized_dt
28
28
  from .client import _Client
29
29
  from .config import logger
30
- from .exception import InvalidError, NotFoundError, RequestSizeError
30
+ from .exception import AlreadyExistsError, InvalidError, NotFoundError, RequestSizeError
31
31
 
32
32
 
33
33
  def _serialize_dict(data):
@@ -49,6 +49,58 @@ class DictInfo:
49
49
  class _DictManager:
50
50
  """Namespace with methods for managing named Dict objects."""
51
51
 
52
+ @staticmethod
53
+ async def create(
54
+ name: str, # Name to use for the new Dict
55
+ *,
56
+ allow_existing: bool = False, # If True, no-op when the Dict already exists
57
+ environment_name: Optional[str] = None, # Uses active environment if not specified
58
+ client: Optional[_Client] = None, # Optional client with Modal credentials
59
+ ) -> None:
60
+ """Create a new Dict object.
61
+
62
+ **Examples:**
63
+
64
+ ```python notest
65
+ modal.Dict.objects.create("my-dict")
66
+ ```
67
+
68
+ Dicts will be created in the active environment, or another one can be specified:
69
+
70
+ ```python notest
71
+ modal.Dict.objects.create("my-dict", environment_name="dev")
72
+ ```
73
+
74
+ By default, an error will be raised if the Dict already exists, but passing
75
+ `allow_existing=True` will make the creation attempt a no-op in this case.
76
+
77
+ ```python notest
78
+ modal.Dict.objects.create("my-dict", allow_existing=True)
79
+ ```
80
+
81
+ Note that this method does not return a local instance of the Dict. You can use
82
+ `modal.Dict.from_name` to perform a lookup after creation.
83
+
84
+ """
85
+ client = await _Client.from_env() if client is None else client
86
+ object_creation_type = (
87
+ api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING
88
+ if allow_existing
89
+ else api_pb2.OBJECT_CREATION_TYPE_CREATE_FAIL_IF_EXISTS
90
+ )
91
+ req = api_pb2.DictGetOrCreateRequest(
92
+ deployment_name=name,
93
+ environment_name=_get_environment_name(environment_name),
94
+ object_creation_type=object_creation_type,
95
+ )
96
+ try:
97
+ await retry_transient_errors(client.stub.DictGetOrCreate, req)
98
+ except GRPCError as exc:
99
+ if exc.status == Status.ALREADY_EXISTS and not allow_existing:
100
+ raise AlreadyExistsError(exc.message)
101
+ else:
102
+ raise
103
+
52
104
  @staticmethod
53
105
  async def list(
54
106
  *,
@@ -89,7 +141,9 @@ class _DictManager:
89
141
  async def retrieve_page(created_before: float) -> bool:
90
142
  max_page_size = 100 if max_objects is None else min(100, max_objects - len(items))
91
143
  pagination = api_pb2.ListPagination(max_objects=max_page_size, created_before=created_before)
92
- req = api_pb2.DictListRequest(environment_name=environment_name, pagination=pagination)
144
+ req = api_pb2.DictListRequest(
145
+ environment_name=_get_environment_name(environment_name), pagination=pagination
146
+ )
93
147
  resp = await retry_transient_errors(client.stub.DictList, req)
94
148
  items.extend(resp.dicts)
95
149
  finished = (len(resp.dicts) < max_page_size) or (max_objects is not None and len(items) >= max_objects)
modal/dict.pyi CHANGED
@@ -35,6 +35,40 @@ class DictInfo:
35
35
 
36
36
  class _DictManager:
37
37
  """Namespace with methods for managing named Dict objects."""
38
+ @staticmethod
39
+ async def create(
40
+ name: str,
41
+ *,
42
+ allow_existing: bool = False,
43
+ environment_name: typing.Optional[str] = None,
44
+ client: typing.Optional[modal.client._Client] = None,
45
+ ) -> None:
46
+ """Create a new Dict object.
47
+
48
+ **Examples:**
49
+
50
+ ```python notest
51
+ modal.Dict.objects.create("my-dict")
52
+ ```
53
+
54
+ Dicts will be created in the active environment, or another one can be specified:
55
+
56
+ ```python notest
57
+ modal.Dict.objects.create("my-dict", environment_name="dev")
58
+ ```
59
+
60
+ By default, an error will be raised if the Dict already exists, but passing
61
+ `allow_existing=True` will make the creation attempt a no-op in this case.
62
+
63
+ ```python notest
64
+ modal.Dict.objects.create("my-dict", allow_existing=True)
65
+ ```
66
+
67
+ Note that this method does not return a local instance of the Dict. You can use
68
+ `modal.Dict.from_name` to perform a lookup after creation.
69
+ """
70
+ ...
71
+
38
72
  @staticmethod
39
73
  async def list(
40
74
  *,
@@ -100,6 +134,79 @@ class DictManager:
100
134
  """Initialize self. See help(type(self)) for accurate signature."""
101
135
  ...
102
136
 
137
+ class __create_spec(typing_extensions.Protocol):
138
+ def __call__(
139
+ self,
140
+ /,
141
+ name: str,
142
+ *,
143
+ allow_existing: bool = False,
144
+ environment_name: typing.Optional[str] = None,
145
+ client: typing.Optional[modal.client.Client] = None,
146
+ ) -> None:
147
+ """Create a new Dict object.
148
+
149
+ **Examples:**
150
+
151
+ ```python notest
152
+ modal.Dict.objects.create("my-dict")
153
+ ```
154
+
155
+ Dicts will be created in the active environment, or another one can be specified:
156
+
157
+ ```python notest
158
+ modal.Dict.objects.create("my-dict", environment_name="dev")
159
+ ```
160
+
161
+ By default, an error will be raised if the Dict already exists, but passing
162
+ `allow_existing=True` will make the creation attempt a no-op in this case.
163
+
164
+ ```python notest
165
+ modal.Dict.objects.create("my-dict", allow_existing=True)
166
+ ```
167
+
168
+ Note that this method does not return a local instance of the Dict. You can use
169
+ `modal.Dict.from_name` to perform a lookup after creation.
170
+ """
171
+ ...
172
+
173
+ async def aio(
174
+ self,
175
+ /,
176
+ name: str,
177
+ *,
178
+ allow_existing: bool = False,
179
+ environment_name: typing.Optional[str] = None,
180
+ client: typing.Optional[modal.client.Client] = None,
181
+ ) -> None:
182
+ """Create a new Dict object.
183
+
184
+ **Examples:**
185
+
186
+ ```python notest
187
+ modal.Dict.objects.create("my-dict")
188
+ ```
189
+
190
+ Dicts will be created in the active environment, or another one can be specified:
191
+
192
+ ```python notest
193
+ modal.Dict.objects.create("my-dict", environment_name="dev")
194
+ ```
195
+
196
+ By default, an error will be raised if the Dict already exists, but passing
197
+ `allow_existing=True` will make the creation attempt a no-op in this case.
198
+
199
+ ```python notest
200
+ modal.Dict.objects.create("my-dict", allow_existing=True)
201
+ ```
202
+
203
+ Note that this method does not return a local instance of the Dict. You can use
204
+ `modal.Dict.from_name` to perform a lookup after creation.
205
+ """
206
+ ...
207
+
208
+ create: __create_spec
209
+
103
210
  class __list_spec(typing_extensions.Protocol):
104
211
  def __call__(
105
212
  self,
modal/queue.py CHANGED
@@ -29,7 +29,7 @@ from ._utils.grpc_utils import retry_transient_errors
29
29
  from ._utils.name_utils import check_object_name
30
30
  from ._utils.time_utils import as_timestamp, timestamp_to_localized_dt
31
31
  from .client import _Client
32
- from .exception import InvalidError, NotFoundError, RequestSizeError
32
+ from .exception import AlreadyExistsError, InvalidError, NotFoundError, RequestSizeError
33
33
 
34
34
 
35
35
  @dataclass
@@ -47,10 +47,62 @@ class QueueInfo:
47
47
  class _QueueManager:
48
48
  """Namespace with methods for managing named Queue objects."""
49
49
 
50
+ @staticmethod
51
+ async def create(
52
+ name: str, # Name to use for the new Queue
53
+ *,
54
+ allow_existing: bool = False, # If True, no-op when the Queue already exists
55
+ environment_name: Optional[str] = None, # Uses active environment if not specified
56
+ client: Optional[_Client] = None, # Optional client with Modal credentials
57
+ ) -> None:
58
+ """Create a new Queue object.
59
+
60
+ **Examples:**
61
+
62
+ ```python notest
63
+ modal.Queue.objects.create("my-queue")
64
+ ```
65
+
66
+ Queues will be created in the active environment, or another one can be specified:
67
+
68
+ ```python notest
69
+ modal.Queue.objects.create("my-queue", environment_name="dev")
70
+ ```
71
+
72
+ By default, an error will be raised if the Queue already exists, but passing
73
+ `allow_existing=True` will make the creation attempt a no-op in this case.
74
+
75
+ ```python notest
76
+ modal.Queue.objects.create("my-queue", allow_existing=True)
77
+ ```
78
+
79
+ Note that this method does not return a local instance of the Queue. You can use
80
+ `modal.Queue.from_name` to perform a lookup after creation.
81
+
82
+ """
83
+ client = await _Client.from_env() if client is None else client
84
+ object_creation_type = (
85
+ api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING
86
+ if allow_existing
87
+ else api_pb2.OBJECT_CREATION_TYPE_CREATE_FAIL_IF_EXISTS
88
+ )
89
+ req = api_pb2.QueueGetOrCreateRequest(
90
+ deployment_name=name,
91
+ environment_name=_get_environment_name(environment_name),
92
+ object_creation_type=object_creation_type,
93
+ )
94
+ try:
95
+ await retry_transient_errors(client.stub.QueueGetOrCreate, req)
96
+ except GRPCError as exc:
97
+ if exc.status == Status.ALREADY_EXISTS and not allow_existing:
98
+ raise AlreadyExistsError(exc.message)
99
+ else:
100
+ raise
101
+
50
102
  @staticmethod
51
103
  async def list(
52
104
  *,
53
- max_objects: Optional[int] = None, # Limit requests to this size
105
+ max_objects: Optional[int] = None, # Limit results to this size
54
106
  created_before: Optional[Union[datetime, str]] = None, # Limit based on creation date
55
107
  environment_name: str = "", # Uses active environment if not specified
56
108
  client: Optional[_Client] = None, # Optional client with Modal credentials
@@ -87,7 +139,9 @@ class _QueueManager:
87
139
  async def retrieve_page(created_before: float) -> bool:
88
140
  max_page_size = 100 if max_objects is None else min(100, max_objects - len(items))
89
141
  pagination = api_pb2.ListPagination(max_objects=max_page_size, created_before=created_before)
90
- req = api_pb2.QueueListRequest(environment_name=environment_name, pagination=pagination)
142
+ req = api_pb2.QueueListRequest(
143
+ environment_name=_get_environment_name(environment_name), pagination=pagination
144
+ )
91
145
  resp = await retry_transient_errors(client.stub.QueueList, req)
92
146
  items.extend(resp.queues)
93
147
  finished = (len(resp.queues) < max_page_size) or (max_objects is not None and len(items) >= max_objects)
modal/queue.pyi CHANGED
@@ -33,6 +33,40 @@ class QueueInfo:
33
33
 
34
34
  class _QueueManager:
35
35
  """Namespace with methods for managing named Queue objects."""
36
+ @staticmethod
37
+ async def create(
38
+ name: str,
39
+ *,
40
+ allow_existing: bool = False,
41
+ environment_name: typing.Optional[str] = None,
42
+ client: typing.Optional[modal.client._Client] = None,
43
+ ) -> None:
44
+ """Create a new Queue object.
45
+
46
+ **Examples:**
47
+
48
+ ```python notest
49
+ modal.Queue.objects.create("my-queue")
50
+ ```
51
+
52
+ Queues will be created in the active environment, or another one can be specified:
53
+
54
+ ```python notest
55
+ modal.Queue.objects.create("my-queue", environment_name="dev")
56
+ ```
57
+
58
+ By default, an error will be raised if the Queue already exists, but passing
59
+ `allow_existing=True` will make the creation attempt a no-op in this case.
60
+
61
+ ```python notest
62
+ modal.Queue.objects.create("my-queue", allow_existing=True)
63
+ ```
64
+
65
+ Note that this method does not return a local instance of the Queue. You can use
66
+ `modal.Queue.from_name` to perform a lookup after creation.
67
+ """
68
+ ...
69
+
36
70
  @staticmethod
37
71
  async def list(
38
72
  *,
@@ -98,6 +132,79 @@ class QueueManager:
98
132
  """Initialize self. See help(type(self)) for accurate signature."""
99
133
  ...
100
134
 
135
+ class __create_spec(typing_extensions.Protocol):
136
+ def __call__(
137
+ self,
138
+ /,
139
+ name: str,
140
+ *,
141
+ allow_existing: bool = False,
142
+ environment_name: typing.Optional[str] = None,
143
+ client: typing.Optional[modal.client.Client] = None,
144
+ ) -> None:
145
+ """Create a new Queue object.
146
+
147
+ **Examples:**
148
+
149
+ ```python notest
150
+ modal.Queue.objects.create("my-queue")
151
+ ```
152
+
153
+ Queues will be created in the active environment, or another one can be specified:
154
+
155
+ ```python notest
156
+ modal.Queue.objects.create("my-queue", environment_name="dev")
157
+ ```
158
+
159
+ By default, an error will be raised if the Queue already exists, but passing
160
+ `allow_existing=True` will make the creation attempt a no-op in this case.
161
+
162
+ ```python notest
163
+ modal.Queue.objects.create("my-queue", allow_existing=True)
164
+ ```
165
+
166
+ Note that this method does not return a local instance of the Queue. You can use
167
+ `modal.Queue.from_name` to perform a lookup after creation.
168
+ """
169
+ ...
170
+
171
+ async def aio(
172
+ self,
173
+ /,
174
+ name: str,
175
+ *,
176
+ allow_existing: bool = False,
177
+ environment_name: typing.Optional[str] = None,
178
+ client: typing.Optional[modal.client.Client] = None,
179
+ ) -> None:
180
+ """Create a new Queue object.
181
+
182
+ **Examples:**
183
+
184
+ ```python notest
185
+ modal.Queue.objects.create("my-queue")
186
+ ```
187
+
188
+ Queues will be created in the active environment, or another one can be specified:
189
+
190
+ ```python notest
191
+ modal.Queue.objects.create("my-queue", environment_name="dev")
192
+ ```
193
+
194
+ By default, an error will be raised if the Queue already exists, but passing
195
+ `allow_existing=True` will make the creation attempt a no-op in this case.
196
+
197
+ ```python notest
198
+ modal.Queue.objects.create("my-queue", allow_existing=True)
199
+ ```
200
+
201
+ Note that this method does not return a local instance of the Queue. You can use
202
+ `modal.Queue.from_name` to perform a lookup after creation.
203
+ """
204
+ ...
205
+
206
+ create: __create_spec
207
+
101
208
  class __list_spec(typing_extensions.Protocol):
102
209
  def __call__(
103
210
  self,
modal/secret.py CHANGED
@@ -19,7 +19,7 @@ from ._utils.grpc_utils import retry_transient_errors
19
19
  from ._utils.name_utils import check_object_name
20
20
  from ._utils.time_utils import as_timestamp, timestamp_to_localized_dt
21
21
  from .client import _Client
22
- from .exception import InvalidError, NotFoundError
22
+ from .exception import AlreadyExistsError, InvalidError, NotFoundError
23
23
 
24
24
  ENV_DICT_WRONG_TYPE_ERR = "the env_dict argument to Secret has to be a dict[str, Union[str, None]]"
25
25
 
@@ -39,6 +39,62 @@ class SecretInfo:
39
39
  class _SecretManager:
40
40
  """Namespace with methods for managing named Secret objects."""
41
41
 
42
+ @staticmethod
43
+ async def create(
44
+ name: str, # Name to use for the new Secret
45
+ env_dict: dict[str, str], # Key-value pairs to set in the Secret
46
+ *,
47
+ allow_existing: bool = False, # If True, no-op when the Secret already exists
48
+ environment_name: Optional[str] = None, # Uses active environment if not specified
49
+ client: Optional[_Client] = None, # Optional client with Modal credentials
50
+ ) -> None:
51
+ """Create a new Secret object.
52
+
53
+ **Examples:**
54
+
55
+ ```python notest
56
+ contents = {"MY_KEY": "my-value", "MY_OTHER_KEY": "my-other-value"}
57
+ modal.Secret.objects.create("my-secret", contents)
58
+ ```
59
+
60
+ Secrets will be created in the active environment, or another one can be specified:
61
+
62
+ ```python notest
63
+ modal.Secret.objects.create("my-secret", contents, environment_name="dev")
64
+ ```
65
+
66
+ By default, an error will be raised if the Secret already exists, but passing
67
+ `allow_existing=True` will make the creation attempt a no-op in this case.
68
+ If the `env_dict` data differs from the existing Secret, it will be ignored.
69
+
70
+ ```python notest
71
+ modal.Secret.objects.create("my-secret", contents, allow_existing=True)
72
+ ```
73
+
74
+ Note that this method does not return a local instance of the Secret. You can use
75
+ `modal.Secret.from_name` to perform a lookup after creation.
76
+
77
+ """
78
+ client = await _Client.from_env() if client is None else client
79
+ object_creation_type = (
80
+ api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING
81
+ if allow_existing
82
+ else api_pb2.OBJECT_CREATION_TYPE_CREATE_FAIL_IF_EXISTS
83
+ )
84
+ req = api_pb2.SecretGetOrCreateRequest(
85
+ deployment_name=name,
86
+ environment_name=_get_environment_name(environment_name),
87
+ object_creation_type=object_creation_type,
88
+ env_dict=env_dict,
89
+ )
90
+ try:
91
+ await retry_transient_errors(client.stub.SecretGetOrCreate, req)
92
+ except GRPCError as exc:
93
+ if exc.status == Status.ALREADY_EXISTS and not allow_existing:
94
+ raise AlreadyExistsError(exc.message)
95
+ else:
96
+ raise
97
+
42
98
  @staticmethod
43
99
  async def list(
44
100
  *,
@@ -79,7 +135,9 @@ class _SecretManager:
79
135
  async def retrieve_page(created_before: float) -> bool:
80
136
  max_page_size = 100 if max_objects is None else min(100, max_objects - len(items))
81
137
  pagination = api_pb2.ListPagination(max_objects=max_page_size, created_before=created_before)
82
- req = api_pb2.SecretListRequest(environment_name=environment_name, pagination=pagination)
138
+ req = api_pb2.SecretListRequest(
139
+ environment_name=_get_environment_name(environment_name), pagination=pagination
140
+ )
83
141
  resp = await retry_transient_errors(client.stub.SecretList, req)
84
142
  items.extend(resp.items)
85
143
  finished = (len(resp.items) < max_page_size) or (max_objects is not None and len(items) >= max_objects)
modal/secret.pyi CHANGED
@@ -31,6 +31,43 @@ class SecretInfo:
31
31
 
32
32
  class _SecretManager:
33
33
  """Namespace with methods for managing named Secret objects."""
34
+ @staticmethod
35
+ async def create(
36
+ name: str,
37
+ env_dict: dict[str, str],
38
+ *,
39
+ allow_existing: bool = False,
40
+ environment_name: typing.Optional[str] = None,
41
+ client: typing.Optional[modal.client._Client] = None,
42
+ ) -> None:
43
+ """Create a new Secret object.
44
+
45
+ **Examples:**
46
+
47
+ ```python notest
48
+ contents = {"MY_KEY": "my-value", "MY_OTHER_KEY": "my-other-value"}
49
+ modal.Secret.objects.create("my-secret", contents)
50
+ ```
51
+
52
+ Secrets will be created in the active environment, or another one can be specified:
53
+
54
+ ```python notest
55
+ modal.Secret.objects.create("my-secret", contents, environment_name="dev")
56
+ ```
57
+
58
+ By default, an error will be raised if the Secret already exists, but passing
59
+ `allow_existing=True` will make the creation attempt a no-op in this case.
60
+ If the `env_dict` data differs from the existing Secret, it will be ignored.
61
+
62
+ ```python notest
63
+ modal.Secret.objects.create("my-secret", contents, allow_existing=True)
64
+ ```
65
+
66
+ Note that this method does not return a local instance of the Secret. You can use
67
+ `modal.Secret.from_name` to perform a lookup after creation.
68
+ """
69
+ ...
70
+
34
71
  @staticmethod
35
72
  async def list(
36
73
  *,
@@ -95,6 +132,85 @@ class SecretManager:
95
132
  """Initialize self. See help(type(self)) for accurate signature."""
96
133
  ...
97
134
 
135
+ class __create_spec(typing_extensions.Protocol):
136
+ def __call__(
137
+ self,
138
+ /,
139
+ name: str,
140
+ env_dict: dict[str, str],
141
+ *,
142
+ allow_existing: bool = False,
143
+ environment_name: typing.Optional[str] = None,
144
+ client: typing.Optional[modal.client.Client] = None,
145
+ ) -> None:
146
+ """Create a new Secret object.
147
+
148
+ **Examples:**
149
+
150
+ ```python notest
151
+ contents = {"MY_KEY": "my-value", "MY_OTHER_KEY": "my-other-value"}
152
+ modal.Secret.objects.create("my-secret", contents)
153
+ ```
154
+
155
+ Secrets will be created in the active environment, or another one can be specified:
156
+
157
+ ```python notest
158
+ modal.Secret.objects.create("my-secret", contents, environment_name="dev")
159
+ ```
160
+
161
+ By default, an error will be raised if the Secret already exists, but passing
162
+ `allow_existing=True` will make the creation attempt a no-op in this case.
163
+ If the `env_dict` data differs from the existing Secret, it will be ignored.
164
+
165
+ ```python notest
166
+ modal.Secret.objects.create("my-secret", contents, allow_existing=True)
167
+ ```
168
+
169
+ Note that this method does not return a local instance of the Secret. You can use
170
+ `modal.Secret.from_name` to perform a lookup after creation.
171
+ """
172
+ ...
173
+
174
+ async def aio(
175
+ self,
176
+ /,
177
+ name: str,
178
+ env_dict: dict[str, str],
179
+ *,
180
+ allow_existing: bool = False,
181
+ environment_name: typing.Optional[str] = None,
182
+ client: typing.Optional[modal.client.Client] = None,
183
+ ) -> None:
184
+ """Create a new Secret object.
185
+
186
+ **Examples:**
187
+
188
+ ```python notest
189
+ contents = {"MY_KEY": "my-value", "MY_OTHER_KEY": "my-other-value"}
190
+ modal.Secret.objects.create("my-secret", contents)
191
+ ```
192
+
193
+ Secrets will be created in the active environment, or another one can be specified:
194
+
195
+ ```python notest
196
+ modal.Secret.objects.create("my-secret", contents, environment_name="dev")
197
+ ```
198
+
199
+ By default, an error will be raised if the Secret already exists, but passing
200
+ `allow_existing=True` will make the creation attempt a no-op in this case.
201
+ If the `env_dict` data differs from the existing Secret, it will be ignored.
202
+
203
+ ```python notest
204
+ modal.Secret.objects.create("my-secret", contents, allow_existing=True)
205
+ ```
206
+
207
+ Note that this method does not return a local instance of the Secret. You can use
208
+ `modal.Secret.from_name` to perform a lookup after creation.
209
+ """
210
+ ...
211
+
212
+ create: __create_spec
213
+
98
214
  class __list_spec(typing_extensions.Protocol):
99
215
  def __call__(
100
216
  self,
modal/volume.py CHANGED
@@ -30,7 +30,7 @@ from synchronicity.async_wrap import asynccontextmanager
30
30
 
31
31
  import modal.exception
32
32
  import modal_proto.api_pb2
33
- from modal.exception import InvalidError, NotFoundError, VolumeUploadTimeoutError
33
+ from modal.exception import AlreadyExistsError, InvalidError, NotFoundError, VolumeUploadTimeoutError
34
34
  from modal_proto import api_pb2
35
35
 
36
36
  from ._object import (
@@ -116,6 +116,57 @@ class VolumeInfo:
116
116
  class _VolumeManager:
117
117
  """Namespace with methods for managing named Volume objects."""
118
118
 
119
+ @staticmethod
120
+ async def create(
121
+ name: str, # Name to use for the new Volume
122
+ *,
123
+ allow_existing: bool = False, # If True, no-op when the Volume already exists
124
+ environment_name: Optional[str] = None, # Uses active environment if not specified
125
+ client: Optional[_Client] = None, # Optional client with Modal credentials
126
+ ) -> None:
127
+ """Create a new Volume object.
128
+
129
+ **Examples:**
130
+
131
+ ```python notest
132
+ modal.Volume.objects.create("my-volume")
133
+ ```
134
+
135
+ Volumes will be created in the active environment, or another one can be specified:
136
+
137
+ ```python notest
138
+ modal.Volume.objects.create("my-volume", environment_name="dev")
139
+ ```
140
+
141
+ `allow_existing=True` will make the creation attempt a no-op in this case.
142
+
143
+ ```python notest
144
+ modal.Volume.objects.create("my-volume", allow_existing=True)
145
+ ```
146
+
147
+ Note that this method does not return a local instance of the Volume. You can use
148
+ `modal.Volume.from_name` to perform a lookup after creation.
149
+
150
+ """
151
+ client = await _Client.from_env() if client is None else client
152
+ object_creation_type = (
153
+ api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING
154
+ if allow_existing
155
+ else api_pb2.OBJECT_CREATION_TYPE_CREATE_FAIL_IF_EXISTS
156
+ )
157
+ req = api_pb2.VolumeGetOrCreateRequest(
158
+ deployment_name=name,
159
+ environment_name=_get_environment_name(environment_name),
160
+ object_creation_type=object_creation_type,
161
+ )
162
+ try:
163
+ await retry_transient_errors(client.stub.VolumeGetOrCreate, req)
164
+ except GRPCError as exc:
165
+ if exc.status == Status.ALREADY_EXISTS and not allow_existing:
166
+ raise AlreadyExistsError(exc.message)
167
+ else:
168
+ raise
169
+
119
170
  @staticmethod
120
171
  async def list(
121
172
  *,
@@ -156,7 +207,9 @@ class _VolumeManager:
156
207
  async def retrieve_page(created_before: float) -> bool:
157
208
  max_page_size = 100 if max_objects is None else min(100, max_objects - len(items))
158
209
  pagination = api_pb2.ListPagination(max_objects=max_page_size, created_before=created_before)
159
- req = api_pb2.VolumeListRequest(environment_name=environment_name, pagination=pagination)
210
+ req = api_pb2.VolumeListRequest(
211
+ environment_name=_get_environment_name(environment_name), pagination=pagination
212
+ )
160
213
  resp = await retry_transient_errors(client.stub.VolumeList, req)
161
214
  items.extend(resp.items)
162
215
  finished = (len(resp.items) < max_page_size) or (max_objects is not None and len(items) >= max_objects)
modal/volume.pyi CHANGED
@@ -82,6 +82,39 @@ class VolumeInfo:
82
82
 
83
83
  class _VolumeManager:
84
84
  """Namespace with methods for managing named Volume objects."""
85
+ @staticmethod
86
+ async def create(
87
+ name: str,
88
+ *,
89
+ allow_existing: bool = False,
90
+ environment_name: typing.Optional[str] = None,
91
+ client: typing.Optional[modal.client._Client] = None,
92
+ ) -> None:
93
+ """Create a new Volume object.
94
+
95
+ **Examples:**
96
+
97
+ ```python notest
98
+ modal.Volume.objects.create("my-volume")
99
+ ```
100
+
101
+ Volumes will be created in the active environment, or another one can be specified:
102
+
103
+ ```python notest
104
+ modal.Volume.objects.create("my-volume", environment_name="dev")
105
+ ```
106
+
107
+ `allow_existing=True` will make the creation attempt a no-op in this case.
108
+
109
+ ```python notest
110
+ modal.Volume.objects.create("my-volume", allow_existing=True)
111
+ ```
112
+
113
+ Note that this method does not return a local instance of the Volume. You can use
114
+ `modal.Volume.from_name` to perform a lookup after creation.
115
+ """
116
+ ...
117
+
85
118
  @staticmethod
86
119
  async def list(
87
120
  *,
@@ -147,6 +180,77 @@ class VolumeManager:
147
180
  """Initialize self. See help(type(self)) for accurate signature."""
148
181
  ...
149
182
 
183
+ class __create_spec(typing_extensions.Protocol):
184
+ def __call__(
185
+ self,
186
+ /,
187
+ name: str,
188
+ *,
189
+ allow_existing: bool = False,
190
+ environment_name: typing.Optional[str] = None,
191
+ client: typing.Optional[modal.client.Client] = None,
192
+ ) -> None:
193
+ """Create a new Volume object.
194
+
195
+ **Examples:**
196
+
197
+ ```python notest
198
+ modal.Volume.objects.create("my-volume")
199
+ ```
200
+
201
+ Volumes will be created in the active environment, or another one can be specified:
202
+
203
+ ```python notest
204
+ modal.Volume.objects.create("my-volume", environment_name="dev")
205
+ ```
206
+
207
+ `allow_existing=True` will make the creation attempt a no-op in this case.
208
+
209
+ ```python notest
210
+ modal.Volume.objects.create("my-volume", allow_existing=True)
211
+ ```
212
+
213
+ Note that this method does not return a local instance of the Volume. You can use
214
+ `modal.Volume.from_name` to perform a lookup after creation.
215
+ """
216
+ ...
217
+
218
+ async def aio(
219
+ self,
220
+ /,
221
+ name: str,
222
+ *,
223
+ allow_existing: bool = False,
224
+ environment_name: typing.Optional[str] = None,
225
+ client: typing.Optional[modal.client.Client] = None,
226
+ ) -> None:
227
+ """Create a new Volume object.
228
+
229
+ **Examples:**
230
+
231
+ ```python notest
232
+ modal.Volume.objects.create("my-volume")
233
+ ```
234
+
235
+ Volumes will be created in the active environment, or another one can be specified:
236
+
237
+ ```python notest
238
+ modal.Volume.objects.create("my-volume", environment_name="dev")
239
+ ```
240
+
241
+ `allow_existing=True` will make the creation attempt a no-op in this case.
242
+
243
+ ```python notest
244
+ modal.Volume.objects.create("my-volume", allow_existing=True)
245
+ ```
246
+
247
+ Note that this method does not return a local instance of the Volume. You can use
248
+ `modal.Volume.from_name` to perform a lookup after creation.
249
+ """
250
+ ...
251
+
252
+ create: __create_spec
253
+
150
254
  class __list_spec(typing_extensions.Protocol):
151
255
  def __call__(
152
256
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.2.dev28
3
+ Version: 1.1.2.dev31
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -18,11 +18,11 @@ modal/_tunnel.py,sha256=zTBxBiuH1O22tS1OliAJdIsSmaZS8PlnifS_6S5z-mk,6320
18
18
  modal/_tunnel.pyi,sha256=rvC7USR2BcKkbZIeCJXwf7-UfGE-LPLjKsGNiK7Lxa4,13366
19
19
  modal/_type_manager.py,sha256=DWjgmjYJuOagw2erin506UUbG2H5UzZCFEekS-7hmfA,9087
20
20
  modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
21
- modal/app.py,sha256=GsClEQIs8i0K-n-DxkCO3flV2xq36sejFd4Dtjxfw0U,47914
21
+ modal/app.py,sha256=NIkdg9tTBsB8xWEOpU8GSpUfHeGleA4M9MQ77PKADok,48052
22
22
  modal/app.pyi,sha256=k0HnXfwV3mEze3PFHmSeqXBqizNqeJWF5oxrqo-P4Wg,43447
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=kyAIVB3Ay-XKJizQ_1ufUFB__EagV0MLmHJpyYyJ7J0,18636
25
- modal/client.pyi,sha256=CDXxQDatqOQa6AUXFGQ1p6qZKhUA3AW3o3fxeYf8SNY,15831
25
+ modal/client.pyi,sha256=-NEyp-OU4a6-yWdgX4T875NFAttgOw2gVzp807aEEQQ,15831
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=-qSfYAQvIoO_l2wsCCGTG5ZUwQieNKXdAO00yP1-LYU,7394
28
28
  modal/cls.py,sha256=1mBcExFrLDTZwkD3Dzu8F26_CL0CGktOV9pE60Y8g_E,40689
@@ -30,8 +30,8 @@ modal/cls.pyi,sha256=TevKBrBez2R0_4Epsx5GB5gyQX_kQV-uVHPxpqEokhQ,28357
30
30
  modal/config.py,sha256=tW-SEGjVvAt3D_MNi3LhxXnFKIA9fjLd3UIgbW8uSJE,12121
31
31
  modal/container_process.py,sha256=XkPwNIW-iD_GB9u9yqv9q8y-i5cQ8eBbLZZ_GvEw9t8,6858
32
32
  modal/container_process.pyi,sha256=9m-st3hCUlNN1GOTctfPPvIvoLtEl7FbuGWwif5-7YU,6037
33
- modal/dict.py,sha256=wqgbV0K0wp-jPF6JLQGOnC7hYEJeV1BfoaqGyNy3DvY,20538
34
- modal/dict.pyi,sha256=zHj9XK1uv8PR8Vvd9-RmMMd52002SxoNjNsrK2Bn1OE,29914
33
+ modal/dict.py,sha256=eKd1I9J345s4kopPjT9Q8L-lDFOpaZKHhHkUwMLQq9E,22557
34
+ modal/dict.pyi,sha256=F9yxTgBjxLOy6boB3N4wc2BtnGIO1TARmyhpMBC8c80,33317
35
35
  modal/environments.py,sha256=gHFNLG78bqgizpQ4w_elz27QOqmcgAonFsmLs7NjUJ4,6804
36
36
  modal/environments.pyi,sha256=9-KtrzAcUe55cCP4020lSUD7-fWS7OPakAHssq4-bro,4219
37
37
  modal/exception.py,sha256=o0V93PK8Hcg2YQ2aeOB1Y-qWBw4Gz5ATfyokR8GapuQ,5634
@@ -59,8 +59,8 @@ modal/partial_function.pyi,sha256=lqqOzZ9-QvHTDWKQ_oAYYOvsXgTOBKhO9u-RI98JbUk,13
59
59
  modal/proxy.py,sha256=CQydu_NPDgApN2GLdd7rrcg8PM-pXyFdVYcTaGMBRCQ,1491
60
60
  modal/proxy.pyi,sha256=yWGWwADCRGrC2w81B7671UTH4Uv3HMZKy5vVqlJUZoA,1417
61
61
  modal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
- modal/queue.py,sha256=TJWkFtOVxg1gtlc40-wGVsYzY7PqQpaJXYSsI_-Rquw,24988
63
- modal/queue.pyi,sha256=cnnd5ZxZA3X0xT-igJbLC3p0TXATNwkJaXC8qCeFphQ,35815
62
+ modal/queue.py,sha256=gzpgtzCah0NgmUAFmUEvnHal5XnTri9Vblf334t2bAE,27013
63
+ modal/queue.pyi,sha256=BEbAa9Fb77Z6Th644FhMnf3BvfLuoBuUz6iUVCkbD1k,39251
64
64
  modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
65
65
  modal/runner.py,sha256=ostdzYpQb-20tlD6dIq7bpWTkZkOhjJBNuMNektqnJA,24068
66
66
  modal/runner.pyi,sha256=lbwLljm1cC8d6PcNvmYQhkE8501V9fg0bYqqKX6G4r4,8489
@@ -69,8 +69,8 @@ modal/sandbox.py,sha256=eQd0Cf9yTFCNshnj7oH8WvecbhVIwsEsmuXB9O-REis,40927
69
69
  modal/sandbox.pyi,sha256=_ddnvZGauSRG-WelsMB5oPil8KVWb0PSvmuAzAzrLIw,41713
70
70
  modal/schedule.py,sha256=ng0g0AqNY5GQI9KhkXZQ5Wam5G42glbkqVQsNpBtbDE,3078
71
71
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
72
- modal/secret.py,sha256=S_7Ck9J0yVqfBiaF2BUpqQ9NRBhxre19bWggl8PS7_Q,16146
73
- modal/secret.pyi,sha256=5YTMzaybIoBtOFhK2T2SuhhvHBbo4lDm8sBqH-rITtk,15912
72
+ modal/secret.py,sha256=Y6vMT7PUFdwCjVqAe9efxbVwKNjLk2yMLDV3HdnbdxI,18483
73
+ modal/secret.pyi,sha256=XDmES3SppQQ6Q8L6ySIg7uEv6AhmXFEnkIE-0rK8V2w,20080
74
74
  modal/serving.py,sha256=3I3WBeVbzZY258u9PXBCW_dZBgypq3OhwBuTVvlgubE,4423
75
75
  modal/serving.pyi,sha256=YfixTaWikyYpwhnNxCHMZnDDQiPmV1xJ87QF91U_WGU,1924
76
76
  modal/snapshot.py,sha256=E3oxYQkYVRB_LeFBfmUV1Y6vHz8-azXJfC4x7A1QKnI,1455
@@ -78,8 +78,8 @@ modal/snapshot.pyi,sha256=0q83hlmWxAhDu8xwZyL5VmYh0i8Tigf7S60or2k30L8,1682
78
78
  modal/stream_type.py,sha256=A6320qoAAWhEfwOCZfGtymQTu5AfLfJXXgARqooTPvY,417
79
79
  modal/token_flow.py,sha256=GWpar0gANs71vm9Bd_Cj87UG1K3ljTURbkEjG3JLsrY,7616
80
80
  modal/token_flow.pyi,sha256=eirYjyqbRiT3GCKMIPHJPpkvBTu8WxDKqSHehWaJI_4,2533
81
- modal/volume.py,sha256=yaFKNuwGAtLUiqBIl2NDnqVLscQSM76cjQejh6_lqCo,50051
82
- modal/volume.pyi,sha256=fnHhR152qCh5St7XT-PReQK_tPAQ0hmcXKoezOulEl4,49427
81
+ modal/volume.py,sha256=8Bw6q9_2lwWq5Vsykkor_0_MYMbVGlpH5DSuJ9TDwYw,52006
82
+ modal/volume.pyi,sha256=k4oEW0xzn6i1eY7nj6ppaGqo72FB3Pqm_OQb3juAgOk,52630
83
83
  modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
84
84
  modal/_runtime/asgi.py,sha256=_2xSTsDD27Cit7xnMs4lzkJA2wzer2_N4Oa3BkXFzVA,22521
85
85
  modal/_runtime/container_io_manager.py,sha256=9oqlKKPuLZjE7rYw3zTK30XUZighT3s4ZlA-9oxXOVI,45206
@@ -135,7 +135,7 @@ modal/cli/dict.py,sha256=YAJtiv41YcCd5Fqam3hXCNTs4Y0yOgGR_i6RfQNSAFM,4572
135
135
  modal/cli/entry_point.py,sha256=F06p54rPOs1xAUeYW76RaimFOgLW_I17RCvNwfZRqPc,4747
136
136
  modal/cli/environment.py,sha256=Ayddkiq9jdj3XYDJ8ZmUqFpPPH8xajYlbexRkzGtUcg,4334
137
137
  modal/cli/import_refs.py,sha256=X59Z5JwgliRO6C-cIFto2Pr7o3SwlZMKQPKA0aI4ZK4,13927
138
- modal/cli/launch.py,sha256=vlr6RHvXkmpUpO8anAyOxyvZUYYVZCJzqGjJ_jUwicY,6472
138
+ modal/cli/launch.py,sha256=VARim2SCzgtI1ZuxQ6JgTTtvFwGA5czCwQZQHWC8Zcc,6498
139
139
  modal/cli/network_file_system.py,sha256=I9IqTpVfk32uKYwGd8LTldkQx6UKYrQYNZ26q7Ab5Oo,8126
140
140
  modal/cli/profile.py,sha256=g8X6tFFK9ccKyu2he9Yu19WLSLNdztzECgmIV__XJFs,3257
141
141
  modal/cli/queues.py,sha256=5vKtKQ7YExdaxNPYZ0g5suU9sX0-F5h0zy0qBV-hN80,6140
@@ -153,7 +153,7 @@ modal/experimental/__init__.py,sha256=dPBPpxsmjZMLF3YjRrXoTvT01pl65wxi4UdFZsOem3
153
153
  modal/experimental/flash.py,sha256=viXQumCIFp5VFsPFURdFTBTjP_QnsAi8nSWXAMmfjeQ,19744
154
154
  modal/experimental/flash.pyi,sha256=A8_qJGtGoXEzKDdHbvhmCw7oqfneFEvJQK3ZdTOvUdU,10830
155
155
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
156
- modal-1.1.2.dev28.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
156
+ modal-1.1.2.dev31.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
157
157
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
158
158
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
159
159
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -176,10 +176,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
176
176
  modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
177
177
  modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
178
178
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
179
- modal_version/__init__.py,sha256=Lzj2VroIOH5TtrYecCtnuvFDtHrnlKvT93cqP_EA2po,121
179
+ modal_version/__init__.py,sha256=1iWHSfCuDUSKpjrPynU8jexFYr7sg8Kt9HenNY4atSw,121
180
180
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
181
- modal-1.1.2.dev28.dist-info/METADATA,sha256=pGEqonaaJntGeHYQb0Xn5NlV94JO6i5J05I8L0nde3E,2460
182
- modal-1.1.2.dev28.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
183
- modal-1.1.2.dev28.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
184
- modal-1.1.2.dev28.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
185
- modal-1.1.2.dev28.dist-info/RECORD,,
181
+ modal-1.1.2.dev31.dist-info/METADATA,sha256=hmVj12BvlRuB9oHUKzvbq3Wu3d2qPxeo8JItNuo2rvY,2460
182
+ modal-1.1.2.dev31.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
183
+ modal-1.1.2.dev31.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
184
+ modal-1.1.2.dev31.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
185
+ modal-1.1.2.dev31.dist-info/RECORD,,
modal_version/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.1.2.dev28"
4
+ __version__ = "1.1.2.dev31"