diff --git a/CHANGES.md b/CHANGES.md
index ee54e97..51aeb22 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -23,6 +23,8 @@
dictionary, or a name that refers to a named configuration of a plugin.
- Other changes:
+ - Property `config` of `Linter` now returns a `ConfigList` instead
+ of a `Config` object.
- Directories that are recognized by file patterns associated with a non-empty
configuration object are no longer recursively traversed.
- Node path names now contain the dataset index if a file path
diff --git a/notebooks/mkdataset.py b/notebooks/mkdataset.py
index c15f0cf..28d4c24 100644
--- a/notebooks/mkdataset.py
+++ b/notebooks/mkdataset.py
@@ -36,7 +36,7 @@ def make_dataset() -> xr.Dataset:
attrs={
"standard_name": "time",
"long_name": "time",
- "units": "days since 2020-01-01 utc",
+ "units": "days since 2020-01-01 +0:00",
"calendar": "gregorian",
},
),
@@ -71,7 +71,7 @@ def make_dataset_with_issues() -> xr.Dataset:
invalid_ds.x.attrs["axis"] = "x"
del invalid_ds.y.attrs["standard_name"]
invalid_ds.y.attrs["axis"] = "y"
- invalid_ds.time.attrs["units"] = "days since 2020-01-01 ß0:000:00"
+ invalid_ds.time.attrs["units"] = "days since 2020-01-01 UTC"
invalid_ds.attrs = {}
invalid_ds.sst.attrs["units"] = 1
invalid_ds["sst_avg"] = xr.DataArray(
diff --git a/notebooks/xrlint-linter.ipynb b/notebooks/xrlint-linter.ipynb
index 0c1e987..cc8a02d 100644
--- a/notebooks/xrlint-linter.ipynb
+++ b/notebooks/xrlint-linter.ipynb
@@ -39,7 +39,7 @@
{
"data": {
"text/plain": [
- "'0.3.0.dev0'"
+ "'0.4.0.dev0'"
]
},
"execution_count": 2,
@@ -51,6 +51,13 @@
"xrl.version"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Make a valid xarray dataset for demonstration:"
+ ]
+ },
{
"cell_type": "code",
"execution_count": 3,
@@ -437,38 +444,38 @@
" * time (time) int64 32B 0 365 730 1095\n",
" spatial_ref int64 8B 0\n",
"Data variables:\n",
- " sst (time, y, x) float64 192B 0.357 0.4776 0.8956 ... 0.2892 0.1911\n",
- " sst_anomaly (time, y, x) float64 192B 0.1693 0.4643 ... 0.6467 0.9646\n",
+ " sst (time, y, x) float64 192B 0.8258 0.8193 ... 0.7022 0.5899\n",
+ " sst_anomaly (time, y, x) float64 192B 0.4368 0.9209 ... 0.1712 0.1026\n",
"Attributes:\n",
- " title: SST-Climatology Subset
PandasIndex
PandasIndex(Index([-180.0, 180.0], dtype='float64', name='x'))
PandasIndex
PandasIndex(Index([-90.0, 0.0, 90.0], dtype='float64', name='y'))
PandasIndex
PandasIndex(Index([0, 365, 730, 1095], dtype='int64', name='time'))
- title :
- SST-Climatology Subset
"
+ " title: SST-Climatology SubsetPandasIndex
PandasIndex(Index([-180.0, 180.0], dtype='float64', name='x'))
PandasIndex
PandasIndex(Index([-90.0, 0.0, 90.0], dtype='float64', name='y'))
PandasIndex
PandasIndex(Index([0, 365, 730, 1095], dtype='int64', name='time'))
- title :
- SST-Climatology Subset
"
],
"text/plain": [
" Size: 464B\n",
@@ -479,8 +486,8 @@
" * time (time) int64 32B 0 365 730 1095\n",
" spatial_ref int64 8B 0\n",
"Data variables:\n",
- " sst (time, y, x) float64 192B 0.357 0.4776 0.8956 ... 0.2892 0.1911\n",
- " sst_anomaly (time, y, x) float64 192B 0.1693 0.4643 ... 0.6467 0.9646\n",
+ " sst (time, y, x) float64 192B 0.8258 0.8193 ... 0.7022 0.5899\n",
+ " sst_anomaly (time, y, x) float64 192B 0.4368 0.9209 ... 0.1712 0.1026\n",
"Attributes:\n",
" title: SST-Climatology Subset"
]
@@ -516,7 +523,7 @@
"<dataset> - ok
\n"
],
"text/plain": [
- "Result(config=Config(name=None, files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins={'__core__': Plugin(meta=PluginMeta(name='__core__', version='0.3.0.dev0', ref='xrlint.plugins.core:export_plugin'), rules={'coords-for-dims': Rule(meta=RuleMeta(name='coords-for-dims', version='1.0.0', description='Dimensions of data variables should have corresponding coordinates.', schema=None, ref=None, docs_url=None, type='problem'), op_class=), 'dataset-title-attr': Rule(meta=RuleMeta(name='dataset-title-attr', version='1.0.0', description='Datasets should be given a non-empty title.', schema=None, ref=None, docs_url=None, type='suggestion'), op_class=), 'grid-mappings': Rule(meta=RuleMeta(name='grid-mappings', version='1.0.0', description='Grid mappings, if any, shall have valid grid mapping coordinate variables.', schema=None, ref=None, docs_url=None, type='problem'), op_class=), 'lat-coordinate': Rule(meta=RuleMeta(name='lat-coordinate', version='1.0.0', description='Latitude coordinate should have standard units and standard names.', schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#latitude-coordinate', type='problem'), op_class=), 'lon-coordinate': Rule(meta=RuleMeta(name='lon-coordinate', version='1.0.0', description='Longitude coordinate should have standard units and standard names.', schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#longitude-coordinate', type='problem'), op_class=), 'no-empty-attrs': Rule(meta=RuleMeta(name='no-empty-attrs', version='1.0.0', description='Every dataset element should have metadata that describes it.', schema=None, ref=None, docs_url=None, type='suggestion'), op_class=), 'time-coordinate': Rule(meta=RuleMeta(name='time-coordinate', version='1.0.0', description=\"Time coordinate (standard_name='time') should have unambiguous time units encoding.\", schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#time-coordinate', type='problem'), op_class=), 'var-units-attr': Rule(meta=RuleMeta(name='var-units-attr', version='1.0.0', description=\"Every variable should have a valid 'units' attribute.\", schema=None, ref=None, docs_url=None, type='suggestion'), op_class=)}, processors={}, configs={'recommended': Config(name='recommended', files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins=None, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=1, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=1, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=1, args=(), kwargs={})}, settings=None), 'all': Config(name='all', files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins=None, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=2, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=2, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=2, args=(), kwargs={})}, settings=None)})}, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=1, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=1, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=1, args=(), kwargs={})}, settings=None), file_path='', messages=[], fixable_error_count=0, fixable_warning_count=0, error_count=0, fatal_error_count=0, warning_count=0)"
+ "Result(config=Config(name=None, files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins={'__core__': Plugin(meta=PluginMeta(name='__core__', version='0.4.0.dev0', ref='xrlint.plugins.core:export_plugin'), rules={'coords-for-dims': Rule(meta=RuleMeta(name='coords-for-dims', version='1.0.0', description='Dimensions of data variables should have corresponding coordinates.', schema=None, ref=None, docs_url=None, type='problem'), op_class=), 'dataset-title-attr': Rule(meta=RuleMeta(name='dataset-title-attr', version='1.0.0', description='Datasets should be given a non-empty title.', schema=None, ref=None, docs_url=None, type='suggestion'), op_class=), 'flags': Rule(meta=RuleMeta(name='flags', version='1.0.0', description=\"Validate attributes 'flag_values', 'flag_masks' and 'flag_meanings' that make variables that contain flag values self describing. \", schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#flags', type='suggestion'), op_class=), 'grid-mappings': Rule(meta=RuleMeta(name='grid-mappings', version='1.0.0', description='Grid mappings, if any, shall have valid grid mapping coordinate variables.', schema=None, ref=None, docs_url=None, type='problem'), op_class=), 'lat-coordinate': Rule(meta=RuleMeta(name='lat-coordinate', version='1.0.0', description='Latitude coordinate should have standard units and standard names.', schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#latitude-coordinate', type='problem'), op_class=), 'lon-coordinate': Rule(meta=RuleMeta(name='lon-coordinate', version='1.0.0', description='Longitude coordinate should have standard units and standard names.', schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#longitude-coordinate', type='problem'), op_class=), 'no-empty-attrs': Rule(meta=RuleMeta(name='no-empty-attrs', version='1.0.0', description='Every dataset element should have metadata that describes it.', schema=None, ref=None, docs_url=None, type='suggestion'), op_class=), 'no-empty-chunks': Rule(meta=RuleMeta(name='no-empty-chunks', version='1.0.0', description='Empty chunks should not be encoded and written. The rule currently applies to Zarr format only.', schema=None, ref=None, docs_url='https://docs.xarray.dev/en/stable/generated/xarray.Dataset.to_zarr.html#xarray-dataset-to-zarr', type='suggestion'), op_class=), 'time-coordinate': Rule(meta=RuleMeta(name='time-coordinate', version='1.0.0', description='Time coordinates should have valid and unambiguous time units encoding.', schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#time-coordinate', type='problem'), op_class=), 'var-units-attr': Rule(meta=RuleMeta(name='var-units-attr', version='1.0.0', description=\"Every variable should have a valid 'units' attribute.\", schema=None, ref=None, docs_url=None, type='suggestion'), op_class=)}, processors={}, configs={'recommended': [Config(name='recommended', files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins=None, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=1, args=(), kwargs={}), 'flags': RuleConfig(severity=2, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=1, args=(), kwargs={}), 'no-empty-chunks': RuleConfig(severity=1, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=1, args=(), kwargs={})}, settings=None)], 'all': [Config(name='all', files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins=None, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=2, args=(), kwargs={}), 'flags': RuleConfig(severity=2, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-chunks': RuleConfig(severity=2, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=2, args=(), kwargs={})}, settings=None)]})}, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=1, args=(), kwargs={}), 'flags': RuleConfig(severity=2, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=1, args=(), kwargs={}), 'no-empty-chunks': RuleConfig(severity=1, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=1, args=(), kwargs={})}, settings=None), file_path='', messages=[], fixable_error_count=0, fixable_warning_count=0, error_count=0, fatal_error_count=0, warning_count=0)"
]
},
"execution_count": 5,
@@ -528,6 +535,13 @@
"linter.verify_dataset(ds)"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Make a xarray dataset with some issues for demonstration:"
+ ]
+ },
{
"cell_type": "code",
"execution_count": 6,
@@ -914,38 +928,38 @@
" * time (time) int64 32B 0 365 730 1095\n",
" spatial_ref int64 8B 0\n",
"Data variables:\n",
- " sst (time, y, x) float64 192B 0.9673 0.8684 ... 0.6397 0.2261\n",
- " sst_anomaly (time, y, x) float64 192B 0.5013 0.1469 0.03853 ... 0.51 0.9694\n",
- " sst_avg (x, y) float64 48B 0.5494 0.02223 0.5723 0.4118 0.1869 0.872sst
(time, y, x)
float64
0.9673 0.8684 ... 0.6397 0.2261
- units :
- 1
- grid_mapping :
- spatial_ref
array([[[0.96731725, 0.8684109 ],\n",
- " [0.39619977, 0.59997665],\n",
- " [0.63287615, 0.89969016]],\n",
- "\n",
- " [[0.9319926 , 0.58000176],\n",
- " [0.82350634, 0.34917117],\n",
- " [0.86295035, 0.28466155]],\n",
- "\n",
- " [[0.54803602, 0.51662934],\n",
- " [0.52600463, 0.6926919 ],\n",
- " [0.85294568, 0.30917634]],\n",
- "\n",
- " [[0.32025665, 0.22962375],\n",
- " [0.10266749, 0.23635291],\n",
- " [0.63968365, 0.2260538 ]]])
sst_anomaly
(time, y, x)
float64
0.5013 0.1469 ... 0.51 0.9694
- units :
- kelvin
- grid_mapping :
- spatial_ref
array([[[0.5012984 , 0.14688672],\n",
- " [0.03852958, 0.87815287],\n",
- " [0.15632951, 0.76000962]],\n",
- "\n",
- " [[0.44990288, 0.45157612],\n",
- " [0.57644988, 0.1373151 ],\n",
- " [0.83785531, 0.24725167]],\n",
- "\n",
- " [[0.20564946, 0.67642054],\n",
- " [0.035706 , 0.96148924],\n",
- " [0.39731164, 0.13817667]],\n",
- "\n",
- " [[0.58632619, 0.71732863],\n",
- " [0.13652191, 0.57510901],\n",
- " [0.50999833, 0.96943729]]])
sst_avg
(x, y)
float64
0.5494 0.02223 ... 0.1869 0.872
array([[0.5494279 , 0.02223383, 0.57233653],\n",
- " [0.41180829, 0.18686494, 0.87197388]])
PandasIndex
PandasIndex(Index([-180.0, 180.0], dtype='float64', name='x'))
PandasIndex
PandasIndex(Index([-90.0, 0.0, 90.0], dtype='float64', name='y'))
PandasIndex
PandasIndex(Index([0, 365, 730, 1095], dtype='int64', name='time'))
"
+ " sst (time, y, x) float64 192B 0.6958 0.9708 ... 0.2524 0.9463\n",
+ " sst_anomaly (time, y, x) float64 192B 0.5294 0.5702 ... 0.3938 0.9155\n",
+ " sst_avg (x, y) float64 48B 0.812 0.2143 0.8362 0.9635 0.1922 0.518sst
(time, y, x)
float64
0.6958 0.9708 ... 0.2524 0.9463
- units :
- 1
- grid_mapping :
- spatial_ref
array([[[0.69580543, 0.97075112],\n",
+ " [0.76247965, 0.31191372],\n",
+ " [0.03834036, 0.48655306]],\n",
+ "\n",
+ " [[0.00692811, 0.89908256],\n",
+ " [0.23565985, 0.40511646],\n",
+ " [0.8162953 , 0.95918601]],\n",
+ "\n",
+ " [[0.93929298, 0.71756946],\n",
+ " [0.69098024, 0.98439265],\n",
+ " [0.15293897, 0.30110137]],\n",
+ "\n",
+ " [[0.29577494, 0.92746276],\n",
+ " [0.2868703 , 0.75824404],\n",
+ " [0.25235165, 0.94634646]]])
sst_anomaly
(time, y, x)
float64
0.5294 0.5702 ... 0.3938 0.9155
- units :
- kelvin
- grid_mapping :
- spatial_ref
array([[[0.52935486, 0.57022606],\n",
+ " [0.34320833, 0.23795523],\n",
+ " [0.4366121 , 0.49972383]],\n",
+ "\n",
+ " [[0.51344211, 0.86197788],\n",
+ " [0.7608243 , 0.95160728],\n",
+ " [0.315642 , 0.50286674]],\n",
+ "\n",
+ " [[0.87833787, 0.68423473],\n",
+ " [0.5596588 , 0.25342987],\n",
+ " [0.78854287, 0.17878567]],\n",
+ "\n",
+ " [[0.53135147, 0.29527431],\n",
+ " [0.82995687, 0.19441664],\n",
+ " [0.39377428, 0.91545353]]])
sst_avg
(x, y)
float64
0.812 0.2143 ... 0.1922 0.518
array([[0.81200122, 0.21425538, 0.83621372],\n",
+ " [0.96347014, 0.19222239, 0.51801288]])
PandasIndex
PandasIndex(Index([-180.0, 180.0], dtype='float64', name='x'))
PandasIndex
PandasIndex(Index([-90.0, 0.0, 90.0], dtype='float64', name='y'))
PandasIndex
PandasIndex(Index([0, 365, 730, 1095], dtype='int64', name='time'))
"
],
"text/plain": [
" Size: 512B\n",
@@ -956,9 +970,9 @@
" * time (time) int64 32B 0 365 730 1095\n",
" spatial_ref int64 8B 0\n",
"Data variables:\n",
- " sst (time, y, x) float64 192B 0.9673 0.8684 ... 0.6397 0.2261\n",
- " sst_anomaly (time, y, x) float64 192B 0.5013 0.1469 0.03853 ... 0.51 0.9694\n",
- " sst_avg (x, y) float64 48B 0.5494 0.02223 0.5723 0.4118 0.1869 0.872"
+ " sst (time, y, x) float64 192B 0.6958 0.9708 ... 0.2524 0.9463\n",
+ " sst_anomaly (time, y, x) float64 192B 0.5294 0.5702 ... 0.3938 0.9155\n",
+ " sst_avg (x, y) float64 48B 0.812 0.2143 0.8362 0.9635 0.1922 0.518"
]
},
"execution_count": 6,
@@ -984,19 +998,19 @@
"<dataset>:
\n",
"\n",
"\n",
- "| dataset | warn | Missing 'title' attribute in dataset. | dataset-title-attr |
\n",
- "| dataset.coords['y'] | error | Attribute 'standard_name' should be 'latitude', was None. | lat-coordinate |
\n",
- "| dataset.coords['y'] | error | Attribute 'axis' should be 'Y', was 'y'. | lat-coordinate |
\n",
- "| dataset.coords['x'] | error | Attribute 'units' should be 'degrees_east', was 'degrees'. | lon-coordinate |
\n",
- "| dataset.coords['x'] | error | Attribute 'axis' should be 'X', was 'x'. | lon-coordinate |
\n",
- "| dataset.attrs | warn | Missing metadata, attributes are empty. | no-empty-attrs |
\n",
- "| dataset.coords['time'] | error | Missing timezone in 'units' attribute: days since 2020-01-01 ß0:000:00 | time-coordinate |
\n",
- "| dataset.data_vars['sst'] | warn | Invalid 'units' attribute in variable 'sst'. | var-units-attr |
\n",
+ "| dataset | warn | Missing 'title' attribute in dataset. | dataset-title-attr |
\n",
+ "| dataset.coords['y'] | error | Attribute 'standard_name' should be 'latitude', was None. | lat-coordinate |
\n",
+ "| dataset.coords['y'] | error | Attribute 'axis' should be 'Y', was 'y'. | lat-coordinate |
\n",
+ "| dataset.coords['x'] | error | Attribute 'units' should be 'degrees_east', was 'degrees'. | lon-coordinate |
\n",
+ "| dataset.coords['x'] | error | Attribute 'axis' should be 'X', was 'x'. | lon-coordinate |
\n",
+ "| dataset.attrs | warn | Missing metadata, attributes are empty. | no-empty-attrs |
\n",
+ "| dataset.coords['time'] | error | Invalid 'units' attribute: 'days since 2020-01-01 UTC'. | time-coordinate |
\n",
+ "| dataset.data_vars['sst'] | warn | Invalid 'units' attribute in variable 'sst'. | var-units-attr |
\n",
"\n",
"
8 problems (5 errors and 3 warnings)
\n"
],
"text/plain": [
- "Result(config=Config(name=None, files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins={'__core__': Plugin(meta=PluginMeta(name='__core__', version='0.3.0.dev0', ref='xrlint.plugins.core:export_plugin'), rules={'coords-for-dims': Rule(meta=RuleMeta(name='coords-for-dims', version='1.0.0', description='Dimensions of data variables should have corresponding coordinates.', schema=None, ref=None, docs_url=None, type='problem'), op_class=), 'dataset-title-attr': Rule(meta=RuleMeta(name='dataset-title-attr', version='1.0.0', description='Datasets should be given a non-empty title.', schema=None, ref=None, docs_url=None, type='suggestion'), op_class=), 'grid-mappings': Rule(meta=RuleMeta(name='grid-mappings', version='1.0.0', description='Grid mappings, if any, shall have valid grid mapping coordinate variables.', schema=None, ref=None, docs_url=None, type='problem'), op_class=), 'lat-coordinate': Rule(meta=RuleMeta(name='lat-coordinate', version='1.0.0', description='Latitude coordinate should have standard units and standard names.', schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#latitude-coordinate', type='problem'), op_class=), 'lon-coordinate': Rule(meta=RuleMeta(name='lon-coordinate', version='1.0.0', description='Longitude coordinate should have standard units and standard names.', schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#longitude-coordinate', type='problem'), op_class=), 'no-empty-attrs': Rule(meta=RuleMeta(name='no-empty-attrs', version='1.0.0', description='Every dataset element should have metadata that describes it.', schema=None, ref=None, docs_url=None, type='suggestion'), op_class=), 'time-coordinate': Rule(meta=RuleMeta(name='time-coordinate', version='1.0.0', description=\"Time coordinate (standard_name='time') should have unambiguous time units encoding.\", schema=None, ref=None, docs_url='https://cfconventions.org/cf-conventions/cf-conventions.html#time-coordinate', type='problem'), op_class=), 'var-units-attr': Rule(meta=RuleMeta(name='var-units-attr', version='1.0.0', description=\"Every variable should have a valid 'units' attribute.\", schema=None, ref=None, docs_url=None, type='suggestion'), op_class=)}, processors={}, configs={'recommended': Config(name='recommended', files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins=None, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=1, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=1, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=1, args=(), kwargs={})}, settings=None), 'all': Config(name='all', files=None, ignores=None, linter_options=None, opener_options=None, processor=None, plugins=None, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=2, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=2, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=2, args=(), kwargs={})}, settings=None)})}, rules={'coords-for-dims': RuleConfig(severity=2, args=(), kwargs={}), 'dataset-title-attr': RuleConfig(severity=1, args=(), kwargs={}), 'grid-mappings': RuleConfig(severity=2, args=(), kwargs={}), 'lat-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'lon-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'no-empty-attrs': RuleConfig(severity=1, args=(), kwargs={}), 'time-coordinate': RuleConfig(severity=2, args=(), kwargs={}), 'var-units-attr': RuleConfig(severity=1, args=(), kwargs={})}, settings=None), file_path='', messages=[Message(message=\"Missing 'title' attribute in dataset.\", node_path='dataset', rule_id='dataset-title-attr', severity=1, fatal=None, fix=None, suggestions=None), Message(message=\"Attribute 'standard_name' should be 'latitude', was None.\", node_path=\"dataset.coords['y']\", rule_id='lat-coordinate', severity=2, fatal=None, fix=None, suggestions=None), Message(message=\"Attribute 'axis' should be 'Y', was 'y'.\", node_path=\"dataset.coords['y']\", rule_id='lat-coordinate', severity=2, fatal=None, fix=None, suggestions=None), Message(message=\"Attribute 'units' should be 'degrees_east', was 'degrees'.\", node_path=\"dataset.coords['x']\", rule_id='lon-coordinate', severity=2, fatal=None, fix=None, suggestions=None), Message(message=\"Attribute 'axis' should be 'X', was 'x'.\", node_path=\"dataset.coords['x']\", rule_id='lon-coordinate', severity=2, fatal=None, fix=None, suggestions=None), Message(message='Missing metadata, attributes are empty.', node_path='dataset.attrs', rule_id='no-empty-attrs', severity=1, fatal=None, fix=None, suggestions=[Suggestion(desc='Make sure to add appropriate metadata attributes to dataset elements.', data=None, fix=None)]), Message(message=\"Missing timezone in 'units' attribute: days since 2020-01-01 ß0:000:00\", node_path=\"dataset.coords['time']\", rule_id='time-coordinate', severity=2, fatal=None, fix=None, suggestions=[Suggestion(desc=\"Specify 'units' attribute using format ' since