databricks-sdk 0.44.1__py3-none-any.whl → 0.45.0__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.
Potentially problematic release.
This version of databricks-sdk might be problematic. Click here for more details.
- databricks/sdk/__init__.py +123 -115
- databricks/sdk/_base_client.py +112 -88
- databricks/sdk/_property.py +12 -7
- databricks/sdk/_widgets/__init__.py +13 -2
- databricks/sdk/_widgets/default_widgets_utils.py +21 -15
- databricks/sdk/_widgets/ipywidgets_utils.py +47 -24
- databricks/sdk/azure.py +8 -6
- databricks/sdk/casing.py +5 -5
- databricks/sdk/config.py +152 -99
- databricks/sdk/core.py +57 -47
- databricks/sdk/credentials_provider.py +300 -205
- databricks/sdk/data_plane.py +86 -3
- databricks/sdk/dbutils.py +123 -87
- databricks/sdk/environments.py +52 -35
- databricks/sdk/errors/base.py +61 -35
- databricks/sdk/errors/customizer.py +3 -3
- databricks/sdk/errors/deserializer.py +38 -25
- databricks/sdk/errors/details.py +417 -0
- databricks/sdk/errors/mapper.py +1 -1
- databricks/sdk/errors/overrides.py +27 -24
- databricks/sdk/errors/parser.py +26 -14
- databricks/sdk/errors/platform.py +10 -10
- databricks/sdk/errors/private_link.py +24 -24
- databricks/sdk/logger/round_trip_logger.py +28 -20
- databricks/sdk/mixins/compute.py +90 -60
- databricks/sdk/mixins/files.py +815 -145
- databricks/sdk/mixins/jobs.py +191 -16
- databricks/sdk/mixins/open_ai_client.py +26 -20
- databricks/sdk/mixins/workspace.py +45 -34
- databricks/sdk/oauth.py +372 -196
- databricks/sdk/retries.py +14 -12
- databricks/sdk/runtime/__init__.py +34 -17
- databricks/sdk/runtime/dbutils_stub.py +52 -39
- databricks/sdk/service/_internal.py +12 -7
- databricks/sdk/service/apps.py +618 -418
- databricks/sdk/service/billing.py +827 -604
- databricks/sdk/service/catalog.py +6552 -4474
- databricks/sdk/service/cleanrooms.py +550 -388
- databricks/sdk/service/compute.py +5241 -3531
- databricks/sdk/service/dashboards.py +1313 -923
- databricks/sdk/service/files.py +442 -309
- databricks/sdk/service/iam.py +2115 -1483
- databricks/sdk/service/jobs.py +4151 -2588
- databricks/sdk/service/marketplace.py +2210 -1517
- databricks/sdk/service/ml.py +3364 -2255
- databricks/sdk/service/oauth2.py +922 -584
- databricks/sdk/service/pipelines.py +1865 -1203
- databricks/sdk/service/provisioning.py +1435 -1029
- databricks/sdk/service/serving.py +2040 -1278
- databricks/sdk/service/settings.py +2846 -1929
- databricks/sdk/service/sharing.py +2201 -877
- databricks/sdk/service/sql.py +4650 -3103
- databricks/sdk/service/vectorsearch.py +816 -550
- databricks/sdk/service/workspace.py +1330 -906
- databricks/sdk/useragent.py +36 -22
- databricks/sdk/version.py +1 -1
- {databricks_sdk-0.44.1.dist-info → databricks_sdk-0.45.0.dist-info}/METADATA +31 -31
- databricks_sdk-0.45.0.dist-info/RECORD +70 -0
- {databricks_sdk-0.44.1.dist-info → databricks_sdk-0.45.0.dist-info}/WHEEL +1 -1
- databricks_sdk-0.44.1.dist-info/RECORD +0 -69
- {databricks_sdk-0.44.1.dist-info → databricks_sdk-0.45.0.dist-info}/LICENSE +0 -0
- {databricks_sdk-0.44.1.dist-info → databricks_sdk-0.45.0.dist-info}/NOTICE +0 -0
- {databricks_sdk-0.44.1.dist-info → databricks_sdk-0.45.0.dist-info}/top_level.txt +0 -0
databricks/sdk/service/files.py
CHANGED
|
@@ -4,11 +4,12 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
-
from typing import BinaryIO, Dict, Iterator, List, Optional
|
|
7
|
+
from typing import Any, BinaryIO, Dict, Iterator, List, Optional
|
|
8
8
|
|
|
9
9
|
from ._internal import _escape_multi_segment_path_parameter, _repeated_dict
|
|
10
10
|
|
|
11
|
-
_LOG = logging.getLogger(
|
|
11
|
+
_LOG = logging.getLogger("databricks.sdk")
|
|
12
|
+
|
|
12
13
|
|
|
13
14
|
# all definitions in this file are in alphabetical order
|
|
14
15
|
|
|
@@ -24,26 +25,29 @@ class AddBlock:
|
|
|
24
25
|
def as_dict(self) -> dict:
|
|
25
26
|
"""Serializes the AddBlock into a dictionary suitable for use as a JSON request body."""
|
|
26
27
|
body = {}
|
|
27
|
-
if self.data is not None:
|
|
28
|
-
|
|
28
|
+
if self.data is not None:
|
|
29
|
+
body["data"] = self.data
|
|
30
|
+
if self.handle is not None:
|
|
31
|
+
body["handle"] = self.handle
|
|
29
32
|
return body
|
|
30
33
|
|
|
31
34
|
def as_shallow_dict(self) -> dict:
|
|
32
35
|
"""Serializes the AddBlock into a shallow dictionary of its immediate attributes."""
|
|
33
36
|
body = {}
|
|
34
|
-
if self.data is not None:
|
|
35
|
-
|
|
37
|
+
if self.data is not None:
|
|
38
|
+
body["data"] = self.data
|
|
39
|
+
if self.handle is not None:
|
|
40
|
+
body["handle"] = self.handle
|
|
36
41
|
return body
|
|
37
42
|
|
|
38
43
|
@classmethod
|
|
39
|
-
def from_dict(cls, d: Dict[str,
|
|
44
|
+
def from_dict(cls, d: Dict[str, Any]) -> AddBlock:
|
|
40
45
|
"""Deserializes the AddBlock from a dictionary."""
|
|
41
|
-
return cls(data=d.get(
|
|
46
|
+
return cls(data=d.get("data", None), handle=d.get("handle", None))
|
|
42
47
|
|
|
43
48
|
|
|
44
49
|
@dataclass
|
|
45
50
|
class AddBlockResponse:
|
|
46
|
-
|
|
47
51
|
def as_dict(self) -> dict:
|
|
48
52
|
"""Serializes the AddBlockResponse into a dictionary suitable for use as a JSON request body."""
|
|
49
53
|
body = {}
|
|
@@ -55,7 +59,7 @@ class AddBlockResponse:
|
|
|
55
59
|
return body
|
|
56
60
|
|
|
57
61
|
@classmethod
|
|
58
|
-
def from_dict(cls, d: Dict[str,
|
|
62
|
+
def from_dict(cls, d: Dict[str, Any]) -> AddBlockResponse:
|
|
59
63
|
"""Deserializes the AddBlockResponse from a dictionary."""
|
|
60
64
|
return cls()
|
|
61
65
|
|
|
@@ -68,24 +72,25 @@ class Close:
|
|
|
68
72
|
def as_dict(self) -> dict:
|
|
69
73
|
"""Serializes the Close into a dictionary suitable for use as a JSON request body."""
|
|
70
74
|
body = {}
|
|
71
|
-
if self.handle is not None:
|
|
75
|
+
if self.handle is not None:
|
|
76
|
+
body["handle"] = self.handle
|
|
72
77
|
return body
|
|
73
78
|
|
|
74
79
|
def as_shallow_dict(self) -> dict:
|
|
75
80
|
"""Serializes the Close into a shallow dictionary of its immediate attributes."""
|
|
76
81
|
body = {}
|
|
77
|
-
if self.handle is not None:
|
|
82
|
+
if self.handle is not None:
|
|
83
|
+
body["handle"] = self.handle
|
|
78
84
|
return body
|
|
79
85
|
|
|
80
86
|
@classmethod
|
|
81
|
-
def from_dict(cls, d: Dict[str,
|
|
87
|
+
def from_dict(cls, d: Dict[str, Any]) -> Close:
|
|
82
88
|
"""Deserializes the Close from a dictionary."""
|
|
83
|
-
return cls(handle=d.get(
|
|
89
|
+
return cls(handle=d.get("handle", None))
|
|
84
90
|
|
|
85
91
|
|
|
86
92
|
@dataclass
|
|
87
93
|
class CloseResponse:
|
|
88
|
-
|
|
89
94
|
def as_dict(self) -> dict:
|
|
90
95
|
"""Serializes the CloseResponse into a dictionary suitable for use as a JSON request body."""
|
|
91
96
|
body = {}
|
|
@@ -97,7 +102,7 @@ class CloseResponse:
|
|
|
97
102
|
return body
|
|
98
103
|
|
|
99
104
|
@classmethod
|
|
100
|
-
def from_dict(cls, d: Dict[str,
|
|
105
|
+
def from_dict(cls, d: Dict[str, Any]) -> CloseResponse:
|
|
101
106
|
"""Deserializes the CloseResponse from a dictionary."""
|
|
102
107
|
return cls()
|
|
103
108
|
|
|
@@ -113,26 +118,29 @@ class Create:
|
|
|
113
118
|
def as_dict(self) -> dict:
|
|
114
119
|
"""Serializes the Create into a dictionary suitable for use as a JSON request body."""
|
|
115
120
|
body = {}
|
|
116
|
-
if self.overwrite is not None:
|
|
117
|
-
|
|
121
|
+
if self.overwrite is not None:
|
|
122
|
+
body["overwrite"] = self.overwrite
|
|
123
|
+
if self.path is not None:
|
|
124
|
+
body["path"] = self.path
|
|
118
125
|
return body
|
|
119
126
|
|
|
120
127
|
def as_shallow_dict(self) -> dict:
|
|
121
128
|
"""Serializes the Create into a shallow dictionary of its immediate attributes."""
|
|
122
129
|
body = {}
|
|
123
|
-
if self.overwrite is not None:
|
|
124
|
-
|
|
130
|
+
if self.overwrite is not None:
|
|
131
|
+
body["overwrite"] = self.overwrite
|
|
132
|
+
if self.path is not None:
|
|
133
|
+
body["path"] = self.path
|
|
125
134
|
return body
|
|
126
135
|
|
|
127
136
|
@classmethod
|
|
128
|
-
def from_dict(cls, d: Dict[str,
|
|
137
|
+
def from_dict(cls, d: Dict[str, Any]) -> Create:
|
|
129
138
|
"""Deserializes the Create from a dictionary."""
|
|
130
|
-
return cls(overwrite=d.get(
|
|
139
|
+
return cls(overwrite=d.get("overwrite", None), path=d.get("path", None))
|
|
131
140
|
|
|
132
141
|
|
|
133
142
|
@dataclass
|
|
134
143
|
class CreateDirectoryResponse:
|
|
135
|
-
|
|
136
144
|
def as_dict(self) -> dict:
|
|
137
145
|
"""Serializes the CreateDirectoryResponse into a dictionary suitable for use as a JSON request body."""
|
|
138
146
|
body = {}
|
|
@@ -144,7 +152,7 @@ class CreateDirectoryResponse:
|
|
|
144
152
|
return body
|
|
145
153
|
|
|
146
154
|
@classmethod
|
|
147
|
-
def from_dict(cls, d: Dict[str,
|
|
155
|
+
def from_dict(cls, d: Dict[str, Any]) -> CreateDirectoryResponse:
|
|
148
156
|
"""Deserializes the CreateDirectoryResponse from a dictionary."""
|
|
149
157
|
return cls()
|
|
150
158
|
|
|
@@ -158,19 +166,21 @@ class CreateResponse:
|
|
|
158
166
|
def as_dict(self) -> dict:
|
|
159
167
|
"""Serializes the CreateResponse into a dictionary suitable for use as a JSON request body."""
|
|
160
168
|
body = {}
|
|
161
|
-
if self.handle is not None:
|
|
169
|
+
if self.handle is not None:
|
|
170
|
+
body["handle"] = self.handle
|
|
162
171
|
return body
|
|
163
172
|
|
|
164
173
|
def as_shallow_dict(self) -> dict:
|
|
165
174
|
"""Serializes the CreateResponse into a shallow dictionary of its immediate attributes."""
|
|
166
175
|
body = {}
|
|
167
|
-
if self.handle is not None:
|
|
176
|
+
if self.handle is not None:
|
|
177
|
+
body["handle"] = self.handle
|
|
168
178
|
return body
|
|
169
179
|
|
|
170
180
|
@classmethod
|
|
171
|
-
def from_dict(cls, d: Dict[str,
|
|
181
|
+
def from_dict(cls, d: Dict[str, Any]) -> CreateResponse:
|
|
172
182
|
"""Deserializes the CreateResponse from a dictionary."""
|
|
173
|
-
return cls(handle=d.get(
|
|
183
|
+
return cls(handle=d.get("handle", None))
|
|
174
184
|
|
|
175
185
|
|
|
176
186
|
@dataclass
|
|
@@ -185,26 +195,29 @@ class Delete:
|
|
|
185
195
|
def as_dict(self) -> dict:
|
|
186
196
|
"""Serializes the Delete into a dictionary suitable for use as a JSON request body."""
|
|
187
197
|
body = {}
|
|
188
|
-
if self.path is not None:
|
|
189
|
-
|
|
198
|
+
if self.path is not None:
|
|
199
|
+
body["path"] = self.path
|
|
200
|
+
if self.recursive is not None:
|
|
201
|
+
body["recursive"] = self.recursive
|
|
190
202
|
return body
|
|
191
203
|
|
|
192
204
|
def as_shallow_dict(self) -> dict:
|
|
193
205
|
"""Serializes the Delete into a shallow dictionary of its immediate attributes."""
|
|
194
206
|
body = {}
|
|
195
|
-
if self.path is not None:
|
|
196
|
-
|
|
207
|
+
if self.path is not None:
|
|
208
|
+
body["path"] = self.path
|
|
209
|
+
if self.recursive is not None:
|
|
210
|
+
body["recursive"] = self.recursive
|
|
197
211
|
return body
|
|
198
212
|
|
|
199
213
|
@classmethod
|
|
200
|
-
def from_dict(cls, d: Dict[str,
|
|
214
|
+
def from_dict(cls, d: Dict[str, Any]) -> Delete:
|
|
201
215
|
"""Deserializes the Delete from a dictionary."""
|
|
202
|
-
return cls(path=d.get(
|
|
216
|
+
return cls(path=d.get("path", None), recursive=d.get("recursive", None))
|
|
203
217
|
|
|
204
218
|
|
|
205
219
|
@dataclass
|
|
206
220
|
class DeleteDirectoryResponse:
|
|
207
|
-
|
|
208
221
|
def as_dict(self) -> dict:
|
|
209
222
|
"""Serializes the DeleteDirectoryResponse into a dictionary suitable for use as a JSON request body."""
|
|
210
223
|
body = {}
|
|
@@ -216,14 +229,13 @@ class DeleteDirectoryResponse:
|
|
|
216
229
|
return body
|
|
217
230
|
|
|
218
231
|
@classmethod
|
|
219
|
-
def from_dict(cls, d: Dict[str,
|
|
232
|
+
def from_dict(cls, d: Dict[str, Any]) -> DeleteDirectoryResponse:
|
|
220
233
|
"""Deserializes the DeleteDirectoryResponse from a dictionary."""
|
|
221
234
|
return cls()
|
|
222
235
|
|
|
223
236
|
|
|
224
237
|
@dataclass
|
|
225
238
|
class DeleteResponse:
|
|
226
|
-
|
|
227
239
|
def as_dict(self) -> dict:
|
|
228
240
|
"""Serializes the DeleteResponse into a dictionary suitable for use as a JSON request body."""
|
|
229
241
|
body = {}
|
|
@@ -235,7 +247,7 @@ class DeleteResponse:
|
|
|
235
247
|
return body
|
|
236
248
|
|
|
237
249
|
@classmethod
|
|
238
|
-
def from_dict(cls, d: Dict[str,
|
|
250
|
+
def from_dict(cls, d: Dict[str, Any]) -> DeleteResponse:
|
|
239
251
|
"""Deserializes the DeleteResponse from a dictionary."""
|
|
240
252
|
return cls()
|
|
241
253
|
|
|
@@ -260,31 +272,43 @@ class DirectoryEntry:
|
|
|
260
272
|
def as_dict(self) -> dict:
|
|
261
273
|
"""Serializes the DirectoryEntry into a dictionary suitable for use as a JSON request body."""
|
|
262
274
|
body = {}
|
|
263
|
-
if self.file_size is not None:
|
|
264
|
-
|
|
265
|
-
if self.
|
|
266
|
-
|
|
267
|
-
if self.
|
|
275
|
+
if self.file_size is not None:
|
|
276
|
+
body["file_size"] = self.file_size
|
|
277
|
+
if self.is_directory is not None:
|
|
278
|
+
body["is_directory"] = self.is_directory
|
|
279
|
+
if self.last_modified is not None:
|
|
280
|
+
body["last_modified"] = self.last_modified
|
|
281
|
+
if self.name is not None:
|
|
282
|
+
body["name"] = self.name
|
|
283
|
+
if self.path is not None:
|
|
284
|
+
body["path"] = self.path
|
|
268
285
|
return body
|
|
269
286
|
|
|
270
287
|
def as_shallow_dict(self) -> dict:
|
|
271
288
|
"""Serializes the DirectoryEntry into a shallow dictionary of its immediate attributes."""
|
|
272
289
|
body = {}
|
|
273
|
-
if self.file_size is not None:
|
|
274
|
-
|
|
275
|
-
if self.
|
|
276
|
-
|
|
277
|
-
if self.
|
|
290
|
+
if self.file_size is not None:
|
|
291
|
+
body["file_size"] = self.file_size
|
|
292
|
+
if self.is_directory is not None:
|
|
293
|
+
body["is_directory"] = self.is_directory
|
|
294
|
+
if self.last_modified is not None:
|
|
295
|
+
body["last_modified"] = self.last_modified
|
|
296
|
+
if self.name is not None:
|
|
297
|
+
body["name"] = self.name
|
|
298
|
+
if self.path is not None:
|
|
299
|
+
body["path"] = self.path
|
|
278
300
|
return body
|
|
279
301
|
|
|
280
302
|
@classmethod
|
|
281
|
-
def from_dict(cls, d: Dict[str,
|
|
303
|
+
def from_dict(cls, d: Dict[str, Any]) -> DirectoryEntry:
|
|
282
304
|
"""Deserializes the DirectoryEntry from a dictionary."""
|
|
283
|
-
return cls(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
305
|
+
return cls(
|
|
306
|
+
file_size=d.get("file_size", None),
|
|
307
|
+
is_directory=d.get("is_directory", None),
|
|
308
|
+
last_modified=d.get("last_modified", None),
|
|
309
|
+
name=d.get("name", None),
|
|
310
|
+
path=d.get("path", None),
|
|
311
|
+
)
|
|
288
312
|
|
|
289
313
|
|
|
290
314
|
@dataclass
|
|
@@ -300,28 +324,38 @@ class DownloadResponse:
|
|
|
300
324
|
def as_dict(self) -> dict:
|
|
301
325
|
"""Serializes the DownloadResponse into a dictionary suitable for use as a JSON request body."""
|
|
302
326
|
body = {}
|
|
303
|
-
if self.content_length is not None:
|
|
304
|
-
|
|
305
|
-
if self.
|
|
306
|
-
|
|
327
|
+
if self.content_length is not None:
|
|
328
|
+
body["content-length"] = self.content_length
|
|
329
|
+
if self.content_type is not None:
|
|
330
|
+
body["content-type"] = self.content_type
|
|
331
|
+
if self.contents:
|
|
332
|
+
body["contents"] = self.contents
|
|
333
|
+
if self.last_modified is not None:
|
|
334
|
+
body["last-modified"] = self.last_modified
|
|
307
335
|
return body
|
|
308
336
|
|
|
309
337
|
def as_shallow_dict(self) -> dict:
|
|
310
338
|
"""Serializes the DownloadResponse into a shallow dictionary of its immediate attributes."""
|
|
311
339
|
body = {}
|
|
312
|
-
if self.content_length is not None:
|
|
313
|
-
|
|
314
|
-
if self.
|
|
315
|
-
|
|
340
|
+
if self.content_length is not None:
|
|
341
|
+
body["content-length"] = self.content_length
|
|
342
|
+
if self.content_type is not None:
|
|
343
|
+
body["content-type"] = self.content_type
|
|
344
|
+
if self.contents:
|
|
345
|
+
body["contents"] = self.contents
|
|
346
|
+
if self.last_modified is not None:
|
|
347
|
+
body["last-modified"] = self.last_modified
|
|
316
348
|
return body
|
|
317
349
|
|
|
318
350
|
@classmethod
|
|
319
|
-
def from_dict(cls, d: Dict[str,
|
|
351
|
+
def from_dict(cls, d: Dict[str, Any]) -> DownloadResponse:
|
|
320
352
|
"""Deserializes the DownloadResponse from a dictionary."""
|
|
321
|
-
return cls(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
353
|
+
return cls(
|
|
354
|
+
content_length=int(d.get("content-length", None)),
|
|
355
|
+
content_type=d.get("content-type", None),
|
|
356
|
+
contents=d.get("contents", None),
|
|
357
|
+
last_modified=d.get("last-modified", None),
|
|
358
|
+
)
|
|
325
359
|
|
|
326
360
|
|
|
327
361
|
@dataclass
|
|
@@ -341,33 +375,42 @@ class FileInfo:
|
|
|
341
375
|
def as_dict(self) -> dict:
|
|
342
376
|
"""Serializes the FileInfo into a dictionary suitable for use as a JSON request body."""
|
|
343
377
|
body = {}
|
|
344
|
-
if self.file_size is not None:
|
|
345
|
-
|
|
346
|
-
if self.
|
|
347
|
-
|
|
378
|
+
if self.file_size is not None:
|
|
379
|
+
body["file_size"] = self.file_size
|
|
380
|
+
if self.is_dir is not None:
|
|
381
|
+
body["is_dir"] = self.is_dir
|
|
382
|
+
if self.modification_time is not None:
|
|
383
|
+
body["modification_time"] = self.modification_time
|
|
384
|
+
if self.path is not None:
|
|
385
|
+
body["path"] = self.path
|
|
348
386
|
return body
|
|
349
387
|
|
|
350
388
|
def as_shallow_dict(self) -> dict:
|
|
351
389
|
"""Serializes the FileInfo into a shallow dictionary of its immediate attributes."""
|
|
352
390
|
body = {}
|
|
353
|
-
if self.file_size is not None:
|
|
354
|
-
|
|
355
|
-
if self.
|
|
356
|
-
|
|
391
|
+
if self.file_size is not None:
|
|
392
|
+
body["file_size"] = self.file_size
|
|
393
|
+
if self.is_dir is not None:
|
|
394
|
+
body["is_dir"] = self.is_dir
|
|
395
|
+
if self.modification_time is not None:
|
|
396
|
+
body["modification_time"] = self.modification_time
|
|
397
|
+
if self.path is not None:
|
|
398
|
+
body["path"] = self.path
|
|
357
399
|
return body
|
|
358
400
|
|
|
359
401
|
@classmethod
|
|
360
|
-
def from_dict(cls, d: Dict[str,
|
|
402
|
+
def from_dict(cls, d: Dict[str, Any]) -> FileInfo:
|
|
361
403
|
"""Deserializes the FileInfo from a dictionary."""
|
|
362
|
-
return cls(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
404
|
+
return cls(
|
|
405
|
+
file_size=d.get("file_size", None),
|
|
406
|
+
is_dir=d.get("is_dir", None),
|
|
407
|
+
modification_time=d.get("modification_time", None),
|
|
408
|
+
path=d.get("path", None),
|
|
409
|
+
)
|
|
366
410
|
|
|
367
411
|
|
|
368
412
|
@dataclass
|
|
369
413
|
class GetDirectoryMetadataResponse:
|
|
370
|
-
|
|
371
414
|
def as_dict(self) -> dict:
|
|
372
415
|
"""Serializes the GetDirectoryMetadataResponse into a dictionary suitable for use as a JSON request body."""
|
|
373
416
|
body = {}
|
|
@@ -379,7 +422,7 @@ class GetDirectoryMetadataResponse:
|
|
|
379
422
|
return body
|
|
380
423
|
|
|
381
424
|
@classmethod
|
|
382
|
-
def from_dict(cls, d: Dict[str,
|
|
425
|
+
def from_dict(cls, d: Dict[str, Any]) -> GetDirectoryMetadataResponse:
|
|
383
426
|
"""Deserializes the GetDirectoryMetadataResponse from a dictionary."""
|
|
384
427
|
return cls()
|
|
385
428
|
|
|
@@ -395,25 +438,33 @@ class GetMetadataResponse:
|
|
|
395
438
|
def as_dict(self) -> dict:
|
|
396
439
|
"""Serializes the GetMetadataResponse into a dictionary suitable for use as a JSON request body."""
|
|
397
440
|
body = {}
|
|
398
|
-
if self.content_length is not None:
|
|
399
|
-
|
|
400
|
-
if self.
|
|
441
|
+
if self.content_length is not None:
|
|
442
|
+
body["content-length"] = self.content_length
|
|
443
|
+
if self.content_type is not None:
|
|
444
|
+
body["content-type"] = self.content_type
|
|
445
|
+
if self.last_modified is not None:
|
|
446
|
+
body["last-modified"] = self.last_modified
|
|
401
447
|
return body
|
|
402
448
|
|
|
403
449
|
def as_shallow_dict(self) -> dict:
|
|
404
450
|
"""Serializes the GetMetadataResponse into a shallow dictionary of its immediate attributes."""
|
|
405
451
|
body = {}
|
|
406
|
-
if self.content_length is not None:
|
|
407
|
-
|
|
408
|
-
if self.
|
|
452
|
+
if self.content_length is not None:
|
|
453
|
+
body["content-length"] = self.content_length
|
|
454
|
+
if self.content_type is not None:
|
|
455
|
+
body["content-type"] = self.content_type
|
|
456
|
+
if self.last_modified is not None:
|
|
457
|
+
body["last-modified"] = self.last_modified
|
|
409
458
|
return body
|
|
410
459
|
|
|
411
460
|
@classmethod
|
|
412
|
-
def from_dict(cls, d: Dict[str,
|
|
461
|
+
def from_dict(cls, d: Dict[str, Any]) -> GetMetadataResponse:
|
|
413
462
|
"""Deserializes the GetMetadataResponse from a dictionary."""
|
|
414
|
-
return cls(
|
|
415
|
-
|
|
416
|
-
|
|
463
|
+
return cls(
|
|
464
|
+
content_length=int(d.get("content-length", None)),
|
|
465
|
+
content_type=d.get("content-type", None),
|
|
466
|
+
last_modified=d.get("last-modified", None),
|
|
467
|
+
)
|
|
417
468
|
|
|
418
469
|
|
|
419
470
|
@dataclass
|
|
@@ -427,22 +478,27 @@ class ListDirectoryResponse:
|
|
|
427
478
|
def as_dict(self) -> dict:
|
|
428
479
|
"""Serializes the ListDirectoryResponse into a dictionary suitable for use as a JSON request body."""
|
|
429
480
|
body = {}
|
|
430
|
-
if self.contents:
|
|
431
|
-
|
|
481
|
+
if self.contents:
|
|
482
|
+
body["contents"] = [v.as_dict() for v in self.contents]
|
|
483
|
+
if self.next_page_token is not None:
|
|
484
|
+
body["next_page_token"] = self.next_page_token
|
|
432
485
|
return body
|
|
433
486
|
|
|
434
487
|
def as_shallow_dict(self) -> dict:
|
|
435
488
|
"""Serializes the ListDirectoryResponse into a shallow dictionary of its immediate attributes."""
|
|
436
489
|
body = {}
|
|
437
|
-
if self.contents:
|
|
438
|
-
|
|
490
|
+
if self.contents:
|
|
491
|
+
body["contents"] = self.contents
|
|
492
|
+
if self.next_page_token is not None:
|
|
493
|
+
body["next_page_token"] = self.next_page_token
|
|
439
494
|
return body
|
|
440
495
|
|
|
441
496
|
@classmethod
|
|
442
|
-
def from_dict(cls, d: Dict[str,
|
|
497
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListDirectoryResponse:
|
|
443
498
|
"""Deserializes the ListDirectoryResponse from a dictionary."""
|
|
444
|
-
return cls(
|
|
445
|
-
|
|
499
|
+
return cls(
|
|
500
|
+
contents=_repeated_dict(d, "contents", DirectoryEntry), next_page_token=d.get("next_page_token", None)
|
|
501
|
+
)
|
|
446
502
|
|
|
447
503
|
|
|
448
504
|
@dataclass
|
|
@@ -453,19 +509,21 @@ class ListStatusResponse:
|
|
|
453
509
|
def as_dict(self) -> dict:
|
|
454
510
|
"""Serializes the ListStatusResponse into a dictionary suitable for use as a JSON request body."""
|
|
455
511
|
body = {}
|
|
456
|
-
if self.files:
|
|
512
|
+
if self.files:
|
|
513
|
+
body["files"] = [v.as_dict() for v in self.files]
|
|
457
514
|
return body
|
|
458
515
|
|
|
459
516
|
def as_shallow_dict(self) -> dict:
|
|
460
517
|
"""Serializes the ListStatusResponse into a shallow dictionary of its immediate attributes."""
|
|
461
518
|
body = {}
|
|
462
|
-
if self.files:
|
|
519
|
+
if self.files:
|
|
520
|
+
body["files"] = self.files
|
|
463
521
|
return body
|
|
464
522
|
|
|
465
523
|
@classmethod
|
|
466
|
-
def from_dict(cls, d: Dict[str,
|
|
524
|
+
def from_dict(cls, d: Dict[str, Any]) -> ListStatusResponse:
|
|
467
525
|
"""Deserializes the ListStatusResponse from a dictionary."""
|
|
468
|
-
return cls(files=_repeated_dict(d,
|
|
526
|
+
return cls(files=_repeated_dict(d, "files", FileInfo))
|
|
469
527
|
|
|
470
528
|
|
|
471
529
|
@dataclass
|
|
@@ -476,24 +534,25 @@ class MkDirs:
|
|
|
476
534
|
def as_dict(self) -> dict:
|
|
477
535
|
"""Serializes the MkDirs into a dictionary suitable for use as a JSON request body."""
|
|
478
536
|
body = {}
|
|
479
|
-
if self.path is not None:
|
|
537
|
+
if self.path is not None:
|
|
538
|
+
body["path"] = self.path
|
|
480
539
|
return body
|
|
481
540
|
|
|
482
541
|
def as_shallow_dict(self) -> dict:
|
|
483
542
|
"""Serializes the MkDirs into a shallow dictionary of its immediate attributes."""
|
|
484
543
|
body = {}
|
|
485
|
-
if self.path is not None:
|
|
544
|
+
if self.path is not None:
|
|
545
|
+
body["path"] = self.path
|
|
486
546
|
return body
|
|
487
547
|
|
|
488
548
|
@classmethod
|
|
489
|
-
def from_dict(cls, d: Dict[str,
|
|
549
|
+
def from_dict(cls, d: Dict[str, Any]) -> MkDirs:
|
|
490
550
|
"""Deserializes the MkDirs from a dictionary."""
|
|
491
|
-
return cls(path=d.get(
|
|
551
|
+
return cls(path=d.get("path", None))
|
|
492
552
|
|
|
493
553
|
|
|
494
554
|
@dataclass
|
|
495
555
|
class MkDirsResponse:
|
|
496
|
-
|
|
497
556
|
def as_dict(self) -> dict:
|
|
498
557
|
"""Serializes the MkDirsResponse into a dictionary suitable for use as a JSON request body."""
|
|
499
558
|
body = {}
|
|
@@ -505,7 +564,7 @@ class MkDirsResponse:
|
|
|
505
564
|
return body
|
|
506
565
|
|
|
507
566
|
@classmethod
|
|
508
|
-
def from_dict(cls, d: Dict[str,
|
|
567
|
+
def from_dict(cls, d: Dict[str, Any]) -> MkDirsResponse:
|
|
509
568
|
"""Deserializes the MkDirsResponse from a dictionary."""
|
|
510
569
|
return cls()
|
|
511
570
|
|
|
@@ -521,26 +580,29 @@ class Move:
|
|
|
521
580
|
def as_dict(self) -> dict:
|
|
522
581
|
"""Serializes the Move into a dictionary suitable for use as a JSON request body."""
|
|
523
582
|
body = {}
|
|
524
|
-
if self.destination_path is not None:
|
|
525
|
-
|
|
583
|
+
if self.destination_path is not None:
|
|
584
|
+
body["destination_path"] = self.destination_path
|
|
585
|
+
if self.source_path is not None:
|
|
586
|
+
body["source_path"] = self.source_path
|
|
526
587
|
return body
|
|
527
588
|
|
|
528
589
|
def as_shallow_dict(self) -> dict:
|
|
529
590
|
"""Serializes the Move into a shallow dictionary of its immediate attributes."""
|
|
530
591
|
body = {}
|
|
531
|
-
if self.destination_path is not None:
|
|
532
|
-
|
|
592
|
+
if self.destination_path is not None:
|
|
593
|
+
body["destination_path"] = self.destination_path
|
|
594
|
+
if self.source_path is not None:
|
|
595
|
+
body["source_path"] = self.source_path
|
|
533
596
|
return body
|
|
534
597
|
|
|
535
598
|
@classmethod
|
|
536
|
-
def from_dict(cls, d: Dict[str,
|
|
599
|
+
def from_dict(cls, d: Dict[str, Any]) -> Move:
|
|
537
600
|
"""Deserializes the Move from a dictionary."""
|
|
538
|
-
return cls(destination_path=d.get(
|
|
601
|
+
return cls(destination_path=d.get("destination_path", None), source_path=d.get("source_path", None))
|
|
539
602
|
|
|
540
603
|
|
|
541
604
|
@dataclass
|
|
542
605
|
class MoveResponse:
|
|
543
|
-
|
|
544
606
|
def as_dict(self) -> dict:
|
|
545
607
|
"""Serializes the MoveResponse into a dictionary suitable for use as a JSON request body."""
|
|
546
608
|
body = {}
|
|
@@ -552,7 +614,7 @@ class MoveResponse:
|
|
|
552
614
|
return body
|
|
553
615
|
|
|
554
616
|
@classmethod
|
|
555
|
-
def from_dict(cls, d: Dict[str,
|
|
617
|
+
def from_dict(cls, d: Dict[str, Any]) -> MoveResponse:
|
|
556
618
|
"""Deserializes the MoveResponse from a dictionary."""
|
|
557
619
|
return cls()
|
|
558
620
|
|
|
@@ -571,30 +633,33 @@ class Put:
|
|
|
571
633
|
def as_dict(self) -> dict:
|
|
572
634
|
"""Serializes the Put into a dictionary suitable for use as a JSON request body."""
|
|
573
635
|
body = {}
|
|
574
|
-
if self.contents is not None:
|
|
575
|
-
|
|
576
|
-
if self.
|
|
636
|
+
if self.contents is not None:
|
|
637
|
+
body["contents"] = self.contents
|
|
638
|
+
if self.overwrite is not None:
|
|
639
|
+
body["overwrite"] = self.overwrite
|
|
640
|
+
if self.path is not None:
|
|
641
|
+
body["path"] = self.path
|
|
577
642
|
return body
|
|
578
643
|
|
|
579
644
|
def as_shallow_dict(self) -> dict:
|
|
580
645
|
"""Serializes the Put into a shallow dictionary of its immediate attributes."""
|
|
581
646
|
body = {}
|
|
582
|
-
if self.contents is not None:
|
|
583
|
-
|
|
584
|
-
if self.
|
|
647
|
+
if self.contents is not None:
|
|
648
|
+
body["contents"] = self.contents
|
|
649
|
+
if self.overwrite is not None:
|
|
650
|
+
body["overwrite"] = self.overwrite
|
|
651
|
+
if self.path is not None:
|
|
652
|
+
body["path"] = self.path
|
|
585
653
|
return body
|
|
586
654
|
|
|
587
655
|
@classmethod
|
|
588
|
-
def from_dict(cls, d: Dict[str,
|
|
656
|
+
def from_dict(cls, d: Dict[str, Any]) -> Put:
|
|
589
657
|
"""Deserializes the Put from a dictionary."""
|
|
590
|
-
return cls(contents=d.get(
|
|
591
|
-
overwrite=d.get('overwrite', None),
|
|
592
|
-
path=d.get('path', None))
|
|
658
|
+
return cls(contents=d.get("contents", None), overwrite=d.get("overwrite", None), path=d.get("path", None))
|
|
593
659
|
|
|
594
660
|
|
|
595
661
|
@dataclass
|
|
596
662
|
class PutResponse:
|
|
597
|
-
|
|
598
663
|
def as_dict(self) -> dict:
|
|
599
664
|
"""Serializes the PutResponse into a dictionary suitable for use as a JSON request body."""
|
|
600
665
|
body = {}
|
|
@@ -606,7 +671,7 @@ class PutResponse:
|
|
|
606
671
|
return body
|
|
607
672
|
|
|
608
673
|
@classmethod
|
|
609
|
-
def from_dict(cls, d: Dict[str,
|
|
674
|
+
def from_dict(cls, d: Dict[str, Any]) -> PutResponse:
|
|
610
675
|
"""Deserializes the PutResponse from a dictionary."""
|
|
611
676
|
return cls()
|
|
612
677
|
|
|
@@ -623,26 +688,29 @@ class ReadResponse:
|
|
|
623
688
|
def as_dict(self) -> dict:
|
|
624
689
|
"""Serializes the ReadResponse into a dictionary suitable for use as a JSON request body."""
|
|
625
690
|
body = {}
|
|
626
|
-
if self.bytes_read is not None:
|
|
627
|
-
|
|
691
|
+
if self.bytes_read is not None:
|
|
692
|
+
body["bytes_read"] = self.bytes_read
|
|
693
|
+
if self.data is not None:
|
|
694
|
+
body["data"] = self.data
|
|
628
695
|
return body
|
|
629
696
|
|
|
630
697
|
def as_shallow_dict(self) -> dict:
|
|
631
698
|
"""Serializes the ReadResponse into a shallow dictionary of its immediate attributes."""
|
|
632
699
|
body = {}
|
|
633
|
-
if self.bytes_read is not None:
|
|
634
|
-
|
|
700
|
+
if self.bytes_read is not None:
|
|
701
|
+
body["bytes_read"] = self.bytes_read
|
|
702
|
+
if self.data is not None:
|
|
703
|
+
body["data"] = self.data
|
|
635
704
|
return body
|
|
636
705
|
|
|
637
706
|
@classmethod
|
|
638
|
-
def from_dict(cls, d: Dict[str,
|
|
707
|
+
def from_dict(cls, d: Dict[str, Any]) -> ReadResponse:
|
|
639
708
|
"""Deserializes the ReadResponse from a dictionary."""
|
|
640
|
-
return cls(bytes_read=d.get(
|
|
709
|
+
return cls(bytes_read=d.get("bytes_read", None), data=d.get("data", None))
|
|
641
710
|
|
|
642
711
|
|
|
643
712
|
@dataclass
|
|
644
713
|
class UploadResponse:
|
|
645
|
-
|
|
646
714
|
def as_dict(self) -> dict:
|
|
647
715
|
"""Serializes the UploadResponse into a dictionary suitable for use as a JSON request body."""
|
|
648
716
|
body = {}
|
|
@@ -654,7 +722,7 @@ class UploadResponse:
|
|
|
654
722
|
return body
|
|
655
723
|
|
|
656
724
|
@classmethod
|
|
657
|
-
def from_dict(cls, d: Dict[str,
|
|
725
|
+
def from_dict(cls, d: Dict[str, Any]) -> UploadResponse:
|
|
658
726
|
"""Deserializes the UploadResponse from a dictionary."""
|
|
659
727
|
return cls()
|
|
660
728
|
|
|
@@ -668,232 +736,272 @@ class DbfsAPI:
|
|
|
668
736
|
|
|
669
737
|
def add_block(self, handle: int, data: str):
|
|
670
738
|
"""Append data block.
|
|
671
|
-
|
|
739
|
+
|
|
672
740
|
Appends a block of data to the stream specified by the input handle. If the handle does not exist,
|
|
673
741
|
this call will throw an exception with ``RESOURCE_DOES_NOT_EXIST``.
|
|
674
|
-
|
|
742
|
+
|
|
675
743
|
If the block of data exceeds 1 MB, this call will throw an exception with ``MAX_BLOCK_SIZE_EXCEEDED``.
|
|
676
|
-
|
|
744
|
+
|
|
677
745
|
:param handle: int
|
|
678
746
|
The handle on an open stream.
|
|
679
747
|
:param data: str
|
|
680
748
|
The base64-encoded data to append to the stream. This has a limit of 1 MB.
|
|
681
|
-
|
|
682
|
-
|
|
749
|
+
|
|
750
|
+
|
|
683
751
|
"""
|
|
684
752
|
body = {}
|
|
685
|
-
if data is not None:
|
|
686
|
-
|
|
687
|
-
|
|
753
|
+
if data is not None:
|
|
754
|
+
body["data"] = data
|
|
755
|
+
if handle is not None:
|
|
756
|
+
body["handle"] = handle
|
|
757
|
+
headers = {
|
|
758
|
+
"Accept": "application/json",
|
|
759
|
+
"Content-Type": "application/json",
|
|
760
|
+
}
|
|
688
761
|
|
|
689
|
-
self._api.do(
|
|
762
|
+
self._api.do("POST", "/api/2.0/dbfs/add-block", body=body, headers=headers)
|
|
690
763
|
|
|
691
764
|
def close(self, handle: int):
|
|
692
765
|
"""Close the stream.
|
|
693
|
-
|
|
766
|
+
|
|
694
767
|
Closes the stream specified by the input handle. If the handle does not exist, this call throws an
|
|
695
768
|
exception with ``RESOURCE_DOES_NOT_EXIST``.
|
|
696
|
-
|
|
769
|
+
|
|
697
770
|
:param handle: int
|
|
698
771
|
The handle on an open stream.
|
|
699
|
-
|
|
700
|
-
|
|
772
|
+
|
|
773
|
+
|
|
701
774
|
"""
|
|
702
775
|
body = {}
|
|
703
|
-
if handle is not None:
|
|
704
|
-
|
|
776
|
+
if handle is not None:
|
|
777
|
+
body["handle"] = handle
|
|
778
|
+
headers = {
|
|
779
|
+
"Accept": "application/json",
|
|
780
|
+
"Content-Type": "application/json",
|
|
781
|
+
}
|
|
705
782
|
|
|
706
|
-
self._api.do(
|
|
783
|
+
self._api.do("POST", "/api/2.0/dbfs/close", body=body, headers=headers)
|
|
707
784
|
|
|
708
785
|
def create(self, path: str, *, overwrite: Optional[bool] = None) -> CreateResponse:
|
|
709
786
|
"""Open a stream.
|
|
710
|
-
|
|
787
|
+
|
|
711
788
|
Opens a stream to write to a file and returns a handle to this stream. There is a 10 minute idle
|
|
712
789
|
timeout on this handle. If a file or directory already exists on the given path and __overwrite__ is
|
|
713
790
|
set to false, this call will throw an exception with ``RESOURCE_ALREADY_EXISTS``.
|
|
714
|
-
|
|
791
|
+
|
|
715
792
|
A typical workflow for file upload would be:
|
|
716
|
-
|
|
793
|
+
|
|
717
794
|
1. Issue a ``create`` call and get a handle. 2. Issue one or more ``add-block`` calls with the handle
|
|
718
795
|
you have. 3. Issue a ``close`` call with the handle you have.
|
|
719
|
-
|
|
796
|
+
|
|
720
797
|
:param path: str
|
|
721
798
|
The path of the new file. The path should be the absolute DBFS path.
|
|
722
799
|
:param overwrite: bool (optional)
|
|
723
800
|
The flag that specifies whether to overwrite existing file/files.
|
|
724
|
-
|
|
801
|
+
|
|
725
802
|
:returns: :class:`CreateResponse`
|
|
726
803
|
"""
|
|
727
804
|
body = {}
|
|
728
|
-
if overwrite is not None:
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
805
|
+
if overwrite is not None:
|
|
806
|
+
body["overwrite"] = overwrite
|
|
807
|
+
if path is not None:
|
|
808
|
+
body["path"] = path
|
|
809
|
+
headers = {
|
|
810
|
+
"Accept": "application/json",
|
|
811
|
+
"Content-Type": "application/json",
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
res = self._api.do("POST", "/api/2.0/dbfs/create", body=body, headers=headers)
|
|
733
815
|
return CreateResponse.from_dict(res)
|
|
734
816
|
|
|
735
817
|
def delete(self, path: str, *, recursive: Optional[bool] = None):
|
|
736
818
|
"""Delete a file/directory.
|
|
737
|
-
|
|
819
|
+
|
|
738
820
|
Delete the file or directory (optionally recursively delete all files in the directory). This call
|
|
739
821
|
throws an exception with `IO_ERROR` if the path is a non-empty directory and `recursive` is set to
|
|
740
822
|
`false` or on other similar errors.
|
|
741
|
-
|
|
823
|
+
|
|
742
824
|
When you delete a large number of files, the delete operation is done in increments. The call returns
|
|
743
825
|
a response after approximately 45 seconds with an error message (503 Service Unavailable) asking you
|
|
744
826
|
to re-invoke the delete operation until the directory structure is fully deleted.
|
|
745
|
-
|
|
827
|
+
|
|
746
828
|
For operations that delete more than 10K files, we discourage using the DBFS REST API, but advise you
|
|
747
829
|
to perform such operations in the context of a cluster, using the [File system utility
|
|
748
830
|
(dbutils.fs)](/dev-tools/databricks-utils.html#dbutils-fs). `dbutils.fs` covers the functional scope
|
|
749
831
|
of the DBFS REST API, but from notebooks. Running such operations using notebooks provides better
|
|
750
832
|
control and manageability, such as selective deletes, and the possibility to automate periodic delete
|
|
751
833
|
jobs.
|
|
752
|
-
|
|
834
|
+
|
|
753
835
|
:param path: str
|
|
754
836
|
The path of the file or directory to delete. The path should be the absolute DBFS path.
|
|
755
837
|
:param recursive: bool (optional)
|
|
756
838
|
Whether or not to recursively delete the directory's contents. Deleting empty directories can be
|
|
757
839
|
done without providing the recursive flag.
|
|
758
|
-
|
|
759
|
-
|
|
840
|
+
|
|
841
|
+
|
|
760
842
|
"""
|
|
761
843
|
body = {}
|
|
762
|
-
if path is not None:
|
|
763
|
-
|
|
764
|
-
|
|
844
|
+
if path is not None:
|
|
845
|
+
body["path"] = path
|
|
846
|
+
if recursive is not None:
|
|
847
|
+
body["recursive"] = recursive
|
|
848
|
+
headers = {
|
|
849
|
+
"Accept": "application/json",
|
|
850
|
+
"Content-Type": "application/json",
|
|
851
|
+
}
|
|
765
852
|
|
|
766
|
-
self._api.do(
|
|
853
|
+
self._api.do("POST", "/api/2.0/dbfs/delete", body=body, headers=headers)
|
|
767
854
|
|
|
768
855
|
def get_status(self, path: str) -> FileInfo:
|
|
769
856
|
"""Get the information of a file or directory.
|
|
770
|
-
|
|
857
|
+
|
|
771
858
|
Gets the file information for a file or directory. If the file or directory does not exist, this call
|
|
772
859
|
throws an exception with `RESOURCE_DOES_NOT_EXIST`.
|
|
773
|
-
|
|
860
|
+
|
|
774
861
|
:param path: str
|
|
775
862
|
The path of the file or directory. The path should be the absolute DBFS path.
|
|
776
|
-
|
|
863
|
+
|
|
777
864
|
:returns: :class:`FileInfo`
|
|
778
865
|
"""
|
|
779
866
|
|
|
780
867
|
query = {}
|
|
781
|
-
if path is not None:
|
|
782
|
-
|
|
868
|
+
if path is not None:
|
|
869
|
+
query["path"] = path
|
|
870
|
+
headers = {
|
|
871
|
+
"Accept": "application/json",
|
|
872
|
+
}
|
|
783
873
|
|
|
784
|
-
res = self._api.do(
|
|
874
|
+
res = self._api.do("GET", "/api/2.0/dbfs/get-status", query=query, headers=headers)
|
|
785
875
|
return FileInfo.from_dict(res)
|
|
786
876
|
|
|
787
877
|
def list(self, path: str) -> Iterator[FileInfo]:
|
|
788
878
|
"""List directory contents or file details.
|
|
789
|
-
|
|
879
|
+
|
|
790
880
|
List the contents of a directory, or details of the file. If the file or directory does not exist,
|
|
791
881
|
this call throws an exception with `RESOURCE_DOES_NOT_EXIST`.
|
|
792
|
-
|
|
882
|
+
|
|
793
883
|
When calling list on a large directory, the list operation will time out after approximately 60
|
|
794
884
|
seconds. We strongly recommend using list only on directories containing less than 10K files and
|
|
795
885
|
discourage using the DBFS REST API for operations that list more than 10K files. Instead, we recommend
|
|
796
886
|
that you perform such operations in the context of a cluster, using the [File system utility
|
|
797
887
|
(dbutils.fs)](/dev-tools/databricks-utils.html#dbutils-fs), which provides the same functionality
|
|
798
888
|
without timing out.
|
|
799
|
-
|
|
889
|
+
|
|
800
890
|
:param path: str
|
|
801
891
|
The path of the file or directory. The path should be the absolute DBFS path.
|
|
802
|
-
|
|
892
|
+
|
|
803
893
|
:returns: Iterator over :class:`FileInfo`
|
|
804
894
|
"""
|
|
805
895
|
|
|
806
896
|
query = {}
|
|
807
|
-
if path is not None:
|
|
808
|
-
|
|
897
|
+
if path is not None:
|
|
898
|
+
query["path"] = path
|
|
899
|
+
headers = {
|
|
900
|
+
"Accept": "application/json",
|
|
901
|
+
}
|
|
809
902
|
|
|
810
|
-
json = self._api.do(
|
|
903
|
+
json = self._api.do("GET", "/api/2.0/dbfs/list", query=query, headers=headers)
|
|
811
904
|
parsed = ListStatusResponse.from_dict(json).files
|
|
812
905
|
return parsed if parsed is not None else []
|
|
813
906
|
|
|
814
907
|
def mkdirs(self, path: str):
|
|
815
908
|
"""Create a directory.
|
|
816
|
-
|
|
909
|
+
|
|
817
910
|
Creates the given directory and necessary parent directories if they do not exist. If a file (not a
|
|
818
911
|
directory) exists at any prefix of the input path, this call throws an exception with
|
|
819
912
|
`RESOURCE_ALREADY_EXISTS`. **Note**: If this operation fails, it might have succeeded in creating some
|
|
820
913
|
of the necessary parent directories.
|
|
821
|
-
|
|
914
|
+
|
|
822
915
|
:param path: str
|
|
823
916
|
The path of the new directory. The path should be the absolute DBFS path.
|
|
824
|
-
|
|
825
|
-
|
|
917
|
+
|
|
918
|
+
|
|
826
919
|
"""
|
|
827
920
|
body = {}
|
|
828
|
-
if path is not None:
|
|
829
|
-
|
|
921
|
+
if path is not None:
|
|
922
|
+
body["path"] = path
|
|
923
|
+
headers = {
|
|
924
|
+
"Accept": "application/json",
|
|
925
|
+
"Content-Type": "application/json",
|
|
926
|
+
}
|
|
830
927
|
|
|
831
|
-
self._api.do(
|
|
928
|
+
self._api.do("POST", "/api/2.0/dbfs/mkdirs", body=body, headers=headers)
|
|
832
929
|
|
|
833
930
|
def move(self, source_path: str, destination_path: str):
|
|
834
931
|
"""Move a file.
|
|
835
|
-
|
|
932
|
+
|
|
836
933
|
Moves a file from one location to another location within DBFS. If the source file does not exist,
|
|
837
934
|
this call throws an exception with `RESOURCE_DOES_NOT_EXIST`. If a file already exists in the
|
|
838
935
|
destination path, this call throws an exception with `RESOURCE_ALREADY_EXISTS`. If the given source
|
|
839
936
|
path is a directory, this call always recursively moves all files.
|
|
840
|
-
|
|
937
|
+
|
|
841
938
|
:param source_path: str
|
|
842
939
|
The source path of the file or directory. The path should be the absolute DBFS path.
|
|
843
940
|
:param destination_path: str
|
|
844
941
|
The destination path of the file or directory. The path should be the absolute DBFS path.
|
|
845
|
-
|
|
846
|
-
|
|
942
|
+
|
|
943
|
+
|
|
847
944
|
"""
|
|
848
945
|
body = {}
|
|
849
|
-
if destination_path is not None:
|
|
850
|
-
|
|
851
|
-
|
|
946
|
+
if destination_path is not None:
|
|
947
|
+
body["destination_path"] = destination_path
|
|
948
|
+
if source_path is not None:
|
|
949
|
+
body["source_path"] = source_path
|
|
950
|
+
headers = {
|
|
951
|
+
"Accept": "application/json",
|
|
952
|
+
"Content-Type": "application/json",
|
|
953
|
+
}
|
|
852
954
|
|
|
853
|
-
self._api.do(
|
|
955
|
+
self._api.do("POST", "/api/2.0/dbfs/move", body=body, headers=headers)
|
|
854
956
|
|
|
855
957
|
def put(self, path: str, *, contents: Optional[str] = None, overwrite: Optional[bool] = None):
|
|
856
958
|
"""Upload a file.
|
|
857
|
-
|
|
959
|
+
|
|
858
960
|
Uploads a file through the use of multipart form post. It is mainly used for streaming uploads, but
|
|
859
961
|
can also be used as a convenient single call for data upload.
|
|
860
|
-
|
|
962
|
+
|
|
861
963
|
Alternatively you can pass contents as base64 string.
|
|
862
|
-
|
|
964
|
+
|
|
863
965
|
The amount of data that can be passed (when not streaming) using the __contents__ parameter is limited
|
|
864
966
|
to 1 MB. `MAX_BLOCK_SIZE_EXCEEDED` will be thrown if this limit is exceeded.
|
|
865
|
-
|
|
967
|
+
|
|
866
968
|
If you want to upload large files, use the streaming upload. For details, see :method:dbfs/create,
|
|
867
969
|
:method:dbfs/addBlock, :method:dbfs/close.
|
|
868
|
-
|
|
970
|
+
|
|
869
971
|
:param path: str
|
|
870
972
|
The path of the new file. The path should be the absolute DBFS path.
|
|
871
973
|
:param contents: str (optional)
|
|
872
974
|
This parameter might be absent, and instead a posted file will be used.
|
|
873
975
|
:param overwrite: bool (optional)
|
|
874
976
|
The flag that specifies whether to overwrite existing file/files.
|
|
875
|
-
|
|
876
|
-
|
|
977
|
+
|
|
978
|
+
|
|
877
979
|
"""
|
|
878
980
|
body = {}
|
|
879
|
-
if contents is not None:
|
|
880
|
-
|
|
881
|
-
if
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
981
|
+
if contents is not None:
|
|
982
|
+
body["contents"] = contents
|
|
983
|
+
if overwrite is not None:
|
|
984
|
+
body["overwrite"] = overwrite
|
|
985
|
+
if path is not None:
|
|
986
|
+
body["path"] = path
|
|
987
|
+
headers = {
|
|
988
|
+
"Accept": "application/json",
|
|
989
|
+
"Content-Type": "application/json",
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
self._api.do("POST", "/api/2.0/dbfs/put", body=body, headers=headers)
|
|
885
993
|
|
|
886
994
|
def read(self, path: str, *, length: Optional[int] = None, offset: Optional[int] = None) -> ReadResponse:
|
|
887
995
|
"""Get the contents of a file.
|
|
888
|
-
|
|
996
|
+
|
|
889
997
|
Returns the contents of a file. If the file does not exist, this call throws an exception with
|
|
890
998
|
`RESOURCE_DOES_NOT_EXIST`. If the path is a directory, the read length is negative, or if the offset
|
|
891
999
|
is negative, this call throws an exception with `INVALID_PARAMETER_VALUE`. If the read length exceeds
|
|
892
1000
|
1 MB, this call throws an exception with `MAX_READ_SIZE_EXCEEDED`.
|
|
893
|
-
|
|
1001
|
+
|
|
894
1002
|
If `offset + length` exceeds the number of bytes in a file, it reads the contents until the end of
|
|
895
1003
|
file.
|
|
896
|
-
|
|
1004
|
+
|
|
897
1005
|
:param path: str
|
|
898
1006
|
The path of the file to read. The path should be the absolute DBFS path.
|
|
899
1007
|
:param length: int (optional)
|
|
@@ -901,17 +1009,22 @@ class DbfsAPI:
|
|
|
901
1009
|
of 0.5 MB.
|
|
902
1010
|
:param offset: int (optional)
|
|
903
1011
|
The offset to read from in bytes.
|
|
904
|
-
|
|
1012
|
+
|
|
905
1013
|
:returns: :class:`ReadResponse`
|
|
906
1014
|
"""
|
|
907
1015
|
|
|
908
1016
|
query = {}
|
|
909
|
-
if length is not None:
|
|
910
|
-
|
|
911
|
-
if
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
1017
|
+
if length is not None:
|
|
1018
|
+
query["length"] = length
|
|
1019
|
+
if offset is not None:
|
|
1020
|
+
query["offset"] = offset
|
|
1021
|
+
if path is not None:
|
|
1022
|
+
query["path"] = path
|
|
1023
|
+
headers = {
|
|
1024
|
+
"Accept": "application/json",
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
res = self._api.do("GET", "/api/2.0/dbfs/read", query=query, headers=headers)
|
|
915
1028
|
return ReadResponse.from_dict(res)
|
|
916
1029
|
|
|
917
1030
|
|
|
@@ -919,19 +1032,19 @@ class FilesAPI:
|
|
|
919
1032
|
"""The Files API is a standard HTTP API that allows you to read, write, list, and delete files and
|
|
920
1033
|
directories by referring to their URI. The API makes working with file content as raw bytes easier and
|
|
921
1034
|
more efficient.
|
|
922
|
-
|
|
1035
|
+
|
|
923
1036
|
The API supports [Unity Catalog volumes], where files and directories to operate on are specified using
|
|
924
1037
|
their volume URI path, which follows the format
|
|
925
1038
|
/Volumes/<catalog_name>/<schema_name>/<volume_name>/<path_to_file>.
|
|
926
|
-
|
|
1039
|
+
|
|
927
1040
|
The Files API has two distinct endpoints, one for working with files (`/fs/files`) and another one for
|
|
928
1041
|
working with directories (`/fs/directories`). Both endpoints use the standard HTTP methods GET, HEAD, PUT,
|
|
929
1042
|
and DELETE to manage files and directories specified using their URI path. The path is always absolute.
|
|
930
|
-
|
|
1043
|
+
|
|
931
1044
|
Some Files API client features are currently experimental. To enable them, set
|
|
932
1045
|
`enable_experimental_files_api_client = True` in your configuration profile or use the environment
|
|
933
1046
|
variable `DATABRICKS_ENABLE_EXPERIMENTAL_FILES_API_CLIENT=True`.
|
|
934
|
-
|
|
1047
|
+
|
|
935
1048
|
[Unity Catalog volumes]: https://docs.databricks.com/en/connect/unity-catalog/volumes.html"""
|
|
936
1049
|
|
|
937
1050
|
def __init__(self, api_client):
|
|
@@ -939,143 +1052,153 @@ class FilesAPI:
|
|
|
939
1052
|
|
|
940
1053
|
def create_directory(self, directory_path: str):
|
|
941
1054
|
"""Create a directory.
|
|
942
|
-
|
|
1055
|
+
|
|
943
1056
|
Creates an empty directory. If necessary, also creates any parent directories of the new, empty
|
|
944
1057
|
directory (like the shell command `mkdir -p`). If called on an existing directory, returns a success
|
|
945
1058
|
response; this method is idempotent (it will succeed if the directory already exists).
|
|
946
|
-
|
|
1059
|
+
|
|
947
1060
|
:param directory_path: str
|
|
948
1061
|
The absolute path of a directory.
|
|
949
|
-
|
|
950
|
-
|
|
1062
|
+
|
|
1063
|
+
|
|
951
1064
|
"""
|
|
952
1065
|
|
|
953
1066
|
headers = {}
|
|
954
1067
|
|
|
955
|
-
self._api.do(
|
|
956
|
-
|
|
957
|
-
|
|
1068
|
+
self._api.do(
|
|
1069
|
+
"PUT", f"/api/2.0/fs/directories{_escape_multi_segment_path_parameter(directory_path)}", headers=headers
|
|
1070
|
+
)
|
|
958
1071
|
|
|
959
1072
|
def delete(self, file_path: str):
|
|
960
1073
|
"""Delete a file.
|
|
961
|
-
|
|
1074
|
+
|
|
962
1075
|
Deletes a file. If the request is successful, there is no response body.
|
|
963
|
-
|
|
1076
|
+
|
|
964
1077
|
:param file_path: str
|
|
965
1078
|
The absolute path of the file.
|
|
966
|
-
|
|
967
|
-
|
|
1079
|
+
|
|
1080
|
+
|
|
968
1081
|
"""
|
|
969
1082
|
|
|
970
1083
|
headers = {}
|
|
971
1084
|
|
|
972
|
-
self._api.do(
|
|
973
|
-
f'/api/2.0/fs/files{_escape_multi_segment_path_parameter(file_path)}',
|
|
974
|
-
headers=headers)
|
|
1085
|
+
self._api.do("DELETE", f"/api/2.0/fs/files{_escape_multi_segment_path_parameter(file_path)}", headers=headers)
|
|
975
1086
|
|
|
976
1087
|
def delete_directory(self, directory_path: str):
|
|
977
1088
|
"""Delete a directory.
|
|
978
|
-
|
|
1089
|
+
|
|
979
1090
|
Deletes an empty directory.
|
|
980
|
-
|
|
1091
|
+
|
|
981
1092
|
To delete a non-empty directory, first delete all of its contents. This can be done by listing the
|
|
982
1093
|
directory contents and deleting each file and subdirectory recursively.
|
|
983
|
-
|
|
1094
|
+
|
|
984
1095
|
:param directory_path: str
|
|
985
1096
|
The absolute path of a directory.
|
|
986
|
-
|
|
987
|
-
|
|
1097
|
+
|
|
1098
|
+
|
|
988
1099
|
"""
|
|
989
1100
|
|
|
990
1101
|
headers = {}
|
|
991
1102
|
|
|
992
|
-
self._api.do(
|
|
993
|
-
|
|
994
|
-
|
|
1103
|
+
self._api.do(
|
|
1104
|
+
"DELETE", f"/api/2.0/fs/directories{_escape_multi_segment_path_parameter(directory_path)}", headers=headers
|
|
1105
|
+
)
|
|
995
1106
|
|
|
996
1107
|
def download(self, file_path: str) -> DownloadResponse:
|
|
997
1108
|
"""Download a file.
|
|
998
|
-
|
|
1109
|
+
|
|
999
1110
|
Downloads a file. The file contents are the response body. This is a standard HTTP file download, not
|
|
1000
1111
|
a JSON RPC. It supports the Range and If-Unmodified-Since HTTP headers.
|
|
1001
|
-
|
|
1112
|
+
|
|
1002
1113
|
:param file_path: str
|
|
1003
1114
|
The absolute path of the file.
|
|
1004
|
-
|
|
1115
|
+
|
|
1005
1116
|
:returns: :class:`DownloadResponse`
|
|
1006
1117
|
"""
|
|
1007
1118
|
|
|
1008
|
-
headers = {
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1119
|
+
headers = {
|
|
1120
|
+
"Accept": "application/octet-stream",
|
|
1121
|
+
}
|
|
1122
|
+
response_headers = [
|
|
1123
|
+
"content-length",
|
|
1124
|
+
"content-type",
|
|
1125
|
+
"last-modified",
|
|
1126
|
+
]
|
|
1127
|
+
res = self._api.do(
|
|
1128
|
+
"GET",
|
|
1129
|
+
f"/api/2.0/fs/files{_escape_multi_segment_path_parameter(file_path)}",
|
|
1130
|
+
headers=headers,
|
|
1131
|
+
response_headers=response_headers,
|
|
1132
|
+
raw=True,
|
|
1133
|
+
)
|
|
1015
1134
|
return DownloadResponse.from_dict(res)
|
|
1016
1135
|
|
|
1017
1136
|
def get_directory_metadata(self, directory_path: str):
|
|
1018
1137
|
"""Get directory metadata.
|
|
1019
|
-
|
|
1138
|
+
|
|
1020
1139
|
Get the metadata of a directory. The response HTTP headers contain the metadata. There is no response
|
|
1021
1140
|
body.
|
|
1022
|
-
|
|
1141
|
+
|
|
1023
1142
|
This method is useful to check if a directory exists and the caller has access to it.
|
|
1024
|
-
|
|
1143
|
+
|
|
1025
1144
|
If you wish to ensure the directory exists, you can instead use `PUT`, which will create the directory
|
|
1026
1145
|
if it does not exist, and is idempotent (it will succeed if the directory already exists).
|
|
1027
|
-
|
|
1146
|
+
|
|
1028
1147
|
:param directory_path: str
|
|
1029
1148
|
The absolute path of a directory.
|
|
1030
|
-
|
|
1031
|
-
|
|
1149
|
+
|
|
1150
|
+
|
|
1032
1151
|
"""
|
|
1033
1152
|
|
|
1034
1153
|
headers = {}
|
|
1035
1154
|
|
|
1036
|
-
self._api.do(
|
|
1037
|
-
|
|
1038
|
-
|
|
1155
|
+
self._api.do(
|
|
1156
|
+
"HEAD", f"/api/2.0/fs/directories{_escape_multi_segment_path_parameter(directory_path)}", headers=headers
|
|
1157
|
+
)
|
|
1039
1158
|
|
|
1040
1159
|
def get_metadata(self, file_path: str) -> GetMetadataResponse:
|
|
1041
1160
|
"""Get file metadata.
|
|
1042
|
-
|
|
1161
|
+
|
|
1043
1162
|
Get the metadata of a file. The response HTTP headers contain the metadata. There is no response body.
|
|
1044
|
-
|
|
1163
|
+
|
|
1045
1164
|
:param file_path: str
|
|
1046
1165
|
The absolute path of the file.
|
|
1047
|
-
|
|
1166
|
+
|
|
1048
1167
|
:returns: :class:`GetMetadataResponse`
|
|
1049
1168
|
"""
|
|
1050
1169
|
|
|
1051
1170
|
headers = {}
|
|
1052
|
-
response_headers = [
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1171
|
+
response_headers = [
|
|
1172
|
+
"content-length",
|
|
1173
|
+
"content-type",
|
|
1174
|
+
"last-modified",
|
|
1175
|
+
]
|
|
1176
|
+
res = self._api.do(
|
|
1177
|
+
"HEAD",
|
|
1178
|
+
f"/api/2.0/fs/files{_escape_multi_segment_path_parameter(file_path)}",
|
|
1179
|
+
headers=headers,
|
|
1180
|
+
response_headers=response_headers,
|
|
1181
|
+
)
|
|
1057
1182
|
return GetMetadataResponse.from_dict(res)
|
|
1058
1183
|
|
|
1059
|
-
def list_directory_contents(
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
page_size: Optional[int] = None,
|
|
1063
|
-
page_token: Optional[str] = None) -> Iterator[DirectoryEntry]:
|
|
1184
|
+
def list_directory_contents(
|
|
1185
|
+
self, directory_path: str, *, page_size: Optional[int] = None, page_token: Optional[str] = None
|
|
1186
|
+
) -> Iterator[DirectoryEntry]:
|
|
1064
1187
|
"""List directory contents.
|
|
1065
|
-
|
|
1188
|
+
|
|
1066
1189
|
Returns the contents of a directory. If there is no directory at the specified path, the API returns a
|
|
1067
1190
|
HTTP 404 error.
|
|
1068
|
-
|
|
1191
|
+
|
|
1069
1192
|
:param directory_path: str
|
|
1070
1193
|
The absolute path of a directory.
|
|
1071
1194
|
:param page_size: int (optional)
|
|
1072
1195
|
The maximum number of directory entries to return. The response may contain fewer entries. If the
|
|
1073
1196
|
response contains a `next_page_token`, there may be more entries, even if fewer than `page_size`
|
|
1074
1197
|
entries are in the response.
|
|
1075
|
-
|
|
1198
|
+
|
|
1076
1199
|
We recommend not to set this value unless you are intentionally listing less than the complete
|
|
1077
1200
|
directory contents.
|
|
1078
|
-
|
|
1201
|
+
|
|
1079
1202
|
If unspecified, at most 1000 directory entries will be returned. The maximum value is 1000. Values
|
|
1080
1203
|
above 1000 will be coerced to 1000.
|
|
1081
1204
|
:param page_token: str (optional)
|
|
@@ -1085,51 +1208,61 @@ class FilesAPI:
|
|
|
1085
1208
|
request. To list all of the entries in a directory, it is necessary to continue requesting pages of
|
|
1086
1209
|
entries until the response contains no `next_page_token`. Note that the number of entries returned
|
|
1087
1210
|
must not be used to determine when the listing is complete.
|
|
1088
|
-
|
|
1211
|
+
|
|
1089
1212
|
:returns: Iterator over :class:`DirectoryEntry`
|
|
1090
1213
|
"""
|
|
1091
1214
|
|
|
1092
1215
|
query = {}
|
|
1093
|
-
if page_size is not None:
|
|
1094
|
-
|
|
1095
|
-
|
|
1216
|
+
if page_size is not None:
|
|
1217
|
+
query["page_size"] = page_size
|
|
1218
|
+
if page_token is not None:
|
|
1219
|
+
query["page_token"] = page_token
|
|
1220
|
+
headers = {
|
|
1221
|
+
"Accept": "application/json",
|
|
1222
|
+
}
|
|
1096
1223
|
|
|
1097
1224
|
while True:
|
|
1098
1225
|
json = self._api.do(
|
|
1099
|
-
|
|
1100
|
-
f
|
|
1226
|
+
"GET",
|
|
1227
|
+
f"/api/2.0/fs/directories{_escape_multi_segment_path_parameter(directory_path)}",
|
|
1101
1228
|
query=query,
|
|
1102
|
-
headers=headers
|
|
1103
|
-
|
|
1104
|
-
|
|
1229
|
+
headers=headers,
|
|
1230
|
+
)
|
|
1231
|
+
if "contents" in json:
|
|
1232
|
+
for v in json["contents"]:
|
|
1105
1233
|
yield DirectoryEntry.from_dict(v)
|
|
1106
|
-
if
|
|
1234
|
+
if "next_page_token" not in json or not json["next_page_token"]:
|
|
1107
1235
|
return
|
|
1108
|
-
query[
|
|
1236
|
+
query["page_token"] = json["next_page_token"]
|
|
1109
1237
|
|
|
1110
1238
|
def upload(self, file_path: str, contents: BinaryIO, *, overwrite: Optional[bool] = None):
|
|
1111
1239
|
"""Upload a file.
|
|
1112
|
-
|
|
1240
|
+
|
|
1113
1241
|
Uploads a file of up to 5 GiB. The file contents should be sent as the request body as raw bytes (an
|
|
1114
1242
|
octet stream); do not encode or otherwise modify the bytes before sending. The contents of the
|
|
1115
1243
|
resulting file will be exactly the bytes sent in the request body. If the request is successful, there
|
|
1116
1244
|
is no response body.
|
|
1117
|
-
|
|
1245
|
+
|
|
1118
1246
|
:param file_path: str
|
|
1119
1247
|
The absolute path of the file.
|
|
1120
1248
|
:param contents: BinaryIO
|
|
1121
1249
|
:param overwrite: bool (optional)
|
|
1122
1250
|
If true, an existing file will be overwritten.
|
|
1123
|
-
|
|
1124
|
-
|
|
1251
|
+
|
|
1252
|
+
|
|
1125
1253
|
"""
|
|
1126
1254
|
|
|
1127
1255
|
query = {}
|
|
1128
|
-
if overwrite is not None:
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1256
|
+
if overwrite is not None:
|
|
1257
|
+
query["overwrite"] = overwrite
|
|
1258
|
+
headers = {
|
|
1259
|
+
"Content-Type": "application/octet-stream",
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
self._api.do(
|
|
1263
|
+
"PUT",
|
|
1264
|
+
f"/api/2.0/fs/files{_escape_multi_segment_path_parameter(file_path)}",
|
|
1265
|
+
query=query,
|
|
1266
|
+
headers=headers,
|
|
1267
|
+
data=contents,
|
|
1268
|
+
)
|