Skip to content

Commit feb2063

Browse files
authored
Merge pull request #1138 from effigies/fix/1137
FIX: Testing for extension/signature mismatches shouldn't use sniff
2 parents 2838c06 + fcd489b commit feb2063

File tree

4 files changed

+32
-29
lines changed

4 files changed

+32
-29
lines changed

nibabel/filebasedimages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ def _sniff_meta_for(klass, filename, sniff_nbytes, sniff=None):
430430
try:
431431
with ImageOpener(meta_fname, 'rb') as fobj:
432432
binaryblock = fobj.read(sniff_nbytes)
433-
except IOError:
433+
except (IOError, EOFError):
434434
return None
435435
return (binaryblock, meta_fname)
436436

nibabel/filename_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def _iendswith(whole, end):
253253

254254

255255
def splitext_addext(filename,
256-
addexts=('.gz', '.bz2'),
256+
addexts=('.gz', '.bz2', '.zst'),
257257
match_case=False):
258258
""" Split ``/pth/fname.ext.gz`` into ``/pth/fname, .ext, .gz``
259259

nibabel/loadsave.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,14 @@
2222
_compressed_suffixes = ('.gz', '.bz2', '.zst')
2323

2424

25-
def _signature_matches_extension(filename, sniff):
25+
def _signature_matches_extension(filename):
2626
"""Check if signature aka magic number matches filename extension.
2727
2828
Parameters
2929
----------
3030
filename : str or os.PathLike
3131
Path to the file to check
3232
33-
sniff : bytes or None
34-
First bytes of the file. If not `None` and long enough to contain the
35-
signature, avoids having to read the start of the file.
36-
3733
Returns
3834
-------
3935
matches : bool
@@ -48,20 +44,20 @@ def _signature_matches_extension(filename, sniff):
4844
"""
4945
signatures = {
5046
".gz": {"signature": b"\x1f\x8b", "format_name": "gzip"},
51-
".bz2": {"signature": b"BZh", "format_name": "bzip2"}
47+
".bz2": {"signature": b"BZh", "format_name": "bzip2"},
48+
".zst": {"signature": b"\x28\xb5\x2f\xfd", "format_name": "ztsd"},
5249
}
5350
filename = _stringify_path(filename)
5451
*_, ext = splitext_addext(filename)
5552
ext = ext.lower()
5653
if ext not in signatures:
5754
return True, ""
5855
expected_signature = signatures[ext]["signature"]
59-
if sniff is None or len(sniff) < len(expected_signature):
60-
try:
61-
with open(filename, "rb") as fh:
62-
sniff = fh.read(len(expected_signature))
63-
except OSError:
64-
return False, f"Could not read file: {filename}"
56+
try:
57+
with open(filename, "rb") as fh:
58+
sniff = fh.read(len(expected_signature))
59+
except OSError:
60+
return False, f"Could not read file: {filename}"
6561
if sniff.startswith(expected_signature):
6662
return True, ""
6763
format_name = signatures[ext]["format_name"]
@@ -100,7 +96,7 @@ def load(filename, **kwargs):
10096
img = image_klass.from_filename(filename, **kwargs)
10197
return img
10298

103-
matches, msg = _signature_matches_extension(filename, sniff)
99+
matches, msg = _signature_matches_extension(filename)
104100
if not matches:
105101
raise ImageFileError(msg)
106102

nibabel/tests/test_loadsave.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
from ..loadsave import load, read_img_data, _signature_matches_extension
1414
from ..filebasedimages import ImageFileError
1515
from ..tmpdirs import InTemporaryDirectory, TemporaryDirectory
16+
from ..openers import Opener
1617

1718
from ..optpkg import optional_package
1819
_, have_scipy, _ = optional_package('scipy')
20+
_, have_pyzstd, _ = optional_package('pyzstd')
1921

2022
from numpy.testing import (assert_almost_equal,
2123
assert_array_equal)
@@ -74,41 +76,46 @@ def test_load_empty_image():
7476
assert str(err.value).startswith('Empty file: ')
7577

7678

77-
@pytest.mark.parametrize("extension", [".gz", ".bz2"])
79+
@pytest.mark.parametrize("extension", [".gz", ".bz2", ".zst"])
7880
def test_load_bad_compressed_extension(tmp_path, extension):
81+
if extension == ".zst" and not have_pyzstd:
82+
pytest.skip()
7983
file_path = tmp_path / f"img.nii{extension}"
8084
file_path.write_bytes(b"bad")
8185
with pytest.raises(ImageFileError, match=".*is not a .* file"):
8286
load(file_path)
8387

8488

89+
@pytest.mark.parametrize("extension", [".gz", ".bz2", ".zst"])
90+
def test_load_good_extension_with_bad_data(tmp_path, extension):
91+
if extension == ".zst" and not have_pyzstd:
92+
pytest.skip()
93+
file_path = tmp_path / f"img.nii{extension}"
94+
with Opener(file_path, "wb") as fobj:
95+
fobj.write(b"bad")
96+
with pytest.raises(ImageFileError, match="Cannot work out file type of .*"):
97+
load(file_path)
98+
99+
85100
def test_signature_matches_extension(tmp_path):
86101
gz_signature = b"\x1f\x8b"
87102
good_file = tmp_path / "good.gz"
88103
good_file.write_bytes(gz_signature)
89104
bad_file = tmp_path / "bad.gz"
90105
bad_file.write_bytes(b"bad")
91-
matches, msg = _signature_matches_extension(
92-
tmp_path / "uncompressed.nii", None)
106+
matches, msg = _signature_matches_extension(tmp_path / "uncompressed.nii")
93107
assert matches
94108
assert msg == ""
95-
matches, msg = _signature_matches_extension(tmp_path / "missing.gz", None)
109+
matches, msg = _signature_matches_extension(tmp_path / "missing.gz")
96110
assert not matches
97111
assert msg.startswith("Could not read")
98-
matches, msg = _signature_matches_extension(bad_file, None)
112+
matches, msg = _signature_matches_extension(bad_file)
99113
assert not matches
100114
assert "is not a" in msg
101-
matches, msg = _signature_matches_extension(bad_file, gz_signature + b"abc")
102-
assert matches
103-
assert msg == ""
104-
matches, msg = _signature_matches_extension(
105-
good_file, gz_signature + b"abc")
106-
assert matches
107-
assert msg == ""
108-
matches, msg = _signature_matches_extension(good_file, gz_signature[:1])
115+
matches, msg = _signature_matches_extension(good_file)
109116
assert matches
110117
assert msg == ""
111-
matches, msg = _signature_matches_extension(good_file, None)
118+
matches, msg = _signature_matches_extension(tmp_path / "missing.nii")
112119
assert matches
113120
assert msg == ""
114121

0 commit comments

Comments
 (0)