Repository: ioos/compliance-checker

Issue:
Coords dont define cf_role
Update an existing check or add a new one to make sure that any referenced coordinates, either coordinate variables, or auxiliary coordinate variables directly associated with a variable don't define `cf_role`.



Discussion:
This comes from reviewing #284 


Resolving patch:
diff --git a/compliance_checker/cf/cf.py b/compliance_checker/cf/cf.py
--- a/compliance_checker/cf/cf.py
+++ b/compliance_checker/cf/cf.py
@@ -2930,6 +2930,24 @@ def check_compression(self, ds):
     #
     ###############################################################################
 
+    def check_instance_variables(self, ds):
+        '''
+        Check that no referenced coordinates (coordinate variables or auxiliary coordinates) define cf_role
+
+        :param netCDF4.Dataset ds: An open netCDF dataset
+        '''
+
+        ret_val = []
+        all_coords = self._find_coord_vars(ds) + self._find_aux_coord_vars(ds)
+        for variable in ds.get_variables_by_attributes(cf_role=lambda x: x is not None):
+            is_not_coord = TestCtx(BaseCheck.HIGH,
+                                   "§9.5 Instance Variable {} is not referenced as a coordinate variable"
+                                   "".format(variable.name))
+            is_not_coord.assert_true(variable.name not in all_coords,
+                                     "{} must not be referenced as a coordinate".format(variable.name))
+            ret_val.append(is_not_coord.to_result())
+        return ret_val
+
     @is_likely_dsg
     def check_all_features_are_same_type(self, ds):
         """


Test patch:
diff --git a/compliance_checker/tests/data/bad-instance.cdl b/compliance_checker/tests/data/bad-instance.cdl
new file mode 100644
--- /dev/null
+++ b/compliance_checker/tests/data/bad-instance.cdl
@@ -0,0 +1,23 @@
+netcdf {
+dimensions:
+    time = 2;
+    max_strlen = 50; 
+    station_id = 2;
+variables:
+    double time(time);
+        time:units = "seconds since 1970-01-01";
+        time:standard_name = "time";
+    char station_name(station_id, max_strlen);
+        station_name:cf_role = "timeseries_id";
+    float temp(time);
+        temp:standard_name = "air_temperature";
+        temp:units = "deg_C";
+        temp:coordinates = "time lat lon station_name"; // illegal in cf 1.6
+    double lat;
+        lat:standard_name = "latitude";
+        lat:units = "degrees_north";
+    double lon;
+        lon:standard_name = "longitude";
+        lon:units = "degrees_east";
+
+}
diff --git a/compliance_checker/tests/resources.py b/compliance_checker/tests/resources.py
--- a/compliance_checker/tests/resources.py
+++ b/compliance_checker/tests/resources.py
@@ -80,4 +80,5 @@ def generate_dataset(cdl_path, nc_path):
     '3d-static-grid'                       : get_filename('tests/data/3d-static-grid.cdl'),
     'illegal-vertical'                     : get_filename('tests/data/illegal-vertical.cdl'),
     'illegal-aux-coords'                   : get_filename('tests/data/illegal-aux-coords.cdl'),
+    'bad-instance'                         : get_filename('tests/data/bad-instance.cdl'),
 }
diff --git a/compliance_checker/tests/test_cf.py b/compliance_checker/tests/test_cf.py
--- a/compliance_checker/tests/test_cf.py
+++ b/compliance_checker/tests/test_cf.py
@@ -839,6 +839,14 @@ def test_check_packed_data(self):
         self.assertTrue(results[2].value)
         self.assertFalse(results[3].value)
 
+    def test_check_instance_variable(self):
+        dataset = self.load_dataset(STATIC_FILES['bad-instance'])
+        results = self.cf.check_instance_variables(dataset)
+
+        result_dict = {result.name: result for result in results}
+        result = result_dict[u'§9.5 Instance Variable station_name is not referenced as a coordinate variable']
+        assert result.value == (0, 1)
+
     def test_check_compression(self):
         dataset = self.load_dataset(STATIC_FILES['bad_data_type'])
         results = self.cf.check_compression(dataset)