Repository: ioos/compliance-checker
Pull request #767 (2020-03-16 15:26:31)

Change standard_name_uri to standard_name_url

daltonkell: Error message:

```
=================================== FAILURES ===================================
________________________ TestACDD1_3.test_time_extents _________________________
self = test_time_extents ( compliance_checker.tests.test_acdd:TestACDD1_3.test_time_extents )
    def test_time_extents(self):
        '''
        Test that the time extents are being checked
        '''
        result = self.acdd.check_time_extents(self.ds)
>       self.assert_result_is_good(result)
compliance_checker/tests/test_acdd.py:434: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = test_time_extents ( compliance_checker.tests.test_acdd:TestACDD1_3.test_time_extents )
result = time_coverage_extents_match (*2): False (Failed to retrieve and convert times for variables time.)
    def assert_result_is_good(self, result):
        if isinstance(result.value, bool):
>           assert result.value is True
E           AssertionError
compliance_checker/tests/__init__.py:32: AssertionError
```

This error message is also present in #766. I suspect it's due to a dependency issue, most likely `pendulum`:

https://github.com/ioos/compliance-checker/blob/54b5300663b70e586ca429e2ecdad12f0e155314/compliance_checker/acdd.py#L532-L547

The `pendulum` version was recently upgraded to `2.1.0` https://github.com/sdispater/pendulum/releases

and that's the only instance where that error message can be returned. Digging in a little deeper.
daltonkell: ## UPDATE

The `pendulum` dependency isn't the problem -- it's `cftime`.

__TL;DR__

`netCDF4.num2date()` no longer returns `datetime` instances, but instead returns instances of `cftime.Datetime`

__Details__

Testing with the same dataset provided for the failed unit test, `ncei_gold_point_2.nc`, I encounter the following:

(`cftime==1.0.3.41`)
```
In [17]: nc4.num2date(ds.variables["time"][0], ds.variables["time"].units)                                             
Out[17]: datetime.datetime(2015, 3, 25, 22, 20, 17)
```

With the upgraded version of `cftime==1.1.1`:

```
In [6]: nc4.num2date(ds.variables["time"][0], ds.variables["time"].units)                                                 
Out[6]: cftime.DatetimeGregorian(2015-03-25 22:20:17)
```

`pendulum.instance()` only takes an argument of type `datetime`:

```
(Pdb) l
535                 # num2date returns as naive date, but with time adjusted to UTC
536                 # we need to attach timezone information here, or the date
537                 # subtraction from t_min/t_max will assume that a naive timestamp is
538                 # in the same time zone and cause erroneous results.
539                 # Pendulum uses UTC by default, but we are being explicit here
540  ->             time0 = pendulum.instance(num2date(ds.variables[timevar][0],
541                                           ds.variables[timevar].units), 'UTC')
542                 time1 = pendulum.instance(num2date(ds.variables[timevar][-1],
543                                           ds.variables[timevar].units), 'UTC')
544             except:
545                 return Result(BaseCheck.MEDIUM,
(Pdb) n
> /home/dalton/compliance-checker/compliance_checker/acdd.py(541)check_time_extents()
-> ds.variables[timevar].units), 'UTC')
(Pdb) n
ValueError: instance() only accepts datetime objects.
```

daltonkell: This behavior was adopted in version `1.1.0`:

> 2/12/2020: version 1.1.0 released. cftime.datetime instances are returned by default from num2date (instead of returning python datetime instances where possible (issue #136)). num2pydate convenience function added (always returns python datetime instances, issue #134). Fix for fraction seconds in reference date string (issue #140). Added daysinmonth attribute (issue #137).

I'll move this to a separate issue.
daltonkell: New issue in #768 
daltonkell: Addresses #754 

Patch:
diff --git a/compliance_checker/ioos.py b/compliance_checker/ioos.py
index 5e94ed1..fd77a18 100644
--- a/compliance_checker/ioos.py
+++ b/compliance_checker/ioos.py
@@ -412,7 +412,7 @@ class IOOS1_2Check(IOOSNCCheck):
 
         # geophysical variables must have the following attrs:
         self.geophys_check_var_attrs = self._default_check_var_attrs.union(set([
-            ("standard_name_uri", BaseCheck.MEDIUM),
+            ("standard_name_url", BaseCheck.MEDIUM),
             #( "platform", BaseCheck.HIGH) # checked under check_single_platform()
             #( "wmo_platform_code", BaseCheck.HIGH) # only "if applicable", see check_wmo_platform_code()
             #( "ancillary_variables", BaseCheck.HIGH) # only "if applicable", see _check_var_gts_ingest() 


Test patch:
diff --git a/compliance_checker/tests/test_ioos_profile.py b/compliance_checker/tests/test_ioos_profile.py
index c7daf3c..4cc80ac 100644
--- a/compliance_checker/tests/test_ioos_profile.py
+++ b/compliance_checker/tests/test_ioos_profile.py
@@ -321,7 +321,7 @@ class TestIOOS1_2(BaseTestCase):
         temp = ds.createVariable("temp", np.float64, fill_value=9999999999.) # _FillValue
         temp.setncattr("missing_value", 9999999999.)
         temp.setncattr("standard_name", "sea_surface_temperature")
-        temp.setncattr("standard_name_uri", "http://cfconventions.org/Data/cf-standard-names/64/build/cf-standard-name-table.html")
+        temp.setncattr("standard_name_url", "http://cfconventions.org/Data/cf-standard-names/64/build/cf-standard-name-table.html")
         temp.setncattr("units", "degree_C")
         temp.setncattr("platform", "myPlatform")
 
@@ -344,7 +344,7 @@ class TestIOOS1_2(BaseTestCase):
         ds = MockTimeSeries(default_fill_value=9999999999.) # time, lat, lon, depth 
 
         ds.variables["time"].setncattr("standard_name", "time")
-        ds.variables["time"].setncattr("standard_name_uri", "time")
+        ds.variables["time"].setncattr("standard_name_url", "http://cfconventions.org/Data/cf-standard-names/64/build/cf-standard-name-table.html")
         ds.variables["time"].setncattr("units", "hours since 1970-01-01T00:00:00")
         ds.variables["time"].setncattr("missing_value", 9999999999.)