diff --git a/examples/loadsave.py b/examples/loadsave.py index 4577c1c..0b799f5 100644 --- a/examples/loadsave.py +++ b/examples/loadsave.py @@ -5,6 +5,8 @@ Usage: loadsave.py """ +from __future__ import print_function + import os import sys diff --git a/examples/timed_reader.py b/examples/timed_reader.py index ca4b181..d4e78d9 100644 --- a/examples/timed_reader.py +++ b/examples/timed_reader.py @@ -6,6 +6,7 @@ Usage: """ from __future__ import print_function + import datetime import os diff --git a/segpy/catalog.py b/segpy/catalog.py index 82b94ee..663b5a3 100644 --- a/segpy/catalog.py +++ b/segpy/catalog.py @@ -6,7 +6,7 @@ from segpy.portability import reprlib from segpy.util import contains_duplicates, measure_stride, minmax -class CatalogBuilder: +class CatalogBuilder(object): """Use a catalog builder to construct optimised, immutable mappings. A CatalogBuilder is useful when, depending on the particular keys and @@ -230,7 +230,7 @@ class RowMajorCatalog(Catalog): j_max (int): The maximum j value. c (int): The constant offset """ - super().__init__() + super(RowMajorCatalog, self).__init__() self._i_min = i_min self._i_max = i_max self._j_min = j_min @@ -305,7 +305,7 @@ class DictionaryCatalog(Catalog): """ def __init__(self, items): - super().__init__() + super(DictionaryCatalog, self).__init__() self._items = OrderedDict(items) def __getitem__(self, key): @@ -349,10 +349,11 @@ class RegularConstantCatalog(Catalog): raise ValueError("RegularIndex key range {!r} is not " "a multiple of stride {!r}".format( key_stride, key_range)) - super().__init__(key_min=key_min, - key_max=key_max, - value_min=value, - value_max=value) + super(RegularConstantCatalog, self).__init__( + key_min=key_min, + key_max=key_max, + value_min=value, + value_max=value) self._key_stride = key_stride def __getitem__(self, key): @@ -397,7 +398,7 @@ class ConstantCatalog(Catalog): key_stride: The difference between successive keys. value: A value associated with all keys. """ - super().__init__(value_min=value, value_max=value) + super(ConstantCatalog, self).__init__(value_min=value, value_max=value) self._items = frozenset(keys) def __getitem__(self, key): @@ -449,7 +450,7 @@ class RegularCatalog(Catalog): raise ValueError("{} key range {!r} is not " "a multiple of stride {!r}".format(self.__class__.__name__, key_stride, key_range)) - super().__init__(key_min=key_min, key_max=key_max) + super(RegularCatalog, self).__init__(key_min=key_min, key_max=key_max) self._key_stride = key_stride self._values = list(values) num_keys = key_range // key_stride @@ -537,11 +538,11 @@ class LinearRegularCatalog(Catalog): value_range)) self._value_stride = value_stride - super().__init__(key_min=key_min, - key_max=key_max, - value_min=value_min, - value_max=value_max) - + super(LinearRegularCatalog, self).__init__( + key_min=key_min, + key_max=key_max, + value_min=value_min, + value_max=value_max) num_keys = (self.key_max() - self.key_min()) // self._key_stride num_values = (self.value_max() - self.value_min()) // self._value_stride diff --git a/segpy/portability.py b/segpy/portability.py index 5524e60..50f506b 100644 --- a/segpy/portability.py +++ b/segpy/portability.py @@ -38,7 +38,7 @@ if sys.version_info >= (3, 0): return bytes(integers) else: def byte_string(integers): - return ''.join(chr(i) for i in integers) + return EMPTY_BYTE_STRING.join(chr(i) for i in integers) if sys.version_info >= (3, 0): @@ -49,9 +49,11 @@ else: if sys.version_info >= (3, 0): izip = zip + from itertools import zip_longest as izip_longest else: - from itertools import izip - izip = izip # Keep the static analyzer happy + from itertools import (izip, izip_longest) + izip = izip # Keep the static analyzer happy + izip_longest = izip_longest # Keep the static analyzer happy if sys.version_info >= (3, 0): @@ -65,3 +67,12 @@ else: c = ord(byte_str[2]) d = ord(byte_str[3]) return a, b, c, d + +if sys.version_info >= (3, 0): + unicode = str +else: + unicode = unicode + + + + diff --git a/segpy/toolkit.py b/segpy/toolkit.py index 2c9c271..75b8714 100644 --- a/segpy/toolkit.py +++ b/segpy/toolkit.py @@ -1,14 +1,18 @@ +from __future__ import print_function + from array import array from collections import namedtuple, OrderedDict import itertools -from itertools import zip_longest +from portability import izip_longest import os import struct import re import sys +import logging from segpy import textual_reel_header_definition + from segpy.catalog import CatalogBuilder from segpy.datatypes import CTYPES, size_in_bytes from segpy.encoding import guess_encoding, is_supported_encoding, UnsupportedEncodingError @@ -32,6 +36,11 @@ TRACE_HEADER_NUM_BYTES = 240 END_TEXT_STANZA = "((SEG: EndText))" +def logger(): + # Defer logger creation until the module is *used* rather than imported. + return logging.getLogger(__name__) + + def extract_revision(binary_reel_header): """Obtain the SEG Y revision from the reel header. @@ -234,7 +243,7 @@ def read_extended_headers_counted(fh, num_expected, encoding): ext_header = read_textual_reel_header(fh, encoding) if has_end_text_stanza(ext_header): if i != num_expected - 1: - print("Unexpected end-text extended header", file=sys.stderr) # TODO: Log this + logger().warning("Unexpected end-text extended header.") break extended_headers.append(ext_header) @@ -522,7 +531,7 @@ def format_standard_textual_header(revision, **kwargs): background_slices = complementary_slices(placeholder_slices.values(), 0, len(template)) chunks = [] - for bg_slice, placeholder in zip_longest(background_slices, placeholder_slices.items()): + for bg_slice, placeholder in izip_longest(background_slices, placeholder_slices.items()): if bg_slice is not None: chunks.append(template[bg_slice]) @@ -890,17 +899,3 @@ def _compile_trace_header_record(): TraceHeader = _compile_trace_header_record() - -if __name__ == '__main__': - from pprint import pprint as pp - header = format_standard_textual_header(1, - client="Lundin", - company="Western Geco", - crew_number=123, - processing1="Sixty North AS", - sweep_start_hz=10, - sweep_end_hz=1000, - sweep_length_ms=10000, - sweep_channel_number=3, - sweep_type='spread') - pp(header, width=200) diff --git a/test/test_extended_textual_header.py b/test/test_extended_textual_header.py index 991ad95..2bed9e5 100644 --- a/test/test_extended_textual_header.py +++ b/test/test_extended_textual_header.py @@ -7,6 +7,7 @@ from hypothesis.searchstrategy import MappedSearchStrategy, StringStrategy from hypothesis.strategytable import StrategyTable from segpy.encoding import EBCDIC, ASCII from segpy.toolkit import format_extended_textual_header, CARDS_PER_HEADER, END_TEXT_STANZA, CARD_LENGTH +from segpy.portability import unicode # class MultiLineString(str): @@ -31,28 +32,28 @@ from segpy.toolkit import format_extended_textual_header, CARDS_PER_HEADER, END_ class TestFormatExtendedTextualHeader(unittest.TestCase): - @given(str, + @given(unicode, sampled_from([ASCII, EBCDIC]), bool) def test_forty_lines_per_page(self, text, encoding, include_text_stop): pages = format_extended_textual_header(text, encoding, include_text_stop) self.assertTrue(all(len(page) == CARDS_PER_HEADER for page in pages)) - @given(str, + @given(unicode, sampled_from([ASCII, EBCDIC]), bool) def test_eighty_bytes_per_encoded_line(self, text, encoding, include_text_stop): pages = format_extended_textual_header(text, encoding, include_text_stop) self.assertTrue(all([len(line.encode(encoding)) == CARD_LENGTH for page in pages for line in page])) - @given(str, + @given(unicode, sampled_from([ASCII, EBCDIC]), bool) def test_lines_end_with_cr_lf(self, text, encoding, include_text_stop): pages = format_extended_textual_header(text, encoding, include_text_stop) self.assertTrue(all([line.endswith('\r\n') for page in pages for line in page])) - @given(str, + @given(unicode, sampled_from([ASCII, EBCDIC]), just(True)) def test_lines_end_with_cr_lf(self, text, encoding, include_text_stop): diff --git a/test/test_float.py b/test/test_float.py index f459871..dc800eb 100644 --- a/test/test_float.py +++ b/test/test_float.py @@ -2,6 +2,7 @@ import unittest from segpy.ibm_float import (ieee2ibm, ibm2ieee, MAX_IBM_FLOAT, SMALLEST_POSITIVE_NORMAL_IBM_FLOAT, LARGEST_NEGATIVE_NORMAL_IBM_FLOAT, MIN_IBM_FLOAT) +from segpy.portability import byte_string class Ibm2Ieee(unittest.TestCase): @@ -10,44 +11,44 @@ class Ibm2Ieee(unittest.TestCase): self.assertEqual(ibm2ieee(b'\0\0\0\0'), 0.0) def test_positive_half(self): - self.assertEqual(ibm2ieee((0b11000000, 0x80, 0x00, 0x00)), -0.5) + self.assertEqual(ibm2ieee(byte_string((0b11000000, 0x80, 0x00, 0x00))), -0.5) def test_negative_half(self): - self.assertEqual(ibm2ieee((0b01000000, 0x80, 0x00, 0x00)), 0.5) + self.assertEqual(ibm2ieee(byte_string((0b01000000, 0x80, 0x00, 0x00))), 0.5) def test_one(self): self.assertEqual(ibm2ieee(b'\x41\x10\x00\x00'), 1.0) def test_negative_118_625(self): # Example taken from Wikipedia http://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture - self.assertEqual(ibm2ieee((0b11000010, 0b01110110, 0b10100000, 0b00000000)), -118.625) + self.assertEqual(ibm2ieee(byte_string((0b11000010, 0b01110110, 0b10100000, 0b00000000))), -118.625) def test_largest_representable_number(self): - self.assertEqual(ibm2ieee((0b01111111, 0b11111111, 0b11111111, 0b11111111)), MAX_IBM_FLOAT) + self.assertEqual(ibm2ieee(byte_string((0b01111111, 0b11111111, 0b11111111, 0b11111111))), MAX_IBM_FLOAT) def test_smallest_positive_normalised_number(self): - self.assertEqual(ibm2ieee((0b00000000, 0b00010000, 0b00000000, 0b00000000)), SMALLEST_POSITIVE_NORMAL_IBM_FLOAT) + self.assertEqual(ibm2ieee(byte_string((0b00000000, 0b00010000, 0b00000000, 0b00000000))), SMALLEST_POSITIVE_NORMAL_IBM_FLOAT) def test_largest_negative_normalised_number(self): - self.assertEqual(ibm2ieee((0b10000000, 0b00010000, 0b00000000, 0b00000000)), LARGEST_NEGATIVE_NORMAL_IBM_FLOAT) + self.assertEqual(ibm2ieee(byte_string((0b10000000, 0b00010000, 0b00000000, 0b00000000))), LARGEST_NEGATIVE_NORMAL_IBM_FLOAT) def test_smallest_representable_number(self): - self.assertEqual(ibm2ieee((0b11111111, 0b11111111, 0b11111111, 0b11111111)), MIN_IBM_FLOAT) + self.assertEqual(ibm2ieee(byte_string((0b11111111, 0b11111111, 0b11111111, 0b11111111))), MIN_IBM_FLOAT) def test_error_1(self): - self.assertEqual(ibm2ieee((196, 74, 194, 143)), -19138.55859375) + self.assertEqual(ibm2ieee(byte_string((196, 74, 194, 143))), -19138.55859375) def test_error_2(self): - self.assertEqual(ibm2ieee((191, 128, 0, 0)), -0.03125) + self.assertEqual(ibm2ieee(byte_string((191, 128, 0, 0))), -0.03125) def test_subnormal(self): - self.assertEqual(ibm2ieee((0x00, 0x00, 0x00, 0x20)), 1.6472184286297693e-83) + self.assertEqual(ibm2ieee(byte_string((0x00, 0x00, 0x00, 0x20))), 1.6472184286297693e-83) def test_subnormal_is_subnormal(self): - self.assertTrue(0 < ibm2ieee((0x00, 0x00, 0x00, 0x20)) < SMALLEST_POSITIVE_NORMAL_IBM_FLOAT) + self.assertTrue(0 < ibm2ieee(byte_string((0x00, 0x00, 0x00, 0x20))) < SMALLEST_POSITIVE_NORMAL_IBM_FLOAT) def test_subnormal_smallest_subnormal(self): - self.assertEqual(ibm2ieee((0x00, 0x00, 0x00, 0x01)), 5.147557589468029e-85) + self.assertEqual(ibm2ieee(byte_string((0x00, 0x00, 0x00, 0x01))), 5.147557589468029e-85) class Ieee2Ibm(unittest.TestCase): @@ -56,28 +57,28 @@ class Ieee2Ibm(unittest.TestCase): self.assertEqual(ieee2ibm(0.0), b'\0\0\0\0') def test_positive_half(self): - self.assertEqual(ieee2ibm(-0.5), bytes((0b11000000, 0x80, 0x00, 0x00))) + self.assertEqual(ieee2ibm(-0.5), byte_string((0b11000000, 0x80, 0x00, 0x00))) def test_negative_half(self): - self.assertEqual(ieee2ibm(0.5), bytes((0b01000000, 0x80, 0x00, 0x00))) + self.assertEqual(ieee2ibm(0.5), byte_string((0b01000000, 0x80, 0x00, 0x00))) def test_one(self): self.assertEqual(ieee2ibm(1.0), b'\x41\x10\x00\x00') def test_negative_118_625(self): # Example taken from Wikipedia http://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture - self.assertEqual(ieee2ibm(-118.625), bytes((0b11000010, 0b01110110, 0b10100000, 0b00000000))) + self.assertEqual(ieee2ibm(-118.625), byte_string((0b11000010, 0b01110110, 0b10100000, 0b00000000))) def test_0_1(self): # Note, this is different from the Wikipedia example, because the Wikipedia example does # round to nearest, and our routine does round to zero - self.assertEqual(ieee2ibm(0.1), bytes((0b01000000, 0b00011001, 0b10011001, 0b10011001))) + self.assertEqual(ieee2ibm(0.1), byte_string((0b01000000, 0b00011001, 0b10011001, 0b10011001))) def test_subnormal(self): - self.assertEqual(ieee2ibm(1.6472184286297693e-83), bytes((0x00, 0x00, 0x00, 0x20))) + self.assertEqual(ieee2ibm(1.6472184286297693e-83), byte_string((0x00, 0x00, 0x00, 0x20))) def test_smallest_subnormal(self): - self.assertEqual(ieee2ibm(5.147557589468029e-85), bytes((0x00, 0x00, 0x00, 0x01))) + self.assertEqual(ieee2ibm(5.147557589468029e-85), byte_string((0x00, 0x00, 0x00, 0x01))) def test_too_small_subnormal(self): with self.assertRaises(FloatingPointError): @@ -109,13 +110,13 @@ class Ibm2IeeeRoundtrip(unittest.TestCase): self.assertEqual(ibm_start, ibm_result) def test_positive_half(self): - ibm_start = bytes((0b11000000, 0x80, 0x00, 0x00)) + ibm_start = byte_string((0b11000000, 0x80, 0x00, 0x00)) f = ibm2ieee(ibm_start) ibm_result = ieee2ibm(f) self.assertEqual(ibm_start, ibm_result) def test_negative_half(self): - ibm_start = bytes((0b01000000, 0x80, 0x00, 0x00)) + ibm_start = byte_string((0b01000000, 0x80, 0x00, 0x00)) f = ibm2ieee(ibm_start) ibm_result = ieee2ibm(f) self.assertEqual(ibm_start, ibm_result) @@ -127,7 +128,7 @@ class Ibm2IeeeRoundtrip(unittest.TestCase): self.assertEqual(ibm_start, ibm_result) def test_subnormal(self): - ibm_start = bytes((0x00, 0x00, 0x00, 0x20)) + ibm_start = byte_string((0x00, 0x00, 0x00, 0x20)) f = ibm2ieee(ibm_start) ibm_result = ieee2ibm(f) self.assertEqual(ibm_start, ibm_result)