fsspec 2024.5.0__py3-none-any.whl → 2024.6.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.
Files changed (73) hide show
  1. fsspec/_version.py +2 -2
  2. fsspec/caching.py +3 -2
  3. fsspec/compression.py +1 -1
  4. fsspec/implementations/cached.py +1 -13
  5. fsspec/implementations/github.py +12 -0
  6. fsspec/implementations/reference.py +6 -0
  7. fsspec/implementations/smb.py +10 -0
  8. fsspec/json.py +81 -0
  9. fsspec/registry.py +24 -18
  10. fsspec/spec.py +76 -34
  11. fsspec/utils.py +1 -1
  12. {fsspec-2024.5.0.dist-info → fsspec-2024.6.0.dist-info}/METADATA +11 -5
  13. fsspec-2024.6.0.dist-info/RECORD +55 -0
  14. fsspec/implementations/tests/__init__.py +0 -0
  15. fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_file_listing.yaml +0 -112
  16. fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_mkdir.yaml +0 -582
  17. fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_read_pyarrow_non_partitioned.yaml +0 -873
  18. fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_read_range.yaml +0 -458
  19. fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_read_range_chunked.yaml +0 -1355
  20. fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_write_and_read.yaml +0 -795
  21. fsspec/implementations/tests/cassettes/test_dbfs/test_dbfs_write_pyarrow_non_partitioned.yaml +0 -613
  22. fsspec/implementations/tests/conftest.py +0 -39
  23. fsspec/implementations/tests/local/__init__.py +0 -0
  24. fsspec/implementations/tests/local/local_fixtures.py +0 -18
  25. fsspec/implementations/tests/local/local_test.py +0 -14
  26. fsspec/implementations/tests/memory/__init__.py +0 -0
  27. fsspec/implementations/tests/memory/memory_fixtures.py +0 -27
  28. fsspec/implementations/tests/memory/memory_test.py +0 -14
  29. fsspec/implementations/tests/out.zip +0 -0
  30. fsspec/implementations/tests/test_archive.py +0 -382
  31. fsspec/implementations/tests/test_arrow.py +0 -259
  32. fsspec/implementations/tests/test_cached.py +0 -1306
  33. fsspec/implementations/tests/test_common.py +0 -35
  34. fsspec/implementations/tests/test_dask.py +0 -29
  35. fsspec/implementations/tests/test_data.py +0 -20
  36. fsspec/implementations/tests/test_dbfs.py +0 -268
  37. fsspec/implementations/tests/test_dirfs.py +0 -588
  38. fsspec/implementations/tests/test_ftp.py +0 -178
  39. fsspec/implementations/tests/test_git.py +0 -76
  40. fsspec/implementations/tests/test_http.py +0 -577
  41. fsspec/implementations/tests/test_jupyter.py +0 -57
  42. fsspec/implementations/tests/test_libarchive.py +0 -33
  43. fsspec/implementations/tests/test_local.py +0 -1285
  44. fsspec/implementations/tests/test_memory.py +0 -382
  45. fsspec/implementations/tests/test_reference.py +0 -720
  46. fsspec/implementations/tests/test_sftp.py +0 -233
  47. fsspec/implementations/tests/test_smb.py +0 -139
  48. fsspec/implementations/tests/test_tar.py +0 -243
  49. fsspec/implementations/tests/test_webhdfs.py +0 -197
  50. fsspec/implementations/tests/test_zip.py +0 -134
  51. fsspec/tests/__init__.py +0 -0
  52. fsspec/tests/conftest.py +0 -188
  53. fsspec/tests/data/listing.html +0 -1
  54. fsspec/tests/test_api.py +0 -498
  55. fsspec/tests/test_async.py +0 -230
  56. fsspec/tests/test_caches.py +0 -255
  57. fsspec/tests/test_callbacks.py +0 -89
  58. fsspec/tests/test_compression.py +0 -164
  59. fsspec/tests/test_config.py +0 -129
  60. fsspec/tests/test_core.py +0 -466
  61. fsspec/tests/test_downstream.py +0 -40
  62. fsspec/tests/test_file.py +0 -200
  63. fsspec/tests/test_fuse.py +0 -147
  64. fsspec/tests/test_generic.py +0 -90
  65. fsspec/tests/test_gui.py +0 -23
  66. fsspec/tests/test_mapping.py +0 -228
  67. fsspec/tests/test_parquet.py +0 -140
  68. fsspec/tests/test_registry.py +0 -134
  69. fsspec/tests/test_spec.py +0 -1167
  70. fsspec/tests/test_utils.py +0 -478
  71. fsspec-2024.5.0.dist-info/RECORD +0 -111
  72. {fsspec-2024.5.0.dist-info → fsspec-2024.6.0.dist-info}/WHEEL +0 -0
  73. {fsspec-2024.5.0.dist-info → fsspec-2024.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,1285 +0,0 @@
1
- import bz2
2
- import gzip
3
- import os
4
- import os.path
5
- import pickle
6
- import posixpath
7
- import sys
8
- import tempfile
9
- from contextlib import contextmanager
10
- from pathlib import Path
11
- from unittest.mock import patch
12
-
13
- import pytest
14
-
15
- import fsspec
16
- from fsspec import compression
17
- from fsspec.core import OpenFile, get_fs_token_paths, open_files
18
- from fsspec.implementations.local import LocalFileSystem, make_path_posix
19
- from fsspec.tests.test_utils import WIN
20
-
21
- files = {
22
- ".test.accounts.1.json": (
23
- b'{"amount": 100, "name": "Alice"}\n'
24
- b'{"amount": 200, "name": "Bob"}\n'
25
- b'{"amount": 300, "name": "Charlie"}\n'
26
- b'{"amount": 400, "name": "Dennis"}\n'
27
- ),
28
- ".test.accounts.2.json": (
29
- b'{"amount": 500, "name": "Alice"}\n'
30
- b'{"amount": 600, "name": "Bob"}\n'
31
- b'{"amount": 700, "name": "Charlie"}\n'
32
- b'{"amount": 800, "name": "Dennis"}\n'
33
- ),
34
- }
35
-
36
- csv_files = {
37
- ".test.fakedata.1.csv": (b"a,b\n1,2\n"),
38
- ".test.fakedata.2.csv": (b"a,b\n3,4\n"),
39
- }
40
- odir = os.getcwd()
41
-
42
-
43
- @pytest.fixture()
44
- def cwd():
45
- pth = os.getcwd().replace("\\", "/")
46
- assert not pth.endswith("/")
47
- yield pth
48
-
49
-
50
- @pytest.fixture()
51
- def current_drive(cwd):
52
- drive = os.path.splitdrive(cwd)[0]
53
- assert not drive or (len(drive) == 2 and drive.endswith(":"))
54
- yield drive
55
-
56
-
57
- @pytest.fixture()
58
- def user_home():
59
- pth = os.path.expanduser("~").replace("\\", "/")
60
- assert not pth.endswith("/")
61
- yield pth
62
-
63
-
64
- def winonly(*args):
65
- return pytest.param(*args, marks=pytest.mark.skipif(not WIN, reason="Windows only"))
66
-
67
-
68
- def posixonly(*args):
69
- return pytest.param(*args, marks=pytest.mark.skipif(WIN, reason="Posix only"))
70
-
71
-
72
- @contextmanager
73
- def filetexts(d, open=open, mode="t"):
74
- """Dumps a number of textfiles to disk
75
-
76
- d - dict
77
- a mapping from filename to text like {'a.csv': '1,1\n2,2'}
78
-
79
- Since this is meant for use in tests, this context manager will
80
- automatically switch to a temporary current directory, to avoid
81
- race conditions when running tests in parallel.
82
- """
83
- dirname = tempfile.mkdtemp()
84
- try:
85
- os.chdir(dirname)
86
- for filename, text in d.items():
87
- if dirname := os.path.dirname(filename):
88
- os.makedirs(dirname, exist_ok=True)
89
- f = open(filename, f"w{mode}")
90
- try:
91
- f.write(text)
92
- finally:
93
- try:
94
- f.close()
95
- except AttributeError:
96
- pass
97
-
98
- yield list(d)
99
-
100
- for filename in d:
101
- if os.path.exists(filename):
102
- try:
103
- os.remove(filename)
104
- except OSError:
105
- pass
106
- finally:
107
- os.chdir(odir)
108
-
109
-
110
- def test_urlpath_inference_strips_protocol(tmpdir):
111
- tmpdir = make_path_posix(str(tmpdir))
112
- paths = ["/".join([tmpdir, f"test.{i:02d}.csv"]) for i in range(20)]
113
-
114
- for path in paths:
115
- with open(path, "wb") as f:
116
- f.write(b"1,2,3\n" * 10)
117
-
118
- # globstring
119
- protocol = "file:///" if sys.platform == "win32" else "file://"
120
- urlpath = protocol + os.path.join(tmpdir, "test.*.csv")
121
- _, _, paths2 = get_fs_token_paths(urlpath)
122
- assert paths2 == paths
123
-
124
- # list of paths
125
- _, _, paths2 = get_fs_token_paths([protocol + p for p in paths])
126
- assert paths2 == paths
127
-
128
-
129
- def test_urlpath_inference_errors():
130
- # Empty list
131
- with pytest.raises(ValueError) as err:
132
- get_fs_token_paths([])
133
- assert "empty" in str(err.value)
134
-
135
- pytest.importorskip("s3fs")
136
- # Protocols differ
137
- with pytest.raises(ValueError) as err:
138
- get_fs_token_paths(["s3://test/path.csv", "/other/path.csv"])
139
- assert "Protocol" in str(err.value)
140
-
141
-
142
- def test_urlpath_expand_read():
143
- """Make sure * is expanded in file paths when reading."""
144
- # when reading, globs should be expanded to read files by mask
145
- with filetexts(csv_files, mode="b"):
146
- _, _, paths = get_fs_token_paths("./.*.csv")
147
- assert len(paths) == 2
148
- _, _, paths = get_fs_token_paths(["./.*.csv"])
149
- assert len(paths) == 2
150
-
151
-
152
- def test_cats():
153
- with filetexts(csv_files, mode="b"):
154
- fs = fsspec.filesystem("file")
155
- assert fs.cat(".test.fakedata.1.csv") == b"a,b\n1,2\n"
156
- out = set(fs.cat([".test.fakedata.1.csv", ".test.fakedata.2.csv"]).values())
157
- assert out == {b"a,b\n1,2\n", b"a,b\n3,4\n"}
158
- assert fs.cat(".test.fakedata.1.csv", None, None) == b"a,b\n1,2\n"
159
- assert fs.cat(".test.fakedata.1.csv", start=1, end=6) == b"a,b\n1,2\n"[1:6]
160
- assert fs.cat(".test.fakedata.1.csv", start=-1) == b"a,b\n1,2\n"[-1:]
161
- assert fs.cat(".test.fakedata.1.csv", start=1, end=-2) == b"a,b\n1,2\n"[1:-2]
162
- out = set(
163
- fs.cat(
164
- [".test.fakedata.1.csv", ".test.fakedata.2.csv"], start=1, end=-1
165
- ).values()
166
- )
167
- assert out == {b"a,b\n1,2\n"[1:-1], b"a,b\n3,4\n"[1:-1]}
168
-
169
-
170
- def test_urlpath_expand_write():
171
- """Make sure * is expanded in file paths when writing."""
172
- _, _, paths = get_fs_token_paths("prefix-*.csv", mode="wb", num=2)
173
- assert all(
174
- p.endswith(pa) for p, pa in zip(paths, ["/prefix-0.csv", "/prefix-1.csv"])
175
- )
176
- _, _, paths = get_fs_token_paths(["prefix-*.csv"], mode="wb", num=2)
177
- assert all(
178
- p.endswith(pa) for p, pa in zip(paths, ["/prefix-0.csv", "/prefix-1.csv"])
179
- )
180
- # we can read with multiple masks, but not write
181
- with pytest.raises(ValueError):
182
- _, _, paths = get_fs_token_paths(
183
- ["prefix1-*.csv", "prefix2-*.csv"], mode="wb", num=2
184
- )
185
-
186
-
187
- def test_open_files():
188
- with filetexts(files, mode="b"):
189
- myfiles = open_files("./.test.accounts.*")
190
- assert len(myfiles) == len(files)
191
- for lazy_file, data_file in zip(myfiles, sorted(files)):
192
- with lazy_file as f:
193
- x = f.read()
194
- assert x == files[data_file]
195
-
196
-
197
- @pytest.mark.parametrize("encoding", ["utf-8", "ascii"])
198
- def test_open_files_text_mode(encoding):
199
- with filetexts(files, mode="b"):
200
- myfiles = open_files("./.test.accounts.*", mode="rt", encoding=encoding)
201
- assert len(myfiles) == len(files)
202
- data = []
203
- for file in myfiles:
204
- with file as f:
205
- data.append(f.read())
206
- assert list(data) == [files[k].decode(encoding) for k in sorted(files)]
207
-
208
-
209
- @pytest.mark.parametrize("mode", ["rt", "rb"])
210
- @pytest.mark.parametrize("fmt", list(compression.compr))
211
- def test_compressions(fmt, mode, tmpdir):
212
- tmpdir = str(tmpdir)
213
- fn = os.path.join(tmpdir, ".tmp.getsize")
214
- fs = LocalFileSystem()
215
- f = OpenFile(fs, fn, compression=fmt, mode="wb")
216
- data = b"Long line of readily compressible text"
217
- with f as fo:
218
- fo.write(data)
219
- if fmt is None:
220
- assert fs.size(fn) == len(data)
221
- else:
222
- assert fs.size(fn) != len(data)
223
-
224
- f = OpenFile(fs, fn, compression=fmt, mode=mode)
225
- with f as fo:
226
- if mode == "rb":
227
- assert fo.read() == data
228
- else:
229
- assert fo.read() == data.decode()
230
-
231
-
232
- def test_bad_compression():
233
- with filetexts(files, mode="b"):
234
- for func in [open_files]:
235
- with pytest.raises(ValueError):
236
- func("./.test.accounts.*", compression="not-found")
237
-
238
-
239
- def test_not_found():
240
- fn = "not-a-file"
241
- fs = LocalFileSystem()
242
- with pytest.raises((FileNotFoundError, OSError)):
243
- with OpenFile(fs, fn, mode="rb"):
244
- pass
245
-
246
-
247
- def test_isfile():
248
- fs = LocalFileSystem()
249
- with filetexts(files, mode="b"):
250
- for f in files.keys():
251
- assert fs.isfile(f)
252
- assert fs.isfile(f"file://{f}")
253
- assert not fs.isfile("not-a-file")
254
- assert not fs.isfile("file://not-a-file")
255
-
256
-
257
- def test_isdir():
258
- fs = LocalFileSystem()
259
- with filetexts(files, mode="b"):
260
- for f in files.keys():
261
- assert fs.isdir(os.path.dirname(os.path.abspath(f)))
262
- assert not fs.isdir(f)
263
- assert not fs.isdir("not-a-dir")
264
-
265
-
266
- @pytest.mark.parametrize("compression_opener", [(None, open), ("gzip", gzip.open)])
267
- def test_open_files_write(tmpdir, compression_opener):
268
- tmpdir = str(tmpdir)
269
- compression, opener = compression_opener
270
- fn = str(tmpdir) + "/*.part"
271
- files = open_files(fn, num=2, mode="wb", compression=compression)
272
- assert len(files) == 2
273
- assert {f.mode for f in files} == {"wb"}
274
- for fil in files:
275
- with fil as f:
276
- f.write(b"000")
277
- files = sorted(os.listdir(tmpdir))
278
- assert files == ["0.part", "1.part"]
279
-
280
- with opener(os.path.join(tmpdir, files[0]), "rb") as f:
281
- d = f.read()
282
- assert d == b"000"
283
-
284
-
285
- def test_pickability_of_lazy_files(tmpdir):
286
- tmpdir = str(tmpdir)
287
- cloudpickle = pytest.importorskip("cloudpickle")
288
-
289
- with filetexts(files, mode="b"):
290
- myfiles = open_files("./.test.accounts.*")
291
- myfiles2 = cloudpickle.loads(cloudpickle.dumps(myfiles))
292
-
293
- for f, f2 in zip(myfiles, myfiles2):
294
- assert f.path == f2.path
295
- assert isinstance(f.fs, type(f2.fs))
296
- with f as f_open, f2 as f2_open:
297
- assert f_open.read() == f2_open.read()
298
-
299
-
300
- def test_abs_paths(tmpdir):
301
- tmpdir = str(tmpdir)
302
- here = os.getcwd()
303
- os.chdir(tmpdir)
304
- with open("tmp", "w") as f:
305
- f.write("hi")
306
- out = LocalFileSystem().glob("./*")
307
- assert len(out) == 1
308
- assert "/" in out[0]
309
- assert "tmp" in out[0]
310
-
311
- # I don't know what this was testing - but should avoid local paths anyway
312
- # fs = LocalFileSystem()
313
- os.chdir(here)
314
- # with fs.open('tmp', 'r') as f:
315
- # res = f.read()
316
- # assert res == 'hi'
317
-
318
-
319
- @pytest.mark.parametrize("sep", ["/", "\\"])
320
- @pytest.mark.parametrize("chars", ["+", "++", "(", ")", "|", "\\"])
321
- def test_glob_weird_characters(tmpdir, sep, chars):
322
- tmpdir = make_path_posix(str(tmpdir))
323
-
324
- subdir = f"{tmpdir}{sep}test{chars}x"
325
- try:
326
- os.makedirs(subdir, exist_ok=True)
327
- except OSError as e:
328
- if WIN and "label syntax" in str(e):
329
- pytest.xfail("Illegal windows directory name")
330
- else:
331
- raise
332
- with open(subdir + sep + "tmp", "w") as f:
333
- f.write("hi")
334
-
335
- out = LocalFileSystem().glob(subdir + sep + "*")
336
- assert len(out) == 1
337
- assert "/" in out[0]
338
- assert "tmp" in out[0]
339
-
340
-
341
- def test_globfind_dirs(tmpdir):
342
- tmpdir = make_path_posix(str(tmpdir))
343
- fs = fsspec.filesystem("file")
344
- fs.mkdir(tmpdir + "/dir")
345
- fs.touch(tmpdir + "/dir/afile")
346
- assert [tmpdir + "/dir"] == fs.glob(tmpdir + "/*")
347
- assert fs.glob(tmpdir + "/*", detail=True)[tmpdir + "/dir"]["type"] == "directory"
348
- assert (
349
- fs.glob(tmpdir + "/dir/*", detail=True)[tmpdir + "/dir/afile"]["type"] == "file"
350
- )
351
- assert [tmpdir + "/dir/afile"] == fs.find(tmpdir)
352
- assert [tmpdir, tmpdir + "/dir", tmpdir + "/dir/afile"] == fs.find(
353
- tmpdir, withdirs=True
354
- )
355
-
356
-
357
- def test_touch(tmpdir):
358
- import time
359
-
360
- fn = str(tmpdir + "/in/file")
361
- fs = fsspec.filesystem("file", auto_mkdir=False)
362
- with pytest.raises(OSError):
363
- fs.touch(fn)
364
- fs = fsspec.filesystem("file", auto_mkdir=True)
365
- fs.touch(fn)
366
- info = fs.info(fn)
367
- time.sleep(0.2)
368
- fs.touch(fn)
369
- info2 = fs.info(fn)
370
- if not WIN:
371
- assert info2["mtime"] > info["mtime"]
372
-
373
-
374
- def test_touch_truncate(tmpdir):
375
- fn = str(tmpdir + "/tfile")
376
- fs = fsspec.filesystem("file")
377
- fs.touch(fn, truncate=True)
378
- fs.pipe(fn, b"a")
379
- fs.touch(fn, truncate=True)
380
- assert fs.cat(fn) == b""
381
- fs.pipe(fn, b"a")
382
- fs.touch(fn, truncate=False)
383
- assert fs.cat(fn) == b"a"
384
-
385
-
386
- def test_directories(tmpdir):
387
- tmpdir = make_path_posix(str(tmpdir))
388
- fs = LocalFileSystem()
389
- fs.mkdir(tmpdir + "/dir")
390
- assert tmpdir + "/dir" in fs.ls(tmpdir)
391
- assert fs.ls(tmpdir, True)[0]["type"] == "directory"
392
- fs.rmdir(tmpdir + "/dir")
393
- assert not fs.ls(tmpdir)
394
- assert fs.ls(fs.root_marker)
395
-
396
-
397
- def test_ls_on_file(tmpdir):
398
- tmpdir = make_path_posix(str(tmpdir))
399
- fs = LocalFileSystem()
400
- resource = tmpdir + "/a.json"
401
- fs.touch(resource)
402
- assert fs.exists(resource)
403
- assert fs.ls(tmpdir) == fs.ls(resource)
404
- assert fs.ls(resource, detail=True)[0] == fs.info(resource)
405
-
406
-
407
- @pytest.mark.parametrize("file_protocol", ["", "file://"])
408
- def test_file_ops(tmpdir, file_protocol):
409
- tmpdir = make_path_posix(str(tmpdir))
410
- tmpdir_with_protocol = file_protocol + tmpdir
411
- fs = LocalFileSystem(auto_mkdir=True)
412
- with pytest.raises(FileNotFoundError):
413
- fs.info(tmpdir_with_protocol + "/nofile")
414
- fs.touch(tmpdir_with_protocol + "/afile")
415
- i1 = fs.ukey(tmpdir_with_protocol + "/afile")
416
-
417
- assert tmpdir + "/afile" in fs.ls(tmpdir_with_protocol)
418
-
419
- with fs.open(tmpdir_with_protocol + "/afile", "wb") as f:
420
- f.write(b"data")
421
- i2 = fs.ukey(tmpdir_with_protocol + "/afile")
422
- assert i1 != i2 # because file changed
423
-
424
- fs.copy(tmpdir_with_protocol + "/afile", tmpdir_with_protocol + "/afile2")
425
- assert tmpdir + "/afile2" in fs.ls(tmpdir_with_protocol)
426
-
427
- fs.move(tmpdir_with_protocol + "/afile", tmpdir_with_protocol + "/afile3")
428
- assert not fs.exists(tmpdir_with_protocol + "/afile")
429
-
430
- fs.cp(
431
- tmpdir_with_protocol + "/afile3", tmpdir_with_protocol + "/deeply/nested/file"
432
- )
433
- assert fs.exists(tmpdir_with_protocol + "/deeply/nested/file")
434
-
435
- fs.rm(tmpdir_with_protocol + "/afile3", recursive=True)
436
- assert not fs.exists(tmpdir_with_protocol + "/afile3")
437
-
438
- files = [tmpdir_with_protocol + "/afile4", tmpdir_with_protocol + "/afile5"]
439
- [fs.touch(f) for f in files]
440
-
441
- with pytest.raises(AttributeError):
442
- fs.rm_file(files)
443
- fs.rm(files)
444
- assert all(not fs.exists(f) for f in files)
445
-
446
- fs.touch(tmpdir_with_protocol + "/afile6")
447
- fs.rm_file(tmpdir_with_protocol + "/afile6")
448
- assert not fs.exists(tmpdir_with_protocol + "/afile6")
449
-
450
- # IsADirectoryError raised on Linux, PermissionError on Windows
451
- with pytest.raises((IsADirectoryError, PermissionError)):
452
- fs.rm_file(tmpdir_with_protocol)
453
-
454
- fs.rm(tmpdir_with_protocol, recursive=True)
455
- assert not fs.exists(tmpdir_with_protocol)
456
-
457
-
458
- def test_recursive_get_put(tmpdir):
459
- tmpdir = make_path_posix(str(tmpdir))
460
- fs = LocalFileSystem(auto_mkdir=True)
461
-
462
- fs.mkdir(tmpdir + "/a1/a2/a3")
463
- fs.touch(tmpdir + "/a1/a2/a3/afile")
464
- fs.touch(tmpdir + "/a1/afile")
465
-
466
- fs.get(f"file://{tmpdir}/a1", tmpdir + "/b1", recursive=True)
467
- assert fs.isfile(tmpdir + "/b1/afile")
468
- assert fs.isfile(tmpdir + "/b1/a2/a3/afile")
469
-
470
- fs.put(tmpdir + "/b1", f"file://{tmpdir}/c1", recursive=True)
471
- assert fs.isfile(tmpdir + "/c1/afile")
472
- assert fs.isfile(tmpdir + "/c1/a2/a3/afile")
473
-
474
-
475
- def test_commit_discard(tmpdir):
476
- tmpdir = str(tmpdir)
477
- fs = LocalFileSystem()
478
- with fs.transaction:
479
- with fs.open(tmpdir + "/afile", "wb") as f:
480
- assert not fs.exists(tmpdir + "/afile")
481
- f.write(b"data")
482
- assert not fs.exists(tmpdir + "/afile")
483
-
484
- assert fs._transaction is None
485
- assert fs.cat(tmpdir + "/afile") == b"data"
486
-
487
- try:
488
- with fs.transaction:
489
- with fs.open(tmpdir + "/bfile", "wb") as f:
490
- f.write(b"data")
491
- raise KeyboardInterrupt
492
- except KeyboardInterrupt:
493
- assert not fs.exists(tmpdir + "/bfile")
494
-
495
-
496
- def test_make_path_posix():
497
- cwd = os.getcwd()
498
- if WIN:
499
- drive = cwd[0]
500
- assert make_path_posix("/a/posix/path") == f"{drive}:/a/posix/path"
501
- assert make_path_posix("/posix") == f"{drive}:/posix"
502
- # Windows drive requires trailing slash
503
- assert make_path_posix("C:\\") == "C:/"
504
- else:
505
- assert make_path_posix("/a/posix/path") == "/a/posix/path"
506
- assert make_path_posix("/posix") == "/posix"
507
- assert make_path_posix("relpath") == posixpath.join(make_path_posix(cwd), "relpath")
508
- assert make_path_posix("rel/path") == posixpath.join(
509
- make_path_posix(cwd), "rel/path"
510
- )
511
- # NT style
512
- if WIN:
513
- assert make_path_posix("C:\\path") == "C:/path"
514
- assert (
515
- make_path_posix(
516
- "\\\\windows-server\\someshare\\path\\more\\path\\dir\\foo.parquet",
517
- )
518
- == "//windows-server/someshare/path/more/path/dir/foo.parquet"
519
- )
520
- assert (
521
- make_path_posix(
522
- "\\\\SERVER\\UserHomeFolder$\\me\\My Documents\\proj\\data\\fname.csv",
523
- )
524
- == "//SERVER/UserHomeFolder$/me/My Documents/proj/data/fname.csv"
525
- )
526
- assert "/" in make_path_posix("rel\\path")
527
- # Relative
528
- pp = make_path_posix("./path")
529
- cd = make_path_posix(cwd)
530
- assert pp == cd + "/path"
531
- # Userpath
532
- userpath = make_path_posix("~/path")
533
- assert userpath.endswith("/path")
534
-
535
-
536
- @pytest.mark.parametrize(
537
- "path",
538
- [
539
- "/abc/def",
540
- "abc/def",
541
- "",
542
- ".",
543
- "//server/share/",
544
- "\\\\server\\share\\",
545
- "C:\\",
546
- "d:/abc/def",
547
- "e:",
548
- pytest.param(
549
- "\\\\server\\share",
550
- marks=[
551
- pytest.mark.xfail(
552
- WIN and sys.version_info < (3, 11),
553
- reason="requires py3.11+ see: python/cpython#96290",
554
- )
555
- ],
556
- ),
557
- pytest.param(
558
- "f:foo",
559
- marks=[pytest.mark.xfail(WIN, reason="unsupported")],
560
- id="relative-path-with-drive",
561
- ),
562
- ],
563
- )
564
- def test_make_path_posix_returns_absolute_paths(path):
565
- posix_pth = make_path_posix(path)
566
- assert os.path.isabs(posix_pth)
567
-
568
-
569
- @pytest.mark.parametrize("container_cls", [list, set, tuple])
570
- def test_make_path_posix_set_list_tuple(container_cls):
571
- paths = container_cls(
572
- [
573
- "/foo/bar",
574
- "bar/foo",
575
- ]
576
- )
577
- posix_paths = make_path_posix(paths)
578
- assert isinstance(posix_paths, container_cls)
579
- assert posix_paths == container_cls(
580
- [
581
- make_path_posix("/foo/bar"),
582
- make_path_posix("bar/foo"),
583
- ]
584
- )
585
-
586
-
587
- @pytest.mark.parametrize(
588
- "obj",
589
- [
590
- 1,
591
- True,
592
- None,
593
- object(),
594
- ],
595
- )
596
- def test_make_path_posix_wrong_type(obj):
597
- with pytest.raises(TypeError):
598
- make_path_posix(obj)
599
-
600
-
601
- def test_parent():
602
- if WIN:
603
- assert LocalFileSystem._parent("C:\\file or folder") == "C:/"
604
- assert LocalFileSystem._parent("C:\\") == "C:/"
605
- else:
606
- assert LocalFileSystem._parent("/file or folder") == "/"
607
- assert LocalFileSystem._parent("/") == "/"
608
-
609
-
610
- @pytest.mark.parametrize(
611
- "path,parent",
612
- [
613
- ("C:\\", "C:/"),
614
- ("C:\\.", "C:/"),
615
- ("C:\\.\\", "C:/"),
616
- ("file:C:/", "C:/"),
617
- ("file://C:/", "C:/"),
618
- ("local:C:/", "C:/"),
619
- ("local://C:/", "C:/"),
620
- ("\\\\server\\share", "//server/share"),
621
- ("\\\\server\\share\\", "//server/share"),
622
- ("\\\\server\\share\\path", "//server/share"),
623
- ("//server/share", "//server/share"),
624
- ("//server/share/", "//server/share"),
625
- ("//server/share/path", "//server/share"),
626
- ("C:\\file or folder", "C:/"),
627
- ("C:\\file or folder\\", "C:/"),
628
- ("file:///", "{current_drive}/"),
629
- ("file:///path", "{current_drive}/"),
630
- ]
631
- if WIN
632
- else [
633
- ("/", "/"),
634
- ("/.", "/"),
635
- ("/./", "/"),
636
- ("file:/", "/"),
637
- ("file:///", "/"),
638
- ("local:/", "/"),
639
- ("local:///", "/"),
640
- ("/file or folder", "/"),
641
- ("/file or folder/", "/"),
642
- ("file:///path", "/"),
643
- ("file://c/", "{cwd}"),
644
- ],
645
- )
646
- def test_parent_edge_cases(path, parent, cwd, current_drive):
647
- parent = parent.format(cwd=cwd, current_drive=current_drive)
648
-
649
- assert LocalFileSystem._parent(path) == parent
650
-
651
-
652
- def test_linked_files(tmpdir):
653
- tmpdir = str(tmpdir)
654
- fn0 = os.path.join(tmpdir, "target")
655
- fn1 = os.path.join(tmpdir, "link1")
656
- fn2 = os.path.join(tmpdir, "link2")
657
- data = b"my target data"
658
- with open(fn0, "wb") as f:
659
- f.write(data)
660
- try:
661
- os.symlink(fn0, fn1)
662
- os.symlink(fn0, fn2)
663
- except OSError:
664
- if WIN:
665
- pytest.xfail("Ran on win without admin permissions")
666
- else:
667
- raise
668
-
669
- fs = LocalFileSystem()
670
- assert fs.info(fn0)["type"] == "file"
671
- assert fs.info(fn1)["type"] == "file"
672
- assert fs.info(fn2)["type"] == "file"
673
-
674
- assert not fs.info(fn0)["islink"]
675
- assert fs.info(fn1)["islink"]
676
- assert fs.info(fn2)["islink"]
677
-
678
- assert fs.info(fn0)["size"] == len(data)
679
- assert fs.info(fn1)["size"] == len(data)
680
- assert fs.info(fn2)["size"] == len(data)
681
-
682
- of = fsspec.open(fn1, "rb")
683
- with of as f:
684
- assert f.read() == data
685
-
686
- of = fsspec.open(fn2, "rb")
687
- with of as f:
688
- assert f.read() == data
689
-
690
-
691
- def test_linked_files_exists(tmpdir):
692
- origin = tmpdir / "original"
693
- copy_file = tmpdir / "copy"
694
-
695
- fs = LocalFileSystem()
696
- fs.touch(origin)
697
-
698
- try:
699
- os.symlink(origin, copy_file)
700
- except OSError:
701
- if WIN:
702
- pytest.xfail("Ran on win without admin permissions")
703
- else:
704
- raise
705
-
706
- assert fs.exists(copy_file)
707
- assert fs.lexists(copy_file)
708
-
709
- os.unlink(origin)
710
-
711
- assert not fs.exists(copy_file)
712
- assert fs.lexists(copy_file)
713
-
714
- os.unlink(copy_file)
715
-
716
- assert not fs.exists(copy_file)
717
- assert not fs.lexists(copy_file)
718
-
719
-
720
- def test_linked_directories(tmpdir):
721
- tmpdir = str(tmpdir)
722
-
723
- subdir0 = os.path.join(tmpdir, "target")
724
- subdir1 = os.path.join(tmpdir, "link1")
725
- subdir2 = os.path.join(tmpdir, "link2")
726
-
727
- os.makedirs(subdir0)
728
-
729
- try:
730
- os.symlink(subdir0, subdir1)
731
- os.symlink(subdir0, subdir2)
732
- except OSError:
733
- if WIN:
734
- pytest.xfail("Ran on win without admin permissions")
735
- else:
736
- raise
737
-
738
- fs = LocalFileSystem()
739
- assert fs.info(subdir0)["type"] == "directory"
740
- assert fs.info(subdir1)["type"] == "directory"
741
- assert fs.info(subdir2)["type"] == "directory"
742
-
743
- assert not fs.info(subdir0)["islink"]
744
- assert fs.info(subdir1)["islink"]
745
- assert fs.info(subdir2)["islink"]
746
-
747
-
748
- def test_isfilestore():
749
- fs = LocalFileSystem(auto_mkdir=False)
750
- assert fs._isfilestore()
751
-
752
-
753
- def test_pickle(tmpdir):
754
- fs = LocalFileSystem()
755
- tmpdir = str(tmpdir)
756
- fn0 = os.path.join(tmpdir, "target")
757
-
758
- with open(fn0, "wb") as f:
759
- f.write(b"data")
760
-
761
- f = fs.open(fn0, "rb")
762
- f.seek(1)
763
- f2 = pickle.loads(pickle.dumps(f))
764
- assert f2.read() == f.read()
765
-
766
- f = fs.open(fn0, "wb")
767
- with pytest.raises(ValueError):
768
- pickle.dumps(f)
769
-
770
- # with context
771
- with fs.open(fn0, "rb") as f:
772
- f.seek(1)
773
- f2 = pickle.loads(pickle.dumps(f))
774
- assert f2.tell() == 1
775
- assert f2.read() == f.read()
776
-
777
- # with fsspec.open https://github.com/fsspec/filesystem_spec/issues/579
778
- with fsspec.open(fn0, "rb") as f:
779
- f.seek(1)
780
- f2 = pickle.loads(pickle.dumps(f))
781
- assert f2.tell() == 1
782
- assert f2.read() == f.read()
783
-
784
-
785
- @pytest.mark.parametrize(
786
- "uri, expected",
787
- [
788
- ("file://~/foo/bar", "{user_home}/foo/bar"),
789
- ("~/foo/bar", "{user_home}/foo/bar"),
790
- winonly("~\\foo\\bar", "{user_home}/foo/bar"),
791
- winonly("file://~\\foo\\bar", "{user_home}/foo/bar"),
792
- ],
793
- )
794
- def test_strip_protocol_expanduser(uri, expected, user_home):
795
- expected = expected.format(user_home=user_home)
796
-
797
- stripped = LocalFileSystem._strip_protocol(uri)
798
- assert expected == stripped
799
-
800
-
801
- @pytest.mark.parametrize(
802
- "uri, expected",
803
- [
804
- ("file://", "{cwd}"),
805
- ("file://.", "{cwd}"),
806
- ("file://./", "{cwd}"),
807
- ("./", "{cwd}"),
808
- ("file:path", "{cwd}/path"),
809
- ("file://path", "{cwd}/path"),
810
- ("path", "{cwd}/path"),
811
- ("./path", "{cwd}/path"),
812
- winonly(".\\", "{cwd}"),
813
- winonly("file://.\\path", "{cwd}/path"),
814
- ],
815
- )
816
- def test_strip_protocol_relative_paths(uri, expected, cwd):
817
- expected = expected.format(cwd=cwd)
818
-
819
- stripped = LocalFileSystem._strip_protocol(uri)
820
- assert expected == stripped
821
-
822
-
823
- @pytest.mark.parametrize(
824
- "uri, expected",
825
- [
826
- posixonly("file:/foo/bar", "/foo/bar"),
827
- winonly("file:/foo/bar", "{current_drive}/foo/bar"),
828
- winonly("file:\\foo\\bar", "{current_drive}/foo/bar"),
829
- winonly("file:D:\\path\\file", "D:/path/file"),
830
- winonly("file:/D:\\path\\file", "D:/path/file"),
831
- winonly("file://D:\\path\\file", "D:/path/file"),
832
- ],
833
- )
834
- def test_strip_protocol_no_authority(uri, expected, cwd, current_drive):
835
- expected = expected.format(cwd=cwd, current_drive=current_drive)
836
-
837
- stripped = LocalFileSystem._strip_protocol(uri)
838
- assert expected == stripped
839
-
840
-
841
- @pytest.mark.parametrize(
842
- "uri, expected",
843
- [
844
- ("file:/path", "/path"),
845
- ("file:///path", "/path"),
846
- ("file:////path", "//path"),
847
- ("local:/path", "/path"),
848
- ("s3://bucket/key", "{cwd}/s3://bucket/key"),
849
- ("/path", "/path"),
850
- ("file:///", "/"),
851
- ]
852
- if not WIN
853
- else [
854
- ("file:c:/path", "c:/path"),
855
- ("file:/c:/path", "c:/path"),
856
- ("file:/C:/path", "C:/path"),
857
- ("file://c:/path", "c:/path"),
858
- ("file:///c:/path", "c:/path"),
859
- ("local:/path", "{current_drive}/path"),
860
- ("s3://bucket/key", "{cwd}/s3://bucket/key"),
861
- ("c:/path", "c:/path"),
862
- ("c:\\path", "c:/path"),
863
- ("file:///", "{current_drive}/"),
864
- pytest.param(
865
- "file://localhost/c:/path",
866
- "c:/path",
867
- marks=pytest.mark.xfail(
868
- reason="rfc8089 section3 'localhost uri' not supported"
869
- ),
870
- ),
871
- ],
872
- )
873
- def test_strip_protocol_absolute_paths(uri, expected, current_drive, cwd):
874
- expected = expected.format(current_drive=current_drive, cwd=cwd)
875
-
876
- stripped = LocalFileSystem._strip_protocol(uri)
877
- assert expected == stripped
878
-
879
-
880
- @pytest.mark.parametrize(
881
- "uri, expected",
882
- [
883
- ("file:c|/path", "c:/path"),
884
- ("file:/D|/path", "D:/path"),
885
- ("file:///C|/path", "C:/path"),
886
- ],
887
- )
888
- @pytest.mark.skipif(not WIN, reason="Windows only")
889
- @pytest.mark.xfail(WIN, reason="legacy dos uris not supported")
890
- def test_strip_protocol_legacy_dos_uris(uri, expected):
891
- stripped = LocalFileSystem._strip_protocol(uri)
892
- assert expected == stripped
893
-
894
-
895
- @pytest.mark.parametrize(
896
- "uri, stripped",
897
- [
898
- ("file://remote/share/pth", "{cwd}/remote/share/pth"),
899
- ("file:////remote/share/pth", "//remote/share/pth"),
900
- ("file://///remote/share/pth", "///remote/share/pth"),
901
- ("//remote/share/pth", "//remote/share/pth"),
902
- winonly("\\\\remote\\share\\pth", "//remote/share/pth"),
903
- ],
904
- )
905
- def test_strip_protocol_windows_remote_shares(uri, stripped, cwd):
906
- stripped = stripped.format(cwd=cwd)
907
-
908
- assert LocalFileSystem._strip_protocol(uri) == stripped
909
-
910
-
911
- def test_mkdir_twice_faile(tmpdir):
912
- fn = os.path.join(tmpdir, "test")
913
- fs = fsspec.filesystem("file")
914
- fs.mkdir(fn)
915
- with pytest.raises(FileExistsError):
916
- fs.mkdir(fn)
917
-
918
-
919
- def test_iterable(tmpdir):
920
- data = b"a\nhello\noi"
921
- fn = os.path.join(tmpdir, "test")
922
- with open(fn, "wb") as f:
923
- f.write(data)
924
- of = fsspec.open(f"file://{fn}", "rb")
925
- with of as f:
926
- out = list(f)
927
- assert b"".join(out) == data
928
-
929
-
930
- def test_mv_empty(tmpdir):
931
- localfs = fsspec.filesystem("file")
932
- src = os.path.join(str(tmpdir), "src")
933
- dest = os.path.join(str(tmpdir), "dest")
934
- assert localfs.isdir(src) is False
935
- localfs.mkdir(src)
936
- assert localfs.isdir(src)
937
- localfs.move(src, dest, recursive=True)
938
- assert localfs.isdir(src) is False
939
- assert localfs.isdir(dest)
940
- assert localfs.info(dest)
941
-
942
-
943
- def test_mv_recursive(tmpdir):
944
- localfs = fsspec.filesystem("file")
945
- src = os.path.join(str(tmpdir), "src")
946
- dest = os.path.join(str(tmpdir), "dest")
947
- assert localfs.isdir(src) is False
948
- localfs.mkdir(src)
949
- assert localfs.isdir(src)
950
- localfs.touch(os.path.join(src, "afile"))
951
- localfs.move(src, dest, recursive=True)
952
- assert localfs.isdir(src) is False
953
- assert localfs.isdir(dest)
954
- assert localfs.info(os.path.join(dest, "afile"))
955
-
956
-
957
- @pytest.mark.xfail(WIN, reason="windows expand path to be revisited")
958
- def test_copy_errors(tmpdir):
959
- localfs = fsspec.filesystem("file", auto_mkdir=True)
960
-
961
- dest1 = os.path.join(str(tmpdir), "dest1")
962
- dest2 = os.path.join(str(tmpdir), "dest2")
963
-
964
- src = os.path.join(str(tmpdir), "src")
965
- file1 = os.path.join(src, "afile1")
966
- file2 = os.path.join(src, "afile2")
967
- dne = os.path.join(str(tmpdir), "src", "notafile")
968
-
969
- localfs.mkdir(src)
970
- localfs.mkdir(dest1)
971
- localfs.mkdir(dest2)
972
- localfs.touch(file1)
973
- localfs.touch(file2)
974
-
975
- # Non recursive should raise an error unless we specify ignore
976
- with pytest.raises(FileNotFoundError):
977
- localfs.copy([file1, file2, dne], dest1)
978
-
979
- localfs.copy([file1, file2, dne], dest1, on_error="ignore")
980
-
981
- assert sorted(localfs.ls(dest1)) == [
982
- make_path_posix(os.path.join(dest1, "afile1")),
983
- make_path_posix(os.path.join(dest1, "afile2")),
984
- ]
985
-
986
- # Recursive should raise an error only if we specify raise
987
- # the patch simulates the filesystem finding a file that does not
988
- # exist in the directory
989
- current_files = localfs.expand_path(src, recursive=True)
990
- with patch.object(localfs, "expand_path", return_value=current_files + [dne]):
991
- with pytest.raises(FileNotFoundError):
992
- localfs.copy(src + "/", dest2, recursive=True, on_error="raise")
993
-
994
- localfs.copy(src + "/", dest2, recursive=True)
995
- assert sorted(localfs.ls(dest2)) == [
996
- make_path_posix(os.path.join(dest2, "afile1")),
997
- make_path_posix(os.path.join(dest2, "afile2")),
998
- ]
999
-
1000
-
1001
- def test_transaction(tmpdir):
1002
- file = str(tmpdir / "test.txt")
1003
- fs = LocalFileSystem()
1004
-
1005
- with fs.transaction:
1006
- content = "hello world"
1007
- with fs.open(file, "w") as fp:
1008
- fp.write(content)
1009
-
1010
- with fs.open(file, "r") as fp:
1011
- read_content = fp.read()
1012
-
1013
- assert content == read_content
1014
-
1015
-
1016
- def test_delete_cwd(tmpdir):
1017
- cwd = os.getcwd()
1018
- fs = LocalFileSystem()
1019
- try:
1020
- os.chdir(tmpdir)
1021
- with pytest.raises(ValueError):
1022
- fs.rm(".", recursive=True)
1023
- finally:
1024
- os.chdir(cwd)
1025
-
1026
-
1027
- def test_delete_non_recursive_dir_fails(tmpdir):
1028
- fs = LocalFileSystem()
1029
- subdir = os.path.join(tmpdir, "testdir")
1030
- fs.mkdir(subdir)
1031
- with pytest.raises(ValueError):
1032
- fs.rm(subdir)
1033
- fs.rm(subdir, recursive=True)
1034
-
1035
-
1036
- @pytest.mark.parametrize(
1037
- "opener, ext", [(bz2.open, ".bz2"), (gzip.open, ".gz"), (open, "")]
1038
- )
1039
- def test_infer_compression(tmpdir, opener, ext):
1040
- filename = str(tmpdir / f"test{ext}")
1041
- content = b"hello world"
1042
- with opener(filename, "wb") as fp:
1043
- fp.write(content)
1044
-
1045
- fs = LocalFileSystem()
1046
- with fs.open(f"file://{filename}", "rb", compression="infer") as fp:
1047
- read_content = fp.read()
1048
-
1049
- assert content == read_content
1050
-
1051
-
1052
- def test_info_path_like(tmpdir):
1053
- path = Path(tmpdir / "test_info")
1054
- path.write_text("fsspec")
1055
-
1056
- fs = LocalFileSystem()
1057
- assert fs.exists(path)
1058
-
1059
-
1060
- def test_seekable(tmpdir):
1061
- fs = LocalFileSystem()
1062
- tmpdir = str(tmpdir)
1063
- fn0 = os.path.join(tmpdir, "target")
1064
-
1065
- with open(fn0, "wb") as f:
1066
- f.write(b"data")
1067
-
1068
- f = fs.open(fn0, "rt")
1069
- assert f.seekable(), "file is not seekable"
1070
- f.seek(1)
1071
- assert f.read(1) == "a"
1072
- assert f.tell() == 2
1073
-
1074
-
1075
- def test_numpy_fromfile(tmpdir):
1076
- # Regression test for #1005.
1077
- np = pytest.importorskip("numpy")
1078
- fn = str(tmpdir / "test_arr.npy")
1079
- dt = np.int64
1080
- arr = np.arange(10, dtype=dt)
1081
- arr.tofile(fn)
1082
- assert np.array_equal(np.fromfile(fn, dtype=dt), arr)
1083
-
1084
-
1085
- def test_link(tmpdir):
1086
- target = os.path.join(tmpdir, "target")
1087
- link = os.path.join(tmpdir, "link")
1088
-
1089
- fs = LocalFileSystem()
1090
- fs.touch(target)
1091
-
1092
- fs.link(target, link)
1093
- assert fs.info(link)["nlink"] > 1
1094
-
1095
-
1096
- def test_symlink(tmpdir):
1097
- target = os.path.join(tmpdir, "target")
1098
- link = os.path.join(tmpdir, "link")
1099
-
1100
- fs = LocalFileSystem()
1101
- fs.touch(target)
1102
- try:
1103
- fs.symlink(target, link)
1104
- except OSError as e:
1105
- if "[WinError 1314]" in str(e):
1106
- # Windows requires developer mode to be enabled to use symbolic links
1107
- return
1108
- raise
1109
- assert fs.islink(link)
1110
-
1111
-
1112
- # https://github.com/fsspec/filesystem_spec/issues/967
1113
- def test_put_file_to_dir(tmpdir):
1114
- src_file = os.path.join(str(tmpdir), "src")
1115
- target_dir = os.path.join(str(tmpdir), "target")
1116
- target_file = os.path.join(target_dir, "src")
1117
-
1118
- fs = LocalFileSystem()
1119
- fs.touch(src_file)
1120
- fs.mkdir(target_dir)
1121
- fs.put(src_file, target_dir)
1122
-
1123
- assert fs.isfile(target_file)
1124
-
1125
-
1126
- def test_du(tmpdir):
1127
- file = tmpdir / "file"
1128
- subdir = tmpdir / "subdir"
1129
- subfile = subdir / "subfile"
1130
-
1131
- fs = LocalFileSystem()
1132
- with open(file, "wb") as f:
1133
- f.write(b"4444")
1134
- fs.mkdir(subdir)
1135
- with open(subfile, "wb") as f:
1136
- f.write(b"7777777")
1137
-
1138
- # Switch to posix paths for comparisons
1139
- tmpdir_posix = Path(tmpdir).as_posix()
1140
- file_posix = Path(file).as_posix()
1141
- subdir_posix = Path(subdir).as_posix()
1142
- subfile_posix = Path(subfile).as_posix()
1143
-
1144
- assert fs.du(tmpdir) == 11
1145
- assert fs.du(tmpdir, total=False) == {file_posix: 4, subfile_posix: 7}
1146
- # Note directory size is OS-specific, but must be >= 0
1147
- assert fs.du(tmpdir, withdirs=True) >= 11
1148
-
1149
- d = fs.du(tmpdir, total=False, withdirs=True)
1150
- assert len(d) == 4
1151
- assert d[file_posix] == 4
1152
- assert d[subfile_posix] == 7
1153
- assert d[tmpdir_posix] >= 0
1154
- assert d[subdir_posix] >= 0
1155
-
1156
- assert fs.du(tmpdir, maxdepth=2) == 11
1157
- assert fs.du(tmpdir, maxdepth=1) == 4
1158
- with pytest.raises(ValueError):
1159
- fs.du(tmpdir, maxdepth=0)
1160
-
1161
- # Size of file only.
1162
- assert fs.du(file) == 4
1163
- assert fs.du(file, withdirs=True) == 4
1164
-
1165
-
1166
- @pytest.mark.parametrize("funcname", ["cp", "get", "put"])
1167
- def test_cp_get_put_directory_recursive(tmpdir, funcname):
1168
- # https://github.com/fsspec/filesystem_spec/issues/1062
1169
- # Recursive cp/get/put of source directory into non-existent target directory.
1170
- fs = LocalFileSystem()
1171
- src = os.path.join(str(tmpdir), "src")
1172
- fs.mkdir(src)
1173
- fs.touch(os.path.join(src, "file"))
1174
-
1175
- target = os.path.join(str(tmpdir), "target")
1176
-
1177
- if funcname == "cp":
1178
- func = fs.cp
1179
- elif funcname == "get":
1180
- func = fs.get
1181
- elif funcname == "put":
1182
- func = fs.put
1183
-
1184
- # cp/get/put without slash
1185
- assert not fs.exists(target)
1186
- for loop in range(2):
1187
- func(src, target, recursive=True)
1188
- assert fs.isdir(target)
1189
-
1190
- if loop == 0:
1191
- assert fs.find(target) == [make_path_posix(os.path.join(target, "file"))]
1192
- else:
1193
- assert sorted(fs.find(target)) == [
1194
- make_path_posix(os.path.join(target, "file")),
1195
- make_path_posix(os.path.join(target, "src", "file")),
1196
- ]
1197
-
1198
- fs.rm(target, recursive=True)
1199
-
1200
- # cp/get/put with slash
1201
- assert not fs.exists(target)
1202
- for loop in range(2):
1203
- func(src + "/", target, recursive=True)
1204
- assert fs.isdir(target)
1205
- assert fs.find(target) == [make_path_posix(os.path.join(target, "file"))]
1206
-
1207
-
1208
- @pytest.mark.parametrize("funcname", ["cp", "get", "put"])
1209
- def test_cp_get_put_empty_directory(tmpdir, funcname):
1210
- # https://github.com/fsspec/filesystem_spec/issues/1198
1211
- # cp/get/put of empty directory.
1212
- fs = LocalFileSystem(auto_mkdir=True)
1213
- empty = os.path.join(str(tmpdir), "empty")
1214
- fs.mkdir(empty)
1215
-
1216
- target = os.path.join(str(tmpdir), "target")
1217
- fs.mkdir(target)
1218
-
1219
- if funcname == "cp":
1220
- func = fs.cp
1221
- elif funcname == "get":
1222
- func = fs.get
1223
- elif funcname == "put":
1224
- func = fs.put
1225
-
1226
- # cp/get/put without slash, target directory exists
1227
- assert fs.isdir(target)
1228
- func(empty, target)
1229
- assert fs.find(target, withdirs=True) == [make_path_posix(target)]
1230
-
1231
- # cp/get/put with slash, target directory exists
1232
- assert fs.isdir(target)
1233
- func(empty + "/", target)
1234
- assert fs.find(target, withdirs=True) == [make_path_posix(target)]
1235
-
1236
- fs.rmdir(target)
1237
-
1238
- # cp/get/put without slash, target directory doesn't exist
1239
- assert not fs.isdir(target)
1240
- func(empty, target)
1241
- assert not fs.isdir(target)
1242
-
1243
- # cp/get/put with slash, target directory doesn't exist
1244
- assert not fs.isdir(target)
1245
- func(empty + "/", target)
1246
- assert not fs.isdir(target)
1247
-
1248
-
1249
- def test_cp_two_files(tmpdir):
1250
- fs = LocalFileSystem(auto_mkdir=True)
1251
- src = os.path.join(str(tmpdir), "src")
1252
- file0 = os.path.join(src, "file0")
1253
- file1 = os.path.join(src, "file1")
1254
- fs.mkdir(src)
1255
- fs.touch(file0)
1256
- fs.touch(file1)
1257
-
1258
- target = os.path.join(str(tmpdir), "target")
1259
- assert not fs.exists(target)
1260
-
1261
- fs.cp([file0, file1], target)
1262
-
1263
- assert fs.isdir(target)
1264
- assert sorted(fs.find(target)) == [
1265
- make_path_posix(os.path.join(target, "file0")),
1266
- make_path_posix(os.path.join(target, "file1")),
1267
- ]
1268
-
1269
-
1270
- @pytest.mark.skipif(WIN, reason="Windows does not support colons in filenames")
1271
- def test_issue_1447():
1272
- files_with_colons = {
1273
- ".local:file:with:colons.txt": b"content1",
1274
- ".colons-after-extension.txt:after": b"content2",
1275
- ".colons-after-extension/file:colon.txt:before/after": b"content3",
1276
- }
1277
- with filetexts(files_with_colons, mode="b"):
1278
- for file, contents in files_with_colons.items():
1279
- with fsspec.filesystem("file").open(file, "rb") as f:
1280
- assert f.read() == contents
1281
-
1282
- fs, urlpath = fsspec.core.url_to_fs(file)
1283
- assert isinstance(fs, fsspec.implementations.local.LocalFileSystem)
1284
- with fs.open(urlpath, "rb") as f:
1285
- assert f.read() == contents