Repository: fsspec/filesystem_spec
Pull request #856 (2021-12-14 19:28:00)

Define a BlocksizeMismatchError exception class
For our purposes, we are interested in catching exceptions caused by trying to open a cached file with a different block size than it was written with.  Currently, the only way to identify such exceptions is by inspecting the error message, which is not the wisest choice.  This PR thus replaces the `ValueError` raised on block size mismatches with a custom `BlocksizeMismatchError` (a subclass of `ValueError`) to ease identification.

yarikoptic: <details>
<summary>FWIW: I don't see how py36 error could relate to these changes</summary> 

```
2021-12-14T19:39:22.5206313Z py36 run-test-pre: PYTHONHASHSEED='997432003'
2021-12-14T19:39:22.5207104Z py36 run-test: commands[0] | pytest --cov=fsspec -v -r s
2021-12-14T19:39:22.5208329Z [5504] /home/runner/work/filesystem_spec/filesystem_spec$ /home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/bin/pytest --cov=fsspec -v -r s
2021-12-14T19:39:23.2504024Z Traceback (most recent call last):
2021-12-14T19:39:23.2505598Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/bin/pytest", line 11, in <module>
2021-12-14T19:39:23.2506640Z     sys.exit(console_main())
2021-12-14T19:39:23.2508718Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/config/__init__.py", line 185, in console_main
2021-12-14T19:39:23.2510192Z     code = main()
2021-12-14T19:39:23.2511736Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/config/__init__.py", line 143, in main
2021-12-14T19:39:23.2512966Z     config = _prepareconfig(args, plugins)
2021-12-14T19:39:23.2514513Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/config/__init__.py", line 319, in _prepareconfig
2021-12-14T19:39:23.2515814Z     pluginmanager=pluginmanager, args=args
2021-12-14T19:39:23.2517329Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/pluggy/_hooks.py", line 265, in __call__
2021-12-14T19:39:23.2518673Z     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
2021-12-14T19:39:23.2520350Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/pluggy/_manager.py", line 80, in _hookexec
2021-12-14T19:39:23.2521706Z     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
2021-12-14T19:39:23.2523429Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/pluggy/_callers.py", line 55, in _multicall
2021-12-14T19:39:23.2525277Z     gen.send(outcome)
2021-12-14T19:39:23.2526687Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/helpconfig.py", line 100, in pytest_cmdline_parse
2021-12-14T19:39:23.2527749Z     config: Config = outcome.get_result()
2021-12-14T19:39:23.2528987Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/pluggy/_result.py", line 60, in get_result
2021-12-14T19:39:23.2530056Z     raise ex[1].with_traceback(ex[2])
2021-12-14T19:39:23.2531265Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/pluggy/_callers.py", line 39, in _multicall
2021-12-14T19:39:23.2532433Z     res = hook_impl.function(*args)
2021-12-14T19:39:23.2533687Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/config/__init__.py", line 1003, in pytest_cmdline_parse
2021-12-14T19:39:23.2534648Z     self.parse(args)
2021-12-14T19:39:23.2535806Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/config/__init__.py", line 1283, in parse
2021-12-14T19:39:23.2536790Z     self._preparse(args, addopts=addopts)
2021-12-14T19:39:23.2538040Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/config/__init__.py", line 1172, in _preparse
2021-12-14T19:39:23.2539203Z     self.pluginmanager.load_setuptools_entrypoints("pytest11")
2021-12-14T19:39:23.2540677Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/pluggy/_manager.py", line 287, in load_setuptools_entrypoints
2021-12-14T19:39:23.2541646Z     plugin = ep.load()
2021-12-14T19:39:23.2542823Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/importlib_metadata/__init__.py", line 194, in load
2021-12-14T19:39:23.2543994Z     module = import_module(match.group('module'))
2021-12-14T19:39:23.2544931Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/importlib/__init__.py", line 126, in import_module
2021-12-14T19:39:23.2545913Z     return _bootstrap._gcd_import(name[level:], package, level)
2021-12-14T19:39:23.2546691Z   File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2021-12-14T19:39:23.2547442Z   File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2021-12-14T19:39:23.2548224Z   File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
2021-12-14T19:39:23.2549039Z   File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
2021-12-14T19:39:23.2550394Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/_pytest/assertion/rewrite.py", line 170, in exec_module
2021-12-14T19:39:23.2551484Z     exec(co, module.__dict__)
2021-12-14T19:39:23.2552675Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/pytest_cov/plugin.py", line 6, in <module>
2021-12-14T19:39:23.2555148Z     import coverage
2021-12-14T19:39:23.2556179Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/coverage/__init__.py", line 15, in <module>
2021-12-14T19:39:23.2557112Z     from coverage.control import Coverage, process_startup
2021-12-14T19:39:23.2558270Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/coverage/control.py", line 19, in <module>
2021-12-14T19:39:23.2559186Z     from coverage.config import read_coverage_config
2021-12-14T19:39:23.2560320Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/coverage/config.py", line 16, in <module>
2021-12-14T19:39:23.2561376Z     from coverage.tomlconfig import TomlConfigParser, TomlDecodeError
2021-12-14T19:39:23.2562700Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/coverage/tomlconfig.py", line 15, in <module>
2021-12-14T19:39:23.2563485Z     import tomli
2021-12-14T19:39:23.2564425Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/tomli/__init__.py", line 6, in <module>
2021-12-14T19:39:23.2565331Z     from tomli._parser import TOMLDecodeError, load, loads
2021-12-14T19:39:23.2566462Z   File "/home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/lib/python3.6/site-packages/tomli/_parser.py", line 1
2021-12-14T19:39:23.2567250Z     from __future__ import annotations
2021-12-14T19:39:23.2567649Z     ^
2021-12-14T19:39:23.2568113Z SyntaxError: future feature annotations is not defined
2021-12-14T19:39:23.4156844Z ERROR: InvocationError for command /home/runner/work/filesystem_spec/filesystem_spec/.tox/py36/bin/pytest --cov=fsspec -v -r s (exited with code 1)
2021-12-14T19:39:23.4184603Z ___________________________________ summary ____________________________________
2021-12-14T19:39:23.4185127Z ERROR:   py36: commands failed
2021-12-14T19:39:23.4800656Z ##[error]Process completed with exit code 1.
```
</details>
martindurant: (please merge from main)

