Skip to content

Commit

Permalink
ENH: Support Level2 files without a volume header (Fixes Unidata#1470)
Browse files Browse the repository at this point in the history
This, for instance, makes it possible to use Level2File with the
realtime chunks available on AWS.
  • Loading branch information
dopplershift committed Aug 26, 2020
1 parent 264ea42 commit 91d599b
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 13 deletions.
8 changes: 6 additions & 2 deletions src/metpy/io/_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,18 @@ class IOBuffer:
def __init__(self, source):
"""Initialize the IOBuffer with the source data."""
self._data = bytearray(source)
self._offset = 0
self.clear_marks()
self.reset()

@classmethod
def fromfile(cls, fobj):
"""Initialize the IOBuffer with the contents of the file object."""
return cls(fobj.read())

def reset(self):
"""Reset buffer back to initial state."""
self._offset = 0
self.clear_marks()

def set_mark(self):
"""Mark the current location and return its id so that the buffer can return later."""
self._bookmarks.append(self._offset)
Expand Down
15 changes: 12 additions & 3 deletions src/metpy/io/nexrad.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class Level2File:
MISSING = float('nan')
RANGE_FOLD = float('nan') # TODO: Need to separate from missing

def __init__(self, filename):
def __init__(self, filename, *, has_volume_header=True):
r"""Create instance of `Level2File`.
Parameters
Expand All @@ -177,10 +177,19 @@ def __init__(self, filename):
with contextlib.closing(fobj):
self._buffer = IOBuffer.fromfile(fobj)

self._read_volume_header()
start = self._buffer.set_mark()
# Try to read the volume header. If this fails, or we're told we don't have one
# then we fall back and try to just read messages, assuming we have e.g. one of
# the real-time chunks.
try:
if has_volume_header:
self._read_volume_header()
except ValueError:
log.error('testing')
log.warning('Unable to read volume header. Attempting to read messages.')
self._buffer.reset()

# See if we need to apply bz2 decompression
start = self._buffer.set_mark()
try:
self._buffer = IOBuffer(self._buffer.read_func(bzip_blocks_decompress_all))
except ValueError:
Expand Down
1 change: 1 addition & 0 deletions src/metpy/static-data-manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ KTLX20130520_201643_V06.gz 772e01b154a5c966982a6d0aa2fc78bc64f08a9b77165b74dc02d
KTLX20150530_000802_V06.bz2 d78689afc525c853dec8ccab4a4eccc2daacef5c7df198a35a3a791016e993b0
Level2_FOP1_20191223_003655.ar2v 4a086f6190c0d324612922e9fcb46262c3a1d825810caa8a11aca3823db17ae3
Level2_KFTG_20150430_1419.ar2v 77c3355c8a503561eb3cddc3854337e640d983a4acdfc27bdfbab60c0b18cfc1
Level2_KLBB_single_chunk 0fc5598a83ff7ab1f5751d43a70160eb3d155d1c8d44d8a7c990dd2815c5f9aa
Level3_Composite_dhr_1km_20180309_2225.gini 19fcc0179c9d3e87c462262ea817e87f52f60db4830314b8f936baa3b9817a44
NAM_test.nc 12338ad06d5bd223e99e2872b20a9c80d58af0c546731e4b00a6619adc247cd0
NHEM-MULTICOMP_1km_IR_20151208_2100.gini c144b29284aa915e6fd1b8f01939c656f2c72c3d7a9e0af5397f93067fe0d952
Expand Down
Binary file added staticdata/Level2_KLBB_single_chunk
Binary file not shown.
30 changes: 22 additions & 8 deletions tests/io/test_nexrad.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,28 @@ def test_conditional_radconst(fname, has_v2):
assert hasattr(f.sweeps[0][0][3], 'calib_dbz0_v') == has_v2


def test_msg15():
"""Check proper decoding of message type 15."""
f = Level2File(get_test_data('KTLX20130520_201643_V06.gz', as_file_obj=False))
data = f.clutter_filter_map['data']
assert isinstance(data[0][0], list)
assert f.clutter_filter_map['datetime'] == datetime(2013, 5, 19, 0, 0, 0, 315000)


def test_single_chunk(caplog):
"""Check that Level2File copes with reading a file containing a single chunk."""
# Need to override the test level set above
caplog.set_level(logging.WARNING, 'metpy.io.nexrad')
f = Level2File(get_test_data('Level2_KLBB_single_chunk'))
assert len(f.sweeps) == 1
assert 'Unable to read volume header' in caplog.text

# Make sure the warning is not present if we pass the right kwarg.
caplog.clear()
Level2File(get_test_data('Level2_KLBB_single_chunk'), has_volume_header=False)
assert 'Unable to read volume header' not in caplog.text


#
# NIDS/Level 3 Tests
#
Expand Down Expand Up @@ -188,14 +210,6 @@ def test31_clear_air():
assert not is_precip_mode(31), 'VCP 31 is not precip'


def test_msg15():
"""Check proper decoding of message type 15."""
f = Level2File(get_test_data('KTLX20130520_201643_V06.gz', as_file_obj=False))
data = f.clutter_filter_map['data']
assert isinstance(data[0][0], list)
assert f.clutter_filter_map['datetime'] == datetime(2013, 5, 19, 0, 0, 0, 315000)


def test_tracks():
"""Check that tracks are properly decoded."""
f = Level3File(get_test_data('nids/KOUN_SDUS34_NSTTLX_201305202016'))
Expand Down

0 comments on commit 91d599b

Please sign in to comment.