[segyio] 269/376: Make generator read-ops exception safe
Jørgen Kvalsvik
jokva-guest at moszumanska.debian.org
Wed Sep 20 08:04:43 UTC 2017
This is an automated email from the git hooks/post-receive script.
jokva-guest pushed a commit to branch debian
in repository segyio.
commit 35aae2aaca0c352ab4adbb53331d56c0353a8a6f
Author: Jørgen Kvalsvik <jokva at statoil.com>
Date: Tue Apr 4 09:32:01 2017 +0200
Make generator read-ops exception safe
Instead of reading directly from file into arrays or buffers that might
already be given to users, read into secondary arrays. This way, when a
read operation fails, user arrays will not be corrupted.
---
python/segyio/_header.py | 16 +++++++++++-----
python/segyio/_line.py | 5 ++++-
python/segyio/_raw_trace.py | 6 ++++--
python/segyio/_trace.py | 21 ++++++++++++++++-----
4 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/python/segyio/_header.py b/python/segyio/_header.py
index be996a7..55c49d0 100644
--- a/python/segyio/_header.py
+++ b/python/segyio/_header.py
@@ -24,12 +24,15 @@ class Header(object):
if isinstance(traceno, tuple):
return self.__getitem__(traceno[0], traceno[1])
- if isinstance(traceno, slice):
- gen_buf = self._header_buffer(buf)
+ buf = self._header_buffer(buf)
+ if isinstance(traceno, slice):
def gen():
+ buf1, buf2 = self._header_buffer(), self._header_buffer()
for i in range(*traceno.indices(self.segy.tracecount)):
- yield self.__getitem__(i, gen_buf)
+ x = self.__getitem__(i, buf1)
+ buf2, buf1 = buf1, buf2
+ yield x
return gen()
@@ -52,13 +55,16 @@ class Header(object):
def __repr__(self):
return "Header(traces = {})".format(self.segy.samples)
- def readfn(self, t0, length, stride, buf):
+ def readfn(self, t0, length, stride, *_):
def gen():
+ buf1, buf2 = self._header_buffer(), self._header_buffer()
start = t0
step = stride * len(self.segy.offsets)
stop = t0 + (length * step)
for i in range(start, stop, step):
- yield Field.trace(buf, traceno=i, segy=self.segy)
+ x = Field.trace(buf1, traceno=i, segy=self.segy)
+ buf2, buf1 = buf1, buf2
+ yield x
return gen()
diff --git a/python/segyio/_line.py b/python/segyio/_line.py
index 8223baf..c852b5a 100644
--- a/python/segyio/_line.py
+++ b/python/segyio/_line.py
@@ -110,9 +110,12 @@ class Line:
def _get_iter(self, lineno, off, buf):
""" :rtype: collections.Iterable[numpy.ndarray]"""
+ buf1, buf2 = buf, self.buffn()
for line, offset in itertools.product(*self._indices(lineno, off)):
- yield self._get(line, offset, buf)
+ buf1 = self._get(line, offset, buf1)
+ buf2, buf1 = buf1, buf2
+ yield buf2
def __getitem__(self, lineno, offset=None):
""" :rtype: numpy.ndarray|collections.Iterable[numpy.ndarray]"""
diff --git a/python/segyio/_raw_trace.py b/python/segyio/_raw_trace.py
index 9b0f581..e001c1d 100644
--- a/python/segyio/_raw_trace.py
+++ b/python/segyio/_raw_trace.py
@@ -20,12 +20,14 @@ class RawTrace(object):
length = max(0, (mstop - mstart + (step - (1 if step > 0 else -1))))
buf = np.zeros(shape = (length, len(f.samples)), dtype = np.single)
l = len(range(start, stop, step))
- return self.trace._readtr(start, step, l, buf)
+ buf, _ = self.trace._readtr(start, step, l, buf)
+ return buf
if int(index) != index:
raise TypeError("Trace index must be integer or slice.")
- return self.trace._readtr(int(index), 1, 1, buf)
+ buf = self.trace._trace_buffer(None)
+ return self.trace._readtr(int(index), 1, 1, buf)[0]
def __repr__(self):
return self.trace.__repr__() + ".raw"
diff --git a/python/segyio/_trace.py b/python/segyio/_trace.py
index df5d425..36de065 100644
--- a/python/segyio/_trace.py
+++ b/python/segyio/_trace.py
@@ -16,9 +16,16 @@ class Trace:
buf = self._trace_buffer(buf)
if isinstance(index, slice):
+ # always read the trace into a second buffer. This is to provide
+ # exception safety: if an exception is raised and at least one
+ # array has already been yielded to the caller, failing to read the
+ # next trace won't make the already-returned array garbage
def gen():
+ buf1 = buf
+ buf2 = self._trace_buffer(None)
for i in range(*index.indices(len(self))):
- yield self._readtr(i, 1, 1, buf)
+ buf1, buf2 = self._readtr(i, 1, 1, buf1, buf2)
+ yield buf1
return gen()
@@ -27,7 +34,7 @@ class Trace:
# map negative a negative to the corresponding positive value
start = (index + len(self)) % len(self)
- return self._readtr(start, 1, 1, buf)
+ return self._readtr(start, 1, 1, buf)[0]
def __setitem__(self, index, val):
if not 0 <= abs(index) < len(self):
@@ -71,18 +78,22 @@ class Trace:
return buf
- def _readtr(self, start, step, length, buf=None):
- buf = self._trace_buffer(buf)
+ def _readtr(self, start, step, length, buf, buf1 = None):
+ if buf1 is None:
+ buf1 = buf
trace0 = self._file._tr0
bsz = self._file._bsz
fmt = self._file._fmt
smp = len(self._file.samples)
- return segyio._segyio.read_trace(self._file.xfd, buf,
+
+ buf1 = segyio._segyio.read_trace(self._file.xfd, buf1,
start, step, length,
fmt, smp,
trace0, bsz)
+ return buf1, buf
+
def _writetr(self, traceno, buf):
if int(traceno) != traceno:
raise TypeError("Trace index must be integer type")
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/segyio.git
More information about the debian-science-commits
mailing list