Patch:
diff --git a/fsspec/exceptions.py b/fsspec/exceptions.py
index 48b5036..2d6e1a4 100644
--- a/fsspec/exceptions.py
+++ b/fsspec/exceptions.py
@@ -4,6 +4,15 @@ fsspec user-defined exception classes
 import asyncio
 
 
+class BlocksizeMismatchError(ValueError):
+    """
+    Raised when a cached file is opened with a different blocksize than it was
+    written with
+    """
+
+    ...
+
+
 class FSTimeoutError(asyncio.TimeoutError):
     """
     Raised when a fsspec function timed out occurs
diff --git a/fsspec/implementations/cached.py b/fsspec/implementations/cached.py
index eef7491..c68ab8d 100644
--- a/fsspec/implementations/cached.py
+++ b/fsspec/implementations/cached.py
@@ -11,6 +11,7 @@ from fsspec import AbstractFileSystem, filesystem
 from fsspec.callbacks import _DEFAULT_CALLBACK
 from fsspec.compression import compr
 from fsspec.core import BaseCache, MMapCache
+from fsspec.exceptions import BlocksizeMismatchError
 from fsspec.spec import AbstractBufferedFile
 from fsspec.utils import infer_compression
 
@@ -327,7 +328,7 @@ class CachingFileSystem(AbstractFileSystem):
             f = compr[comp](f, mode="rb")
         if "blocksize" in detail:
             if detail["blocksize"] != f.blocksize:
-                raise ValueError(
+                raise BlocksizeMismatchError(
                     "Cached file must be reopened with same block"
                     "size as original (old: %i, new %i)"
                     "" % (detail["blocksize"], f.blocksize)


Test patch:
diff --git a/fsspec/implementations/tests/test_cached.py b/fsspec/implementations/tests/test_cached.py
index 5232c05..ea5bd4d 100644
--- a/fsspec/implementations/tests/test_cached.py
+++ b/fsspec/implementations/tests/test_cached.py
@@ -7,6 +7,7 @@ import pytest
 
 import fsspec
 from fsspec.compression import compr
+from fsspec.exceptions import BlocksizeMismatchError
 from fsspec.implementations.cached import CachingFileSystem
 
 from .test_ftp import FTPFileSystem
@@ -213,7 +214,7 @@ def test_blocksize(ftp_writable):
 
     with fs.open("/out_block", block_size=20) as f:
         assert f.read(1) == b"t"
-    with pytest.raises(ValueError):
+    with pytest.raises(BlocksizeMismatchError):
         fs.open("/out_block", block_size=30)