Skip to content

Commit 4c89d94

Browse files
committed
tests: add more cache tests and add clear_instance_cache fixture
1 parent 8d9eaa9 commit 4c89d94

File tree

3 files changed

+81
-16
lines changed

3 files changed

+81
-16
lines changed

fsspec/conftest.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,55 @@ def m():
2727
m.pseudo_dirs.append("")
2828

2929

30-
@pytest.fixture
30+
def _recursive_clear_instance_caches(*classes):
31+
"""
32+
Clear instance caches for the given filesystem classes and their subclasses.
33+
"""
34+
for cls in classes:
35+
cls.clear_instance_cache()
36+
_recursive_clear_instance_caches(*cls.__subclasses__())
37+
38+
39+
@pytest.fixture(scope="function")
40+
def clear_instance_cache(request):
41+
"""
42+
Fixture to ensure empty filesystem instance caches before and after a test.
43+
44+
Can be used with and without indirect parametrization.
45+
Defaults to clearing caches of all imported filesystem classes.
46+
47+
Usage:
48+
@pytest.mark.parametrize(
49+
"clear_instance_cache",
50+
["s3,simplecache", "ftp", "file,memory,simplecache"],
51+
indirect=True,
52+
)
53+
"""
54+
from fsspec import get_filesystem_class
55+
from fsspec.spec import AbstractFileSystem
56+
57+
try:
58+
protocols = request.param.split(",")
59+
except AttributeError:
60+
classes = [AbstractFileSystem]
61+
else:
62+
classes = [get_filesystem_class(p) for p in protocols]
63+
64+
try:
65+
_recursive_clear_instance_caches(*classes)
66+
yield
67+
finally:
68+
_recursive_clear_instance_caches(*classes)
69+
70+
71+
@pytest.fixture(scope="function")
3172
def ftp_writable(tmpdir):
3273
"""
3374
Fixture providing a writable FTP filesystem.
3475
"""
3576
pytest.importorskip("pyftpdlib")
3677
from fsspec.implementations.ftp import FTPFileSystem
3778

38-
FTPFileSystem.clear_instance_cache() # remove lingering connections
39-
CachingFileSystem.clear_instance_cache()
4079
d = str(tmpdir)
4180
with open(os.path.join(d, "out"), "wb") as f:
4281
f.write(b"hello" * 10000)
@@ -53,3 +92,6 @@ def ftp_writable(tmpdir):
5392
shutil.rmtree(tmpdir)
5493
except Exception:
5594
pass
95+
_recursive_clear_instance_caches(
96+
FTPFileSystem, CachingFileSystem
97+
) # remove lingering connections

fsspec/implementations/tests/test_cached.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,8 +1361,44 @@ def test_local_temp_file_put_by_list2(protocol, mocker, tmp_path) -> None:
13611361

13621362

13631363
def test_simplecache_tokenization_independent_of_path():
1364+
# check that the tokenization is independent of the path
13641365
of0 = fsspec.open("simplecache::memory://foo/bar.txt")
13651366
of1 = fsspec.open("simplecache::memory://baz/qux.txt")
13661367
assert of0.path != of1.path
13671368
assert of0.fs._fs_token_ == of1.fs._fs_token_
13681369
assert of0.fs is of1.fs
1370+
1371+
1372+
@pytest.mark.parametrize(
1373+
"clear_instance_cache",
1374+
["simplecache"],
1375+
indirect=True,
1376+
)
1377+
def test_simplecache_instance_cache_(clear_instance_cache):
1378+
cache = fsspec.get_filesystem_class("simplecache")._cache
1379+
1380+
assert len(cache) == 0
1381+
1382+
# check that the cache does not grow with multiple paths
1383+
fsspec.open("simplecache::memory://foo/bar.txt")
1384+
fsspec.open("simplecache::memory://bar/baz.txt")
1385+
fsspec.open("simplecache::memory://baz/qux.txt")
1386+
fsspec.open("simplecache::file:///foo/bar.txt")
1387+
fsspec.open("simplecache::memory://bar/baz.txt")
1388+
fsspec.open("simplecache::https://example.com/")
1389+
1390+
assert len(cache) == 3
1391+
assert [obj.storage_options for obj in cache.values()] == [
1392+
{
1393+
"target_protocol": "memory",
1394+
"target_options": {},
1395+
},
1396+
{
1397+
"target_protocol": "file",
1398+
"target_options": {},
1399+
},
1400+
{
1401+
"target_protocol": "https",
1402+
"target_options": {},
1403+
},
1404+
]

fsspec/tests/test_core.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,6 @@
2020
)
2121

2222

23-
@pytest.fixture(scope="function", autouse=True)
24-
def clear_cachingfilesystem_instance_caches():
25-
# prevent test cross-contamination due to cached fs instances
26-
from fsspec.implementations.cached import CachingFileSystem
27-
28-
classes = [CachingFileSystem]
29-
while classes:
30-
cls = classes.pop()
31-
cls.clear_instance_cache()
32-
classes.extend(cls.__subclasses__())
33-
yield
34-
35-
3623
@contextmanager
3724
def tempzip(data=None):
3825
data = data or {}

0 commit comments

Comments
 (0)