Skip to content

Commit

Permalink
MNT: Clean up code for nexrad spec parser
Browse files Browse the repository at this point in the history
flake8 is picking up this file now, might as well make it compliant.
  • Loading branch information
dopplershift committed Oct 26, 2018
1 parent 619eebb commit 7861d9c
Showing 1 changed file with 34 additions and 15 deletions.
49 changes: 34 additions & 15 deletions metpy/io/_nexrad_msgs/parse_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,28 @@
# Copyright (c) 2015 MetPy Developers.
# Distributed under the terms of the BSD 3-Clause License.
# SPDX-License-Identifier: BSD-3-Clause
"""Parse specification extracted from NEXRAD ICD PDFs and generate Python code."""

from __future__ import print_function

import warnings


def register_processor(num):
"""Register functions to handle particular message numbers."""
def inner(func):
"""Perform actual function registration."""
processors[num] = func
return func
return inner


processors = {}


@register_processor(3)
def process_msg3(fname):
"""Handle information for message type 3."""
with open(fname, 'r') as infile:
info = []
for lineno, line in enumerate(infile):
Expand All @@ -37,16 +46,17 @@ def process_msg3(fname):
info.append({'name': var_name, 'desc': full_desc, 'fmt': fmt})

if ignored_item(info[-1]) and var_name != 'Spare':
print('WARNING: {} has type {}. Setting as Spare'.format(var_name, typ))
warnings.warn('{} has type {}. Setting as Spare'.format(var_name, typ))

except (ValueError, AssertionError):
print('{} > {}'.format(lineno + 1, ':'.join(parts)))
warnings.warn('{} > {}'.format(lineno + 1, ':'.join(parts)))
raise
return info


@register_processor(18)
def process_msg18(fname):
"""Handle information for message type 18."""
with open(fname, 'r') as infile:
info = []
for lineno, line in enumerate(infile):
Expand All @@ -63,21 +73,21 @@ def process_msg18(fname):
additional=[('See Note (5)', ('{size}s', 1172))])

if ' ' in var_name:
print('WARNING: space in {}'.format(var_name))
warnings.warn('Space in {}'.format(var_name))
if not desc:
print('WARNING: null description for {}'.format(var_name))
warnings.warn('null description for {}'.format(var_name))

var_name = fix_var_name(var_name)
full_desc = fix_desc(desc, units)

info.append({'name': var_name, 'desc': full_desc, 'fmt': fmt})

if (ignored_item(info[-1]) and var_name != 'SPARE' and
'SPARE' not in full_desc):
print('WARNING: {} has type {}. Setting as SPARE'.format(var_name, typ))
if (ignored_item(info[-1]) and var_name != 'SPARE'
and 'SPARE' not in full_desc):
warnings.warn('{} has type {}. Setting as SPARE'.format(var_name, typ))

except (ValueError, AssertionError):
print('{} > {}'.format(lineno + 1, ':'.join(parts)))
warnings.warn('{} > {}'.format(lineno + 1, ':'.join(parts)))
raise
return info

Expand All @@ -89,6 +99,7 @@ def process_msg18(fname):


def fix_type(typ, size, additional=None):
"""Fix up creating the appropriate struct type based on the information in the column."""
if additional is not None:
my_types = types + additional
else:
Expand All @@ -102,17 +113,18 @@ def fix_type(typ, size, additional=None):

if matches:
if callable(info):
fmtStr, trueSize = info(size)
fmt_str, true_size = info(size)
else:
fmtStr, trueSize = info
assert size == trueSize, ('Got size {} instead of {} for {}'.format(size,
trueSize, typ))
return fmtStr.format(size=size)
fmt_str, true_size = info
assert size == true_size, ('{}: Got size {} instead of {}'.format(typ, size,
true_size))
return fmt_str.format(size=size)

raise ValueError('No type match! ({})'.format(typ))


def fix_var_name(var_name):
"""Clean up and apply standard formatting to variable names."""
name = var_name.strip()
for char in '(). /#,':
name = name.replace(char, '_')
Expand All @@ -124,6 +136,7 @@ def fix_var_name(var_name):


def fix_desc(desc, units=None):
"""Clean up description column."""
full_desc = desc.strip()
if units and units != 'N/A':
if full_desc:
Expand All @@ -134,25 +147,30 @@ def fix_desc(desc, units=None):


def ignored_item(item):
"""Determine whether this item should be ignored."""
return item['name'].upper() == 'SPARE' or 'x' in item['fmt']


def need_desc(item):
"""Determine whether we need a description for this item."""
return item['desc'] and not ignored_item(item)


def field_name(item):
"""Return the field name if appropriate."""
return '"{:s}"'.format(item['name']) if not ignored_item(item) else None


def field_fmt(item):
"""Return the field format if appropriate."""
return '"{:s}"'.format(item['fmt']) if '"' not in item['fmt'] else item['fmt']


def write_file(fname, info):
"""Write out the generated Python code."""
with open(fname, 'w') as outfile:
# File header
outfile.write('# Copyright (c) 2014,2015 MetPy Developers.\n')
outfile.write('# Copyright (c) 2018 MetPy Developers.\n')
outfile.write('# Distributed under the terms of the BSD 3-Clause License.\n')
outfile.write('# SPDX-License-Identifier: BSD-3-Clause\n\n')
outfile.write('# flake8: noqa\n')
Expand All @@ -172,12 +190,13 @@ def write_file(fname, info):
outfile.write(outdata)
outfile.write(']\n')


if __name__ == '__main__':
import os.path

for num in [18, 3]:
fname = 'msg{:d}.spec'.format(num)
print('Processing {}...'.format(fname))
print('Processing {}...'.format(fname)) # noqa: T001
info = processors[num](fname)
fname = os.path.splitext(fname)[0] + '.py'
write_file(fname, info)

0 comments on commit 7861d9c

Please sign in to comment.