Skip to content

Commit 588df34

Browse files
committed
Initial ACDD Tests
An initial set of ACDD tests. Adapted from ioos/compliance_checker.
1 parent cbaf81a commit 588df34

14 files changed

Lines changed: 612 additions & 0 deletions

pyproject.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ exclude = ["**/*.ipynb"]
6464
xrlint = "xrlint.cli.main:main"
6565

6666
[project.optional-dependencies]
67+
acdd = [
68+
"isodate>=0.7.2",
69+
]
70+
71+
[dependency-groups]
6772
dev = [
6873
# Development tools
6974
"build",
@@ -93,3 +98,6 @@ Documentation = "https://bcdev.github.io/xrlint"
9398
Repository = "https://github.com/bcdev/xrlint"
9499
Changelog = "https://github.com/bcdev/xrlint/blob/main/CHANGES.md"
95100
Issues = "https://github.com/bcdev/xrlint/issues"
101+
102+
[tool.uv.pip]
103+
all-extras = true
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import xarray as xr
2+
from xrlint.testing import RuleTest, RuleTester
3+
4+
from xrlint.plugins.acdd.rules.attributes import (
5+
Attributes_1_3_Highly_Reccomended,
6+
)
7+
8+
valid_1_3_highly_rec_dataset = xr.Dataset(
9+
attrs={
10+
"title": "Tis only a test",
11+
"summary": "This is only a test dataset.",
12+
"keywords": "test, example, sample",
13+
"conventions": "ACDD-1.3",
14+
},
15+
)
16+
invalid_1_3_highly_rec_dataset = xr.Dataset()
17+
18+
19+
Attributes_1_3_Highly_ReccomendedTest = RuleTester.define_test(
20+
"1.3_attrs_highly_recommended",
21+
Attributes_1_3_Highly_Reccomended,
22+
valid=[RuleTest(dataset=valid_1_3_highly_rec_dataset)],
23+
invalid=[
24+
RuleTest(
25+
dataset=invalid_1_3_highly_rec_dataset,
26+
expected=[
27+
"Missing highly recommended attribute 'title'",
28+
"Missing highly recommended attribute 'keywords'",
29+
"Missing highly recommended attribute 'summary'",
30+
"Missing highly recommended attribute 'conventions'",
31+
],
32+
),
33+
],
34+
)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import xarray as xr
2+
from xrlint.testing import RuleTest, RuleTester
3+
4+
from xrlint.plugins.acdd.rules.conventions import Conventions
5+
6+
valid_dataset_0 = xr.Dataset(attrs={"Conventions": "ACDD-1.3"})
7+
8+
invalid_dataset_0 = xr.Dataset()
9+
invalid_dataset_1 = xr.Dataset(attrs={"Conventions": "ACDD-1.2"})
10+
invalid_dataset_2 = xr.Dataset(attrs={"Conventions": 1.3})
11+
12+
13+
ConventionsTest = RuleTester.define_test(
14+
"1.3_conventions",
15+
Conventions,
16+
valid=[
17+
RuleTest(dataset=valid_dataset_0),
18+
],
19+
invalid=[
20+
RuleTest(
21+
dataset=invalid_dataset_0,
22+
expected=["Missing attribute 'Conventions'."],
23+
),
24+
RuleTest(
25+
dataset=invalid_dataset_1,
26+
expected=[
27+
"Attribute 'Conventions' needs to contain 'ACDD-1.3' in addition to the current: 'ACDD-1.2'",
28+
],
29+
),
30+
RuleTest(
31+
dataset=invalid_dataset_2,
32+
expected=["Invalid attribute 'Conventions': 1.3"],
33+
),
34+
],
35+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import xarray as xr
2+
from xrlint.testing import RuleTest, RuleTester
3+
4+
from xrlint.plugins.acdd.rules.no_id_blanks import NoBlanksInID
5+
6+
valid_dataset_0 = xr.Dataset(attrs={"id": "testind_dataset"})
7+
8+
invalid_dataset_0 = xr.Dataset()
9+
invalid_dataset_1 = xr.Dataset(attrs={"id": "testing dataset"})
10+
11+
12+
IdBlanksTest = RuleTester.define_test(
13+
"1.3_no_blanks_in_id",
14+
NoBlanksInID,
15+
valid=[RuleTest(dataset=valid_dataset_0)],
16+
invalid=[
17+
RuleTest(
18+
dataset=invalid_dataset_0,
19+
expected=["Missing attribute 'id'"],
20+
),
21+
RuleTest(
22+
dataset=invalid_dataset_1,
23+
expected=["There should be no blanks in the id field"],
24+
),
25+
],
26+
)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import xarray as xr
2+
from xrlint.testing import RuleTest, RuleTester
3+
4+
from xrlint.plugins.acdd.rules.iso_dates import IsoDates
5+
6+
valid_dataset_0 = xr.Dataset(attrs={"date_created": "2023-10-05T12:34:56Z"})
7+
valid_dataset_1 = xr.Dataset(attrs={"date_modified": "2023-10-05"})
8+
valid_dataset_2 = xr.Dataset(attrs={"date_issued": "2023-10-05T12:34:56+00:00"})
9+
valid_dataset_3 = xr.Dataset(
10+
attrs={"date_metadata_modified": "2023-10-05T12:34:56-05:00"},
11+
)
12+
valid_dataset_4 = xr.Dataset() # No date attributes
13+
14+
15+
invalid_dataset_0 = xr.Dataset(attrs={"date_created": "10/05/2023"})
16+
invalid_dataset_1 = xr.Dataset(attrs={"date_issued": "2023-13-05"})
17+
invalid_dataset_2 = xr.Dataset(attrs={"date_modified": "2023-10-05 12:34:56"})
18+
invalid_dataset_3 = xr.Dataset(attrs={"date_metadata_modified": "2023/10/05"})
19+
invalid_dataset_4 = xr.Dataset(
20+
attrs={"date_created": "2023-10-05T25:34:56Z"},
21+
) # Invalid hour
22+
23+
IsoDatesTest = RuleTester.define_test(
24+
"1.3_dates_iso_format",
25+
IsoDates,
26+
valid=[
27+
RuleTest(dataset=valid_dataset_0),
28+
RuleTest(dataset=valid_dataset_1),
29+
RuleTest(dataset=valid_dataset_2),
30+
RuleTest(dataset=valid_dataset_3),
31+
RuleTest(dataset=valid_dataset_4),
32+
],
33+
invalid=[
34+
RuleTest(
35+
dataset=invalid_dataset_0,
36+
expected=["Attribute 'date_created' is not in ISO format: '10/05/2023'"],
37+
),
38+
RuleTest(
39+
dataset=invalid_dataset_1,
40+
expected=["Attribute 'date_issued' is not in ISO format: '2023-13-05'"],
41+
),
42+
RuleTest(
43+
dataset=invalid_dataset_2,
44+
expected=[
45+
"Attribute 'date_modified' is not in ISO format: '2023-10-05 12:34:56'",
46+
],
47+
),
48+
RuleTest(
49+
dataset=invalid_dataset_3,
50+
expected=[
51+
"Attribute 'date_metadata_modified' is not in ISO format: '2023/10/05'",
52+
],
53+
),
54+
RuleTest(
55+
dataset=invalid_dataset_4,
56+
expected=[
57+
"Attribute 'date_created' is not in ISO format: '2023-10-05T25:34:56Z'",
58+
],
59+
),
60+
],
61+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import xarray as xr
2+
from xrlint.testing import RuleTest, RuleTester
3+
4+
from xrlint.plugins.acdd.rules.metadata_link import MetadataLink
5+
6+
valid_dataset_0 = xr.Dataset(attrs={"metadata_link": "http://example.com/metadata"})
7+
valid_dataset_1 = xr.Dataset(attrs={"metadata_link": "https://example.com/metadata"})
8+
valid_dataset_2 = xr.Dataset()
9+
10+
invalid_dataset_0 = xr.Dataset(attrs={"metadata_link": "example.com/metadata"})
11+
12+
Metadata_LinkTest = RuleTester.define_test(
13+
"1.3_metadata_link",
14+
MetadataLink,
15+
valid=[
16+
RuleTest(dataset=valid_dataset_0),
17+
RuleTest(dataset=valid_dataset_1),
18+
RuleTest(dataset=valid_dataset_2),
19+
],
20+
invalid=[
21+
RuleTest(
22+
dataset=invalid_dataset_0,
23+
expected=[
24+
"Metadata URL should include http:// or https://: 'example.com/metadata'",
25+
],
26+
),
27+
],
28+
)

tests/plugins/acdd/test_plugin.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from unittest import TestCase
2+
3+
from xrlint.plugins.acdd import export_plugin
4+
5+
6+
class TestACDDPlugin(TestCase):
7+
def test_rules_complete(self):
8+
plugin = export_plugin()
9+
self.assertEqual(
10+
{
11+
"1.3_conventions",
12+
"1.0_attrs_suggested",
13+
"1.0_attrs_highly_recommended",
14+
"1.0_attrs_recommended",
15+
"1.3_attrs_recommended",
16+
"1.3_attrs_suggested",
17+
"1.3_attrs_highly_recommended",
18+
"1.3_no_blanks_in_id",
19+
"1.3_metadata_link",
20+
"1.3_dates_iso_format",
21+
},
22+
set(plugin.rules.keys()),
23+
)
24+
25+
def test_configs_complete(self):
26+
plugin = export_plugin()
27+
self.assertEqual(
28+
{
29+
"recommended",
30+
"acdd_1.3",
31+
"acdd_1.3_strict_reccomended",
32+
"acdd_1.3_strict",
33+
"acdd_1.3_warn",
34+
"acdd_1.1",
35+
"acdd_1.0",
36+
},
37+
set(plugin.configs.keys()),
38+
)

xrlint/plugins/acdd/__init__.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from xrlint.plugin import Plugin
2+
from xrlint.util.importutil import import_submodules
3+
4+
5+
def export_plugin() -> Plugin:
6+
from .plugin import plugin
7+
8+
import_submodules("xrlint.plugins.acdd.rules")
9+
10+
common_configs = [
11+
{
12+
"plugins": {
13+
"acdd": plugin,
14+
}
15+
}
16+
]
17+
18+
rules_1_0 = {
19+
"acdd/1.0-attrs-highly-recommended": "error",
20+
"acdd/1.0-attrs-recommended": "warn",
21+
"acdd/1.0-attrs-suggested": "warn",
22+
}
23+
24+
rules_1_1 = {
25+
"acdd/1.1-attrs-highly-recommended": "error",
26+
"acdd/1.1-attrs-recommended": "warn",
27+
"acdd/1.1-attrs-suggested": "warn",
28+
}
29+
30+
rules_1_3 = {
31+
"acdd/1.3-conventions": "error",
32+
"acdd/1.3-attrs-highly-recommended": "error",
33+
"acdd/1.3-attrs-recommended": "warn",
34+
"acdd/1.3-attrs-suggested": "warn",
35+
"acdd/1.3-no-blanks-in-id": "warn",
36+
"acdd/1.3-metadata-link": "warn",
37+
"acdd/1.3-dates-iso-format": "warn",
38+
}
39+
40+
plugin.define_config(
41+
"recommended", [*common_configs, {"name": "recommended", "rules": rules_1_3}]
42+
)
43+
44+
plugin.define_config(
45+
"acdd_1.3", [*common_configs, {"name": "ACDD 1.3", "rules": rules_1_3}]
46+
)
47+
48+
plugin.define_config(
49+
"acdd_1.3_strict_reccomended",
50+
[
51+
*common_configs,
52+
{
53+
"name": "ACDD 1.3 (strict recommended)",
54+
"rules": {
55+
**rules_1_3,
56+
"1.3-attrs-recommended": "error",
57+
},
58+
},
59+
],
60+
)
61+
62+
plugin.define_config(
63+
"acdd_1.3_strict",
64+
[
65+
*common_configs,
66+
{"name": "ACDD 1.3 (strict)", "rules": dict.fromkeys(rules_1_3, "error")},
67+
],
68+
)
69+
70+
plugin.define_config(
71+
"acdd_1.3_warn",
72+
[
73+
*common_configs,
74+
{
75+
"name": "ACDD 1.3 (as warnings)",
76+
"rules": dict.fromkeys(rules_1_3, "warn"),
77+
},
78+
],
79+
)
80+
81+
plugin.define_config(
82+
"acdd_1.1", [*common_configs, {"name": "ACDD 1.1", "rules": rules_1_1}]
83+
)
84+
85+
plugin.define_config(
86+
"acdd_1.0", [*common_configs, {"name": "ACDD 1.0", "rules": rules_1_0}]
87+
)
88+
89+
return plugin

xrlint/plugins/acdd/plugin.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from xrlint.plugin import new_plugin
2+
3+
plugin = new_plugin(
4+
"acdd",
5+
"1.3",
6+
docs_url="https://wiki.esipfed.org/Attribute_Convention_for_Data_Discovery_1-3",
7+
)

0 commit comments

Comments
 (0)