Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge develop into main for pre-release preparation #1101

Closed
wants to merge 12 commits into from
Closed
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ It currently supports the following sources and standards:
| Standard | Source | .nc/OPeNDAP/.cdl | SOS |
| ---------------------------------------------------------------------------------------------------- | ----------- | ------ | ------------------------------- |
| [ACDD (1.1, 1.3)](https://wiki.esipfed.org/Attribute_Convention_for_Data_Discovery_1-3) | Built-in | X | - |
| [CF (1.9)](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html) | Built-in | X | - |
| [CF (1.8)](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html) | Built-in | X | - |
| [CF (1.7)](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/cf-conventions.html) | Built-in | X | - |
| [CF (1.6)](http://cfconventions.org/cf-conventions/v1.6.0/cf-conventions.html) | Built-in | X | - |
Expand Down
23 changes: 14 additions & 9 deletions cchecker.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,25 @@ def _print_checker_name_header(checker_str):

def parse_options(opts):
"""
Helper function to parse possible options. Splits option after the first
colon to split into key/value pairs.
Helper function to parse possible options. Splits option into key/value
pairs and optionally a value for the checker option. The separator
is a colon.

:param opts: Iterable of strings with options
:rtype: dict
:return: Dictionary with keys as checker type (i.e. "cf", "acdd")
:return: Dictionary with keys as checker type (i.e. "cf", "acdd").
Each value is a dictionary where keys are checker options and values
are checker option values or None if not provided.
"""
options_dict = defaultdict(set)
options_dict = defaultdict(dict)
for opt_str in opts:
try:
checker_type, checker_opt = opt_str.split(":", 1)
checker_type, checker_opt, *checker_val = opt_str.split(":", 2)
checker_val = checker_val[0] if checker_val else None
except ValueError:
warnings.warn(f"Could not split option {opt_str}, ignoring", stacklevel=2)
else:
options_dict[checker_type].add(checker_opt)
options_dict[checker_type][checker_opt] = checker_val
return options_dict


Expand Down Expand Up @@ -174,8 +178,9 @@ def main():
checkers. Multiple options can be specified
via multiple invocations of this switch.
Options should be prefixed with a the
checker name followed by the option, e.g.
'<checker>:<option_name>'
checker name followed by the option,
potentially followed by a value, e.g.
'<checker>:<option_name>[:<option_value>]'

Available options:
'cf:enable_appendix_a_checks' - Allow check
Expand Down Expand Up @@ -235,7 +240,7 @@ def main():
print(f"IOOS compliance checker version {__version__}")
sys.exit(0)

options_dict = parse_options(args.option) if args.option else defaultdict(set)
options_dict = parse_options(args.option) if args.option else defaultdict(dict)

if args.describe_checks:
error_stat = 0
Expand Down
2 changes: 1 addition & 1 deletion compliance_checker/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def setup(self, ds):
def __init__(self, options=None):
self._defined_results = defaultdict(lambda: defaultdict(dict))
if options is None:
self.options = set()
self.options = {}
else:
self.options = options

Expand Down
2 changes: 1 addition & 1 deletion compliance_checker/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ def run_all(self, ds, checker_names, include_checks=None, skip_checks=None):
# use some kind of checker object with checker type and
# version baked in
checker_type_name = checker_name.split(":")[0]
checker_opts = self.options.get(checker_type_name, set())
checker_opts = self.options.get(checker_type_name, {})

# instantiate a Checker object
try:
Expand Down
2 changes: 1 addition & 1 deletion compliance_checker/tests/test_cf.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def test_appendix_a(self):
dataset = self.load_dataset(STATIC_FILES["bad_data_type"])
# Ordinarily, options would be specified in the checker constructor, but
# we set them manually here so we don't have to monkey patch `setUp`
self.cf.options = {"enable_appendix_a_checks"}
self.cf.options = {"enable_appendix_a_checks": None}
new_check = copy.deepcopy(self.cf)
self.cf.setup(dataset)
aa_results = self.cf.check_appendix_a(dataset)
Expand Down
28 changes: 28 additions & 0 deletions compliance_checker/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
import subprocess
import sys
from argparse import Namespace
from collections import defaultdict
import importlib.util
from importlib.machinery import SourceFileLoader

import pytest

Expand Down Expand Up @@ -268,3 +271,28 @@ def test_nczarr_pass_through(self, zarr_url):
output_format="text",
)
assert not errors


def test_parse_options():
"""Test the option parser of cchecker.py"""
# Load cchecker.py
cchecker_file_path = os.path.join(os.path.dirname(__file__), "..", "..",
"cchecker.py")
spec = importlib.util.spec_from_file_location("cchecker",
cchecker_file_path)
module = importlib.util.module_from_spec(spec)
SourceFileLoader(spec.name, spec.origin).exec_module(module)
# Simple test checker_type:checker_opt
opt_dict = module.parse_options(["cf:enable_appendix_a_checks"])
assert opt_dict == defaultdict(dict, {"cf": {"enable_appendix_a_checks": None}})
# Test case checker_type:checker_opt:checker_val
opt_dict = module.parse_options(
["type:opt:val", "type:opt2:val:2", "cf:enable_appendix_a_checks"],
)
assert opt_dict == defaultdict(
dict,
{
"type": {"opt": "val", "opt2": "val:2"},
"cf": {"enable_appendix_a_checks": None},
},
)
Loading