Skip to content

Commit eef3b78

Browse files
authored
Merge pull request #34 from cta-observatory/fix_iter_blocks
Fix iter blocks
2 parents 1030e7e + f42baa8 commit eef3b78

4 files changed

Lines changed: 67 additions & 8 deletions

File tree

corsikaio/file.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ def run_end(self):
7171
return self._run_end
7272

7373
def __next__(self):
74-
block = next(self._block_iter)
74+
try:
75+
block = next(self._block_iter)
76+
except StopIteration:
77+
raise IOError("File seems to be truncated")
7578

7679
if block[:4] == b'RUNE':
7780
self._run_end = parse_run_end(block)
@@ -88,15 +91,22 @@ def __next__(self):
8891
data_bytes = bytearray()
8992
long_bytes = bytearray()
9093

91-
block = next(self._block_iter)
94+
try:
95+
block = next(self._block_iter)
96+
except StopIteration:
97+
raise IOError("File seems to be truncated")
98+
9299
while block[:4] != b'EVTE':
93100

94101
if block[:4] == b'LONG':
95102
long_bytes += block[longitudinal_header_dtype.itemsize:]
96103
else:
97104
data_bytes += block
98105

99-
block = next(self._block_iter)
106+
try:
107+
block = next(self._block_iter)
108+
except StopIteration:
109+
raise IOError("File seems to be truncated")
100110

101111
if self.parse_blocks:
102112
event_end = parse_event_end(block)[0]

corsikaio/io.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,31 @@ def iter_blocks(f):
7272
# for the fortran-chunked output, we need to read the record size
7373
if is_fortran_file:
7474
data = f.read(RECORD_MARKER.size)
75+
if len(data) == 0:
76+
return
77+
7578
if len(data) < RECORD_MARKER.size:
7679
raise IOError("Read less bytes than expected, file seems to be truncated")
7780

7881
buffer_size, = RECORD_MARKER.unpack(data)
7982

8083
data = f.read(buffer_size)
84+
if is_fortran_file:
85+
if len(data) < buffer_size:
86+
raise IOError("Read less bytes than expected, file seems to be truncated")
87+
88+
else:
89+
if len(data) == 0:
90+
return
91+
92+
n_blocks, rest = divmod(len(data), BLOCK_SIZE_BYTES)
93+
if rest != 0:
94+
raise IOError("Read less bytes than expected, file seems to be truncated")
8195

82-
n_blocks = len(data) // BLOCK_SIZE_BYTES
8396
for block in range(n_blocks):
8497
start = block * BLOCK_SIZE_BYTES
8598
stop = start + BLOCK_SIZE_BYTES
8699
block = data[start:stop]
87-
if len(block) < BLOCK_SIZE_BYTES:
88-
raise IOError("Read less bytes than expected, file seems to be truncated")
89100
yield block
90101

91102
# read trailing record marker

tests/test_file.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import pytest
22
import numpy as np
33

4+
from corsikaio.constants import BLOCK_SIZE_BYTES
5+
from corsikaio.io import RECORD_MARKER
6+
47

58
def test_version():
69
from corsikaio import CorsikaFile
@@ -88,7 +91,16 @@ def test_particle_no_parse():
8891

8992

9093

91-
def test_truncated(tmp_path):
94+
@pytest.mark.parametrize(
95+
"size",
96+
(
97+
RECORD_MARKER.size + 22932,
98+
RECORD_MARKER.size + 2 * 22932,
99+
RECORD_MARKER.size + 3 * 22932,
100+
2000,
101+
)
102+
)
103+
def test_truncated(tmp_path, size):
92104
'''Test we raise a meaningful error for a truncated file
93105
94106
Truncated files might happen if corsika crashes or the disk is full.
@@ -100,7 +112,7 @@ def test_truncated(tmp_path):
100112

101113
with open("tests/resources/corsika757_particle", "rb") as f:
102114
with path.open("wb") as out:
103-
out.write(f.read(273 * 10))
115+
out.write(f.read(size))
104116

105117
with pytest.raises(IOError, match="seems to be truncated"):
106118
with CorsikaParticleFile(path) as f:

tests/test_io.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,20 @@ def test_iter_blocks_simple_file(dummy_file):
125125
assert block[:4] == b'RUNE'
126126
assert (np.frombuffer(block[4:], np.float32) == data[1:]).all()
127127

128+
with pytest.raises(StopIteration):
129+
next(block_it)
128130

129131

132+
def test_iter_blocks_all(dummy_file):
133+
"""Test for iterblocks for the case of no record markers"""
134+
135+
with dummy_file.open('rb') as f:
136+
n_blocks_read = 0
137+
for _ in iter_blocks(f):
138+
n_blocks_read += 1
139+
140+
assert n_blocks_read == 27
141+
130142
def test_versions():
131143
from corsikaio.io import read_buffer_size, read_block
132144
from corsikaio.subblocks import get_version
@@ -142,3 +154,17 @@ def test_versions():
142154

143155
block = read_block(f, buffer_size)
144156
assert get_version(block, EVTH_VERSION_POSITION) == version
157+
158+
159+
160+
@pytest.mark.parametrize("size", (100, 1000, 5000))
161+
def test_iter_blocks_truncated(size, tmp_path, dummy_file):
162+
path = tmp_path / f"test_truncated_{size}.dat"
163+
164+
with path.open("wb") as out, dummy_file.open("rb") as infile:
165+
out.write(infile.read(size))
166+
167+
with pytest.raises(IOError, match="file seems to be truncated"):
168+
with path.open("rb") as f:
169+
for _ in iter_blocks(f):
170+
pass

0 commit comments

Comments
 (0)