1
1
import io
2
+ import os
2
3
from types import TracebackType
3
4
from typing import List , Optional , Type , Union
4
5
5
6
import tiledb .cc as lt
6
7
7
8
from .ctx import Config , Ctx , default_ctx
8
9
10
+ _AnyPath = Union [str , bytes , os .PathLike ]
11
+
9
12
10
13
class VFS (lt .VFS ):
11
14
"""TileDB VFS class
@@ -29,7 +32,7 @@ def __init__(self, config: Union[Config, dict] = None, ctx: Optional[Ctx] = None
29
32
else :
30
33
try :
31
34
config = dict (config )
32
- except :
35
+ except Exception :
33
36
raise ValueError ("`config` argument must be of type Config or dict" )
34
37
35
38
ccfg = lt .Config (config )
@@ -51,7 +54,7 @@ def config(self) -> Config:
51
54
"""
52
55
return self ._config
53
56
54
- def open (self , uri : str , mode : str = "rb" ):
57
+ def open (self , uri : _AnyPath , mode : str = "rb" ):
55
58
"""Opens a VFS file resource for reading / writing / appends at URI.
56
59
57
60
If the file did not exist upon opening, a new file is created.
@@ -144,145 +147,145 @@ def supports(self, scheme: str) -> bool:
144
147
145
148
return self ._ctx .is_supported_fs (scheme_to_fs_type [scheme ])
146
149
147
- def create_bucket (self , uri : str ):
150
+ def create_bucket (self , uri : _AnyPath ):
148
151
"""Creates an object store bucket with the input URI.
149
152
150
153
:param str uri: Input URI of the bucket
151
154
152
155
"""
153
- return self ._create_bucket (uri )
156
+ return self ._create_bucket (_to_path_str ( uri ) )
154
157
155
- def remove_bucket (self , uri : str ):
158
+ def remove_bucket (self , uri : _AnyPath ):
156
159
"""Deletes an object store bucket with the input URI.
157
160
158
161
:param str uri: Input URI of the bucket
159
162
160
163
"""
161
- return self ._remove_bucket (uri )
164
+ return self ._remove_bucket (_to_path_str ( uri ) )
162
165
163
- def is_bucket (self , uri : str ) -> bool :
166
+ def is_bucket (self , uri : _AnyPath ) -> bool :
164
167
"""
165
168
:param str uri: Input URI of the bucket
166
169
:rtype: bool
167
170
:return: True if an object store bucket with the input URI exists, False otherwise
168
171
169
172
"""
170
- return self ._is_bucket (uri )
173
+ return self ._is_bucket (_to_path_str ( uri ) )
171
174
172
- def empty_bucket (self , uri : str ):
175
+ def empty_bucket (self , uri : _AnyPath ):
173
176
"""Empty an object store bucket.
174
177
175
178
:param str uri: Input URI of the bucket
176
179
177
180
"""
178
- return self ._empty_bucket (uri )
181
+ return self ._empty_bucket (_to_path_str ( uri ) )
179
182
180
- def is_empty_bucket (self , uri : str ) -> bool :
183
+ def is_empty_bucket (self , uri : _AnyPath ) -> bool :
181
184
"""
182
185
:param str uri: Input URI of the bucket
183
186
:rtype: bool
184
187
:return: True if an object store bucket is empty, False otherwise
185
188
186
189
"""
187
- return self ._is_empty_bucket (uri )
190
+ return self ._is_empty_bucket (_to_path_str ( uri ) )
188
191
189
- def create_dir (self , uri : str ):
192
+ def create_dir (self , uri : _AnyPath ):
190
193
"""Check if an object store bucket is empty.
191
194
192
195
:param str uri: Input URI of the bucket
193
196
194
197
"""
195
- return self ._create_dir (uri )
198
+ return self ._create_dir (_to_path_str ( uri ) )
196
199
197
- def is_dir (self , uri : str ) -> bool :
200
+ def is_dir (self , uri : _AnyPath ) -> bool :
198
201
"""
199
202
:param str uri: Input URI of the directory
200
203
:rtype: bool
201
204
:return: True if a directory with the input URI exists, False otherwise
202
205
203
206
"""
204
- return self ._is_dir (uri )
207
+ return self ._is_dir (_to_path_str ( uri ) )
205
208
206
- def remove_dir (self , uri : str ):
209
+ def remove_dir (self , uri : _AnyPath ):
207
210
"""Removes a directory (recursively) with the input URI.
208
211
209
212
:param str uri: Input URI of the directory
210
213
211
214
"""
212
- return self ._remove_dir (uri )
215
+ return self ._remove_dir (_to_path_str ( uri ) )
213
216
214
- def dir_size (self , uri : str ) -> int :
217
+ def dir_size (self , uri : _AnyPath ) -> int :
215
218
"""
216
219
:param str uri: Input URI of the directory
217
220
:rtype: int
218
221
:return: The size of a directory with the input URI
219
222
220
223
"""
221
- return self ._dir_size (uri )
224
+ return self ._dir_size (_to_path_str ( uri ) )
222
225
223
- def move_dir (self , old_uri : str , new_uri : str ):
226
+ def move_dir (self , old_uri : _AnyPath , new_uri : _AnyPath ):
224
227
"""Renames a TileDB directory from an old URI to a new URI.
225
228
226
229
:param str old_uri: Input of the old directory URI
227
230
:param str new_uri: Input of the new directory URI
228
231
229
232
"""
230
- return self ._move_dir (old_uri , new_uri )
233
+ return self ._move_dir (_to_path_str ( old_uri ), _to_path_str ( new_uri ) )
231
234
232
- def copy_dir (self , old_uri : str , new_uri : str ):
235
+ def copy_dir (self , old_uri : _AnyPath , new_uri : _AnyPath ):
233
236
"""Copies a TileDB directory from an old URI to a new URI.
234
237
235
238
:param str old_uri: Input of the old directory URI
236
239
:param str new_uri: Input of the new directory URI
237
240
238
241
"""
239
- return self ._copy_dir (old_uri , new_uri )
242
+ return self ._copy_dir (_to_path_str ( old_uri ), _to_path_str ( new_uri ) )
240
243
241
- def is_file (self , uri : str ) -> bool :
244
+ def is_file (self , uri : _AnyPath ) -> bool :
242
245
"""
243
246
:param str uri: Input URI of the file
244
247
:rtype: bool
245
248
:return: True if a file with the input URI exists, False otherwise
246
249
247
250
"""
248
- return self ._is_file (uri )
251
+ return self ._is_file (_to_path_str ( uri ) )
249
252
250
- def remove_file (self , uri : str ):
253
+ def remove_file (self , uri : _AnyPath ):
251
254
"""Removes a file with the input URI.
252
255
253
256
:param str uri: Input URI of the file
254
257
255
258
"""
256
- return self ._remove_file (uri )
259
+ return self ._remove_file (_to_path_str ( uri ) )
257
260
258
- def file_size (self , uri : str ) -> int :
261
+ def file_size (self , uri : _AnyPath ) -> int :
259
262
"""
260
263
:param str uri: Input URI of the file
261
264
:rtype: int
262
265
:return: The size of a file with the input URI
263
266
264
267
"""
265
- return self ._file_size (uri )
268
+ return self ._file_size (_to_path_str ( uri ) )
266
269
267
- def move_file (self , old_uri : str , new_uri : str ):
270
+ def move_file (self , old_uri : _AnyPath , new_uri : _AnyPath ):
268
271
"""Renames a TileDB file from an old URI to a new URI.
269
272
270
273
:param str old_uri: Input of the old file URI
271
274
:param str new_uri: Input of the new file URI
272
275
273
276
"""
274
- return self ._move_file (old_uri , new_uri )
277
+ return self ._move_file (_to_path_str ( old_uri ), _to_path_str ( new_uri ) )
275
278
276
- def copy_file (self , old_uri : str , new_uri : str ):
279
+ def copy_file (self , old_uri : _AnyPath , new_uri : _AnyPath ):
277
280
"""Copies a TileDB file from an old URI to a new URI.
278
281
279
282
:param str old_uri: Input of the old file URI
280
283
:param str new_uri: Input of the new file URI
281
284
282
285
"""
283
- return self ._copy_file (old_uri , new_uri )
286
+ return self ._copy_file (_to_path_str ( old_uri ), _to_path_str ( new_uri ) )
284
287
285
- def ls (self , uri : str ) -> List [str ]:
288
+ def ls (self , uri : _AnyPath ) -> List [str ]:
286
289
"""Retrieves the children in directory `uri`. This function is
287
290
non-recursive, i.e., it focuses in one level below `uri`.
288
291
@@ -291,22 +294,23 @@ def ls(self, uri: str) -> List[str]:
291
294
:return: The children in directory `uri`
292
295
293
296
"""
294
- return self ._ls (uri )
297
+ return self ._ls (_to_path_str ( uri ) )
295
298
296
- def touch (self , uri : str ):
299
+ def touch (self , uri : _AnyPath ):
297
300
"""Touches a file with the input URI, i.e., creates a new empty file.
298
301
299
302
:param str uri: Input URI of the file
300
303
301
304
"""
302
- return self ._touch (uri )
305
+ return self ._touch (_to_path_str ( uri ) )
303
306
304
307
305
308
class FileIO (io .RawIOBase ):
306
309
"""TileDB FileIO class that encapsulates files opened by tiledb.VFS. The file
307
310
operations are meant to mimic Python's built-in file I/O methods."""
308
311
309
- def __init__ (self , vfs : VFS , uri : str , mode : str = "rb" ):
312
+ def __init__ (self , vfs : VFS , uri : _AnyPath , mode : str = "rb" ):
313
+ uri = _to_path_str (uri )
310
314
self ._vfs = vfs
311
315
312
316
str_to_vfs_mode = {
@@ -324,8 +328,8 @@ def __init__(self, vfs: VFS, uri: str, mode: str = "rb"):
324
328
if self ._mode == "rb" :
325
329
try :
326
330
self ._nbytes = vfs .file_size (uri )
327
- except :
328
- raise lt .TileDBError (f"URI { uri } is not a valid file" )
331
+ except Exception as e :
332
+ raise lt .TileDBError (f"URI { uri !r } is not a valid file" ) from e
329
333
330
334
self ._fh = lt .FileHandle (
331
335
self ._vfs ._ctx , self ._vfs , uri , str_to_vfs_mode [self ._mode ]
@@ -504,3 +508,14 @@ def readinto(self, buff: bytes) -> int:
504
508
505
509
def readinto1 (self , b ):
506
510
return self .readinto (b )
511
+
512
+
513
+ def _to_path_str (pth : _AnyPath ) -> Union [str , bytes ]:
514
+ if isinstance (pth , (str , bytes )):
515
+ return pth
516
+ try :
517
+ return pth .__fspath__ ()
518
+ except AttributeError as ae :
519
+ raise TypeError (
520
+ "VFS paths must be strings, bytes, or os.PathLike objects"
521
+ ) from ae
0 commit comments