From bec5ae0c3616422e314bca7df762261770684be6 Mon Sep 17 00:00:00 2001 From: Bob Weigel Date: Wed, 8 Jul 2026 14:23:38 -0400 Subject: [PATCH] first draft --- hapiclient/info.py | 3 +- hapiclient/util.py | 79 +++++++++++++++++-------- test/test_subset_meta.py | 125 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 26 deletions(-) create mode 100644 test/test_subset_meta.py diff --git a/hapiclient/info.py b/hapiclient/info.py index 5f70ade..fd3b2f0 100644 --- a/hapiclient/info.py +++ b/hapiclient/info.py @@ -21,6 +21,7 @@ def info(SERVER, DATASET, PARAMETERS, opts): meta.update({"x_dataset": DATASET}) if PARAMETERS is not None: - return subset_meta(meta, PARAMETERS) + subset_meta(meta, PARAMETERS) + return meta else: return meta diff --git a/hapiclient/util.py b/hapiclient/util.py index 29d7c2a..c457632 100644 --- a/hapiclient/util.py +++ b/hapiclient/util.py @@ -364,46 +364,75 @@ def urlretrieve(url, fname): def subset_meta(meta, params): """Extract subset of parameters from meta object returned by hapi(). - ``metar = subset_meta(meta, parameters)`` modifies ``meta["parameters"]`` array - so that it only contains elements for the time variable and the parameters - in the comma-separated string ``parameters``. + ``subset_meta(meta, parameters)`` modifies ``meta["parameters"]`` list + in place so that it only contains elements for the time variable and the + parameters in the comma-separated string ``parameters``. """ + # Note that tests for subset_meta() are in test_subset_meta.py, which also + # has tests for error message strings. If error message strings change, + # update tests in test_subset_meta.py. + if params == '': return meta - p = params.split(',') - pm = [] # Parameter names in metadata + pw = params.split(',') # Wanted parameters names as list + + # Check for duplicate parameters in pw + if len(pw) != len(set(pw)): + # Print duplicate parameters + duplicates = ','.join([x for x in pw if pw.count(x) > 1]) + error("Duplicate parameters in requested parameter list: '" + duplicates + "'") + + # Check for errors in pw + for p in pw: + if p == '': + error("Empty parameter name in requested parameter list: '" + params + "'") + if p.startswith(' '): + error("Leading space before parameter name '" + p + "'") + if p.endswith(' '): + error("Trailing space after parameter name '" + p + "'") + + pa = [] # Available parameter names in metadata as list for i in range(0, len(meta['parameters'])): - pm.append(meta['parameters'][i]['name']) + pa.append(meta['parameters'][i]['name']) + + # Check if meta has duplicate parameter names. + if len(pa) != len(set(pa)): + duplicates = ','.join([x for x in pa if pa.count(x) > 1]) + error('Duplicate parameter names in metadata returned by server: ' + duplicates) - # Check for parameters requested that are not in metadata - for i in range(0, len(p)): - if p[i] not in pm: - error('Parameter %s is not in meta' % p[i] + '\n') + # Check for parameters wanted that are not available + for i in range(0, len(pw)): + if pw[i] not in pa: + error("Parameter '%s' is not in metadata from server" % pw[i]) return - pa = [meta['parameters'][0]] # First parameter is always the time parameter + # Keep first parameter, which is always the primary time parameter + pa = [meta['parameters'][0]] - params_reordered = [] # Re-ordered params - # If time parameter explicitly requested, put it first in params_reordered. - if meta['parameters'][0]['name'] in p: - params_reordered = [meta['parameters'][0]['name']] + pw_reordered = [] # Re-ordered params + # If time parameter explicitly requested, put it first in pw_reordered. + if meta['parameters'][0]['name'] in pw: + pw_reordered = [meta['parameters'][0]['name']] # Create subset of parameter metadata - for i in range(1, len(pm)): - if pm[i] in p: + for i in range(1, len(meta['parameters'])): + if meta['parameters'][i]['name'] in pw: pa.append(meta['parameters'][i]) - params_reordered.append(pm[i]) - meta['parameters'] = pa + pw_reordered.append(meta['parameters'][i]['name']) + + pw_reordered_str = ','.join(pw_reordered) - params_reordered_str = ','.join(params_reordered) + if not params == pw_reordered_str: + msg = 'Order of requested parameters does not match order of ' + msg += 'parameters in server info metadata. ' + msg += "\n " + "Order requested: " + params + msg += "\n " + "Order required: " + pw_reordered_str + error(msg) - if not params == params_reordered_str: - msg = "\n " + "Order requested: " + params - msg = msg + "\n " + "Order required: " + params_reordered_str - error('Order of requested parameters does not match order of ' \ - 'parameters in server info metadata.' + msg + '\n') + # Modify meta to only include time parameter and parameters in pw. + meta['parameters'] = pa return meta diff --git a/test/test_subset_meta.py b/test/test_subset_meta.py new file mode 100644 index 0000000..9f12083 --- /dev/null +++ b/test/test_subset_meta.py @@ -0,0 +1,125 @@ +from hapiclient.util import HAPIError, subset_meta + +meta = { +"parameters": [ + {"name": "Time"}, + {"name": "Parameter1"}, + {"name": "Parameter2"}, + {"name": "Parameter3"} + ] +} + +msg_o = "Exception not raised by subset_meta() with " + +def test_simple(): + params = 'Parameter1,Parameter2' + subset_meta(meta, params) + assert len(meta['parameters']) == 3 + assert meta['parameters'][0]['name'] == 'Time' + assert meta['parameters'][1]['name'] == 'Parameter1' + assert meta['parameters'][2]['name'] == 'Parameter2' + + +def test_params_wrong_order(): + params = 'Parameter2,Parameter1' + try: + subset_meta(meta, params) + except Exception as e: + assert isinstance(e, HAPIError) + assert str(e).startswith('Order of requested parameters does not match') + else: + assert False, msg_o + "parameters in wrong order." + + +def test_params_duplicate_name(): + params = 'Parameter1,Parameter1' + try: + subset_meta(meta, params) + except Exception as e: + assert isinstance(e, HAPIError) + assert str(e).startswith('Duplicate parameters in requested parameter list') + else: + assert False, msg_o + "duplicate parameter names." + + +def test_params_invalid_name(): + params = 'Parameter1,ParameterX' + try: + subset_meta(meta, params) + except Exception as e: + assert isinstance(e, HAPIError) + assert str(e).startswith("Parameter 'ParameterX' is not in metadata from server") + else: + assert False, msg_o + "invalid parameter name." + + +def test_params_empty_value(): + params = 'Parameter2,' + try: + subset_meta(meta, params) + except Exception as e: + assert isinstance(e, HAPIError) + assert str(e).startswith('Empty parameter name') + else: + assert False, msg_o + "empty parameter name." + + +def test_params_leading_space(): + params = ' Parameter1,Parameter2' + try: + subset_meta(meta, params) + except Exception as e: + assert isinstance(e, HAPIError) + assert str(e).startswith('Leading space') + else: + assert False, msg_o + "leading space in parameter name." + + +def test_params_trailing_space(): + params = 'Parameter1,Parameter2 ' + try: + subset_meta(meta, params) + except Exception as e: + assert isinstance(e, HAPIError) + assert str(e).startswith('Trailing space') + else: + assert False, msg_o + "trailing space in parameter name." + + +def test_params_time_given(): + params = 'Time,Parameter1' + subset_meta(meta, params) + assert len(meta['parameters']) == 2 + assert meta['parameters'][0]['name'] == 'Time' + assert meta['parameters'][1]['name'] == 'Parameter1' + + +def test_meta_duplicate_names(): + meta_dup = { + "parameters": [ + {"name": "Time"}, + {"name": "Parameter1"}, + {"name": "Parameter1"}, + {"name": "Parameter3"} + ] + } + params = 'Parameter1' + try: + subset_meta(meta_dup, params) + except Exception as e: + assert isinstance(e, HAPIError) + assert str(e).startswith('Duplicate parameter names in metadata returned by server') + else: + assert False, msg_o + "duplicate parameter names in metadata returned by server." + + +if __name__ == "__main__": + test_simple() + test_params_wrong_order() + test_params_duplicate_name() + test_params_invalid_name() + test_params_empty_value() + test_params_leading_space() + test_params_trailing_space() + test_params_time_given() + test_meta_duplicate_names() \ No newline at end of file