Mostly PEP8 cleanups in the course of reading the code.

I took the liberty of adding a few specific exception types, some
documentation, and things like that, but this is mostly a cosmetic chance.
This commit is contained in:
Austin Bingham
2014-09-02 09:39:04 +02:00
parent dcac37022d
commit e02b7be182
5 changed files with 259 additions and 119 deletions
+95 -35
View File
@@ -29,23 +29,28 @@ class CatalogBuilder:
def add(self, index, value):
"""Add an item.
Each index must be unique if create() is to be subsequently called successfully,
although duplicate index values will be accepted by this call without complaint.
Each index must be unique if create() is to be subsequently
called successfully, although duplicate index values will be
accepted by this call without complaint.
"""
self._catalog.append((index, value))
def create(self):
"""Create a possibly more optimized representation of the mapping.
In this worst case, this method returns an object which is essentially an immutable dictionary. In the best
case, the space savings can be vast.
In this worst case, this method returns an object which is
essentially an immutable dictionary. In the best case, the
space savings can be vast.
Returns:
A mapping, if a unique mapping from indexes to values is possible, otherwise None.
A mapping, if a unique mapping from indexes to values is
possible, otherwise None.
"""
# This method examines the contents of the mapping using various heuristics to come up with
# a better representation.
# This method examines the contents of the mapping using
# various heuristics to come up with a better representation.
if len(self._catalog) < 2:
return DictionaryCatalog(self._catalog)
@@ -56,7 +61,8 @@ class CatalogBuilder:
if contains_duplicates(index for index, value in self._catalog):
return None
if all(isinstance(index, Sequence) and (len(index) == 2) for index, value in self._catalog):
if all(isinstance(index, Sequence) and (len(index) == 2)
for index, value in self._catalog):
return self._create_catalog_2()
return self._create_catalog_1()
@@ -79,10 +85,18 @@ class CatalogBuilder:
if index_stride is not None and value_stride is None:
# Regular index - regular keys and arbitrary values
return RegularCatalog(index_min, index_max, index_stride, (value for index, value in self._catalog))
return RegularCatalog(index_min,
index_max,
index_stride,
(value for index, value in self._catalog))
assert (index_stride is not None) and (value_stride is not None)
catalog = LinearRegularCatalog(index_min, index_max, index_stride, value_min, value_max, value_stride)
catalog = LinearRegularCatalog(index_min,
index_max,
index_stride,
value_min,
value_max,
value_stride)
return catalog
def _create_catalog_2(self):
@@ -128,8 +142,9 @@ class CatalogBuilder:
class RowMajorCatalog(Mapping):
"""A mapping which assumes a row-major ordering of a two-dimensional matrix.
This is the ordering of items in a two-dimensional matrix where in the (i, j)
key tuple the j value changes fastest when iterating through the items in order.
This is the ordering of items in a two-dimensional matrix where in
the (i, j) key tuple the j value changes fastest when iterating
through the items in order.
A RowMajorCatalog predicts the value v from the key (i, j) according to the
following formula:
@@ -189,14 +204,16 @@ class RowMajorCatalog(Mapping):
def __getitem__(self, key):
i, j = key
if not (self._i_min <= i <= self._i_max) and (self._j_min <= j <= self._j_max):
if not (self._i_min <= i <= self._i_max) and \
(self._j_min <= j <= self._j_max):
raise KeyError("{!r} key {!r} out of range".format(self, key))
value = (i - self._i_min) * self._j_max + (j - self._j_min) + self._c
return value
def __contains__(self, key):
i, j = key
return (self._i_min <= i <= self._i_max) and (self._j_min <= j <= self._j_max)
return (self._i_min <= i <= self._i_max) and \
(self._j_min <= j <= self._j_max)
def __len__(self):
return (self._i_max - self._i_min) * (self._j_max - self._j_min)
@@ -207,8 +224,9 @@ class RowMajorCatalog(Mapping):
yield (i, j)
def __repr__(self):
return '{}({}, {}, {}, {}, {})'.format(self.__class__.__name__,
self._i_min, self._i_max, self._j_min, self._j_max, self._c)
return '{}({}, {}, {}, {}, {})'.format(
self.__class__.__name__,
self._i_min, self._i_max, self._j_min, self._j_max, self._c)
class DictionaryCatalog(Mapping):
@@ -231,7 +249,8 @@ class DictionaryCatalog(Mapping):
return item in self._items
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, repr.repr(self._items.items()))
return '{}({})'.format(
self.__class__.__name__, repr.repr(self._items.items()))
class RegularCatalog(Mapping):
@@ -251,10 +270,16 @@ class RegularCatalog(Mapping):
key_max: The maximum key.
key_stride: The difference between successive keys.
values: An iterable series of values corresponding to the keys.
Raises:
ValueError: There is any inconsistency in the keys, stride,
and/or values.
"""
key_range = key_max - key_min
if key_range % key_stride != 0:
raise ("RegularIndex key range {!r} is not a multiple of stride {!r}".format(key_stride, key_range))
raise ValueError("RegularIndex key range {!r} is not "
"a multiple of stride {!r}".format(
key_stride, key_range))
self._key_min = key_min
self._key_max = key_max
self._key_stride = key_stride
@@ -276,21 +301,29 @@ class RegularCatalog(Mapping):
return len(self._values)
def __contains__(self, key):
return (self._key_min <= key <= self._key_max) and ((key - self._key_min) % self._key_stride == 0)
return (self._key_min <= key <= self._key_max) and \
((key - self._key_min) % self._key_stride == 0)
def __iter__(self):
return iter(range(self._key_min, self._key_max + 1, self._index_stride))
return iter(range(self._key_min,
self._key_max + 1,
self._index_stride))
def __repr__(self):
return '{}({}, {}, {}, {})'.format(self.__class__.__name, self._key_min, self._key_max, self._key_stride,
repr.repr(self._values))
return '{}({}, {}, {}, {})'.format(
self.__class__.__name,
self._key_min,
self._key_max,
self._key_stride,
repr.repr(self._values))
class LinearRegularCatalog(Mapping):
"""A mapping which assumes a linear relationship between keys and values.
This is the ordering of items in a two-dimensional matrix where in the (i, j)
key tuple the j value changes fastest when iterating through the items in order.
This is the ordering of items in a two-dimensional matrix where in
the (i, j) key tuple the j value changes fastest when iterating
through the items in order.
A LinearRegularCatalog predicts the value v from the key according to the
following formula:
@@ -298,7 +331,13 @@ class LinearRegularCatalog(Mapping):
v = (value_max - value_min) / (key_max - key_min) * (key - key_min) + value_min
"""
def __init__(self, key_min, key_max, key_stride, value_min, value_max, value_stride):
def __init__(self,
key_min,
key_max,
key_stride,
value_min,
value_max,
value_stride):
"""Initialize a LinearRegularCatalog.
Args:
@@ -307,19 +346,29 @@ class LinearRegularCatalog(Mapping):
key_stride: The difference between successive keys.
value_min: The minimum value.
value_max: The maximum value.
Raises:
ValueError: There is any inconsistency in the keys, strides,
and/or values.
"""
key_range = key_max - key_min
if key_range % key_stride != 0:
raise ("{} key range {!r} is not a multiple of key stride {!r}".format(
self.__class__.__name__, key_stride, key_range))
raise ValueError("{} key range {!r} is not "
"a multiple of key stride {!r}".format(
self.__class__.__name__,
key_stride,
key_range))
self._key_min = key_min
self._key_max = key_max
self._key_stride = key_stride
value_range = value_max - value_min
if value_range % value_stride != 0:
raise ("{} value range {!r} is not a multiple of value stride {!r}".format(
self.__class__.__name__, value_stride, value_range))
raise ValueError("{} value range {!r} is not "
"a multiple of value stride {!r}".format(
self.__class__.__name__,
value_stride,
value_range))
self._value_min = value_min
self._value_max = value_max
self._value_stride = value_stride
@@ -327,10 +376,14 @@ class LinearRegularCatalog(Mapping):
num_keys = (self._key_max - self._key_min) // self._key_stride
num_values = (self._value_max - self._value_min) // self._value_stride
if num_keys != num_values:
raise ("{} inconsistent number of keys {} and values {}".format(
self.__class__.__name__, num_keys, num_values))
raise ValueError("{} inconsistent number of "
"keys {} and values {}".format(
self.__class__.__name__,
num_keys,
num_values))
self._m = Fraction(self._value_max - self._value_min, self._key_max - self._key_min)
self._m = Fraction(self._value_max - self._value_min,
self._key_max - self._key_min)
def __getitem__(self, key):
if not (self._key_min <= key <= self._key_max):
@@ -347,11 +400,18 @@ class LinearRegularCatalog(Mapping):
return 1 + (self._key_max - self._key_min) // self._key_stride
def __contains__(self, key):
return (self._key_min <= key <= self._key_max) and ((key - self._key_min) % self._key_stride == 0)
return (self._key_min <= key <= self._key_max) and \
((key - self._key_min) % self._key_stride == 0)
def __iter__(self):
return iter(range(self._key_min, self._key_max + 1, self._key_stride))
def __repr__(self):
return '{}({}, {}, {}, {}, {}, {})'.format(self.__class__.__name__,
self._key_min, self._key_max, self._key_stride, self._value_min, self._value_max, self._value_stride)
return '{}({}, {}, {}, {}, {}, {})'.format(
self.__class__.__name__,
self._key_min,
self._key_max,
self._key_stride,
self._value_min,
self._value_max,
self._value_stride)
+121 -63
View File
@@ -3,31 +3,50 @@ from __future__ import print_function
from portability import seekable
from util import file_length, filename_from_handle
from datatypes import DATA_SAMPLE_FORMAT, CTYPE_DESCRIPTION, CTYPES
from toolkit import (extract_revision, bytes_per_sample, read_reel_header, catalog_traces, read_binary_values,
compile_trace_header_format, TraceHeader, REEL_HEADER_NUM_BYTES, TRACE_HEADER_NUM_BYTES)
from toolkit import (extract_revision,
bytes_per_sample,
read_reel_header,
catalog_traces,
read_binary_values,
compile_trace_header_format,
TraceHeader,
REEL_HEADER_NUM_BYTES,
TRACE_HEADER_NUM_BYTES)
def create_reader(fh, endian='>'):
"""Create a SegYReader (or one of its subclasses) based on performing a scan of SEG Y data.
"""Create a SegYReader (or one of its subclasses) based on performing
a scan of SEG Y data.
This function is the preferred method for creating SegYReader objects. It reads basic header
information and attempts to build indexes for traces, CDP numbers (for 2D surveys), and inline
and cross line co-ordinates (for 3D surveys) to facilitate subsequent random-access to traces.
This function is the preferred method for creating SegYReader
objects. It reads basic header information and attempts to build
indexes for traces, CDP numbers (for 2D surveys), and inline and
cross line co-ordinates (for 3D surveys) to facilitate subsequent
random-access to traces.
Args:
fh: A file-like-object open in binary mode positioned such that the
beginning of the reel header will be the next byte to be read. For disk-based
SEG Y files, this is the beginning of the file.
fh: A file-like-object open in binary mode positioned such
that the beginning of the reel header will be the next
byte to be read. For disk-based SEG Y files, this is the
beginning of the file.
endian: '>' for big-endian data (the standard and default), '<' for
little-endian (non-standard)
endian: '>' for big-endian data (the standard and default), '<'
for little-endian (non-standard)
Raises:
ValueError: ``fh`` is unsuitable for some reason, such as not
being open, not being seekable, not being in
binary mode, or being too short.
Returns:
A SegYReader object. Depending on the exact type of the SegYReader returned different capabilities may be
available. Inspect the returned object to determine these capabilities, or be prepared for capabilities not
defined in the SegYReader base class to be unavailable. The underlying file-like object must remain open
for the duration of use of the returned reader object. It is the caller's responsibility to close the
underlying file.
A SegYReader object. Depending on the exact type of the
SegYReader returned different capabilities may be
available. Inspect the returned object to determine these
capabilities, or be prepared for capabilities not defined in
the SegYReader base class to be unavailable. The underlying
file-like object must remain open for the duration of use of
the returned reader object. It is the caller's responsibility
to close the underlying file.
Example:
@@ -37,18 +56,23 @@ def create_reader(fh, endian='>'):
"""
if fh.encoding is not None:
raise TypeError("SegYReader must be provided with a binary mode file object")
raise TypeError(
"SegYReader must be provided with a binary mode file object")
if not seekable(fh):
raise TypeError("SegYReader must be provided with a seekable file object")
raise TypeError(
"SegYReader must be provided with a seekable file object")
if fh.closed:
raise ValueError("SegYReader must be provided with an open file object")
raise ValueError(
"SegYReader must be provided with an open file object")
num_file_bytes = file_length(fh)
if num_file_bytes < REEL_HEADER_NUM_BYTES:
raise ValueError("SEG Y file {!r} of {} bytes is too short".format(filename_from_handle(fh),
num_file_bytes))
raise ValueError(
"SEG Y file {!r} of {} bytes is too short".format(
filename_from_handle(fh),
num_file_bytes))
if endian not in ('<', '>'):
raise ValueError("Unrecognised endian value {!r}".format(endian))
@@ -59,37 +83,43 @@ def create_reader(fh, endian='>'):
trace_catalog, cdp_catalog, line_catalog = catalog_traces(fh, bps, endian)
if cdp_catalog is not None and line_catalog is None:
return SegYReader2D(fh, reel_header, trace_catalog, cdp_catalog, endian)
return SegYReader2D(fh, reel_header, trace_catalog,
cdp_catalog, endian)
if cdp_catalog is None and line_catalog is not None:
return SegYReader3D(fh, reel_header, trace_catalog, line_catalog, endian)
return SegYReader3D(fh, reel_header, trace_catalog,
line_catalog, endian)
return SegYReader(fh, reel_header, trace_catalog, endian)
class SegYReader(object):
"""A basic SEG Y reader.
Use to obtain read the reel header, the trace headers or trace values. Traces can be accessed
only by trace index.
Use to obtain read the reel header, the trace headers or trace
values. Traces can be accessed only by trace index.
"""
def __init__(self, fh, reel_header, trace_catalog, endian='>'):
"""Initialize a SegYReader around a file-like-object.
Note:
Usually a SegYReader is most easily constructed using the create_reader() function.
Usually a SegYReader is most easily constructed using the
create_reader() function.
Args:
fh: A file-like object, which must support seeking and support binary reading.
fh: A file-like object, which must support seeking and
support binary reading.
reel_header: A dictionary containing reel header data.
trace_catalog: A mapping from zero-based trace index to the byte-offset to
individual traces within the file.
trace_catalog: A mapping from zero-based trace index to
the byte-offset to individual traces within the file.
endian: '>' for big-endian data (the standard and default), '<' for
little-endian (non-standard)
"""
self._fh = fh
self._endian = endian
@@ -99,13 +129,15 @@ class SegYReader(object):
self._trace_catalog = trace_catalog
self._revision = extract_revision(self._reel_header)
self._bytes_per_sample = bytes_per_sample(self._reel_header, self.revision)
self._bytes_per_sample = bytes_per_sample(
self._reel_header, self.revision)
def trace_indexes(self):
"""An iterator over zero-based trace indexes.
Returns:
An iterator which yields integers in the range zero to num_traces() - 1
An iterator which yields integers in the range zero to
num_traces() - 1
"""
return iter(self._trace_catalog)
@@ -120,8 +152,8 @@ class SegYReader(object):
trace_index: An integer in the range zero to num_traces() - 1
Returns:
A 2-tuple containing a TraceHeader as the first item and a sequence of numeric trace samples
as the second item.
A 2-tuple containing a TraceHeader as the first item and a
sequence of numeric trace samples as the second item.
Example:
@@ -134,7 +166,8 @@ class SegYReader(object):
dsf = self._reel_header['DataSampleFormat']
ctype = DATA_SAMPLE_FORMAT[dsf]
pos = self._trace_catalog[trace_index] + TRACE_HEADER_NUM_BYTES
trace_values = read_binary_values(self._fh, pos, ctype, num_samples, self._endian)
trace_values = read_binary_values(
self._fh, pos, ctype, num_samples, self._endian)
return trace_header, trace_values
def read_trace_header(self, trace_index):
@@ -155,7 +188,8 @@ class SegYReader(object):
pos = self._trace_catalog[trace_index]
self._fh.seek(pos)
data = self._fh.read(TRACE_HEADER_NUM_BYTES)
trace_header = TraceHeader._make(self._trace_header_format.unpack(data))
trace_header = TraceHeader._make(
self._trace_header_format.unpack(data))
return trace_header
@property
@@ -163,7 +197,9 @@ class SegYReader(object):
"""The spatial dimensionality of the data.
Returns:
3 for 3D seismic volumes, 2 for 2D seismic lines, 1 for a single trace, otherwise 0.
3 for 3D seismic volumes, 2 for 2D seismic lines, 1 for a
single trace, otherwise 0.
"""
return self._dimensionality()
@@ -222,31 +258,40 @@ class SegYReader(object):
class SegYReader3D(SegYReader):
"""A reader for 3D seismic data.
In addition to the capabilities provided by the SegYReader base class, this reader
provides an index to facilitate random access to individual traces via crossline and
inline co-ordinates.
In addition to the capabilities provided by the SegYReader base
class, this reader provides an index to facilitate random access
to individual traces via crossline and inline co-ordinates.
"""
def __init__(self, fh, reel_header, trace_catalog, line_catalog, endian='>'):
def __init__(self,
fh,
reel_header,
trace_catalog,
line_catalog,
endian='>'):
"""Initialize a SegYReader3D around a file-like-object.
Note:
Usually a SegYReader is most easily constructed using the create_reader() function.
Usually a SegYReader is most easily constructed using the
create_reader() function.
Args:
fh: A file-like object, which must support seeking and support binary reading.
fh: A file-like object, which must support seeking and
support binary reading.
reel_header: A dictionary containing reel header data.
trace_catalog: A mapping from zero-based trace indexes to the byte-offset to
individual traces within the file.
trace_catalog: A mapping from zero-based trace indexes to
the byte-offset to individual traces within the file.
line_catalog: A mapping from (xline, inline) tuples to trace_indexes.
line_catalog: A mapping from (xline, inline) tuples to
trace_indexes.
endian: '>' for big-endian data (the standard and default), '<' for
little-endian (non-standard)
"""
super(SegYReader3D, self).__init__(fh, reel_header, trace_catalog, endian)
super(SegYReader3D, self).__init__(
fh, reel_header, trace_catalog, endian)
self._line_catalog = line_catalog
def _dimensionality(self):
@@ -271,7 +316,8 @@ class SegYReader3D(SegYReader):
return len(set(i for i, j in self._line_catalog))
def inline_xlines(self):
"""An iterator over all (xline_number, inline_number) tuples corresponding to traces.
"""An iterator over all (xline_number, inline_number) tuples
corresponding to traces.
"""
return iter(self._line_catalog)
@@ -279,12 +325,14 @@ class SegYReader3D(SegYReader):
"""Obtain the trace index given an xline and a inline.
Note:
Do not assume that all combinations of crossline and inline co-ordinates are valid.
The volume may not be rectangular. Valid values can be obtained from the
Do not assume that all combinations of crossline and
inline co-ordinates are valid. The volume may not be
rectangular. Valid values can be obtained from the
inline_xlines() iterator.
Furthermore, inline and crossline numbers should not be relied upon to be zero- or one-based
indexes (although they may be).
Furthermore, inline and crossline numbers should not be
relied upon to be zero- or one-based indexes (although
they may be).
Args:
xline: A crossline number.
@@ -298,26 +346,34 @@ class SegYReader3D(SegYReader):
class SegYReader2D(SegYReader):
def __init__(self, fh, reel_header, trace_catalog, cdp_catalog, endian='>'):
def __init__(self,
fh,
reel_header,
trace_catalog,
cdp_catalog,
endian='>'):
"""Initialize a SegYReader2D around a file-like-object.
Note:
Usually a SegYReader is most easily constructed using the create_reader() function.
Usually a SegYReader is most easily constructed using the
create_reader() function.
Args:
fh: A file-like object, which must support seeking and support binary reading.
fh: A file-like object, which must support seeking and
support binary reading.
reel_header: A dictionary containing reel header data.
trace_catalog: A mapping from zero-based trace index to the byte-offset to
individual traces within the file.
trace_catalog: A mapping from zero-based trace index to
the byte-offset to individual traces within the file.
cdp_catalog: A mapping from CDP numbers to trace_indexes.
endian: '>' for big-endian data (the standard and default), '<' for
little-endian (non-standard)
"""
super(SegYReader2D, self).__init__(fh, reel_header, trace_catalog, endian)
super(SegYReader2D, self).__init__(
fh, reel_header, trace_catalog, endian)
self._cdp_catalog = cdp_catalog
def _dimensionality(self):
@@ -335,12 +391,14 @@ class SegYReader2D(SegYReader):
"""Obtain the trace index given an xline and a inline.
Note:
Do not assume that all combinations of crossline and inline co-ordinates are valid.
The volume may not be rectangular. Valid values can be obtained from the
Do not assume that all combinations of crossline and
inline co-ordinates are valid. The volume may not be
rectangular. Valid values can be obtained from the
inline_xlines() iterator.
Furthermore, inline and crossline numbers should not be relied upon to be zero- or one-based
indexes (although they may be).
Furthermore, inline and crossline numbers should not be
relied upon to be zero- or one-based indexes (although
they may be).
Args:
xline: A crossline number.
@@ -364,7 +422,8 @@ def main(argv=None):
print("Filename: ", segy_reader.filename)
print("SEG Y revision: ", segy_reader.revision)
print("Number of traces: ", segy_reader.num_traces())
print("Data format: ", segy_reader.data_sample_format_description)
print("Data format: ",
segy_reader.data_sample_format_description)
print("Dimensionality: ", segy_reader.dimensionality)
try:
@@ -380,4 +439,3 @@ def main(argv=None):
if __name__ == '__main__':
main()
+41 -19
View File
@@ -120,7 +120,8 @@ def catalog_traces(fh, bps, endian='>'):
little-endian (non-standard)
Returns:
An immutable sequence containing byte offsets to the beginning of each trace.
A tuple of the form `(trace-catalog, cdp-catalog, line-catalog)` where
each catalog is an instance of ``collections.Mapping``.
"""
trace_header_format = compile_trace_header_format(endian)
@@ -140,7 +141,9 @@ def catalog_traces(fh, bps, endian='>'):
samples_bytes = num_samples * bps
trace_catalog_builder.add(trace_number, pos_begin)
# Should we check the data actually exists?
line_catalog.add((trace_header.Inline3D, trace_header.Crossline3D), trace_number)
line_catalog.add((trace_header.Inline3D,
trace_header.Crossline3D),
trace_number)
cdp_catalog.add(trace_header.cdp, trace_number)
pos_end = pos_begin + TRACE_HEADER_NUM_BYTES + samples_bytes
pos_begin = pos_end
@@ -173,9 +176,12 @@ def read_binary_values(fh, pos, ctype='l', count=1, endian='>'):
buf = fh.read(block_size)
if len(buf) < block_size:
raise EOFError("{} bytes requested but only {} available".format(block_size, len(buf)))
raise EOFError("{} bytes requested but only {} available".format(
block_size, len(buf)))
values = unpack_ibm_floats(buf, count) if fmt == 'ibm' else unpack_values(buf, count, item_size, fmt)
values = (unpack_ibm_floats(buf, count)
if fmt == 'ibm'
else unpack_values(buf, count, item_size, fmt))
assert len(values) == count
return values
@@ -184,7 +190,8 @@ def unpack_ibm_floats(data, count):
"""Unpack a series of binary-encoded big-endian single-precision IBM floats.
Args:
data: A sequence of bytes. (Python 2 - a str object, Python 3 - a bytes object)
data: A sequence of bytes. (Python 2 - a str object,
Python 3 - a bytes object)
count: The number of floats to be read.
@@ -198,38 +205,50 @@ def unpack_values(buf, count, item_size, fmt, endian='>'):
"""Unpack a series items from a byte string.
Args:
data: A sequence of bytes. (Python 2 - a str object, Python 3 - a bytes object)
data: A sequence of bytes. (Python 2 - a str object,
Python 3 - a bytes object)
count: The number of floats to be read.
fmt: A format code (one of the values in the datatype.CTYPES dictionary)
fmt: A format code (one of the values in the datatype.CTYPES
dictionary)
Returns:
A sequence of objects with type corresponding to the format code.
"""
c_format = '{}{}{}'.format(endian, count, fmt)
return struct.unpack(c_format, buf)
# We could use array.fromfile() here. On the one hand it's likely to be faster and more compact,
# On the other, it only works on "real" files, not arbitrary file-like-objects and it would require us
# to handle endian byte swapping ourselves.
# We could use array.fromfile() here. On the one hand it's likely
# to be faster and more compact,
#
# On the other, it only works on "real" files, not arbitrary
# file-like-objects and it would require us to handle endian byte
# swapping ourselves.
_TraceAttributeSpec = namedtuple('Record', ['name', 'pos', 'type'])
def compile_trace_header_format(endian='>'):
"""Compile a format string for use with the struct module from the trace header definition.
"""Compile a format string for use with the struct module from the
trace header definition.
Args:
endian: '>' for big-endian data (the standard and default), '<' for
little-endian (non-standard)
Returns:
A string which can be used with the struct module for parsing trace headers.
A string which can be used with the struct module for parsing
trace headers.
"""
record_specs = sorted([_TraceAttributeSpec(name, TRACE_HEADER_DEF[name]['pos'], TRACE_HEADER_DEF[name]['type']) for name in TRACE_HEADER_DEF],
key=lambda r : r.pos)
record_specs = sorted(
[_TraceAttributeSpec(name,
TRACE_HEADER_DEF[name]['pos'],
TRACE_HEADER_DEF[name]['type'])
for name in TRACE_HEADER_DEF],
key=lambda r: r.pos)
fmt = [endian]
length = 0
@@ -251,11 +270,14 @@ def compile_trace_header_format(endian='>'):
def _compile_trace_header_record():
"""Build a TraceHeader namedtuple from the trace header definition"""
record_specs = sorted([_TraceAttributeSpec(name, TRACE_HEADER_DEF[name]['pos'], TRACE_HEADER_DEF[name]['type']) for name in TRACE_HEADER_DEF],
key=lambda r : r.pos)
return namedtuple('TraceHeader', (record_spec.name for record_spec in record_specs))
record_specs = sorted(
[_TraceAttributeSpec(name,
TRACE_HEADER_DEF[name]['pos'],
TRACE_HEADER_DEF[name]['type'])
for name in TRACE_HEADER_DEF],
key=lambda r: r.pos)
return namedtuple('TraceHeader',
(record_spec.name for record_spec in record_specs))
TraceHeader = _compile_trace_header_record()
+1 -1
View File
@@ -50,7 +50,7 @@ TRACE_HEADER_DEF["DataUse"]["descr"] = {0: {
2: "Test"}}
TRACE_HEADER_DEF["DataUse"]["descr"][1] = TRACE_HEADER_DEF["DataUse"]["descr"][0]
TRACE_HEADER_DEF["offset"] = {"pos": 36, "type": "int32"}
TRACE_HEADER_DEF["ReceiverGroupElevation"] = {"pos": 40, "type": "int32"}
TTRACE_HEADER_DEF["ReceiverGroupElevation"] = {"pos": 40, "type": "int32"}
TRACE_HEADER_DEF["SourceSurfaceElevation"] = {"pos": 44, "type": "int32"}
TRACE_HEADER_DEF["SourceDepth"] = {"pos": 48, "type": "int32"}
TRACE_HEADER_DEF["ReceiverDatumElevation"] = {"pos": 52, "type": "int32"}
+1 -1
View File
@@ -33,7 +33,7 @@ def contains_duplicates(sorted_iterable):
def measure_stride(iterable):
"""Determine whether successive numeric items differ by a contant amount.
"""Determine whether successive numeric items differ by a constant amount.
Args:
iterable: An iterable series of numeric values.