diff --git a/catalog.py b/catalog.py index 16ec6f8..cd8966a 100644 --- a/catalog.py +++ b/catalog.py @@ -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) \ No newline at end of file + return '{}({}, {}, {}, {}, {}, {})'.format( + self.__class__.__name__, + self._key_min, + self._key_max, + self._key_stride, + self._value_min, + self._value_max, + self._value_stride) diff --git a/reader.py b/reader.py index 88ab259..d94e140 100644 --- a/reader.py +++ b/reader.py @@ -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() - diff --git a/toolkit.py b/toolkit.py index e53cea8..b7366fb 100644 --- a/toolkit.py +++ b/toolkit.py @@ -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() - - diff --git a/trace_header_definition.py b/trace_header_definition.py index faeda6b..67721ec 100644 --- a/trace_header_definition.py +++ b/trace_header_definition.py @@ -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"} diff --git a/util.py b/util.py index bae04c8..4c46736 100644 --- a/util.py +++ b/util.py @@ -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.