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