fsspec 2024.3.1__py3-none-any.whl → 2024.5.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.
- fsspec/__init__.py +2 -3
- fsspec/_version.py +14 -19
- fsspec/caching.py +83 -14
- fsspec/compression.py +1 -0
- fsspec/core.py +32 -8
- fsspec/exceptions.py +1 -0
- fsspec/generic.py +1 -1
- fsspec/gui.py +1 -1
- fsspec/implementations/arrow.py +0 -2
- fsspec/implementations/cache_mapper.py +1 -2
- fsspec/implementations/cache_metadata.py +7 -7
- fsspec/implementations/dirfs.py +2 -2
- fsspec/implementations/http.py +9 -9
- fsspec/implementations/local.py +78 -45
- fsspec/implementations/memory.py +9 -0
- fsspec/implementations/smb.py +3 -1
- fsspec/implementations/tests/__init__.py +0 -0
- fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_file_listing.yaml +112 -0
- fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_mkdir.yaml +582 -0
- fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_read_pyarrow_non_partitioned.yaml +873 -0
- fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_read_range.yaml +458 -0
- fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_read_range_chunked.yaml +1355 -0
- fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_write_and_read.yaml +795 -0
- fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_write_pyarrow_non_partitioned.yaml +613 -0
- fsspec/implementations/tests/conftest.py +39 -0
- fsspec/implementations/tests/local/__init__.py +0 -0
- fsspec/implementations/tests/local/local_fixtures.py +18 -0
- fsspec/implementations/tests/local/local_test.py +14 -0
- fsspec/implementations/tests/memory/__init__.py +0 -0
- fsspec/implementations/tests/memory/memory_fixtures.py +27 -0
- fsspec/implementations/tests/memory/memory_test.py +14 -0
- fsspec/implementations/tests/out.zip +0 -0
- fsspec/implementations/tests/test_archive.py +382 -0
- fsspec/implementations/tests/test_arrow.py +259 -0
- fsspec/implementations/tests/test_cached.py +1306 -0
- fsspec/implementations/tests/test_common.py +35 -0
- fsspec/implementations/tests/test_dask.py +29 -0
- fsspec/implementations/tests/test_data.py +20 -0
- fsspec/implementations/tests/test_dbfs.py +268 -0
- fsspec/implementations/tests/test_dirfs.py +588 -0
- fsspec/implementations/tests/test_ftp.py +178 -0
- fsspec/implementations/tests/test_git.py +76 -0
- fsspec/implementations/tests/test_http.py +577 -0
- fsspec/implementations/tests/test_jupyter.py +57 -0
- fsspec/implementations/tests/test_libarchive.py +33 -0
- fsspec/implementations/tests/test_local.py +1285 -0
- fsspec/implementations/tests/test_memory.py +382 -0
- fsspec/implementations/tests/test_reference.py +720 -0
- fsspec/implementations/tests/test_sftp.py +233 -0
- fsspec/implementations/tests/test_smb.py +139 -0
- fsspec/implementations/tests/test_tar.py +243 -0
- fsspec/implementations/tests/test_webhdfs.py +197 -0
- fsspec/implementations/tests/test_zip.py +134 -0
- fsspec/implementations/webhdfs.py +1 -3
- fsspec/parquet.py +0 -8
- fsspec/registry.py +4 -0
- fsspec/spec.py +21 -4
- fsspec/tests/__init__.py +0 -0
- fsspec/tests/abstract/mv.py +57 -0
- fsspec/tests/conftest.py +188 -0
- fsspec/tests/data/listing.html +1 -0
- fsspec/tests/test_api.py +498 -0
- fsspec/tests/test_async.py +230 -0
- fsspec/tests/test_caches.py +255 -0
- fsspec/tests/test_callbacks.py +89 -0
- fsspec/tests/test_compression.py +164 -0
- fsspec/tests/test_config.py +129 -0
- fsspec/tests/test_core.py +466 -0
- fsspec/tests/test_downstream.py +40 -0
- fsspec/tests/test_file.py +200 -0
- fsspec/tests/test_fuse.py +147 -0
- fsspec/tests/test_generic.py +90 -0
- fsspec/tests/test_gui.py +23 -0
- fsspec/tests/test_mapping.py +228 -0
- fsspec/tests/test_parquet.py +140 -0
- fsspec/tests/test_registry.py +134 -0
- fsspec/tests/test_spec.py +1167 -0
- fsspec/tests/test_utils.py +478 -0
- fsspec/utils.py +0 -2
- fsspec-2024.5.0.dist-info/METADATA +273 -0
- fsspec-2024.5.0.dist-info/RECORD +111 -0
- {fsspec-2024.3.1.dist-info → fsspec-2024.5.0.dist-info}/WHEEL +1 -2
- fsspec-2024.3.1.dist-info/METADATA +0 -167
- fsspec-2024.3.1.dist-info/RECORD +0 -54
- fsspec-2024.3.1.dist-info/top_level.txt +0 -1
- {fsspec-2024.3.1.dist-info → fsspec-2024.5.0.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import PurePosixPath, PureWindowsPath
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from fsspec.implementations.local import LocalFileSystem, make_path_posix
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_1(m):
|
|
10
|
+
m.touch("/somefile") # NB: is found with or without initial /
|
|
11
|
+
m.touch("afiles/and/another")
|
|
12
|
+
files = m.find("")
|
|
13
|
+
assert files == ["/afiles/and/another", "/somefile"]
|
|
14
|
+
|
|
15
|
+
files = sorted(m.get_mapper())
|
|
16
|
+
assert files == ["afiles/and/another", "somefile"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_strip(m):
|
|
20
|
+
assert m._strip_protocol("") == ""
|
|
21
|
+
assert m._strip_protocol("memory://") == ""
|
|
22
|
+
assert m._strip_protocol("afile") == "/afile"
|
|
23
|
+
assert m._strip_protocol("/b/c") == "/b/c"
|
|
24
|
+
assert m._strip_protocol("/b/c/") == "/b/c"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_ls(m):
|
|
28
|
+
m.mkdir("/dir")
|
|
29
|
+
m.mkdir("/dir/dir1")
|
|
30
|
+
|
|
31
|
+
m.touch("/dir/afile")
|
|
32
|
+
m.touch("/dir/dir1/bfile")
|
|
33
|
+
m.touch("/dir/dir1/cfile")
|
|
34
|
+
|
|
35
|
+
assert m.ls("/", False) == ["/dir"]
|
|
36
|
+
assert m.ls("/dir", False) == ["/dir/afile", "/dir/dir1"]
|
|
37
|
+
assert m.ls("/dir", True)[0]["type"] == "file"
|
|
38
|
+
assert m.ls("/dir", True)[1]["type"] == "directory"
|
|
39
|
+
assert m.ls("/dir/afile", False) == ["/dir/afile"]
|
|
40
|
+
assert m.ls("/dir/afile", True)[0]["type"] == "file"
|
|
41
|
+
|
|
42
|
+
assert len(m.ls("/dir/dir1")) == 2
|
|
43
|
+
assert len(m.ls("/dir/afile")) == 1
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_directories(m):
|
|
47
|
+
m.mkdir("outer/inner")
|
|
48
|
+
assert m.info("outer/inner")["type"] == "directory"
|
|
49
|
+
|
|
50
|
+
assert m.ls("outer")
|
|
51
|
+
assert m.ls("outer/inner") == []
|
|
52
|
+
|
|
53
|
+
with pytest.raises(OSError):
|
|
54
|
+
m.rmdir("outer")
|
|
55
|
+
|
|
56
|
+
m.rmdir("outer/inner")
|
|
57
|
+
m.rmdir("outer")
|
|
58
|
+
|
|
59
|
+
assert not m.store
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_exists_isdir_isfile(m):
|
|
63
|
+
m.mkdir("/root")
|
|
64
|
+
m.touch("/root/a")
|
|
65
|
+
|
|
66
|
+
assert m.exists("/root")
|
|
67
|
+
assert m.isdir("/root")
|
|
68
|
+
assert not m.isfile("/root")
|
|
69
|
+
|
|
70
|
+
assert m.exists("/root/a")
|
|
71
|
+
assert m.isfile("/root/a")
|
|
72
|
+
assert not m.isdir("/root/a")
|
|
73
|
+
|
|
74
|
+
assert not m.exists("/root/not-exists")
|
|
75
|
+
assert not m.isfile("/root/not-exists")
|
|
76
|
+
assert not m.isdir("/root/not-exists")
|
|
77
|
+
|
|
78
|
+
m.rm("/root/a")
|
|
79
|
+
m.rmdir("/root")
|
|
80
|
+
|
|
81
|
+
assert not m.exists("/root")
|
|
82
|
+
|
|
83
|
+
m.touch("/a/b")
|
|
84
|
+
assert m.isfile("/a/b")
|
|
85
|
+
|
|
86
|
+
assert m.exists("/a")
|
|
87
|
+
assert m.isdir("/a")
|
|
88
|
+
assert not m.isfile("/a")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_touch(m):
|
|
92
|
+
m.touch("/root/a")
|
|
93
|
+
with pytest.raises(FileExistsError):
|
|
94
|
+
m.touch("/root/a/b")
|
|
95
|
+
with pytest.raises(FileExistsError):
|
|
96
|
+
m.touch("/root/a/b/c")
|
|
97
|
+
assert not m.exists("/root/a/b/")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_mv_recursive(m):
|
|
101
|
+
m.mkdir("src")
|
|
102
|
+
m.touch("src/file.txt")
|
|
103
|
+
m.mv("src", "dest", recursive=True)
|
|
104
|
+
assert m.exists("dest/file.txt")
|
|
105
|
+
assert not m.exists("src")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_mv_same_paths(m):
|
|
109
|
+
m.mkdir("src")
|
|
110
|
+
m.touch("src/file.txt")
|
|
111
|
+
m.mv("src", "src", recursive=True)
|
|
112
|
+
assert m.exists("src/file.txt")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_rm_no_pseudo_dir(m):
|
|
116
|
+
m.touch("/dir1/dir2/file")
|
|
117
|
+
m.rm("/dir1", recursive=True)
|
|
118
|
+
assert not m.exists("/dir1/dir2/file")
|
|
119
|
+
assert not m.exists("/dir1/dir2")
|
|
120
|
+
assert not m.exists("/dir1")
|
|
121
|
+
|
|
122
|
+
with pytest.raises(FileNotFoundError):
|
|
123
|
+
m.rm("/dir1", recursive=True)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_rewind(m):
|
|
127
|
+
# https://github.com/fsspec/filesystem_spec/issues/349
|
|
128
|
+
with m.open("src/file.txt", "w") as f:
|
|
129
|
+
f.write("content")
|
|
130
|
+
with m.open("src/file.txt") as f:
|
|
131
|
+
assert f.tell() == 0
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_empty_raises(m):
|
|
135
|
+
with pytest.raises(FileNotFoundError):
|
|
136
|
+
m.ls("nonexistent")
|
|
137
|
+
|
|
138
|
+
with pytest.raises(FileNotFoundError):
|
|
139
|
+
m.info("nonexistent")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_dir_errors(m):
|
|
143
|
+
m.mkdir("/first")
|
|
144
|
+
|
|
145
|
+
with pytest.raises(FileExistsError):
|
|
146
|
+
m.mkdir("/first")
|
|
147
|
+
with pytest.raises(FileExistsError):
|
|
148
|
+
m.makedirs("/first", exist_ok=False)
|
|
149
|
+
m.makedirs("/first", exist_ok=True)
|
|
150
|
+
m.makedirs("/first/second/third")
|
|
151
|
+
assert "/first/second" in m.pseudo_dirs
|
|
152
|
+
|
|
153
|
+
m.touch("/afile")
|
|
154
|
+
with pytest.raises(NotADirectoryError):
|
|
155
|
+
m.mkdir("/afile/nodir")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_no_rewind_append_mode(m):
|
|
159
|
+
# https://github.com/fsspec/filesystem_spec/issues/349
|
|
160
|
+
with m.open("src/file.txt", "w") as f:
|
|
161
|
+
f.write("content")
|
|
162
|
+
with m.open("src/file.txt", "a") as f:
|
|
163
|
+
assert f.tell() == 7
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_moves(m):
|
|
167
|
+
m.touch("source.txt")
|
|
168
|
+
m.mv("source.txt", "target.txt")
|
|
169
|
+
|
|
170
|
+
m.touch("source2.txt")
|
|
171
|
+
m.mv("source2.txt", "target2.txt", recursive=True)
|
|
172
|
+
assert m.find("") == ["/target.txt", "/target2.txt"]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_rm_reursive_empty_subdir(m):
|
|
176
|
+
# https://github.com/fsspec/filesystem_spec/issues/500
|
|
177
|
+
m.mkdir("recdir")
|
|
178
|
+
m.mkdir("recdir/subdir2")
|
|
179
|
+
m.rm("recdir/", recursive=True)
|
|
180
|
+
assert not m.exists("dir")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_seekable(m):
|
|
184
|
+
fn0 = "foo.txt"
|
|
185
|
+
with m.open(fn0, "wb") as f:
|
|
186
|
+
f.write(b"data")
|
|
187
|
+
|
|
188
|
+
f = m.open(fn0, "rt")
|
|
189
|
+
assert f.seekable(), "file is not seekable"
|
|
190
|
+
f.seek(1)
|
|
191
|
+
assert f.read(1) == "a"
|
|
192
|
+
assert f.tell() == 2
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# https://github.com/fsspec/filesystem_spec/issues/1425
|
|
196
|
+
@pytest.mark.parametrize("mode", ["r", "rb", "w", "wb", "ab", "r+b"])
|
|
197
|
+
def test_open_mode(m, mode):
|
|
198
|
+
filename = "mode.txt"
|
|
199
|
+
m.touch(filename)
|
|
200
|
+
with m.open(filename, mode=mode) as _:
|
|
201
|
+
pass
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_remove_all(m):
|
|
205
|
+
m.touch("afile")
|
|
206
|
+
m.rm("/", recursive=True)
|
|
207
|
+
assert not m.ls("/")
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_cp_directory_recursive(m):
|
|
211
|
+
# https://github.com/fsspec/filesystem_spec/issues/1062
|
|
212
|
+
# Recursive cp/get/put of source directory into non-existent target directory.
|
|
213
|
+
src = "/src"
|
|
214
|
+
src_file = src + "/file"
|
|
215
|
+
m.mkdir(src)
|
|
216
|
+
m.touch(src_file)
|
|
217
|
+
|
|
218
|
+
target = "/target"
|
|
219
|
+
|
|
220
|
+
# cp without slash
|
|
221
|
+
assert not m.exists(target)
|
|
222
|
+
for loop in range(2):
|
|
223
|
+
m.cp(src, target, recursive=True)
|
|
224
|
+
assert m.isdir(target)
|
|
225
|
+
|
|
226
|
+
if loop == 0:
|
|
227
|
+
correct = [target + "/file"]
|
|
228
|
+
assert m.find(target) == correct
|
|
229
|
+
else:
|
|
230
|
+
correct = [target + "/file", target + "/src/file"]
|
|
231
|
+
assert sorted(m.find(target)) == correct
|
|
232
|
+
|
|
233
|
+
m.rm(target, recursive=True)
|
|
234
|
+
|
|
235
|
+
# cp with slash
|
|
236
|
+
assert not m.exists(target)
|
|
237
|
+
for loop in range(2):
|
|
238
|
+
m.cp(src + "/", target, recursive=True)
|
|
239
|
+
assert m.isdir(target)
|
|
240
|
+
correct = [target + "/file"]
|
|
241
|
+
assert m.find(target) == correct
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def test_get_directory_recursive(m, tmpdir):
|
|
245
|
+
# https://github.com/fsspec/filesystem_spec/issues/1062
|
|
246
|
+
# Recursive cp/get/put of source directory into non-existent target directory.
|
|
247
|
+
src = "/src"
|
|
248
|
+
src_file = src + "/file"
|
|
249
|
+
m.mkdir(src)
|
|
250
|
+
m.touch(src_file)
|
|
251
|
+
|
|
252
|
+
target = os.path.join(tmpdir, "target")
|
|
253
|
+
target_fs = LocalFileSystem()
|
|
254
|
+
|
|
255
|
+
# get without slash
|
|
256
|
+
assert not target_fs.exists(target)
|
|
257
|
+
for loop in range(2):
|
|
258
|
+
m.get(src, target, recursive=True)
|
|
259
|
+
assert target_fs.isdir(target)
|
|
260
|
+
|
|
261
|
+
if loop == 0:
|
|
262
|
+
correct = [make_path_posix(os.path.join(target, "file"))]
|
|
263
|
+
assert target_fs.find(target) == correct
|
|
264
|
+
else:
|
|
265
|
+
correct = [
|
|
266
|
+
make_path_posix(os.path.join(target, "file")),
|
|
267
|
+
make_path_posix(os.path.join(target, "src", "file")),
|
|
268
|
+
]
|
|
269
|
+
assert sorted(target_fs.find(target)) == correct
|
|
270
|
+
|
|
271
|
+
target_fs.rm(target, recursive=True)
|
|
272
|
+
|
|
273
|
+
# get with slash
|
|
274
|
+
assert not target_fs.exists(target)
|
|
275
|
+
for loop in range(2):
|
|
276
|
+
m.get(src + "/", target, recursive=True)
|
|
277
|
+
assert target_fs.isdir(target)
|
|
278
|
+
correct = [make_path_posix(os.path.join(target, "file"))]
|
|
279
|
+
assert target_fs.find(target) == correct
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def test_put_directory_recursive(m, tmpdir):
|
|
283
|
+
# https://github.com/fsspec/filesystem_spec/issues/1062
|
|
284
|
+
# Recursive cp/get/put of source directory into non-existent target directory.
|
|
285
|
+
src = os.path.join(tmpdir, "src")
|
|
286
|
+
src_file = os.path.join(src, "file")
|
|
287
|
+
source_fs = LocalFileSystem()
|
|
288
|
+
source_fs.mkdir(src)
|
|
289
|
+
source_fs.touch(src_file)
|
|
290
|
+
|
|
291
|
+
target = "/target"
|
|
292
|
+
|
|
293
|
+
# put without slash
|
|
294
|
+
assert not m.exists(target)
|
|
295
|
+
for loop in range(2):
|
|
296
|
+
m.put(src, target, recursive=True)
|
|
297
|
+
assert m.isdir(target)
|
|
298
|
+
|
|
299
|
+
if loop == 0:
|
|
300
|
+
correct = [target + "/file"]
|
|
301
|
+
assert m.find(target) == correct
|
|
302
|
+
else:
|
|
303
|
+
correct = [target + "/file", target + "/src/file"]
|
|
304
|
+
assert sorted(m.find(target)) == correct
|
|
305
|
+
|
|
306
|
+
m.rm(target, recursive=True)
|
|
307
|
+
|
|
308
|
+
# put with slash
|
|
309
|
+
assert not m.exists(target)
|
|
310
|
+
for loop in range(2):
|
|
311
|
+
m.put(src + "/", target, recursive=True)
|
|
312
|
+
assert m.isdir(target)
|
|
313
|
+
correct = [target + "/file"]
|
|
314
|
+
assert m.find(target) == correct
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def test_cp_empty_directory(m):
|
|
318
|
+
# https://github.com/fsspec/filesystem_spec/issues/1198
|
|
319
|
+
# cp/get/put of empty directory.
|
|
320
|
+
empty = "/src/empty"
|
|
321
|
+
m.mkdir(empty)
|
|
322
|
+
|
|
323
|
+
target = "/target"
|
|
324
|
+
m.mkdir(target)
|
|
325
|
+
|
|
326
|
+
# cp without slash, target directory exists
|
|
327
|
+
assert m.isdir(target)
|
|
328
|
+
m.cp(empty, target)
|
|
329
|
+
assert m.find(target, withdirs=True) == [target]
|
|
330
|
+
|
|
331
|
+
# cp with slash, target directory exists
|
|
332
|
+
assert m.isdir(target)
|
|
333
|
+
m.cp(empty + "/", target)
|
|
334
|
+
assert m.find(target, withdirs=True) == [target]
|
|
335
|
+
|
|
336
|
+
m.rmdir(target)
|
|
337
|
+
|
|
338
|
+
# cp without slash, target directory doesn't exist
|
|
339
|
+
assert not m.isdir(target)
|
|
340
|
+
m.cp(empty, target)
|
|
341
|
+
assert not m.isdir(target)
|
|
342
|
+
|
|
343
|
+
# cp with slash, target directory doesn't exist
|
|
344
|
+
assert not m.isdir(target)
|
|
345
|
+
m.cp(empty + "/", target)
|
|
346
|
+
assert not m.isdir(target)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def test_cp_two_files(m):
|
|
350
|
+
src = "/src"
|
|
351
|
+
file0 = src + "/file0"
|
|
352
|
+
file1 = src + "/file1"
|
|
353
|
+
m.mkdir(src)
|
|
354
|
+
m.touch(file0)
|
|
355
|
+
m.touch(file1)
|
|
356
|
+
|
|
357
|
+
target = "/target"
|
|
358
|
+
assert not m.exists(target)
|
|
359
|
+
|
|
360
|
+
m.cp([file0, file1], target)
|
|
361
|
+
|
|
362
|
+
assert m.isdir(target)
|
|
363
|
+
assert sorted(m.find(target)) == [
|
|
364
|
+
"/target/file0",
|
|
365
|
+
"/target/file1",
|
|
366
|
+
]
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def test_open_path_posix(m):
|
|
370
|
+
path = PurePosixPath("/myfile/foo/bar")
|
|
371
|
+
with m.open(path, "wb") as f:
|
|
372
|
+
f.write(b"some\nlines\nof\ntext")
|
|
373
|
+
|
|
374
|
+
assert m.read_text(path) == "some\nlines\nof\ntext"
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def test_open_path_windows(m):
|
|
378
|
+
path = PureWindowsPath("C:\\myfile\\foo\\bar")
|
|
379
|
+
with m.open(path, "wb") as f:
|
|
380
|
+
f.write(b"some\nlines\nof\ntext")
|
|
381
|
+
|
|
382
|
+
assert m.read_text(path) == "some\nlines\nof\ntext"
|