[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