modal 1.0.4.dev12__py3-none-any.whl → 1.0.5__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/_clustered_functions.pyi +13 -3
- modal/_functions.py +84 -46
- modal/_partial_function.py +1 -1
- modal/_runtime/container_io_manager.pyi +222 -40
- modal/_runtime/execution_context.pyi +60 -6
- modal/_serialization.py +25 -2
- modal/_tunnel.pyi +380 -12
- modal/_utils/async_utils.py +1 -1
- modal/_utils/blob_utils.py +56 -19
- modal/_utils/function_utils.py +33 -7
- modal/_utils/grpc_utils.py +11 -4
- modal/app.py +5 -5
- modal/app.pyi +658 -48
- modal/cli/run.py +2 -1
- modal/client.pyi +224 -36
- modal/cloud_bucket_mount.pyi +192 -4
- modal/cls.py +7 -7
- modal/cls.pyi +442 -35
- modal/container_process.pyi +103 -14
- modal/dict.py +4 -4
- modal/dict.pyi +453 -51
- modal/environments.pyi +41 -9
- modal/exception.py +6 -2
- modal/experimental/__init__.py +90 -0
- modal/experimental/ipython.py +11 -7
- modal/file_io.pyi +236 -45
- modal/functions.pyi +573 -65
- modal/gpu.py +1 -1
- modal/image.py +1 -1
- modal/image.pyi +1256 -74
- modal/io_streams.py +8 -4
- modal/io_streams.pyi +348 -38
- modal/mount.pyi +261 -31
- modal/network_file_system.py +3 -3
- modal/network_file_system.pyi +307 -26
- modal/object.pyi +48 -9
- modal/parallel_map.py +93 -19
- modal/parallel_map.pyi +160 -15
- modal/partial_function.pyi +255 -14
- modal/proxy.py +1 -1
- modal/proxy.pyi +28 -3
- modal/queue.py +4 -4
- modal/queue.pyi +447 -30
- modal/runner.pyi +160 -22
- modal/sandbox.py +8 -7
- modal/sandbox.pyi +310 -50
- modal/schedule.py +1 -1
- modal/secret.py +2 -2
- modal/secret.pyi +164 -15
- modal/snapshot.pyi +25 -4
- modal/token_flow.pyi +28 -8
- modal/volume.py +41 -4
- modal/volume.pyi +693 -59
- {modal-1.0.4.dev12.dist-info → modal-1.0.5.dist-info}/METADATA +3 -3
- {modal-1.0.4.dev12.dist-info → modal-1.0.5.dist-info}/RECORD +67 -67
- modal_proto/api.proto +56 -0
- modal_proto/api_grpc.py +48 -0
- modal_proto/api_pb2.py +874 -780
- modal_proto/api_pb2.pyi +194 -8
- modal_proto/api_pb2_grpc.py +100 -0
- modal_proto/api_pb2_grpc.pyi +32 -0
- modal_proto/modal_api_grpc.py +3 -0
- modal_version/__init__.py +1 -1
- {modal-1.0.4.dev12.dist-info → modal-1.0.5.dist-info}/WHEEL +0 -0
- {modal-1.0.4.dev12.dist-info → modal-1.0.5.dist-info}/entry_points.txt +0 -0
- {modal-1.0.4.dev12.dist-info → modal-1.0.5.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.4.dev12.dist-info → modal-1.0.5.dist-info}/top_level.txt +0 -0
modal/volume.pyi
CHANGED
@@ -24,6 +24,8 @@ class FileEntryType(enum.IntEnum):
|
|
24
24
|
SOCKET = 5
|
25
25
|
|
26
26
|
class FileEntry:
|
27
|
+
"""A file or directory entry listed from a Modal volume."""
|
28
|
+
|
27
29
|
path: str
|
28
30
|
type: FileEntryType
|
29
31
|
mtime: int
|
@@ -31,16 +33,96 @@ class FileEntry:
|
|
31
33
|
|
32
34
|
@classmethod
|
33
35
|
def _from_proto(cls, proto: modal_proto.api_pb2.FileEntry) -> FileEntry: ...
|
34
|
-
def __init__(self, path: str, type: FileEntryType, mtime: int, size: int) -> None:
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
def
|
39
|
-
|
36
|
+
def __init__(self, path: str, type: FileEntryType, mtime: int, size: int) -> None:
|
37
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
38
|
+
...
|
39
|
+
|
40
|
+
def __repr__(self):
|
41
|
+
"""Return repr(self)."""
|
42
|
+
...
|
43
|
+
|
44
|
+
def __eq__(self, other):
|
45
|
+
"""Return self==value."""
|
46
|
+
...
|
47
|
+
|
48
|
+
def __setattr__(self, name, value):
|
49
|
+
"""Implement setattr(self, name, value)."""
|
50
|
+
...
|
51
|
+
|
52
|
+
def __delattr__(self, name):
|
53
|
+
"""Implement delattr(self, name)."""
|
54
|
+
...
|
55
|
+
|
56
|
+
def __hash__(self):
|
57
|
+
"""Return hash(self)."""
|
58
|
+
...
|
40
59
|
|
41
60
|
class _Volume(modal._object._Object):
|
61
|
+
"""A writeable volume that can be used to share files between one or more Modal functions.
|
62
|
+
|
63
|
+
The contents of a volume is exposed as a filesystem. You can use it to share data between different functions, or
|
64
|
+
to persist durable state across several instances of the same function.
|
65
|
+
|
66
|
+
Unlike a networked filesystem, you need to explicitly reload the volume to see changes made since it was mounted.
|
67
|
+
Similarly, you need to explicitly commit any changes you make to the volume for the changes to become visible
|
68
|
+
outside the current container.
|
69
|
+
|
70
|
+
Concurrent modification is supported, but concurrent modifications of the same files should be avoided! Last write
|
71
|
+
wins in case of concurrent modification of the same file - any data the last writer didn't have when committing
|
72
|
+
changes will be lost!
|
73
|
+
|
74
|
+
As a result, volumes are typically not a good fit for use cases where you need to make concurrent modifications to
|
75
|
+
the same file (nor is distributed file locking supported).
|
76
|
+
|
77
|
+
Volumes can only be reloaded if there are no open files for the volume - attempting to reload with open files
|
78
|
+
will result in an error.
|
79
|
+
|
80
|
+
**Usage**
|
81
|
+
|
82
|
+
```python
|
83
|
+
import modal
|
84
|
+
|
85
|
+
app = modal.App()
|
86
|
+
volume = modal.Volume.from_name("my-persisted-volume", create_if_missing=True)
|
87
|
+
|
88
|
+
@app.function(volumes={"/root/foo": volume})
|
89
|
+
def f():
|
90
|
+
with open("/root/foo/bar.txt", "w") as f:
|
91
|
+
f.write("hello")
|
92
|
+
volume.commit() # Persist changes
|
93
|
+
|
94
|
+
@app.function(volumes={"/root/foo": volume})
|
95
|
+
def g():
|
96
|
+
volume.reload() # Fetch latest changes
|
97
|
+
with open("/root/foo/bar.txt", "r") as f:
|
98
|
+
print(f.read())
|
99
|
+
```
|
100
|
+
"""
|
101
|
+
|
42
102
|
_lock: typing.Optional[asyncio.locks.Lock]
|
43
103
|
_metadata: typing.Optional[modal_proto.api_pb2.VolumeMetadata]
|
104
|
+
_read_only: bool
|
105
|
+
|
106
|
+
def read_only(self) -> _Volume:
|
107
|
+
"""Configure Volume to mount as read-only.
|
108
|
+
|
109
|
+
**Example**
|
110
|
+
|
111
|
+
```python
|
112
|
+
import modal
|
113
|
+
|
114
|
+
volume = modal.Volume.from_name("my-volume", create_if_missing=True)
|
115
|
+
|
116
|
+
@app.function(volumes={"/mnt/items": volume.read_only()})
|
117
|
+
def f():
|
118
|
+
with open("/mnt/items/my-file.txt") as f:
|
119
|
+
return f.read()
|
120
|
+
```
|
121
|
+
|
122
|
+
The Volume is mounted as a read-only volume in a function. Any file system write operation into the
|
123
|
+
mounted volume will result in an error.
|
124
|
+
"""
|
125
|
+
...
|
44
126
|
|
45
127
|
async def _get_lock(self): ...
|
46
128
|
@staticmethod
|
@@ -51,7 +133,26 @@ class _Volume(modal._object._Object):
|
|
51
133
|
environment_name: typing.Optional[str] = None,
|
52
134
|
create_if_missing: bool = False,
|
53
135
|
version: typing.Optional[int] = None,
|
54
|
-
) -> _Volume:
|
136
|
+
) -> _Volume:
|
137
|
+
"""Reference a Volume by name, creating if necessary.
|
138
|
+
|
139
|
+
This is a lazy method that defers hydrating the local
|
140
|
+
object with metadata from Modal servers until the first
|
141
|
+
time is is actually used.
|
142
|
+
|
143
|
+
```python
|
144
|
+
vol = modal.Volume.from_name("my-volume", create_if_missing=True)
|
145
|
+
|
146
|
+
app = modal.App()
|
147
|
+
|
148
|
+
# Volume refers to the same object, even across instances of `app`.
|
149
|
+
@app.function(volumes={"/data": vol})
|
150
|
+
def f():
|
151
|
+
pass
|
152
|
+
```
|
153
|
+
"""
|
154
|
+
...
|
155
|
+
|
55
156
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
56
157
|
def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
|
57
158
|
@property
|
@@ -63,7 +164,23 @@ class _Volume(modal._object._Object):
|
|
63
164
|
environment_name: typing.Optional[str] = None,
|
64
165
|
version: typing.Optional[int] = None,
|
65
166
|
_heartbeat_sleep: float = 300,
|
66
|
-
) -> typing.AsyncContextManager[_Volume]:
|
167
|
+
) -> typing.AsyncContextManager[_Volume]:
|
168
|
+
"""Creates a new ephemeral volume within a context manager:
|
169
|
+
|
170
|
+
Usage:
|
171
|
+
```python
|
172
|
+
import modal
|
173
|
+
with modal.Volume.ephemeral() as vol:
|
174
|
+
assert vol.listdir("/") == []
|
175
|
+
```
|
176
|
+
|
177
|
+
```python notest
|
178
|
+
async with modal.Volume.ephemeral() as vol:
|
179
|
+
assert await vol.listdir("/") == []
|
180
|
+
```
|
181
|
+
"""
|
182
|
+
...
|
183
|
+
|
67
184
|
@staticmethod
|
68
185
|
async def lookup(
|
69
186
|
name: str,
|
@@ -72,7 +189,22 @@ class _Volume(modal._object._Object):
|
|
72
189
|
environment_name: typing.Optional[str] = None,
|
73
190
|
create_if_missing: bool = False,
|
74
191
|
version: typing.Optional[int] = None,
|
75
|
-
) -> _Volume:
|
192
|
+
) -> _Volume:
|
193
|
+
"""mdmd:hidden
|
194
|
+
Lookup a named Volume.
|
195
|
+
|
196
|
+
DEPRECATED: This method is deprecated in favor of `modal.Volume.from_name`.
|
197
|
+
|
198
|
+
In contrast to `modal.Volume.from_name`, this is an eager method
|
199
|
+
that will hydrate the local object with metadata from Modal servers.
|
200
|
+
|
201
|
+
```python notest
|
202
|
+
vol = modal.Volume.from_name("my-volume")
|
203
|
+
print(vol.listdir("/"))
|
204
|
+
```
|
205
|
+
"""
|
206
|
+
...
|
207
|
+
|
76
208
|
@staticmethod
|
77
209
|
async def create_deployed(
|
78
210
|
deployment_name: str,
|
@@ -80,24 +212,127 @@ class _Volume(modal._object._Object):
|
|
80
212
|
client: typing.Optional[modal.client._Client] = None,
|
81
213
|
environment_name: typing.Optional[str] = None,
|
82
214
|
version: typing.Optional[int] = None,
|
83
|
-
) -> str:
|
215
|
+
) -> str:
|
216
|
+
"""mdmd:hidden"""
|
217
|
+
...
|
218
|
+
|
84
219
|
async def _do_reload(self, lock=True): ...
|
85
|
-
async def commit(self):
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
220
|
+
async def commit(self):
|
221
|
+
"""Commit changes to the volume.
|
222
|
+
|
223
|
+
If successful, the changes made are now persisted in durable storage and available to other containers accessing
|
224
|
+
the volume.
|
225
|
+
"""
|
226
|
+
...
|
227
|
+
|
228
|
+
async def reload(self):
|
229
|
+
"""Make latest committed state of volume available in the running container.
|
230
|
+
|
231
|
+
Any uncommitted changes to the volume, such as new or modified files, may implicitly be committed when
|
232
|
+
reloading.
|
233
|
+
|
234
|
+
Reloading will fail if there are open files for the volume.
|
235
|
+
"""
|
236
|
+
...
|
237
|
+
|
238
|
+
def iterdir(self, path: str, *, recursive: bool = True) -> collections.abc.AsyncIterator[FileEntry]:
|
239
|
+
"""Iterate over all files in a directory in the volume.
|
240
|
+
|
241
|
+
Passing a directory path lists all files in the directory. For a file path, return only that
|
242
|
+
file's description. If `recursive` is set to True, list all files and folders under the path
|
243
|
+
recursively.
|
244
|
+
"""
|
245
|
+
...
|
246
|
+
|
247
|
+
async def listdir(self, path: str, *, recursive: bool = False) -> list[FileEntry]:
|
248
|
+
"""List all files under a path prefix in the modal.Volume.
|
249
|
+
|
250
|
+
Passing a directory path lists all files in the directory. For a file path, return only that
|
251
|
+
file's description. If `recursive` is set to True, list all files and folders under the path
|
252
|
+
recursively.
|
253
|
+
"""
|
254
|
+
...
|
255
|
+
|
256
|
+
def read_file(self, path: str) -> collections.abc.AsyncIterator[bytes]:
|
257
|
+
"""Read a file from the modal.Volume.
|
258
|
+
|
259
|
+
Note - this function is primarily intended to be used outside of a Modal App.
|
260
|
+
For more information on downloading files from a Modal Volume, see
|
261
|
+
[the guide](https://modal.com/docs/guide/volumes).
|
262
|
+
|
263
|
+
**Example:**
|
264
|
+
|
265
|
+
```python notest
|
266
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
267
|
+
data = b""
|
268
|
+
for chunk in vol.read_file("1mb.csv"):
|
269
|
+
data += chunk
|
270
|
+
print(len(data)) # == 1024 * 1024
|
271
|
+
```
|
272
|
+
"""
|
273
|
+
...
|
274
|
+
|
90
275
|
async def read_file_into_fileobj(
|
91
276
|
self,
|
92
277
|
path: str,
|
93
278
|
fileobj: typing.IO[bytes],
|
94
279
|
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
95
|
-
) -> int:
|
96
|
-
|
280
|
+
) -> int:
|
281
|
+
"""mdmd:hidden
|
282
|
+
Read volume file into file-like IO object.
|
283
|
+
"""
|
284
|
+
...
|
285
|
+
|
286
|
+
async def remove_file(self, path: str, recursive: bool = False) -> None:
|
287
|
+
"""Remove a file or directory from a volume."""
|
288
|
+
...
|
289
|
+
|
97
290
|
async def copy_files(
|
98
291
|
self, src_paths: collections.abc.Sequence[str], dst_path: str, recursive: bool = False
|
99
|
-
) -> None:
|
100
|
-
|
292
|
+
) -> None:
|
293
|
+
"""Copy files within the volume from src_paths to dst_path.
|
294
|
+
The semantics of the copy operation follow those of the UNIX cp command.
|
295
|
+
|
296
|
+
The `src_paths` parameter is a list. If you want to copy a single file, you should pass a list with a
|
297
|
+
single element.
|
298
|
+
|
299
|
+
`src_paths` and `dst_path` should refer to the desired location *inside* the volume. You do not need to prepend
|
300
|
+
the volume mount path.
|
301
|
+
|
302
|
+
**Usage**
|
303
|
+
|
304
|
+
```python notest
|
305
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
306
|
+
|
307
|
+
vol.copy_files(["bar/example.txt"], "bar2") # Copy files to another directory
|
308
|
+
vol.copy_files(["bar/example.txt"], "bar/example2.txt") # Rename a file by copying
|
309
|
+
```
|
310
|
+
|
311
|
+
Note that if the volume is already mounted on the Modal function, you should use normal filesystem operations
|
312
|
+
like `os.rename()` and then `commit()` the volume. The `copy_files()` method is useful when you don't have
|
313
|
+
the volume mounted as a filesystem, e.g. when running a script on your local computer.
|
314
|
+
"""
|
315
|
+
...
|
316
|
+
|
317
|
+
async def batch_upload(self, force: bool = False) -> _AbstractVolumeUploadContextManager:
|
318
|
+
"""Initiate a batched upload to a volume.
|
319
|
+
|
320
|
+
To allow overwriting existing files, set `force` to `True` (you cannot overwrite existing directories with
|
321
|
+
uploaded files regardless).
|
322
|
+
|
323
|
+
**Example:**
|
324
|
+
|
325
|
+
```python notest
|
326
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
327
|
+
|
328
|
+
with vol.batch_upload() as batch:
|
329
|
+
batch.put_file("local-path.txt", "/remote-path.txt")
|
330
|
+
batch.put_directory("/local/directory/", "/remote/directory")
|
331
|
+
batch.put_file(io.BytesIO(b"some data"), "/foobar")
|
332
|
+
```
|
333
|
+
"""
|
334
|
+
...
|
335
|
+
|
101
336
|
async def _instance_delete(self): ...
|
102
337
|
@staticmethod
|
103
338
|
async def delete(
|
@@ -115,10 +350,75 @@ class _Volume(modal._object._Object):
|
|
115
350
|
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
116
351
|
|
117
352
|
class Volume(modal.object.Object):
|
353
|
+
"""A writeable volume that can be used to share files between one or more Modal functions.
|
354
|
+
|
355
|
+
The contents of a volume is exposed as a filesystem. You can use it to share data between different functions, or
|
356
|
+
to persist durable state across several instances of the same function.
|
357
|
+
|
358
|
+
Unlike a networked filesystem, you need to explicitly reload the volume to see changes made since it was mounted.
|
359
|
+
Similarly, you need to explicitly commit any changes you make to the volume for the changes to become visible
|
360
|
+
outside the current container.
|
361
|
+
|
362
|
+
Concurrent modification is supported, but concurrent modifications of the same files should be avoided! Last write
|
363
|
+
wins in case of concurrent modification of the same file - any data the last writer didn't have when committing
|
364
|
+
changes will be lost!
|
365
|
+
|
366
|
+
As a result, volumes are typically not a good fit for use cases where you need to make concurrent modifications to
|
367
|
+
the same file (nor is distributed file locking supported).
|
368
|
+
|
369
|
+
Volumes can only be reloaded if there are no open files for the volume - attempting to reload with open files
|
370
|
+
will result in an error.
|
371
|
+
|
372
|
+
**Usage**
|
373
|
+
|
374
|
+
```python
|
375
|
+
import modal
|
376
|
+
|
377
|
+
app = modal.App()
|
378
|
+
volume = modal.Volume.from_name("my-persisted-volume", create_if_missing=True)
|
379
|
+
|
380
|
+
@app.function(volumes={"/root/foo": volume})
|
381
|
+
def f():
|
382
|
+
with open("/root/foo/bar.txt", "w") as f:
|
383
|
+
f.write("hello")
|
384
|
+
volume.commit() # Persist changes
|
385
|
+
|
386
|
+
@app.function(volumes={"/root/foo": volume})
|
387
|
+
def g():
|
388
|
+
volume.reload() # Fetch latest changes
|
389
|
+
with open("/root/foo/bar.txt", "r") as f:
|
390
|
+
print(f.read())
|
391
|
+
```
|
392
|
+
"""
|
393
|
+
|
118
394
|
_lock: typing.Optional[asyncio.locks.Lock]
|
119
395
|
_metadata: typing.Optional[modal_proto.api_pb2.VolumeMetadata]
|
396
|
+
_read_only: bool
|
397
|
+
|
398
|
+
def __init__(self, *args, **kwargs):
|
399
|
+
"""mdmd:hidden"""
|
400
|
+
...
|
401
|
+
|
402
|
+
def read_only(self) -> Volume:
|
403
|
+
"""Configure Volume to mount as read-only.
|
120
404
|
|
121
|
-
|
405
|
+
**Example**
|
406
|
+
|
407
|
+
```python
|
408
|
+
import modal
|
409
|
+
|
410
|
+
volume = modal.Volume.from_name("my-volume", create_if_missing=True)
|
411
|
+
|
412
|
+
@app.function(volumes={"/mnt/items": volume.read_only()})
|
413
|
+
def f():
|
414
|
+
with open("/mnt/items/my-file.txt") as f:
|
415
|
+
return f.read()
|
416
|
+
```
|
417
|
+
|
418
|
+
The Volume is mounted as a read-only volume in a function. Any file system write operation into the
|
419
|
+
mounted volume will result in an error.
|
420
|
+
"""
|
421
|
+
...
|
122
422
|
|
123
423
|
class ___get_lock_spec(typing_extensions.Protocol[SUPERSELF]):
|
124
424
|
def __call__(self, /): ...
|
@@ -134,7 +434,26 @@ class Volume(modal.object.Object):
|
|
134
434
|
environment_name: typing.Optional[str] = None,
|
135
435
|
create_if_missing: bool = False,
|
136
436
|
version: typing.Optional[int] = None,
|
137
|
-
) -> Volume:
|
437
|
+
) -> Volume:
|
438
|
+
"""Reference a Volume by name, creating if necessary.
|
439
|
+
|
440
|
+
This is a lazy method that defers hydrating the local
|
441
|
+
object with metadata from Modal servers until the first
|
442
|
+
time is is actually used.
|
443
|
+
|
444
|
+
```python
|
445
|
+
vol = modal.Volume.from_name("my-volume", create_if_missing=True)
|
446
|
+
|
447
|
+
app = modal.App()
|
448
|
+
|
449
|
+
# Volume refers to the same object, even across instances of `app`.
|
450
|
+
@app.function(volumes={"/data": vol})
|
451
|
+
def f():
|
452
|
+
pass
|
453
|
+
```
|
454
|
+
"""
|
455
|
+
...
|
456
|
+
|
138
457
|
def _hydrate_metadata(self, metadata: typing.Optional[google.protobuf.message.Message]): ...
|
139
458
|
def _get_metadata(self) -> typing.Optional[google.protobuf.message.Message]: ...
|
140
459
|
@property
|
@@ -146,7 +465,22 @@ class Volume(modal.object.Object):
|
|
146
465
|
environment_name: typing.Optional[str] = None,
|
147
466
|
version: typing.Optional[int] = None,
|
148
467
|
_heartbeat_sleep: float = 300,
|
149
|
-
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[Volume]:
|
468
|
+
) -> synchronicity.combined_types.AsyncAndBlockingContextManager[Volume]:
|
469
|
+
"""Creates a new ephemeral volume within a context manager:
|
470
|
+
|
471
|
+
Usage:
|
472
|
+
```python
|
473
|
+
import modal
|
474
|
+
with modal.Volume.ephemeral() as vol:
|
475
|
+
assert vol.listdir("/") == []
|
476
|
+
```
|
477
|
+
|
478
|
+
```python notest
|
479
|
+
async with modal.Volume.ephemeral() as vol:
|
480
|
+
assert await vol.listdir("/") == []
|
481
|
+
```
|
482
|
+
"""
|
483
|
+
...
|
150
484
|
|
151
485
|
class __lookup_spec(typing_extensions.Protocol):
|
152
486
|
def __call__(
|
@@ -158,7 +492,22 @@ class Volume(modal.object.Object):
|
|
158
492
|
environment_name: typing.Optional[str] = None,
|
159
493
|
create_if_missing: bool = False,
|
160
494
|
version: typing.Optional[int] = None,
|
161
|
-
) -> Volume:
|
495
|
+
) -> Volume:
|
496
|
+
"""mdmd:hidden
|
497
|
+
Lookup a named Volume.
|
498
|
+
|
499
|
+
DEPRECATED: This method is deprecated in favor of `modal.Volume.from_name`.
|
500
|
+
|
501
|
+
In contrast to `modal.Volume.from_name`, this is an eager method
|
502
|
+
that will hydrate the local object with metadata from Modal servers.
|
503
|
+
|
504
|
+
```python notest
|
505
|
+
vol = modal.Volume.from_name("my-volume")
|
506
|
+
print(vol.listdir("/"))
|
507
|
+
```
|
508
|
+
"""
|
509
|
+
...
|
510
|
+
|
162
511
|
async def aio(
|
163
512
|
self,
|
164
513
|
/,
|
@@ -168,7 +517,21 @@ class Volume(modal.object.Object):
|
|
168
517
|
environment_name: typing.Optional[str] = None,
|
169
518
|
create_if_missing: bool = False,
|
170
519
|
version: typing.Optional[int] = None,
|
171
|
-
) -> Volume:
|
520
|
+
) -> Volume:
|
521
|
+
"""mdmd:hidden
|
522
|
+
Lookup a named Volume.
|
523
|
+
|
524
|
+
DEPRECATED: This method is deprecated in favor of `modal.Volume.from_name`.
|
525
|
+
|
526
|
+
In contrast to `modal.Volume.from_name`, this is an eager method
|
527
|
+
that will hydrate the local object with metadata from Modal servers.
|
528
|
+
|
529
|
+
```python notest
|
530
|
+
vol = modal.Volume.from_name("my-volume")
|
531
|
+
print(vol.listdir("/"))
|
532
|
+
```
|
533
|
+
"""
|
534
|
+
...
|
172
535
|
|
173
536
|
lookup: __lookup_spec
|
174
537
|
|
@@ -181,7 +544,10 @@ class Volume(modal.object.Object):
|
|
181
544
|
client: typing.Optional[modal.client.Client] = None,
|
182
545
|
environment_name: typing.Optional[str] = None,
|
183
546
|
version: typing.Optional[int] = None,
|
184
|
-
) -> str:
|
547
|
+
) -> str:
|
548
|
+
"""mdmd:hidden"""
|
549
|
+
...
|
550
|
+
|
185
551
|
async def aio(
|
186
552
|
self,
|
187
553
|
/,
|
@@ -190,7 +556,9 @@ class Volume(modal.object.Object):
|
|
190
556
|
client: typing.Optional[modal.client.Client] = None,
|
191
557
|
environment_name: typing.Optional[str] = None,
|
192
558
|
version: typing.Optional[int] = None,
|
193
|
-
) -> str:
|
559
|
+
) -> str:
|
560
|
+
"""mdmd:hidden"""
|
561
|
+
...
|
194
562
|
|
195
563
|
create_deployed: __create_deployed_spec
|
196
564
|
|
@@ -201,32 +569,127 @@ class Volume(modal.object.Object):
|
|
201
569
|
_do_reload: ___do_reload_spec[typing_extensions.Self]
|
202
570
|
|
203
571
|
class __commit_spec(typing_extensions.Protocol[SUPERSELF]):
|
204
|
-
def __call__(self, /):
|
205
|
-
|
572
|
+
def __call__(self, /):
|
573
|
+
"""Commit changes to the volume.
|
574
|
+
|
575
|
+
If successful, the changes made are now persisted in durable storage and available to other containers accessing
|
576
|
+
the volume.
|
577
|
+
"""
|
578
|
+
...
|
579
|
+
|
580
|
+
async def aio(self, /):
|
581
|
+
"""Commit changes to the volume.
|
582
|
+
|
583
|
+
If successful, the changes made are now persisted in durable storage and available to other containers accessing
|
584
|
+
the volume.
|
585
|
+
"""
|
586
|
+
...
|
206
587
|
|
207
588
|
commit: __commit_spec[typing_extensions.Self]
|
208
589
|
|
209
590
|
class __reload_spec(typing_extensions.Protocol[SUPERSELF]):
|
210
|
-
def __call__(self, /):
|
211
|
-
|
591
|
+
def __call__(self, /):
|
592
|
+
"""Make latest committed state of volume available in the running container.
|
593
|
+
|
594
|
+
Any uncommitted changes to the volume, such as new or modified files, may implicitly be committed when
|
595
|
+
reloading.
|
596
|
+
|
597
|
+
Reloading will fail if there are open files for the volume.
|
598
|
+
"""
|
599
|
+
...
|
600
|
+
|
601
|
+
async def aio(self, /):
|
602
|
+
"""Make latest committed state of volume available in the running container.
|
603
|
+
|
604
|
+
Any uncommitted changes to the volume, such as new or modified files, may implicitly be committed when
|
605
|
+
reloading.
|
606
|
+
|
607
|
+
Reloading will fail if there are open files for the volume.
|
608
|
+
"""
|
609
|
+
...
|
212
610
|
|
213
611
|
reload: __reload_spec[typing_extensions.Self]
|
214
612
|
|
215
613
|
class __iterdir_spec(typing_extensions.Protocol[SUPERSELF]):
|
216
|
-
def __call__(self, /, path: str, *, recursive: bool = True) -> typing.Iterator[FileEntry]:
|
217
|
-
|
614
|
+
def __call__(self, /, path: str, *, recursive: bool = True) -> typing.Iterator[FileEntry]:
|
615
|
+
"""Iterate over all files in a directory in the volume.
|
616
|
+
|
617
|
+
Passing a directory path lists all files in the directory. For a file path, return only that
|
618
|
+
file's description. If `recursive` is set to True, list all files and folders under the path
|
619
|
+
recursively.
|
620
|
+
"""
|
621
|
+
...
|
622
|
+
|
623
|
+
def aio(self, /, path: str, *, recursive: bool = True) -> collections.abc.AsyncIterator[FileEntry]:
|
624
|
+
"""Iterate over all files in a directory in the volume.
|
625
|
+
|
626
|
+
Passing a directory path lists all files in the directory. For a file path, return only that
|
627
|
+
file's description. If `recursive` is set to True, list all files and folders under the path
|
628
|
+
recursively.
|
629
|
+
"""
|
630
|
+
...
|
218
631
|
|
219
632
|
iterdir: __iterdir_spec[typing_extensions.Self]
|
220
633
|
|
221
634
|
class __listdir_spec(typing_extensions.Protocol[SUPERSELF]):
|
222
|
-
def __call__(self, /, path: str, *, recursive: bool = False) -> list[FileEntry]:
|
223
|
-
|
635
|
+
def __call__(self, /, path: str, *, recursive: bool = False) -> list[FileEntry]:
|
636
|
+
"""List all files under a path prefix in the modal.Volume.
|
637
|
+
|
638
|
+
Passing a directory path lists all files in the directory. For a file path, return only that
|
639
|
+
file's description. If `recursive` is set to True, list all files and folders under the path
|
640
|
+
recursively.
|
641
|
+
"""
|
642
|
+
...
|
643
|
+
|
644
|
+
async def aio(self, /, path: str, *, recursive: bool = False) -> list[FileEntry]:
|
645
|
+
"""List all files under a path prefix in the modal.Volume.
|
646
|
+
|
647
|
+
Passing a directory path lists all files in the directory. For a file path, return only that
|
648
|
+
file's description. If `recursive` is set to True, list all files and folders under the path
|
649
|
+
recursively.
|
650
|
+
"""
|
651
|
+
...
|
224
652
|
|
225
653
|
listdir: __listdir_spec[typing_extensions.Self]
|
226
654
|
|
227
655
|
class __read_file_spec(typing_extensions.Protocol[SUPERSELF]):
|
228
|
-
def __call__(self, /, path: str) -> typing.Iterator[bytes]:
|
229
|
-
|
656
|
+
def __call__(self, /, path: str) -> typing.Iterator[bytes]:
|
657
|
+
"""Read a file from the modal.Volume.
|
658
|
+
|
659
|
+
Note - this function is primarily intended to be used outside of a Modal App.
|
660
|
+
For more information on downloading files from a Modal Volume, see
|
661
|
+
[the guide](https://modal.com/docs/guide/volumes).
|
662
|
+
|
663
|
+
**Example:**
|
664
|
+
|
665
|
+
```python notest
|
666
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
667
|
+
data = b""
|
668
|
+
for chunk in vol.read_file("1mb.csv"):
|
669
|
+
data += chunk
|
670
|
+
print(len(data)) # == 1024 * 1024
|
671
|
+
```
|
672
|
+
"""
|
673
|
+
...
|
674
|
+
|
675
|
+
def aio(self, /, path: str) -> collections.abc.AsyncIterator[bytes]:
|
676
|
+
"""Read a file from the modal.Volume.
|
677
|
+
|
678
|
+
Note - this function is primarily intended to be used outside of a Modal App.
|
679
|
+
For more information on downloading files from a Modal Volume, see
|
680
|
+
[the guide](https://modal.com/docs/guide/volumes).
|
681
|
+
|
682
|
+
**Example:**
|
683
|
+
|
684
|
+
```python notest
|
685
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
686
|
+
data = b""
|
687
|
+
for chunk in vol.read_file("1mb.csv"):
|
688
|
+
data += chunk
|
689
|
+
print(len(data)) # == 1024 * 1024
|
690
|
+
```
|
691
|
+
"""
|
692
|
+
...
|
230
693
|
|
231
694
|
read_file: __read_file_spec[typing_extensions.Self]
|
232
695
|
|
@@ -237,36 +700,130 @@ class Volume(modal.object.Object):
|
|
237
700
|
path: str,
|
238
701
|
fileobj: typing.IO[bytes],
|
239
702
|
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
240
|
-
) -> int:
|
703
|
+
) -> int:
|
704
|
+
"""mdmd:hidden
|
705
|
+
Read volume file into file-like IO object.
|
706
|
+
"""
|
707
|
+
...
|
708
|
+
|
241
709
|
async def aio(
|
242
710
|
self,
|
243
711
|
/,
|
244
712
|
path: str,
|
245
713
|
fileobj: typing.IO[bytes],
|
246
714
|
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
247
|
-
) -> int:
|
715
|
+
) -> int:
|
716
|
+
"""mdmd:hidden
|
717
|
+
Read volume file into file-like IO object.
|
718
|
+
"""
|
719
|
+
...
|
248
720
|
|
249
721
|
read_file_into_fileobj: __read_file_into_fileobj_spec[typing_extensions.Self]
|
250
722
|
|
251
723
|
class __remove_file_spec(typing_extensions.Protocol[SUPERSELF]):
|
252
|
-
def __call__(self, /, path: str, recursive: bool = False) -> None:
|
253
|
-
|
724
|
+
def __call__(self, /, path: str, recursive: bool = False) -> None:
|
725
|
+
"""Remove a file or directory from a volume."""
|
726
|
+
...
|
727
|
+
|
728
|
+
async def aio(self, /, path: str, recursive: bool = False) -> None:
|
729
|
+
"""Remove a file or directory from a volume."""
|
730
|
+
...
|
254
731
|
|
255
732
|
remove_file: __remove_file_spec[typing_extensions.Self]
|
256
733
|
|
257
734
|
class __copy_files_spec(typing_extensions.Protocol[SUPERSELF]):
|
258
|
-
def __call__(
|
259
|
-
|
260
|
-
|
735
|
+
def __call__(self, /, src_paths: collections.abc.Sequence[str], dst_path: str, recursive: bool = False) -> None:
|
736
|
+
"""Copy files within the volume from src_paths to dst_path.
|
737
|
+
The semantics of the copy operation follow those of the UNIX cp command.
|
738
|
+
|
739
|
+
The `src_paths` parameter is a list. If you want to copy a single file, you should pass a list with a
|
740
|
+
single element.
|
741
|
+
|
742
|
+
`src_paths` and `dst_path` should refer to the desired location *inside* the volume. You do not need to prepend
|
743
|
+
the volume mount path.
|
744
|
+
|
745
|
+
**Usage**
|
746
|
+
|
747
|
+
```python notest
|
748
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
749
|
+
|
750
|
+
vol.copy_files(["bar/example.txt"], "bar2") # Copy files to another directory
|
751
|
+
vol.copy_files(["bar/example.txt"], "bar/example2.txt") # Rename a file by copying
|
752
|
+
```
|
753
|
+
|
754
|
+
Note that if the volume is already mounted on the Modal function, you should use normal filesystem operations
|
755
|
+
like `os.rename()` and then `commit()` the volume. The `copy_files()` method is useful when you don't have
|
756
|
+
the volume mounted as a filesystem, e.g. when running a script on your local computer.
|
757
|
+
"""
|
758
|
+
...
|
759
|
+
|
261
760
|
async def aio(
|
262
761
|
self, /, src_paths: collections.abc.Sequence[str], dst_path: str, recursive: bool = False
|
263
|
-
) -> None:
|
762
|
+
) -> None:
|
763
|
+
"""Copy files within the volume from src_paths to dst_path.
|
764
|
+
The semantics of the copy operation follow those of the UNIX cp command.
|
765
|
+
|
766
|
+
The `src_paths` parameter is a list. If you want to copy a single file, you should pass a list with a
|
767
|
+
single element.
|
768
|
+
|
769
|
+
`src_paths` and `dst_path` should refer to the desired location *inside* the volume. You do not need to prepend
|
770
|
+
the volume mount path.
|
771
|
+
|
772
|
+
**Usage**
|
773
|
+
|
774
|
+
```python notest
|
775
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
776
|
+
|
777
|
+
vol.copy_files(["bar/example.txt"], "bar2") # Copy files to another directory
|
778
|
+
vol.copy_files(["bar/example.txt"], "bar/example2.txt") # Rename a file by copying
|
779
|
+
```
|
780
|
+
|
781
|
+
Note that if the volume is already mounted on the Modal function, you should use normal filesystem operations
|
782
|
+
like `os.rename()` and then `commit()` the volume. The `copy_files()` method is useful when you don't have
|
783
|
+
the volume mounted as a filesystem, e.g. when running a script on your local computer.
|
784
|
+
"""
|
785
|
+
...
|
264
786
|
|
265
787
|
copy_files: __copy_files_spec[typing_extensions.Self]
|
266
788
|
|
267
789
|
class __batch_upload_spec(typing_extensions.Protocol[SUPERSELF]):
|
268
|
-
def __call__(self, /, force: bool = False) -> AbstractVolumeUploadContextManager:
|
269
|
-
|
790
|
+
def __call__(self, /, force: bool = False) -> AbstractVolumeUploadContextManager:
|
791
|
+
"""Initiate a batched upload to a volume.
|
792
|
+
|
793
|
+
To allow overwriting existing files, set `force` to `True` (you cannot overwrite existing directories with
|
794
|
+
uploaded files regardless).
|
795
|
+
|
796
|
+
**Example:**
|
797
|
+
|
798
|
+
```python notest
|
799
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
800
|
+
|
801
|
+
with vol.batch_upload() as batch:
|
802
|
+
batch.put_file("local-path.txt", "/remote-path.txt")
|
803
|
+
batch.put_directory("/local/directory/", "/remote/directory")
|
804
|
+
batch.put_file(io.BytesIO(b"some data"), "/foobar")
|
805
|
+
```
|
806
|
+
"""
|
807
|
+
...
|
808
|
+
|
809
|
+
async def aio(self, /, force: bool = False) -> AbstractVolumeUploadContextManager:
|
810
|
+
"""Initiate a batched upload to a volume.
|
811
|
+
|
812
|
+
To allow overwriting existing files, set `force` to `True` (you cannot overwrite existing directories with
|
813
|
+
uploaded files regardless).
|
814
|
+
|
815
|
+
**Example:**
|
816
|
+
|
817
|
+
```python notest
|
818
|
+
vol = modal.Volume.from_name("my-modal-volume")
|
819
|
+
|
820
|
+
with vol.batch_upload() as batch:
|
821
|
+
batch.put_file("local-path.txt", "/remote-path.txt")
|
822
|
+
batch.put_directory("/local/directory/", "/remote/directory")
|
823
|
+
batch.put_file(io.BytesIO(b"some data"), "/foobar")
|
824
|
+
```
|
825
|
+
"""
|
826
|
+
...
|
270
827
|
|
271
828
|
batch_upload: __batch_upload_spec[typing_extensions.Self]
|
272
829
|
|
@@ -341,7 +898,10 @@ class _AbstractVolumeUploadContextManager:
|
|
341
898
|
) -> _AbstractVolumeUploadContextManager: ...
|
342
899
|
|
343
900
|
class AbstractVolumeUploadContextManager:
|
344
|
-
def __init__(self, /, *args, **kwargs):
|
901
|
+
def __init__(self, /, *args, **kwargs):
|
902
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
903
|
+
...
|
904
|
+
|
345
905
|
def __enter__(self): ...
|
346
906
|
async def __aenter__(self): ...
|
347
907
|
def __exit__(self, exc_type, exc_val, exc_tb): ...
|
@@ -368,6 +928,8 @@ class AbstractVolumeUploadContextManager:
|
|
368
928
|
) -> AbstractVolumeUploadContextManager: ...
|
369
929
|
|
370
930
|
class _VolumeUploadContextManager(_AbstractVolumeUploadContextManager):
|
931
|
+
"""Context manager for batch-uploading files to a Volume."""
|
932
|
+
|
371
933
|
_volume_id: str
|
372
934
|
_client: modal.client._Client
|
373
935
|
_force: bool
|
@@ -382,7 +944,10 @@ class _VolumeUploadContextManager(_AbstractVolumeUploadContextManager):
|
|
382
944
|
client: modal.client._Client,
|
383
945
|
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
384
946
|
force: bool = False,
|
385
|
-
):
|
947
|
+
):
|
948
|
+
"""mdmd:hidden"""
|
949
|
+
...
|
950
|
+
|
386
951
|
async def __aenter__(self): ...
|
387
952
|
async def __aexit__(self, exc_type, exc_val, exc_tb): ...
|
388
953
|
def put_file(
|
@@ -390,18 +955,34 @@ class _VolumeUploadContextManager(_AbstractVolumeUploadContextManager):
|
|
390
955
|
local_file: typing.Union[pathlib.Path, str, typing.BinaryIO, _io.BytesIO],
|
391
956
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
392
957
|
mode: typing.Optional[int] = None,
|
393
|
-
):
|
958
|
+
):
|
959
|
+
"""Upload a file from a local file or file-like object.
|
960
|
+
|
961
|
+
Will create any needed parent directories automatically.
|
962
|
+
|
963
|
+
If `local_file` is a file-like object it must remain readable for the lifetime of the batch.
|
964
|
+
"""
|
965
|
+
...
|
966
|
+
|
394
967
|
def put_directory(
|
395
968
|
self,
|
396
969
|
local_path: typing.Union[pathlib.Path, str],
|
397
970
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
398
971
|
recursive: bool = True,
|
399
|
-
):
|
972
|
+
):
|
973
|
+
"""Upload all files in a local directory.
|
974
|
+
|
975
|
+
Will create any needed parent directories automatically.
|
976
|
+
"""
|
977
|
+
...
|
978
|
+
|
400
979
|
async def _upload_file(
|
401
980
|
self, file_spec: modal._utils.blob_utils.FileUploadSpec
|
402
981
|
) -> modal_proto.api_pb2.MountFile: ...
|
403
982
|
|
404
983
|
class VolumeUploadContextManager(AbstractVolumeUploadContextManager):
|
984
|
+
"""Context manager for batch-uploading files to a Volume."""
|
985
|
+
|
405
986
|
_volume_id: str
|
406
987
|
_client: modal.client.Client
|
407
988
|
_force: bool
|
@@ -416,7 +997,10 @@ class VolumeUploadContextManager(AbstractVolumeUploadContextManager):
|
|
416
997
|
client: modal.client.Client,
|
417
998
|
progress_cb: typing.Optional[collections.abc.Callable[..., typing.Any]] = None,
|
418
999
|
force: bool = False,
|
419
|
-
):
|
1000
|
+
):
|
1001
|
+
"""mdmd:hidden"""
|
1002
|
+
...
|
1003
|
+
|
420
1004
|
def __enter__(self): ...
|
421
1005
|
async def __aenter__(self): ...
|
422
1006
|
def __exit__(self, exc_type, exc_val, exc_tb): ...
|
@@ -426,13 +1010,26 @@ class VolumeUploadContextManager(AbstractVolumeUploadContextManager):
|
|
426
1010
|
local_file: typing.Union[pathlib.Path, str, typing.BinaryIO, _io.BytesIO],
|
427
1011
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
428
1012
|
mode: typing.Optional[int] = None,
|
429
|
-
):
|
1013
|
+
):
|
1014
|
+
"""Upload a file from a local file or file-like object.
|
1015
|
+
|
1016
|
+
Will create any needed parent directories automatically.
|
1017
|
+
|
1018
|
+
If `local_file` is a file-like object it must remain readable for the lifetime of the batch.
|
1019
|
+
"""
|
1020
|
+
...
|
1021
|
+
|
430
1022
|
def put_directory(
|
431
1023
|
self,
|
432
1024
|
local_path: typing.Union[pathlib.Path, str],
|
433
1025
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
434
1026
|
recursive: bool = True,
|
435
|
-
):
|
1027
|
+
):
|
1028
|
+
"""Upload all files in a local directory.
|
1029
|
+
|
1030
|
+
Will create any needed parent directories automatically.
|
1031
|
+
"""
|
1032
|
+
...
|
436
1033
|
|
437
1034
|
class ___upload_file_spec(typing_extensions.Protocol[SUPERSELF]):
|
438
1035
|
def __call__(self, /, file_spec: modal._utils.blob_utils.FileUploadSpec) -> modal_proto.api_pb2.MountFile: ...
|
@@ -441,6 +1038,8 @@ class VolumeUploadContextManager(AbstractVolumeUploadContextManager):
|
|
441
1038
|
_upload_file: ___upload_file_spec[typing_extensions.Self]
|
442
1039
|
|
443
1040
|
class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
|
1041
|
+
"""Context manager for batch-uploading files to a Volume version 2."""
|
1042
|
+
|
444
1043
|
_volume_id: str
|
445
1044
|
_client: modal.client._Client
|
446
1045
|
_progress_cb: collections.abc.Callable[..., typing.Any]
|
@@ -463,7 +1062,10 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
|
|
463
1062
|
force: bool = False,
|
464
1063
|
hash_concurrency: int = 4,
|
465
1064
|
put_concurrency: int = 128,
|
466
|
-
):
|
1065
|
+
):
|
1066
|
+
"""mdmd:hidden"""
|
1067
|
+
...
|
1068
|
+
|
467
1069
|
async def __aenter__(self): ...
|
468
1070
|
async def __aexit__(self, exc_type, exc_val, exc_tb): ...
|
469
1071
|
def put_file(
|
@@ -471,16 +1073,32 @@ class _VolumeUploadContextManager2(_AbstractVolumeUploadContextManager):
|
|
471
1073
|
local_file: typing.Union[pathlib.Path, str, typing.BinaryIO, _io.BytesIO],
|
472
1074
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
473
1075
|
mode: typing.Optional[int] = None,
|
474
|
-
):
|
1076
|
+
):
|
1077
|
+
"""Upload a file from a local file or file-like object.
|
1078
|
+
|
1079
|
+
Will create any needed parent directories automatically.
|
1080
|
+
|
1081
|
+
If `local_file` is a file-like object it must remain readable for the lifetime of the batch.
|
1082
|
+
"""
|
1083
|
+
...
|
1084
|
+
|
475
1085
|
def put_directory(
|
476
1086
|
self,
|
477
1087
|
local_path: typing.Union[pathlib.Path, str],
|
478
1088
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
479
1089
|
recursive: bool = True,
|
480
|
-
):
|
1090
|
+
):
|
1091
|
+
"""Upload all files in a local directory.
|
1092
|
+
|
1093
|
+
Will create any needed parent directories automatically.
|
1094
|
+
"""
|
1095
|
+
...
|
1096
|
+
|
481
1097
|
async def _put_file_specs(self, file_specs: list[modal._utils.blob_utils.FileUploadSpec2]): ...
|
482
1098
|
|
483
1099
|
class VolumeUploadContextManager2(AbstractVolumeUploadContextManager):
|
1100
|
+
"""Context manager for batch-uploading files to a Volume version 2."""
|
1101
|
+
|
484
1102
|
_volume_id: str
|
485
1103
|
_client: modal.client.Client
|
486
1104
|
_progress_cb: collections.abc.Callable[..., typing.Any]
|
@@ -503,7 +1121,10 @@ class VolumeUploadContextManager2(AbstractVolumeUploadContextManager):
|
|
503
1121
|
force: bool = False,
|
504
1122
|
hash_concurrency: int = 4,
|
505
1123
|
put_concurrency: int = 128,
|
506
|
-
):
|
1124
|
+
):
|
1125
|
+
"""mdmd:hidden"""
|
1126
|
+
...
|
1127
|
+
|
507
1128
|
def __enter__(self): ...
|
508
1129
|
async def __aenter__(self): ...
|
509
1130
|
def __exit__(self, exc_type, exc_val, exc_tb): ...
|
@@ -513,13 +1134,26 @@ class VolumeUploadContextManager2(AbstractVolumeUploadContextManager):
|
|
513
1134
|
local_file: typing.Union[pathlib.Path, str, typing.BinaryIO, _io.BytesIO],
|
514
1135
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
515
1136
|
mode: typing.Optional[int] = None,
|
516
|
-
):
|
1137
|
+
):
|
1138
|
+
"""Upload a file from a local file or file-like object.
|
1139
|
+
|
1140
|
+
Will create any needed parent directories automatically.
|
1141
|
+
|
1142
|
+
If `local_file` is a file-like object it must remain readable for the lifetime of the batch.
|
1143
|
+
"""
|
1144
|
+
...
|
1145
|
+
|
517
1146
|
def put_directory(
|
518
1147
|
self,
|
519
1148
|
local_path: typing.Union[pathlib.Path, str],
|
520
1149
|
remote_path: typing.Union[pathlib.PurePosixPath, str],
|
521
1150
|
recursive: bool = True,
|
522
|
-
):
|
1151
|
+
):
|
1152
|
+
"""Upload all files in a local directory.
|
1153
|
+
|
1154
|
+
Will create any needed parent directories automatically.
|
1155
|
+
"""
|
1156
|
+
...
|
523
1157
|
|
524
1158
|
class ___put_file_specs_spec(typing_extensions.Protocol[SUPERSELF]):
|
525
1159
|
def __call__(self, /, file_specs: list[modal._utils.blob_utils.FileUploadSpec2]): ...
|