1
1
#!/usr/bin/env python
2
2
import csv
3
- import datetime as dt
3
+ from datetime import datetime
4
4
from collections import defaultdict , namedtuple
5
- from itertools import chain
6
- from os import listdir , remove
7
- from os .path import exists , join
8
5
9
6
debug = False
10
7
11
8
def parse_table_version (fname ):
12
- # filenames need to look like UserTable_MRMS_v<version>.csv
9
+ # Filenames need to look like path/blah/ UserTable_MRMS_v<version>.csv
13
10
return fname .split ('S_v' , 1 )[1 ].replace ('.csv' , '' )
14
11
15
12
def parse_file (fname ):
@@ -56,40 +53,36 @@ def fix_item(item):
56
53
57
54
return item
58
55
59
- # extract the important parameters needed by netCDF-Java
56
+ # Extract the important parameters needed by netCDF-Java
60
57
def important_table_info (param ):
61
- important_info = '{0 .Discipline}, {0 .Category}, {0 .Parameter}, "{0 .Name}", ' + \
62
- '"{0 .Description}", "{0 .Unit}", {0 .No_Coverage}, ' + \
63
- '{0 .Missing}'
58
+ return ( f' { param .Discipline } , { param .Category } , { param .Parameter } , "{ param .Name } ", '
59
+ f '"{ param .Description } ", "{ param .Unit } ", { param .No_Coverage } , '
60
+ f' { param .Missing } ')
64
61
65
- return important_info .format (param )
66
-
67
- # extract the critical parameters needed by netCDF-Java
62
+ # Extract the critical parameters needed by netCDF-Java
68
63
def critical_table_info (param ):
69
- critical_info = '{0.Discipline}, {0.Category}, {0.Parameter}, "{0.Unit}", {0.No_Coverage}, ' + \
70
- '{0.Missing}'
71
-
72
- return critical_info .format (param )
64
+ return (f'{ param .Discipline } , { param .Category } , { param .Parameter } , "{ param .Unit } ", '
65
+ f'{ param .No_Coverage } , { param .Missing } ' )
73
66
74
67
def sorter (item ):
75
- # extract the discipline, category, and parameter as int values
68
+ # Extract the discipline, category, and parameter as int values
76
69
parts = important_table_info (item ).split (',' )
77
70
return tuple (map (lambda x : int (x ), parts [0 :3 ]))
78
71
79
72
def make_java (info , tables ):
80
- filename = 'MergedTableCode.txt' . format ( dt . datetime . now ())
81
- # sort by discipline, category, and parameter, in that order.
73
+ filename = 'MergedTableCode.txt'
74
+ # Sort by discipline, category, and parameter, in that order.
82
75
info = sorted (info , key = lambda item : sorter (item ))
83
76
with open (filename , 'w' ) as f :
84
- f .write ('# created {0:%Y}-{0:%m}-{0:%d}T{0:%I%M}\n ' .format (dt . datetime .now ()))
77
+ f .write ('# created {0:%Y}-{0:%m}-{0:%d}T{0:%I%M}\n ' .format (datetime .now ()))
85
78
f .write ('# using tables {}\n ' .format (', ' .join (tables )))
86
79
for i in info :
87
80
i = fix_item (i )
88
- # make sure the discipline value is numeric (skip the "Not GRIB2" items)
81
+ # Make sure the discipline value is numeric (skip the "Not GRIB2" items)
89
82
if i .Discipline .isnumeric ():
90
83
f .write ('add({}); // v{}\n ' .format (important_table_info (i ), i .TableVersion ))
91
84
92
- # return true if the parameters needed by netcdf-java are the same.
85
+ # Return true if the parameters needed by netcdf-java are the same.
93
86
def parameter_comparison (param_a , param_b ):
94
87
critical = False
95
88
if critical :
@@ -106,7 +99,9 @@ def parameter_comparison(param_a, param_b):
106
99
return marker_a .lower () == marker_b .lower ()
107
100
108
101
def process_tables (tables , interactive = False ):
109
-
102
+ # Sort tables by name, lexicographically.
103
+ # Should restuld in the tables being sorted by version (older to newer).
104
+ tables .sort ()
110
105
params = defaultdict (list )
111
106
for table in tables :
112
107
info = parse_file (table )
@@ -118,32 +113,23 @@ def process_tables(tables, interactive=False):
118
113
dupes = 0
119
114
unique_params = []
120
115
for param_key in params :
121
- # if there is only one entry for a given discipline-category-parameter combination, use it
122
- if len (params [param_key ]) == 1 :
123
- unique_params .append (params [param_key ][0 ])
124
- else :
125
- # let's figure out if there are differences between the table entries with the same discipline-category-parameter combination
126
- has_diffs = False
116
+ if len (params [param_key ]) > 1 :
117
+ # There are multiple entries for a given discipline-category-parameter combination.
118
+ # Let's figure out if there are differences between the table entries with the same discipline-category-parameter combination
127
119
param_versions = params [param_key ]
128
120
first = param_versions [0 ]
121
+ # By default, we will pick the latest version (for non-interactive cases)
122
+ selection = - 1
129
123
for version in range (1 , len (param_versions )):
130
- # compare the parameters from different tables to see if they are different
131
- has_diffs = not parameter_comparison (first , param_versions [version ])
132
- if has_diffs :
133
- # ok, at least one entry is different, so let's stop checking here
134
- break
135
- # If they are all equal (except for the table version part)
136
- if not has_diffs :
137
- # all the same, so pick one (we'll go with the latest)
138
- unique_params .append (param_versions [- 1 ])
139
- else :
140
- # So we have multiple table entries for a given discipline-category-parameter combination.
141
- # Need a human to sort this out. List the options and ask.
124
+ if parameter_comparison (first , param_versions [version ]):
125
+ # Parameter definitions are the same, check next version
126
+ continue
127
+
128
+ # If we make it here, we have multiple table entries for a given discipline-category-parameter
129
+ # combination that are different. We might need a human to sort this out.
142
130
dupes += 1
143
131
144
- if not interactive :
145
- selection = - 1
146
- else :
132
+ if interactive :
147
133
print ('Which version of {} would you like to use?' .format (param_key ))
148
134
number_of_choices = len (param_versions )
149
135
# figure out padding for pretty printing
@@ -159,27 +145,31 @@ def process_tables(tables, interactive=False):
159
145
padding = ' ' * (max_version_len - len (versioned_param [- 1 ]))
160
146
print (' {} ({}): {}{}' .format (version + 1 , versioned_param [- 1 ], padding , important_table_info (versioned_param )))
161
147
162
- valid_selection = False
163
- while not valid_selection :
148
+ while True :
149
+ # default selection - empty string
150
+ selection = ''
164
151
if interactive :
165
152
selection = input (' 1 - {} (default {}): ' .format (number_of_choices , number_of_choices ))
166
- else :
167
- selection = ''
168
153
169
154
if selection == '' :
170
155
# if default, select the last choice in the list
171
156
selection = - 1
172
- valid_selection = True
157
+ break
173
158
elif selection .isnumeric ():
174
159
selection = int (selection )
175
160
if (selection > 0 ) and (selection <= number_of_choices ):
176
161
selection -= 1
177
- valid_selection = True
178
-
179
- if not valid_selection :
162
+ break
163
+ else :
180
164
print (' --> {} is invalid. Please choose between 1 and {}.' .format (selection , number_of_choices ))
181
-
182
- unique_params .append (param_versions [selection ])
165
+ break # break out of version loop since we resolved the multiple versions
166
+ # The issue of multiple, possibly conflicting, versions of a parameter has been resolved - add that result
167
+ # to the unique parameter list
168
+ unique_params .append (param_versions [selection ])
169
+ else :
170
+ # Only one entry for a given discipline-category-parameter combination exists across various versions of a
171
+ # table, so add it to the unique parameter list.
172
+ unique_params .append (params [param_key ][0 ])
183
173
184
174
if debug or interactive :
185
175
print ('Selected {}' .format (param_versions [selection ]))
@@ -191,23 +181,17 @@ def process_tables(tables, interactive=False):
191
181
192
182
if __name__ == '__main__' :
193
183
import argparse
184
+ from pathlib import Path
194
185
195
186
parser = argparse .ArgumentParser (description = "Convert MRMS GRIB 2 table to Java code" )
196
- parser .add_argument ('--table' , type = str , required = False , action = 'append' , nargs = '+' ,
197
- help = "One or more source table (multiple tables separated by spaces ). If missing, will try to merge all source tables located in tables/" )
187
+ parser .add_argument ('--table' , type = str , required = False , action = 'append' ,
188
+ help = "Path to a GRIB table (can be used multiple times to provide multiple tables ). If missing, will try to merge all GRIB tables located in tables/" )
198
189
parser .add_argument ('--interactive' , action = 'store_true' ,
199
190
help = "When merging tables, prompt user to select between conflicting parameter definitions." )
200
191
args = parser .parse_args ()
201
192
202
193
tables = args .table
203
194
if tables is None :
204
- table_directory_name = 'tables/'
205
- tables = listdir (table_directory_name )
206
- tables = map (lambda x : join (table_directory_name , x ), tables )
207
- else :
208
- if isinstance (tables , str ):
209
- tables = [tables ]
210
- else :
211
- tables = list (chain .from_iterable (tables ))
195
+ tables = list (map (str , Path ('tables/' ).iterdir ()))
212
196
213
- process_tables (tables , interactive = args .interactive )
197
+ process_tables (tables , interactive = args .interactive )
0 commit comments