Repository: ioos/compliance-checker
Pull request #903 (2022-01-17 19:40:18)

Fix undefined variables/tests, linter fixes
Fixes a number of undefined variables and add some tests where coverage is not present.  Also address various linter messages.
Addresses #898.


Patch:
diff --git a/compliance_checker/cf/cf.py b/compliance_checker/cf/cf.py
index 3fc3cf1..a98f455 100644
--- a/compliance_checker/cf/cf.py
+++ b/compliance_checker/cf/cf.py
@@ -43,7 +43,7 @@ def print_exceptions(f):
     def wrapper(*args, **kwargs):
         try:
             return f(*args, **kwargs)
-        except Exception as e:
+        except:
             from traceback import print_exc
 
             print_exc()
@@ -2870,7 +2870,6 @@ class CF1_6Check(CFNCCheck):
         """
         ret_val = []
 
-        z_variables = cfutil.get_z_variables(ds)
         deprecated_units = ["level", "layer", "sigma_level"]
 
         ret_val.extend(
@@ -3136,7 +3135,6 @@ class CF1_6Check(CFNCCheck):
         for name in geophysical_variables:
             no_duplicates = TestCtx(BaseCheck.HIGH, self.section_titles["5"])
             axis_map = cfutil.get_axis_map(ds, name)
-            axes = []
             # For every coordinate associated with this variable, keep track of
             # which coordinates define an axis and assert that there are no
             # duplicate axis attributes defined in the set of associated
@@ -4066,7 +4064,6 @@ class CF1_6Check(CFNCCheck):
                     BaseCheck.MEDIUM, False, (self.section_titles["7.4"]), reasoning
                 )
                 ret_val.append(result)
-                return ret_val
 
             # make sure the climatology variable referenced actually exists
             elif clim_coord_var.climatology not in ds.variables:
@@ -4079,7 +4076,6 @@ class CF1_6Check(CFNCCheck):
                     BaseCheck.MEDIUM, False, (self.section_titles["7.4"]), reasoning
                 )
                 ret_val.append(result)
-                return ret_val
 
             # check that coordinate bounds are in the proper order.
             # make sure last elements are boundary variable specific dimensions
@@ -4089,24 +4085,36 @@ class CF1_6Check(CFNCCheck):
                     : clim_coord_var.ndim
                 ]
             ):
+                total_climate_count += 1
                 reasoning.append(
                     "Climatology variable coordinates are in improper order: {}. Bounds-specific dimensions should be last".format(
                         ds.variables[clim_coord_var.climatology].dimensions
                     )
                 )
-                return ret_val
+                result = Result(
+                    BaseCheck.MEDIUM,
+                    (valid_climate_count, total_climate_count),
+                    (self.section_titles["7.4"]),
+                    reasoning,
+                )
+                ret_val.append(result)
 
-            elif (
-                ds.dimensions[
+            elif (ds.dimensions[
                     ds.variables[clim_coord_var.climatology].dimensions[-1]
-                ].size
-                != 2
-            ):
+                ].size != 2):
                 reasoning.append(
-                    "Climatology dimension {} should only contain two elements".format(
-                        boundary_variable.dimensions
+                    "Climatology dimension \"{}\" should only contain two elements".format(
+                        ds.variables[clim_coord_var.climatology].name
                     )
                 )
+                total_climate_count += 1
+                result = Result(
+                    BaseCheck.MEDIUM,
+                    (valid_climate_count, total_climate_count),
+                    (self.section_titles["7.4"]),
+                    reasoning,
+                )
+                ret_val.append(result)
 
             # passed all these checks, so we can add this clim_coord_var to our total list
             all_clim_coord_var_names.append(clim_coord_var.name)
@@ -4400,10 +4408,9 @@ class CF1_6Check(CFNCCheck):
         """
         valid_roles = ["timeseries_id", "profile_id", "trajectory_id"]
         variable_count = 0
+        valid_cf_role = TestCtx(BaseCheck.HIGH, self.section_titles["9.5"])
         for variable in ds.get_variables_by_attributes(cf_role=lambda x: x is not None):
             variable_count += 1
-            name = variable.name
-            valid_cf_role = TestCtx(BaseCheck.HIGH, self.section_titles["9.5"])
             cf_role = variable.cf_role
             valid_cf_role.assert_true(
                 cf_role in valid_roles,
@@ -5183,7 +5190,6 @@ class CF1_7Check(CF1_6Check):
     def check_grid_mapping(self, ds):
         __doc__ = super(CF1_7Check, self).check_grid_mapping.__doc__
         prev_return = super(CF1_7Check, self).check_grid_mapping(ds)
-        ret_val = []
         grid_mapping_variables = cfutil.get_grid_mapping_variables(ds)
         for var_name in sorted(grid_mapping_variables):
             var = ds.variables[var_name]
@@ -5237,7 +5243,8 @@ class CF1_7Check(CF1_6Check):
                 )
             elif len_vdatum_name_attrs == 1:
                 # should be one or zero attrs
-                proj_db_path = os.path.join(pyproj.datadir.get_data_dir(), "proj.db")
+                proj_db_path = os.path.join(pyproj.datadir.get_data_dir(),
+                                            "proj.db")
                 try:
                     with sqlite3.connect(proj_db_path) as conn:
                         v_datum_attr = next(iter(vert_datum_attrs))
@@ -5289,7 +5296,6 @@ class CF1_7Check(CF1_6Check):
         """
         variable = ds.variables[vname]
         standard_name = getattr(variable, "standard_name", None)
-        units = getattr(variable, "units", None)
         formula_terms = getattr(variable, "formula_terms", None)
         # Skip the variable if it's dimensional
         if formula_terms is None and standard_name not in dim_vert_coords_dict:
@@ -5332,7 +5338,6 @@ class CF1_7Check(CF1_6Check):
         """
         ret_val = []
 
-        z_variables = cfutil.get_z_variables(ds)
         deprecated_units = ["level", "layer", "sigma_level"]
 
         # compose this function to use the results from the CF-1.6 check
diff --git a/compliance_checker/cf/cf_18.py b/compliance_checker/cf/cf_18.py
index 6f34560..cc41ac2 100644
--- a/compliance_checker/cf/cf_18.py
+++ b/compliance_checker/cf/cf_18.py
@@ -1,4 +1,3 @@
-
 from compliance_checker.base import BaseCheck, TestCtx, Result
 from compliance_checker import MemoizedDataset
 from compliance_checker.cf.cf import CF1_7Check
@@ -9,15 +8,14 @@ from lxml import etree
 from shapely.geometry import Polygon
 import numpy as np
 import re
-from compliance_checker.cf.util import (reference_attr_variables,
-                                        string_from_var_type)
+from compliance_checker.cf.util import reference_attr_variables, string_from_var_type
 import itertools
 import warnings
 from shapely.geometry import (MultiPoint, LineString, MultiLineString, Polygon,
                               MultiPolygon)
 from compliance_checker.cf.util import reference_attr_variables
 
-'''
+"""
 What's new in CF-1.8
 --------------------
 2.7. Groups
@@ -27,17 +25,18 @@ What's new in CF-1.8
 6.1.2. Taxon Names and Identifiers
 
 7.5. Geometries
-'''
+"""
+
 
 class CF1_8Check(CF1_7Check):
-    """ Implementation for CF v1.8. Inherits from CF1_7Check. """
+    """Implementation for CF v1.8. Inherits from CF1_7Check."""
 
     # things that are specific to 1.8
     _cc_spec_version = "1.8"
     _cc_url = "http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html"
 
-    ROOT_GROUP_ONLY_ATTRS = ['Conventions', 'external_variables']
-    NON_ROOT_GROUP_OPT = ['title', 'history']
+    ROOT_GROUP_ONLY_ATTRS = ["Conventions", "external_variables"]
+    NON_ROOT_GROUP_OPT = ["title", "history"]
 
     def __init__(self, options=None):
         super(CF1_8Check, self).__init__(options)
@@ -48,7 +47,7 @@ class CF1_8Check(CF1_7Check):
                                     "7.5": "§7.5 Geometries"})
 
     def check_groups(self, ds: MemoizedDataset):
-        '''
+        """
         2.7.2. Application of attributes
 
         The following attributes are optional for non-root groups. They are allowed in order to
@@ -79,7 +78,7 @@ class CF1_8Check(CF1_7Check):
         not to ancestor or sibling groups. If a group attribute is defined in a parent group, and
         one of the child group redefines the same attribute, the definition within the child group
         applies for the child and all of its descendants.
-        '''
+        """
 
         results = []
 
@@ -89,14 +88,16 @@ class CF1_8Check(CF1_7Check):
         # Make sure `Conventions` & `external_variables` attributes are only present in the
         # root group.
         for gname in ds.groups:
-            ginstance = ds.createGroup(gname) # returns existing Group; doesn't create a new one
+            ginstance = ds.createGroup(
+                gname
+            )  # returns existing Group; doesn't create a new one
 
             for attr in ginstance.ncattrs():
                 if attr in CF1_8Check.ROOT_GROUP_ONLY_ATTRS:
 
                     ctx_hi.messages.append(
                         f'§2.7.2 Attribute "{ attr }" MAY ONLY be used in the root group '
-                        'and SHALL NOT be duplicated or overridden in child groups.'
+                        "and SHALL NOT be duplicated or overridden in child groups."
                     )
 
                     results.append(ctx_hi.to_result())
@@ -104,10 +105,10 @@ class CF1_8Check(CF1_7Check):
                 elif attr in CF1_8Check.NON_ROOT_GROUP_OPT:
 
                     ctx_lo.messages.append(
-    f"§2.7.2 Note: attribute '{ attr }' found on non-root group '{ gname }'. "
-    "This is optional for non-root groups. It is allowed in order to provide additional "
-    "provenance and description of the subsidiary data. It does not override "
-    "attributes from parent groups."
+                        f"§2.7.2 Note: attribute '{ attr }' found on non-root group '{ gname }'. "
+                        "This is optional for non-root groups. It is allowed in order to provide additional "
+                        "provenance and description of the subsidiary data. It does not override "
+                        "attributes from parent groups."
                     )
                     results.append(ctx_lo.to_result())
 
@@ -204,7 +205,7 @@ class CF1_8Check(CF1_7Check):
         return results
 
     def check_taxa(self, ds: Dataset):
-        '''
+        """
         6.1.2. Taxon Names and Identifiers
 
         A taxon is a named level within a biological classification, such as a class, genus and
@@ -232,68 +233,79 @@ class CF1_8Check(CF1_7Check):
         biological_taxon_lsid coordinate. If LSIDs are available for some taxa in a dataset then
         the biological_taxon_lsid auxiliary coordinate variable should be included and missing data
         given for those taxa that do not have an identifier.
-        '''
+        """
         ret_val = []
         # taxa identification variables
         taxa_name_variables = ds.get_variables_by_attributes(
                                                           standard_name="biological_taxon_name")
         taxa_lsid_variables = ds.get_variables_by_attributes(
                                                           standard_name="biological_taxon_identifier")
+        
         def match_taxa_standard_names(standard_name_string):
             """
             Match variables which are standard_names related to taxa, but
             are not the taxon identifiers or LSIDs themselves.
             """
-            return (standard_name_string is not None and
-                    "taxon" in standard_name_string and
-                    # exclude the identifiers we just looked at
-                    standard_name_string not in {"biological_taxon_lsid",
-                                                 "biological_taxon_name"} and
-                    standard_name_string in self._std_names)
-
+            return (
+                standard_name_string is not None
+                and "taxon" in standard_name_string
+                and
+                # exclude the identifiers we just looked at
+                standard_name_string
+                not in {"biological_taxon_lsid", "biological_taxon_name"}
+                and standard_name_string in self._std_names
+            )
 
         taxa_quantifier_variables = ds.get_variables_by_attributes(
-                                                standard_name=match_taxa_standard_names)
+            standard_name=match_taxa_standard_names
+        )
         # If there are no matches, there either are no taxa variables
         # or the standard names are not appropriate, which will be picked up
         # by the standard_name check
         if not taxa_quantifier_variables:
             return
 
-
         for taxon_quantifier_variable in taxa_quantifier_variables:
             valid_taxa = TestCtx(BaseCheck.HIGH, self.section_titles["6.1.2"])
-            if not isinstance(getattr(taxon_quantifier_variable,
-                                      "coordinates", None), str):
-                valid_taxa.add_failure(f"{taxon_quantifier_variable.name} must have a string valued \"coordinates\" attribute")
+            if not isinstance(
+                getattr(taxon_quantifier_variable, "coordinates", None), str
+            ):
+                valid_taxa.add_failure(
+                    f'{taxon_quantifier_variable.name} must have a string valued "coordinates" attribute'
+                )
                 continue
 
-            coordinate_var_names = (taxon_quantifier_variable.coordinates
-                                    .split(" "))
+            coordinate_var_names = taxon_quantifier_variable.coordinates.split(" ")
             invalid_coord_vars = set(coordinate_var_names) - ds.variables.keys()
             if invalid_coord_vars:
-                valid_taxa.add_failure("The following values for \"coordinates\" attributes were not found in the dataset's variables "
-                                       f"{invalid_coord_vars}")
+                valid_taxa.add_failure(
+                    'The following values for "coordinates" attributes were not found in the dataset\'s variables '
+                    f"{invalid_coord_vars}"
+                )
 
             if len(coordinate_var_names) > 2:
-                valid_taxa.add_failure("coordinates attribute for taxon data must either reference one or two variable names")
+                valid_taxa.add_failure(
+                    "coordinates attribute for taxon data must either reference one or two variable names"
+                )
                 continue
 
-            coordinate_vars = [ds.variables[var_name] for var_name in
-                                coordinate_var_names]
-
+            coordinate_vars = [
+                ds.variables[var_name] for var_name in coordinate_var_names
+            ]
 
-            coord_var_standard_names = {var:
-                                        getattr(var, 'standard_name', None)
-                                        for var in coordinate_vars}
+            coord_var_standard_names = {
+                var: getattr(var, "standard_name", None) for var in coordinate_vars
+            }
             # if we have no authority, we can't check validity of the name -- assume it's OK
             standard_name_set = set(coord_var_standard_names.values())
             if set(coord_var_standard_names.keys()) == {"biological_taxon_name"}:
                 # TODO: Check for at least binomial nomenclature?
                 continue
             # check against WoRMS or ITIS if applicable
-            elif (standard_name_set == {"biological_taxon_name",
-                                        "biological_taxon_lsid"}):
+            elif standard_name_set == {
+                "biological_taxon_name",
+                "biological_taxon_lsid",
+            }:
                 inverted_dict = {v: k for k, v in coord_var_standard_names.items()}
                 taxon_lsid_var = inverted_dict["biological_taxon_lsid"]
                 taxon_name_var = inverted_dict["biological_taxon_name"]
@@ -304,8 +316,10 @@ class CF1_8Check(CF1_7Check):
                 else:
                     valid_taxa.score += 1
             else:
-                valid_taxa.add_failure(f'coordinates attribute for variable {taxon_quantifier_variable} must consist of '
-                                        'variables containing standard names of either just "biological_taxon_name", or "biological_taxon_name" and "biological_taxon_identifier"')
+                valid_taxa.add_failure(
+                    f"coordinates attribute for variable {taxon_quantifier_variable} must consist of "
+                    'variables containing standard names of either just "biological_taxon_name", or "biological_taxon_name" and "biological_taxon_identifier"'
+                )
             ret_val.append(valid_taxa.to_result())
 
         return ret_val
@@ -318,31 +332,36 @@ class CF1_8Check(CF1_7Check):
         currently checked for correctness.
         """
         messages = []
-        match_str = (r"(?:http://(?:www\.)?lsid.info/)?urn:lsid:"
-                     r"(?P<authority>[^:]+):(?P<namespace>[^:]+):"
-                     r"(?P<object_id>\w+)(?::(?P<version>\w+))?")
-        for taxon_lsid, taxon_name in zip(taxon_lsid_variable[:],
-                                          taxon_name_variable[:]):
+        match_str = (
+            r"(?:http://(?:www\.)?lsid.info/)?urn:lsid:"
+            r"(?P<authority>[^:]+):(?P<namespace>[^:]+):"
+            r"(?P<object_id>\w+)(?::(?P<version>\w+))?"
+        )
+        for taxon_lsid, taxon_name in zip(
+            taxon_lsid_variable[:], taxon_name_variable[:]
+        ):
             # TODO: handle case where LSID is not present.  This can happen
             #       if the species is not present in the database desired.
             taxon_name_str = string_from_var_type(taxon_name)
             lsid_str = string_from_var_type(taxon_lsid)
             # if nodata/empty string for LSID, skip validity check
-            if lsid_str == '':
+            if lsid_str == "":
                 continue
             taxon_match = re.fullmatch(match_str, lsid_str)
             if not taxon_match:
-                messages.append("Taxon id must match one of the following forms:\n"
-                             "- urn:lsid:<authority>:<namespace>:<object_id>\n"
-                             "- urn:lsid:<authority>:<namespace>:<object_id>:<version>\n"
-                             "- www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
-                             "- www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>\n"
-                             "- lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
-                             "- lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>\n"
-                             "- http://lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
-                             "- http://lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>\n"
-                             "- http://www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
-                             "- http://www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>")
+                messages.append(
+                    "Taxon id must match one of the following forms:\n"
+                    "- urn:lsid:<authority>:<namespace>:<object_id>\n"
+                    "- urn:lsid:<authority>:<namespace>:<object_id>:<version>\n"
+                    "- www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
+                    "- www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>\n"
+                    "- lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
+                    "- lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>\n"
+                    "- http://lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
+                    "- http://lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>\n"
+                    "- http://www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>\n"
+                    "- http://www.lsid.info/urn:lsid.info:<authority>:<namespace>/<object_id>:<version>"
+                )
                 continue
             if lsid_str.startswith("urn"):
                 lsid_url = f"http://www.lsid.info/{lsid_str}"
@@ -352,79 +371,102 @@ class CF1_8Check(CF1_7Check):
             try:
                 response = requests.get(lsid_url, timeout=10)
                 response.raise_for_status()
-            except requests.exceptions.RequestException as e:
+            except requests.exceptions.RequestException:
                 # 400 error code indicates something is malformed on client's
                 # end
                 if response.status_code == 400:
                     tree = etree.HTML(response.text)
                     problem_text = tree.find("./body/p").text
-                    messages.append("http://lsid.info returned an error message "
-                                 f"for submitted LSID string '{lsid_str}': "
-                                 f"{problem_text}")
+                    messages.append(
+                        "http://lsid.info returned an error message "
+                        f"for submitted LSID string '{lsid_str}': "
+                        f"{problem_text}"
+                    )
                 else:
-                    messages.append("Error occurred attempting to check LSID "
-                                    f"'{lsid_str}': {str(e)}")
+                    messages.append(
+                        "Error occurred attempting to check LSID "
+                        f"'{lsid_str}': {str(e)}"
+                    )
                 continue
 
             # WoRMS -- marine bio data
-            if (taxon_match["authority"] == "marinespecies.org" and
-                taxon_match["namespace"] == "taxname"):
+            if (
+                taxon_match["authority"] == "marinespecies.org"
+                and taxon_match["namespace"] == "taxname"
+            ):
                 try:
-                    response = requests.get(f"http://www.marinespecies.org/rest/AphiaRecordByAphiaID/{taxon_match['object_id']}",
-                                            timeout=15)
+                    response = requests.get(
+                        f"http://www.marinespecies.org/rest/AphiaRecordByAphiaID/{taxon_match['object_id']}",
+                        timeout=15,
+                    )
                     response.raise_for_status()
-                except requests.exceptions.RequestException as e:
-                    messages.append("Aphia ID {taxon_match['object_id'] returned "
-                                    "other error: {str(e)}")
+                except requests.exceptions.RequestException:
+                    messages.append(
+                        "Aphia ID {taxon_match['object_id'] returned "
+                        "other error: {str(e)}"
+                    )
                 # record not found in database
                 if response.status_code == 204:
-                    messages.append("Aphia ID {taxon_match['object_id'] "
-                                    "not found in WoRMS database")
+                    messages.append(
+                        "Aphia ID {taxon_match['object_id'] "
+                        "not found in WoRMS database"
+                    )
                 # good case, parse JSON
                 elif response.status_code == 200:
                     valid_name = response.json()["valid_name"]
                     if valid_name != taxon_name_str:
-                        messages.append("Supplied taxon name and WoRMS valid name do not match. "
-                                        f"Supplied taxon name is '{taxon_name_str}', WoRMS valid name "
-                                        f"is '{valid_name}.'")
+                        messages.append(
+                            "Supplied taxon name and WoRMS valid name do not match. "
+                            f"Supplied taxon name is '{taxon_name_str}', WoRMS valid name "
+                            f"is '{valid_name}.'"
+                        )
                 # Misc non-error code.  Should not reach here.
                 else:
-                    messages.append(f"Aphia ID {taxon_match['object_id']}"
-                                    "returned an unhandled HTTP status "
-                                    f"code {response.status_code}")
+                    messages.append(
+                        f"Aphia ID {taxon_match['object_id']}"
+                        "returned an unhandled HTTP status "
+                        f"code {response.status_code}"
+                    )
                     continue
 
-
             # ITIS -- freshwater bio data
-            elif (taxon_match["authority"] == "itis.gov" and
-                  taxon_match["namespace"] == "itis_tsn"):
+            elif (
+                taxon_match["authority"] == "itis.gov"
+                and taxon_match["namespace"] == "itis_tsn"
+            ):
                 itis_url = f"https://www.itis.gov/ITISWebService/jsonservice/getFullRecordFromTSN?tsn={taxon_match['object_id']}"
                 try:
                     itis_response = requests.get(itis_url, timeout=15)
                     itis_response.raise_for_status()
-                except requests.exceptions.RequestException as e:
+                except requests.exceptions.RequestException:
                     if itis_response.status_code == 404:
-                        messages.append("itis.gov TSN "
-                                     f"{taxon_match['object_id']} not found.")
+                        messages.append(
+                            "itis.gov TSN " f"{taxon_match['object_id']} not found."
+                        )
                         continue
                     else:
-                        messages.append("itis.gov identifier returned other "
-                                     f"error: {str(e)}")
+                        messages.append(
+                            "itis.gov identifier returned other " f"error: {str(e)}"
+                        )
                         continue
                 json_contents = itis_response.json()
                 combined_name = json_contents["scientificName"]["combinedName"]
 
                 if taxon_name_str != combined_name:
-                    messages.append("Supplied taxon name and ITIS scientific name do not match. "
-                                    f"Supplied taxon name is '{taxon_name_str}', ITIS scientific name "
-                                    f"for TSN {taxon_match['object_id']} is '{combined_name}.'")
+                    messages.append(
+                        "Supplied taxon name and ITIS scientific name do not match. "
+                        f"Supplied taxon name is '{taxon_name_str}', ITIS scientific name "
+                        f"for TSN {taxon_match['object_id']} is '{combined_name}.'"
+                    )
 
             else:
-                warnings.warn("Compliance checker only supports checking valid "
-                              "LSID URNs of the form "
-                              "'urn:lsid:marinespecies.org:taxname:<AphiaID>' or "
-                              "'urn:lsid:itis.gov:itis_tsn:<TSN>'.  Assuming "
-                              "pass condition")
+                warnings.warn(
+                    "Compliance checker only supports checking valid "
+                    "LSID URNs of the form "
+                    "'urn:lsid:marinespecies.org:taxname:<AphiaID>' or "
+                    "'urn:lsid:itis.gov:itis_tsn:<TSN>'.  Assuming "
+                    "pass condition"
+                )
 
         return messages
 
@@ -505,6 +547,7 @@ class LineGeometry(GeometryStorage):
                                    "to the value of node_count")
         return geom_errors
 
+
 class PolygonGeometry(LineGeometry):
     """Class for validating Line/MultiLine geometries"""
     # TODO/clarify: Should polygons be simple, i.e. non-self intersecting?
@@ -588,7 +631,8 @@ class PolygonGeometry(LineGeometry):
 
         """
         vars_with_geometry = ds.get_variables_by_attributes(
-                                geometry=lambda g: g is not None)
+            geometry=lambda g: g is not None
+        )
         results = []
         unique_geometry_var_names = {var.geometry for var in vars_with_geometry}
         if unique_geometry_var_names:
@@ -596,8 +640,9 @@ class PolygonGeometry(LineGeometry):
             geom_valid.out_of += 1
         for geometry_var_name in unique_geometry_var_names:
             if geometry_var_name not in ds.variables:
-                geom_valid.messages.append("Cannot find geometry variable "
-                                           f"named {geometry_var_name}")
+                geom_valid.messages.append(
+                    "Cannot find geometry variable " f"named {geometry_var_name}"
+                )
                 results.append(geom_valid.to_result())
                 continue
             else:
@@ -606,16 +651,20 @@ class PolygonGeometry(LineGeometry):
             geometry_type = getattr(geometry_var, "geometry_type")
             try:
                 node_coord_var_names = geometry_var.node_coordinates
-            except AttributeError as e:
-                geom_valid.messages.append('Could not find required attribute '
-                                            '"node_coordinates" in geometry '
-                                            f'variable "{geometry_var_name}"')
+            except AttributeError:
+                geom_valid.messages.append(
+                    "Could not find required attribute "
+                    '"node_coordinates" in geometry '
+                    f'variable "{geometry_var_name}"'
+                )
                 results.append(geom_valid.to_result())
+                continue
             if not isinstance(node_coord_var_names, str):
                 geom_valid.messages.append(
-                                  'Attribute "node_coordinates" in geometry '
-                                  f'variable "{geometry_var_name}" must be '
-                                  'a string')
+                    'Attribute "node_coordinates" in geometry '
+                    f'variable "{geometry_var_name}" must be '
+                    "a string"
+                )
                 results.append(geom_valid.to_result())
                 continue
             split_coord_names = node_coord_var_names.strip().split(" ")
@@ -628,46 +677,51 @@ class PolygonGeometry(LineGeometry):
             # If any variables weren't found, we can't continue
             if not_found_node_vars:
                 geom_valid.messages.append(
-                                  "The following referenced node coordinate"
-                                  "variables for geometry variable"
-                                  f'"{geometry_var_name}" were not found: '
-                                  f'{not_found_node_vars}')
+                    "The following referenced node coordinate"
+                    "variables for geometry variable"
+                    f'"{geometry_var_name}" were not found: '
+                    f"{not_found_node_vars}"
+                )
                 results.append(geom_valid.to_result())
                 continue
 
-            node_count = reference_attr_variables(ds,
-                               getattr(geometry_var, "node_count", None))
+            node_count = reference_attr_variables(
+                ds, getattr(geometry_var, "node_count", None)
+            )
             # multipart lines and polygons only
-            part_node_count = reference_attr_variables(ds,
-                                getattr(geometry_var, "part_node_count", None))
+            part_node_count = reference_attr_variables(
+                ds, getattr(geometry_var, "part_node_count", None)
+            )
             # polygons with interior geometry only
-            interior_ring = reference_attr_variables(ds,
-                               getattr(geometry_var, "interior_ring", None))
+            interior_ring = reference_attr_variables(
+                ds, getattr(geometry_var, "interior_ring", None)
+            )
 
             if geometry_type == "point":
                 geometry = PointGeometry(node_coord_vars, node_count)
             elif geometry_type == "line":
-                geometry = LineGeometry(node_coord_vars, node_count,
-                                        part_node_count)
+                geometry = LineGeometry(node_coord_vars, node_count, part_node_count)
             elif geometry_type == "polygon":
-                geometry = PolygonGeometry(node_coord_vars, node_count,
-                                                    part_node_count,
-                                                    interior_ring)
+                geometry = PolygonGeometry(
+                    node_coord_vars, node_count, part_node_count, interior_ring
+                )
             else:
                 geom_valid.messages.append(
-                                  f'For geometry variable "{geometry_var_name}'
-                                  'the attribute "geometry_type" must exist'
-                                  'and have one of the following values:'
-                                  '"point", "line", "polygon"')
+                    f'For geometry variable "{geometry_var_name}'
+                    'the attribute "geometry_type" must exist'
+                    "and have one of the following values:"
+                    '"point", "line", "polygon"'
+                )
                 results.append(geom_valid.to_result())
                 continue
             # check geometry
             geometry.check_geometry()
-            if not geometry.errors: #geom_valid.messages:
+            if not geometry.errors:  # geom_valid.messages:
                 geom_valid.score += 1
             results.append(geom_valid.to_result())
         return results
 
+
 class GeometryStorage(object):
     """Abstract base class for geometries"""
 
@@ -685,15 +739,17 @@ class GeometryStorage(object):
                 invalid_vars.append(coord_var.name)
         # can't continue if the geometry variables are not the correct size
         if invalid_vars:
-            self.errors.append("The following geometry variables "
-                               f"have non-numeric contents: {invalid_vars}")
+            self.errors.append(
+                "The following geometry variables "
+                f"have non-numeric contents: {invalid_vars}"
+            )
 
     def _split_mulitpart_geometry(self):
         arr_extents_filt = self.part_node_count[self.part_node_count > 0]
-        splits = np.split(np.vstack(self.coord_vars).T,
-                          arr_extents_filt.cumsum()[:-1])
+        splits = np.split(np.vstack(self.coord_vars).T, arr_extents_filt.cumsum()[:-1])
         return splits
 
+
 class PointGeometry(GeometryStorage):
     """Class for validating Point/MultiPoint geometries"""
 
@@ -701,19 +757,21 @@ class PointGeometry(GeometryStorage):
         super().check_geometry()
 
         if all(len(cv.dimensions) != 0 for cv in self.coord_vars):
-            same_dim_group = itertools.groupby(self.coord_vars,
-                                            lambda x: x.dimensions)
-            same_dim = (next(same_dim_group, True) and
-                             not next(same_dim_group, False))
+            same_dim_group = itertools.groupby(self.coord_vars, lambda x: x.dimensions)
+            same_dim = next(same_dim_group, True) and not next(same_dim_group, False)
             if not same_dim:
-                self.errors.append("For a point geometry, coordinate "
-                                   "variables must be the same length as "
-                                   "node_count defined, or must be "
-                                   "length 1 if node_count is not set")
+                self.errors.append(
+                    "For a point geometry, coordinate "
+                    "variables must be the same length as "
+                    "node_count defined, or must be "
+                    "length 1 if node_count is not set"
+                )
         return self.errors
 
+
 class LineGeometry(GeometryStorage):
     """Class for validating Line/MultiLine geometries"""
+
     def __init__(self, coord_vars, node_count, part_node_count):
         super().__init__(coord_vars, node_count)
         self.part_node_count = part_node_count
@@ -722,39 +780,46 @@ class LineGeometry(GeometryStorage):
 
     def check_geometry(self):
         geom_errors = []
-        same_dim_group = itertools.groupby(self.coord_vars,
-                                           lambda x: x.dimensions)
-        same_dim = (next(same_dim_group, True) and
-                         not next(same_dim_group, False))
+        same_dim_group = itertools.groupby(self.coord_vars, lambda x: x.dimensions)
+        same_dim = next(same_dim_group, True) and not next(same_dim_group, False)
         if not same_dim:
-            raise IndexError("Coordinate variables must be the same length. "
-                            "If node_count is specified, this value must "
-                            "also sum to the length of the coordinate "
-                            "variables.")
+            raise IndexError(
+                "Coordinate variables must be the same length. "
+                "If node_count is specified, this value must "
+                "also sum to the length of the coordinate "
+                "variables."
+            )
         # if a multipart
         if self.node_count is not None:
             same_length = len(self.coord_vars[0]) == self.node_count[:].sum()
             if not same_length:
-                geom_errors.append("Coordinate variables must be the same "
-                                   "length. If node_count is specified, this "
-                                   "value must also sum to the length of the "
-                                    "coordinate variables.")
+                geom_errors.append(
+                    "Coordinate variables must be the same "
+                    "length. If node_count is specified, this "
+                    "value must also sum to the length of the "
+                    "coordinate variables."
+                )
         if self.part_node_count is not None:
             if not np.issubdtype(self.part_node_count.dtype, np.integer):
-                geom_errors.append("when part_node_count is specified, it must "
-                                   "be an array of integers")
+                geom_errors.append(
+                    "when part_node_count is specified, it must "
+                    "be an array of integers"
+                )
             same_node_count = len(self.coord_vars[0]) == self.node_count[:].sum()
             if not same_node_count:
-                geom_errors.append("The sum of part_node_count must be equal "
-                                   "to the value of node_count")
+                geom_errors.append(
+                    "The sum of part_node_count must be equal "
+                    "to the value of node_count"
+                )
         return geom_errors
 
+
 class PolygonGeometry(LineGeometry):
     """Class for validating Line/MultiLine geometries"""
+
     # TODO/clarify: Should polygons be simple, i.e. non-self intersecting?
     # Presumably
-    def __init__(self, coord_vars, node_count, part_node_count,
-                    interior_ring):
+    def __init__(self, coord_vars, node_count, part_node_count, interior_ring):
         super().__init__(coord_vars, node_count, part_node_count)
         self.part_node_count = part_node_count
         self.interior_ring = interior_ring
@@ -779,7 +844,9 @@ class PolygonGeometry(LineGeometry):
         try:
             polygon = Polygon(transposed_coords.tolist())
         except ValueError:
-            raise ValueError("Polygon contains too few points to perform orientation test")
+            raise ValueError(
+                "Polygon contains too few points to perform orientation test"
+            )
 
         ccw = polygon.exterior.is_ccw
         return not ccw if interior else ccw
@@ -791,16 +858,14 @@ class PolygonGeometry(LineGeometry):
         if messages:
             return messages
         if self.part_node_count is not None:
-            extents = np.concatenate([np.array([0]),
-                                     self.part_node_count[:].cumsum()])
+            extents = np.concatenate([np.array([0]), self.part_node_count[:].cumsum()])
             if self.interior_ring is not None:
                 ring_orientation = self.interior_ring[:].astype(bool)
             else:
                 ring_orientation = np.zeros(len(self.part_count), dtype=bool)
             node_indexer_len = len(self.part_node_count)
         else:
-            extents = np.concatenate([np.array([0]),
-                                     self.node_count[:].cumsum()])
+            extents = np.concatenate([np.array([0]), self.node_count[:].cumsum()])
             node_indexer_len = len(self.node_count)
             ring_orientation = np.zeros(node_indexer_len, dtype=bool)
         # TODO: is it necessary to check whether part_node_count "consumes"
@@ -808,39 +873,21 @@ class PolygonGeometry(LineGeometry):
         #       a node part of 9, follow by next 3 will consume a node part of
         #       3 after consuming
         for i in range(node_indexer_len):
-            extent_slice = slice(extents[i], extents[i+1])
-            poly_sliced = np.vstack([cv[extent_slice] for cv in
-                                     self.coord_vars]).T
-            pass_orientation = (self.check_polygon_orientation(
-                                            poly_sliced,
-                                            ring_orientation[i]))
+            extent_slice = slice(extents[i], extents[i + 1])
+            poly_sliced = np.vstack([cv[extent_slice] for cv in self.coord_vars]).T
+            pass_orientation = self.check_polygon_orientation(
+                poly_sliced, ring_orientation[i]
+            )
             if not pass_orientation:
-                orient_fix = (("exterior", "counterclockwise")
-                                 if not ring_orientation[i] else
-                               ("interior", "clockwise"))
-                message = (f"An {orient_fix[0]} polygon referred to by "
-                           f"coordinates ({poly_sliced}) must have coordinates "
-                           f"in {orient_fix[1]} order")
+                orient_fix = (
+                    ("exterior", "counterclockwise")
+                    if not ring_orientation[i]
+                    else ("interior", "clockwise")
+                )
+                message = (
+                    f"An {orient_fix[0]} polygon referred to by "
+                    f"coordinates ({poly_sliced}) must have coordinates "
+                    f"in {orient_fix[1]} order"
+                )
                 messages.append(message)
         return messages
-
-
-        ## TODO
-        # find standard names contains 'organisms_in_taxon'
-        # find aux. coord. vars with standard_name='biological_taxon_name'
-        # LSID,'biological_taxon_lsid' = "urn:lsid:<Authority>:<Namespace>:<ObjectID>[:<Version>]"
-
-        results = []
-
-        ctx_hi = TestCtx(BaseCheck.HIGH, self.section_titles["6.1"])
-        ctx_med = TestCtx(BaseCheck.MEDIUM, self.section_titles["6.1"])
-        ctx_lo = TestCtx(BaseCheck.LOW, self.section_titles["6.1"])
-
-        for var in [ds[name] for name in ds.variables]:
-            if 'organisms_in_taxon' in var.standard_name:
-
-                # taxa identified by aux. coordinate vars
-                for aux_var in [ds[name] for name in var.coordinates.split()]:
-                    print(ds[aux_var.name])
-
-
diff --git a/compliance_checker/cf/util.py b/compliance_checker/cf/util.py
index b635c8e..4e97a38 100644
--- a/compliance_checker/cf/util.py
+++ b/compliance_checker/cf/util.py
@@ -237,13 +237,16 @@ def get_safe(dict_instance, keypath, default=None):
 
 class VariableReferenceError(Exception):
     """A variable to assign bad variable references to"""
-    def __init__(self, name: str, dataset: Dataset=None):
+
+    def __init__(self, name: str, dataset: Dataset = None):
         self.name = name
         self.dataset_path = dataset.filepath() if dataset is not None else None
 
     def __str__(self):
-        return (f'Cannot find variable named {self.name} in dataset '
-                f'{self}.dataset_path')
+        return (
+            f"Cannot find variable named {self.name} in dataset " f"{self}.dataset_path"
+        )
+
 
 class NCGraph(object):
     def __init__(
@@ -572,18 +575,23 @@ def is_vertical_coordinate(var_name, var):
         satisfied |= getattr(var, "positive", "").lower() in ("up", "down")
     return satisfied
 
+
 def string_from_var_type(variable):
     if isinstance(variable, str):
         return variable[:]
-    elif variable.dtype.kind == 'S':
+    elif variable.dtype.kind == "S":
         strip_char = variable.fill_value or b"\x00"
         return variable.tobytes().rstrip(strip_char).decode("utf-8")
     else:
-        raise TypeError(f"Variable '{variable.name} has non-string/character' "
-                        f"dtype {variable.dtype}")
+        raise TypeError(
+            f"Variable '{variable.name} has non-string/character' "
+            f"dtype {variable.dtype}"
+        )
+
 
-def reference_attr_variables(dataset: Dataset, attributes_string: str,
-                             split_by: str = None):
+def reference_attr_variables(
+    dataset: Dataset, attributes_string: str, split_by: str = None
+):
     """
     Attempts to reference variables in the string, optionally splitting by
     a string
@@ -591,10 +599,12 @@ def reference_attr_variables(dataset: Dataset, attributes_string: str,
     if attributes_string is None:
         return None
     elif split_by is None:
-        return dataset.variables.get(attributes_string,
-                                     VariableReferenceError(attributes_string))
+        return dataset.variables.get(
+            attributes_string, VariableReferenceError(attributes_string)
+        )
     else:
         string_proc = attributes_string.split(split_by)
-        return [dataset.variables.get(var_name,
-                                      VariableReferenceError(var_name))
-                for var_name in string_proc]
+        return [
+            dataset.variables.get(var_name, VariableReferenceError(var_name))
+            for var_name in string_proc
+        ]
diff --git a/compliance_checker/cfutil.py b/compliance_checker/cfutil.py
index bec1365..414e473 100644
--- a/compliance_checker/cfutil.py
+++ b/compliance_checker/cfutil.py
@@ -81,7 +81,7 @@ def attr_membership(attr_val, value_set, attr_type=str, modifier_fn=lambda x: x)
             else:
                 new_attr_val = attr_type(attr_val)
         # catch casting errors
-        except (ValueError, UnicodeEncodeError) as e:
+        except (ValueError, UnicodeEncodeError):
             warnings.warn("Could not cast to type {}".format(attr_type))
             return False
     else:
diff --git a/compliance_checker/ioos.py b/compliance_checker/ioos.py
index ea91fc4..6a21522 100644
--- a/compliance_checker/ioos.py
+++ b/compliance_checker/ioos.py
@@ -925,38 +925,43 @@ class IOOS1_2Check(IOOSNCCheck):
         https://github.com/ioos/compliance-checker/issues/828
         """
 
-        fType = getattr(ds, "featureType", None)
-        if (not fType) or (not isinstance(fType, str)):  # can't do anything, pass
+        feature_type_attr = getattr(ds, "featureType", None)
+        # can't do anything, pass
+        if not feature_type_attr or not isinstance(feature_type_attr, str):
             return Result(
                 BaseCheck.MEDIUM,
                 False,
                 "CF DSG: Invalid featureType",
                 [
                     (
-                        f"Invalid featureType '{fType}'; please see the "
-                        "IOOS 1.2 Profile and CF-1.7 Conformance documents for valid featureType"
+                        f"Invalid featureType '{feature_type_attr}'; please see the "
+                         "IOOS 1.2 Profile and CF-1.7 Conformance documents for valid featureType"
                     )
                 ],
             )
-        featType = fType.lower()
 
-        if featType == "timeseries":
+        feature_type = feature_type_attr.lower()
+
+        if feature_type == "timeseries":
             return self._check_feattype_timeseries_cf_role(ds)
 
-        elif featType == "timeseriesprofile":
+        elif feature_type == "timeseriesprofile":
             return self._check_feattype_timeseriesprof_cf_role(ds)
 
-        elif featType == "trajectory":
+        elif feature_type == "trajectory":
             return self._check_feattype_trajectory_cf_role(ds)
 
-        elif featType == "trajectoryprofile":
-            return self._check_feattype_trajprof_cf_role(ds)
+        elif feature_type == "trajectoryprofile":
+            return self._check_feattype_trajectoryprof_cf_role(ds)
 
-        elif featType == "profile":
+        elif feature_type == "profile":
             return self._check_feattype_profile_cf_role(ds)
 
-        elif featType == "point":
-            return good_result  # can't do anything
+        elif feature_type == "point":
+            return Result(
+                BaseCheck.MEDIUM,
+                True,
+                "CF DSG: featureType=trajectoryProfile")
 
         else:
             return Result(
@@ -965,8 +970,9 @@ class IOOS1_2Check(IOOSNCCheck):
                 "CF DSG: Unknown featureType",
                 [
                     (
-                        f"Invalid featureType '{featType}'; please see the "
-                        "IOOS 1.2 Profile and CF-1.7 Conformance documents for valid featureType"
+                        f"Invalid featureType '{feature_type_attr}'; "
+                          "please see the IOOS 1.2 Profile and CF-1.7 "
+                          "Conformance documents for valid featureType"
                     )
                 ],
             )
@@ -1106,7 +1112,7 @@ class IOOS1_2Check(IOOSNCCheck):
         trj_prof_msg = (
             "Dimension length of non-platform variable with cf_role={cf_role} "
             "(the '{dim_type}' dimension) is {dim_len}. "
-            "The IOOS profile restricts trjectory and trajectoryProfile "
+            "The IOOS profile restricts trajectory and trajectoryProfile "
             "datasets to a single platform (ie. trajectory) per dataset "
             "(the profile dimension is permitted to be >= 1)."
         )
diff --git a/compliance_checker/suite.py b/compliance_checker/suite.py
index 066236a..62ac435 100644
--- a/compliance_checker/suite.py
+++ b/compliance_checker/suite.py
@@ -677,13 +677,16 @@ class CheckSuite(object):
                                 print out the appropriate header string
         """
 
-        sort_fn = lambda x: x.weight
-        groups_sorted = sorted(groups, key=sort_fn, reverse=True)
+        def weight_sort(result):
+            return result.weight
+
+        groups_sorted = sorted(groups, key=weight_sort, reverse=True)
 
         # create dict of the groups -> {level: [reasons]}
         result = {
             key: [v for v in valuesiter if v.value[0] != v.value[1]]
-            for key, valuesiter in itertools.groupby(groups_sorted, key=sort_fn)
+            for key, valuesiter in itertools.groupby(groups_sorted,
+                                                     key=weight_sort)
         }
         priorities = self.checkers[check]._cc_display_headers
 
@@ -728,7 +731,8 @@ class CheckSuite(object):
                     print("{:^{width}}".format(level_name, width=width))
                     print("-" * width)
 
-                data_issues = [process_table(res, check) for res in result[level]]
+                data_issues = [process_table(res, check) for res in
+                               result[level]]
 
                 has_printed = False
                 for issue, reasons in data_issues:
@@ -738,7 +742,8 @@ class CheckSuite(object):
                         print("")
                     # join alphabetized reasons together
                     reason_str = "\n".join(
-                        "* {}".format(r) for r in sorted(reasons, key=lambda x: x[0])
+                        "* {}".format(r) for r in sorted(reasons,
+                                                         key=lambda x: x[0])
                     )
                     proc_str = "{}\n{}".format(issue, reason_str)
                     print(proc_str)
@@ -827,7 +832,7 @@ class CheckSuite(object):
                 return MemoizedDataset(
                     urlparse(response.url).path, memory=response.content
                 )
-            except OSError as e:
+            except OSError:
                 # handle case when netCDF C libs weren't compiled with
                 # in-memory support by using tempfile
                 with tempnc(response.content) as _nc:
diff --git a/compliance_checker/util.py b/compliance_checker/util.py
index a9c02fd..7127965 100644
--- a/compliance_checker/util.py
+++ b/compliance_checker/util.py
@@ -11,9 +11,9 @@ def datetime_is_iso(date_str):
     """Attempts to parse a date formatted in ISO 8601 format"""
     try:
         if len(date_str) > 10:
-            dt = isodate.parse_datetime(date_str)
+            isodate.parse_datetime(date_str)
         else:
-            dt = isodate.parse_date(date_str)
+            isodate.parse_date(date_str)
         return True, []
     except:  # Any error qualifies as not ISO format
         return False, ["Datetime provided is not in a valid ISO 8601 format"]
diff --git a/setup.py b/setup.py
index 2faa361..49789c0 100644
--- a/setup.py
+++ b/setup.py
@@ -16,9 +16,11 @@ def pip_requirements(fname="requirements.txt"):
             if not line or line.startswith("#"):
                 continue
             reqs.append(line)
+
     return reqs
 
 
+
 setup(
     name="compliance-checker",
     description="Checks Datasets and SOS endpoints for standards compliance",


Test patch:
diff --git a/compliance_checker/tests/helpers.py b/compliance_checker/tests/helpers.py
index 2f3edd2..19ecd56 100644
--- a/compliance_checker/tests/helpers.py
+++ b/compliance_checker/tests/helpers.py
@@ -62,9 +62,11 @@ class MockVariable(object):
     def __getitem__(self, idx):
         return self._arr[idx]
 
+
     def __setitem__(self, idx, val):
         self._arr[idx] = val
 
+
     def ncattrs(self):
         return [
             att
diff --git a/compliance_checker/tests/test_cf.py b/compliance_checker/tests/test_cf.py
index 0bde0ec..9342746 100644
--- a/compliance_checker/tests/test_cf.py
+++ b/compliance_checker/tests/test_cf.py
@@ -33,11 +33,8 @@ from compliance_checker.cf.util import (
 )
 from compliance_checker.suite import CheckSuite
 from compliance_checker.tests import BaseTestCase
-from compliance_checker.tests.helpers import (
-    MockRaggedArrayRepr,
-    MockTimeSeries,
-    MockVariable,
-)
+from compliance_checker.tests.helpers import (MockRaggedArrayRepr,
+                                              MockTimeSeries, MockVariable)
 import requests_mock
 import json
 import re
@@ -113,7 +110,6 @@ class TestCF1_6(BaseTestCase):
         # present in coord_data_vars
         self.assertEqual(self.cf.coord_data_vars, {"time", "sigma"})
 
-
     # --------------------------------------------------------------------------------
     # Compliance Tests
     # --------------------------------------------------------------------------------
@@ -558,6 +554,17 @@ class TestCF1_6(BaseTestCase):
         score, out_of, messages = get_results(results)
         self.assertEqual(score, out_of)
 
+        bad_dim_ds = MockTimeSeries()
+        bad_dim_ds.createDimension("clim_bounds", 3)
+
+        temp = bad_dim_ds.createVariable("temperature", "f8", ("time",))
+        bad_dim_ds.createVariable("clim_bounds", "f8", ("time"))
+        temp.climatology = "clim_bounds"
+        results = self.cf.check_climatological_statistics(bad_dim_ds)
+        assert results[0].value[0] < results[0].value[1]
+        assert (results[0].msgs[0] == 'Climatology dimension "clim_bounds" '
+                "should only contain two elements")
+
     def test_check_ancillary_variables(self):
         """
         Test to ensure that ancillary variables are properly checked
@@ -2250,7 +2257,6 @@ class TestCF1_7(BaseTestCase):
 
 
 class TestCF1_8(BaseTestCase):
-
     def setUp(self):
         self.cf = CF1_8Check()
 
@@ -2289,7 +2295,6 @@ class TestCF1_8(BaseTestCase):
         results = self.cf.check_geometry(dataset)
         assert results[0].value[0] < results[0].value[1]
 
-
     def test_line_geometry(self):
         dataset = self.load_dataset(STATIC_FILES["line_geometry"])
         self.cf.check_geometry(dataset)
@@ -2297,11 +2302,11 @@ class TestCF1_8(BaseTestCase):
     def test_polygon_geometry(self):
         dataset = self.load_dataset(STATIC_FILES["polygon_geometry"])
         self.cf.check_geometry(dataset)
-        dataset.variables["interior_ring"] = (
-                MockVariable(dataset.variables["interior_ring"]))
+        dataset.variables["interior_ring"] = MockVariable(
+            dataset.variables["interior_ring"]
+        )
         # Flip sign indicator for interior rings.  Should cause failure
-        flip_ring_bits = (dataset.variables["interior_ring"][:]
-                          == 0).astype(int)
+        flip_ring_bits = (dataset.variables["interior_ring"][:] == 0).astype(int)
         dataset.variables["interior_ring"][:] = flip_ring_bits
         results = self.cf.check_geometry(dataset)
         # There should be messages regarding improper polygon order
@@ -2315,30 +2320,38 @@ class TestCF1_8(BaseTestCase):
         dataset = MockTimeSeries()
         # TODO: handle scalar dimension
         dataset.createDimension("taxon", 1)
-        abundance = dataset.createVariable('abundance', "f8", ('time',))
-        abundance.standard_name = "number_concentration_of_biological_taxon_in_sea_water"
+        abundance = dataset.createVariable("abundance", "f8", ("time",))
+        abundance.standard_name = (
+            "number_concentration_of_biological_taxon_in_sea_water"
+        )
         abundance.units = "m-3"
         abundance.coordinates = "taxon_name taxon_lsid"
-        taxon_name = dataset.createVariable('taxon_name', str, ("taxon",))
+        taxon_name = dataset.createVariable("taxon_name", str, ("taxon",))
         taxon_name.standard_name = "biological_taxon_name"
-        taxon_lsid = dataset.createVariable('taxon_lsid', str, ("taxon",))
+        taxon_lsid = dataset.createVariable("taxon_lsid", str, ("taxon",))
         taxon_lsid.standard_name = "biological_taxon_lsid"
         taxon_name[0] = "Esox lucius"
         taxon_lsid[0] = "urn:lsid:itis.gov:itis_tsn:99999999999"
         with requests_mock.Mocker() as m:
             # bad ID
             taxon_lsid[0] = "99999999999"
-            m.get("http://www.lsid.info/urn:lsid:marinespecies.org:taxname:99999999999",
-                  status_code=400,
-                  text="<html><head><title>400 Bad Request</head><body><h1>Bad Request</h1><p>Unknown LSID</p></body></html>")
+            m.get(
+                "http://www.lsid.info/urn:lsid:marinespecies.org:taxname:99999999999",
+                status_code=400,
+                text="<html><head><title>400 Bad Request</head><body><h1>Bad Request</h1><p>Unknown LSID</p></body></html>",
+            )
             results = self.cf.check_taxa(dataset)
             assert len(results) == 1
             messages = results[0].msgs
             assert results[0].value[0] < results[0].value[1]
             assert len(messages) == 1
-            taxon_lsid[0] = "http://www.lsid.info/urn:lsid:marinespecies.org:taxname:99999999999"
+            taxon_lsid[
+                0
+            ] = "http://www.lsid.info/urn:lsid:marinespecies.org:taxname:99999999999"
             results = self.cf.check_taxa(dataset)
-            assert messages[0].startswith("Taxon id must match one of the following forms:")
+            assert messages[0].startswith(
+                "Taxon id must match one of the following forms:"
+            )
             assert results[0].value[0] < results[0].value[1]
 
     def test_taxonomy_data_worms_valid(self):
@@ -2347,32 +2360,81 @@ class TestCF1_8(BaseTestCase):
         """
         with requests_mock.Mocker() as m:
             # assume LSID lookups for WoRMS return valid HTTP status code
-            m.get(re.compile(r"^http://www.lsid.info/urn:lsid:marinespecies.org:taxname:\d+$"))
-            response_1 = json.dumps({'AphiaID': 104464, 'url':
-                                    'http://www.marinespecies.org/aphia.php?p=taxdetails&id=104464',
-                                    'scientificname': 'Calanus finmarchicus', 'authority': '(Gunnerus, 1770)',
-                                    'status': 'accepted', 'unacceptreason': None, 'taxonRankID': 220, 'rank':
-                                    'Species', 'valid_AphiaID': 104464, 'valid_name': 'Calanus finmarchicus',
-                                    'valid_authority': '(Gunnerus, 1770)', 'parentNameUsageID': 104152, 'kingdom':
-                                    'Animalia', 'phylum': 'Arthropoda', 'class': 'Hexanauplia', 'order':
-                                    'Calanoida', 'family': 'Calanidae', 'genus': 'Calanus', 'citation': 'Walter, T.C.; Boxshall, G. (2021). World of Copepods Database. Calanus finmarchicus (Gunnerus, 1770). Accessed through: World Register of Marine Species at: http://www.marinespecies.org/aphia.php?p=taxdetails&id=104464 on 2021-11-11',
-                                    'lsid': 'urn:lsid:marinespecies.org:taxname:104464', 'isMarine': 1,
-                                    'isBrackish': 0, 'isFreshwater': 0, 'isTerrestrial': 0, 'isExtinct': None,
-                                    'match_type': 'exact', 'modified': '2020-10-06T15:25:25.040Z'})
-            m.get("http://www.marinespecies.org/rest/AphiaRecordByAphiaID/104464",
-                  text=response_1)
-            response_2 = json.dumps({'AphiaID': 104466, 'url': 'http://www.marinespecies.org/aphia.php?p=taxdetails&id=104466',
-                                     'scientificname': 'Calanus helgolandicus', 'authority': '(Claus, 1863)',
-                                     'status': 'accepted', 'unacceptreason': None, 'taxonRankID': 220, 'rank':
-                                     'Species', 'valid_AphiaID': 104466, 'valid_name': 'Calanus helgolandicus',
-                                     'valid_authority': '(Claus, 1863)', 'parentNameUsageID': 104152, 'kingdom':
-                                     'Animalia', 'phylum': 'Arthropoda', 'class': 'Hexanauplia', 'order':
-                                     'Calanoida', 'family': 'Calanidae', 'genus': 'Calanus', 'citation': 'Walter, T.C.; Boxshall, G. (2021). World of Copepods Database. Calanus helgolandicus (Claus, 1863). Accessed through: World Register of Marine Species at: http://www.marinespecies.org/aphia.php?p=taxdetails&id=104466 on 2021-11-11',
-                                     'lsid': 'urn:lsid:marinespecies.org:taxname:104466', 'isMarine': 1,
-                                     'isBrackish': 0, 'isFreshwater': 0, 'isTerrestrial': 0, 'isExtinct': None,
-                                     'match_type': 'exact', 'modified': '2004-12-21T15:54:05Z'})
-            m.get("http://www.marinespecies.org/rest/AphiaRecordByAphiaID/104466",
-                  text=response_2)
+            m.get(
+                re.compile(
+                    r"^http://www.lsid.info/urn:lsid:marinespecies.org:taxname:\d+$"
+                )
+            )
+            response_1 = json.dumps(
+                {
+                    "AphiaID": 104464,
+                    "url": "http://www.marinespecies.org/aphia.php?p=taxdetails&id=104464",
+                    "scientificname": "Calanus finmarchicus",
+                    "authority": "(Gunnerus, 1770)",
+                    "status": "accepted",
+                    "unacceptreason": None,
+                    "taxonRankID": 220,
+                    "rank": "Species",
+                    "valid_AphiaID": 104464,
+                    "valid_name": "Calanus finmarchicus",
+                    "valid_authority": "(Gunnerus, 1770)",
+                    "parentNameUsageID": 104152,
+                    "kingdom": "Animalia",
+                    "phylum": "Arthropoda",
+                    "class": "Hexanauplia",
+                    "order": "Calanoida",
+                    "family": "Calanidae",
+                    "genus": "Calanus",
+                    "citation": "Walter, T.C.; Boxshall, G. (2021). World of Copepods Database. Calanus finmarchicus (Gunnerus, 1770). Accessed through: World Register of Marine Species at: http://www.marinespecies.org/aphia.php?p=taxdetails&id=104464 on 2021-11-11",
+                    "lsid": "urn:lsid:marinespecies.org:taxname:104464",
+                    "isMarine": 1,
+                    "isBrackish": 0,
+                    "isFreshwater": 0,
+                    "isTerrestrial": 0,
+                    "isExtinct": None,
+                    "match_type": "exact",
+                    "modified": "2020-10-06T15:25:25.040Z",
+                }
+            )
+            m.get(
+                "http://www.marinespecies.org/rest/AphiaRecordByAphiaID/104464",
+                text=response_1,
+            )
+            response_2 = json.dumps(
+                {
+                    "AphiaID": 104466,
+                    "url": "http://www.marinespecies.org/aphia.php?p=taxdetails&id=104466",
+                    "scientificname": "Calanus helgolandicus",
+                    "authority": "(Claus, 1863)",
+                    "status": "accepted",
+                    "unacceptreason": None,
+                    "taxonRankID": 220,
+                    "rank": "Species",
+                    "valid_AphiaID": 104466,
+                    "valid_name": "Calanus helgolandicus",
+                    "valid_authority": "(Claus, 1863)",
+                    "parentNameUsageID": 104152,
+                    "kingdom": "Animalia",
+                    "phylum": "Arthropoda",
+                    "class": "Hexanauplia",
+                    "order": "Calanoida",
+                    "family": "Calanidae",
+                    "genus": "Calanus",
+                    "citation": "Walter, T.C.; Boxshall, G. (2021). World of Copepods Database. Calanus helgolandicus (Claus, 1863). Accessed through: World Register of Marine Species at: http://www.marinespecies.org/aphia.php?p=taxdetails&id=104466 on 2021-11-11",
+                    "lsid": "urn:lsid:marinespecies.org:taxname:104466",
+                    "isMarine": 1,
+                    "isBrackish": 0,
+                    "isFreshwater": 0,
+                    "isTerrestrial": 0,
+                    "isExtinct": None,
+                    "match_type": "exact",
+                    "modified": "2004-12-21T15:54:05Z",
+                }
+            )
+            m.get(
+                "http://www.marinespecies.org/rest/AphiaRecordByAphiaID/104466",
+                text=response_2,
+            )
             dataset = self.load_dataset(STATIC_FILES["taxonomy_example"])
 
             results = self.cf.check_taxa(dataset)
@@ -2386,13 +2448,15 @@ class TestCF1_8(BaseTestCase):
         dataset = MockTimeSeries()
         # TODO: handle scalar dimension
         dataset.createDimension("taxon", 1)
-        abundance = dataset.createVariable('abundance', "f8", ('time',))
-        abundance.standard_name = "number_concentration_of_biological_taxon_in_sea_water"
+        abundance = dataset.createVariable("abundance", "f8", ("time",))
+        abundance.standard_name = (
+            "number_concentration_of_biological_taxon_in_sea_water"
+        )
         abundance.units = "m-3"
         abundance.coordinates = "taxon_name taxon_lsid"
-        taxon_name = dataset.createVariable('taxon_name', str, ("taxon",))
+        taxon_name = dataset.createVariable("taxon_name", str, ("taxon",))
         taxon_name.standard_name = "biological_taxon_name"
-        taxon_lsid = dataset.createVariable('taxon_lsid', str, ("taxon",))
+        taxon_lsid = dataset.createVariable("taxon_lsid", str, ("taxon",))
         taxon_lsid.standard_name = "biological_taxon_lsid"
         taxon_name[0] = "Esox lucius"
         taxon_lsid[0] = "urn:lsid:itis.gov:itis_tsn:162139"
@@ -2400,8 +2464,10 @@ class TestCF1_8(BaseTestCase):
         with requests_mock.Mocker() as m:
             m.get(re.compile(r"^http://www.lsid.info/urn:lsid:itis.gov:itis_tsn:\d+$"))
             response = r"""{"acceptedNameList":{"acceptedNames":[null],"class":"gov.usgs.itis.itis_service.data.SvcAcceptedNameList","tsn":"162139"},"class":"gov.usgs.itis.itis_service.data.SvcFullRecord","commentList":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonCommentList","comments":[null],"tsn":"162139"},"commonNameList":{"class":"gov.usgs.itis.itis_service.data.SvcCommonNameList","commonNames":[{"class":"gov.usgs.itis.itis_service.data.SvcCommonName","commonName":"northern pike","language":"English","tsn":"162139"},{"class":"gov.usgs.itis.itis_service.data.SvcCommonName","commonName":"grand brochet","language":"French","tsn":"162139"}],"tsn":"162139"},"completenessRating":{"class":"gov.usgs.itis.itis_service.data.SvcGlobalSpeciesCompleteness","completeness":"","rankId":220,"tsn":"162139"},"coreMetadata":{"class":"gov.usgs.itis.itis_service.data.SvcCoreMetadata","credRating":"TWG standards met","rankId":220,"taxonCoverage":"","taxonCurrency":"","taxonUsageRating":"valid","tsn":"162139","unacceptReason":""},"credibilityRating":{"class":"gov.usgs.itis.itis_service.data.SvcCredibilityData","credRating":"TWG standards met","tsn":"162139"},"currencyRating":{"class":"gov.usgs.itis.itis_service.data.SvcCurrencyData","rankId":220,"taxonCurrency":"","tsn":"162139"},"dateData":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonDateData","initialTimeStamp":"1996-06-13 14:51:08.0","tsn":"162139","updateDate":"2004-01-22"},"expertList":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonExpertList","experts":[{"class":"gov.usgs.itis.itis_service.data.SvcTaxonExpert","comment":"Research Curator of Fishes, North Carolina State Museum of Natural Sciences, Research Laboratory, 4301 Reedy Creek Rd., Raleigh, NC, 27607, USA","expert":"Wayne C. Starnes","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"}],"updateDate":"2004-02-23"}],"tsn":"162139"},"geographicDivisionList":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonGeoDivisionList","geoDivisions":[{"class":"gov.usgs.itis.itis_service.data.SvcTaxonGeoDivision","geographicValue":"North America","updateDate":"1998-09-14"}],"tsn":"162139"},"hierarchyUp":{"author":null,"class":"gov.usgs.itis.itis_service.data.SvcHierarchyRecord","parentName":"Esox","parentTsn":"162138","rankName":"Species","taxonName":"Esox lucius","tsn":"162139"},"jurisdictionalOriginList":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonJurisdictionalOriginList","jurisdictionalOrigins":[{"class":"gov.usgs.itis.itis_service.data.SvcTaxonJurisdictionalOrigin","jurisdictionValue":"Alaska","origin":"Native","updateDate":"2004-01-22"},{"class":"gov.usgs.itis.itis_service.data.SvcTaxonJurisdictionalOrigin","jurisdictionValue":"Canada","origin":"Native","updateDate":"2004-01-22"},{"class":"gov.usgs.itis.itis_service.data.SvcTaxonJurisdictionalOrigin","jurisdictionValue":"Continental US","origin":"Native & Introduced","updateDate":"2004-01-22"}],"tsn":"162139"},"kingdom":{"class":"gov.usgs.itis.itis_service.data.SvcKingdomInfo","kingdomId":"5","kingdomName":"Animalia  ","tsn":"162139"},"otherSourceList":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonOtherSourceList","otherSources":[{"acquisitionDate":"2003-03-17","class":"gov.usgs.itis.itis_service.data.SvcTaxonOtherSource","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"}],"source":"Catalog of Fishes, 17-Mar-2003","sourceComment":"http://www.calacademy.org/research/ichthyology/catalog/","sourceType":"website","updateDate":"2004-02-11","version":"13-Mar-03"},{"acquisitionDate":"1996-07-29","class":"gov.usgs.itis.itis_service.data.SvcTaxonOtherSource","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"}],"source":"NODC Taxonomic Code","sourceComment":"","sourceType":"database","updateDate":"2010-01-14","version":"8.0"},{"acquisitionDate":"2003-05-06","class":"gov.usgs.itis.itis_service.data.SvcTaxonOtherSource","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"northern pike","refLanguage":"English","referredTsn":"162139"},{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"},{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"grand brochet","refLanguage":"French","referredTsn":"162139"}],"source":"<a href=\"http://www.menv.gouv.qc.ca/biodiversite/centre.htm\">CDP","sourceComment":"","sourceType":"database","updateDate":"2003-05-08","version":"1999"}],"tsn":"162139"},"parentTSN":{"class":"gov.usgs.itis.itis_service.data.SvcParentTsn","parentTsn":"162138","tsn":"162139"},"publicationList":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonPublicationList","publications":[{"actualPubDate":"2004-07-01","class":"gov.usgs.itis.itis_service.data.SvcTaxonPublication","isbn":"1-888569-61-1","issn":"0097-0638","listedPubDate":"2004-01-01","pages":"ix + 386","pubComment":"Full author list: Nelson, Joseph S., Edwin J. Crossman, H�ctor Espinosa-P�rez, Lloyd T. Findley, Carter R. Gilbert, Robert N. Lea, and James D. Williams","pubName":"American Fisheries Society Special Publication, no. 29","pubPlace":"Bethesda, Maryland, USA","publisher":"American Fisheries Society","referenceAuthor":"Nelson, Joseph S., Edwin J. Crossman, H. Espinosa-P�rez, L. T. Findley, C. R. Gilbert, et al., eds.","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"grand brochet","refLanguage":"French","referredTsn":"162139"},{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"},{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"northern pike","refLanguage":"English","referredTsn":"162139"}],"title":"Common and scientific names of fishes from the United States, Canada, and Mexico, Sixth Edition","updateDate":"2021-10-27"},{"actualPubDate":"2003-12-31","class":"gov.usgs.itis.itis_service.data.SvcTaxonPublication","isbn":"","issn":"","listedPubDate":"2003-12-31","pages":"","pubComment":"As-yet (2003) unpublished manuscript from 1998","pubName":"Checklist of Vertebrates of the United States, the U.S. Territories, and Canada","pubPlace":"","publisher":"","referenceAuthor":"Banks, R. C., R. W. McDiarmid, A. L. Gardner, and W. C. Starnes","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"}],"title":"","updateDate":"2021-08-26"},{"actualPubDate":"1980-01-01","class":"gov.usgs.itis.itis_service.data.SvcTaxonPublication","isbn":"","issn":"0097-0638","listedPubDate":"1980-01-01","pages":"174","pubComment":"","pubName":"American Fisheries Society Special Publication, no. 12","pubPlace":"Bethesda, Maryland, USA","publisher":"American Fisheries Society","referenceAuthor":"Robins, Richard C., Reeve M. Bailey, Carl E. Bond, James R. Brooker, Ernest A. Lachner, et al.","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"},{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"northern pike","refLanguage":"English","referredTsn":"162139"}],"title":"A List of Common and Scientific Names of Fishes from the United States and Canada, Fourth Edition","updateDate":"2021-10-27"},{"actualPubDate":"1991-01-01","class":"gov.usgs.itis.itis_service.data.SvcTaxonPublication","isbn":"0-913235-70-9","issn":"0097-0638","listedPubDate":"1991-01-01","pages":"183","pubComment":"","pubName":"American Fisheries Society Special Publication, no. 20","pubPlace":"Bethesda, Maryland, USA","publisher":"American Fisheries Society","referenceAuthor":"Robins, Richard C., Reeve M. Bailey, Carl E. Bond, James R. Brooker, Ernest A. Lachner, et al.","referenceFor":[{"class":"gov.usgs.itis.itis_service.data.SvcReferenceForElement","name":"Esox lucius","refLanguage":null,"referredTsn":"162139"}],"title":"Common and Scientific Names of Fishes from the United States and Canada, Fifth Edition","updateDate":"2021-10-27"}],"tsn":"162139"},"scientificName":{"author":"Linnaeus, 1758","class":"gov.usgs.itis.itis_service.data.SvcScientificName","combinedName":"Esox lucius","kingdom":null,"tsn":"162139","unitInd1":null,"unitInd2":null,"unitInd3":null,"unitInd4":null,"unitName1":"Esox                               ","unitName2":"lucius","unitName3":null,"unitName4":null},"synonymList":{"class":"gov.usgs.itis.itis_service.data.SvcSynonymNameList","synonyms":[null],"tsn":"162139"},"taxRank":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonRankInfo","kingdomId":"5","kingdomName":"Animalia  ","rankId":"220","rankName":"Species        ","tsn":"162139"},"taxonAuthor":{"authorship":"Linnaeus, 1758","class":"gov.usgs.itis.itis_service.data.SvcTaxonAuthorship","tsn":"162139","updateDate":"2004-04-09"},"tsn":"162139","unacceptReason":{"class":"gov.usgs.itis.itis_service.data.SvcUnacceptData","tsn":"162139","unacceptReason":null},"usage":{"class":"gov.usgs.itis.itis_service.data.SvcTaxonUsageData","taxonUsageRating":"valid","tsn":"162139"}}"""
-            m.get("https://www.itis.gov/ITISWebService/jsonservice/getFullRecordFromTSN?tsn=162139",
-                  text=response)
+            m.get(
+                "https://www.itis.gov/ITISWebService/jsonservice/getFullRecordFromTSN?tsn=162139",
+                text=response,
+            )
 
             results = self.cf.check_taxa(dataset)
 
@@ -2412,10 +2478,11 @@ class TestCF1_8(BaseTestCase):
             taxon_name[0] = "Morone saxitilis"
             results = self.cf.check_taxa(dataset)
             result = results[0]
-            assert (result.msgs ==
-                    ["Supplied taxon name and ITIS scientific name do not match. "
-                     "Supplied taxon name is 'Morone saxitilis', ITIS scientific name "
-                     "for TSN 162139 is 'Esox lucius.'"])
+            assert result.msgs == [
+                "Supplied taxon name and ITIS scientific name do not match. "
+                "Supplied taxon name is 'Morone saxitilis', ITIS scientific name "
+                "for TSN 162139 is 'Esox lucius.'"
+            ]
 
     def test_taxonomy_skip_lsid(self):
         """
@@ -2424,13 +2491,15 @@ class TestCF1_8(BaseTestCase):
         dataset = MockTimeSeries()
         # TODO: handle scalar dimension
         dataset.createDimension("taxon", 1)
-        abundance = dataset.createVariable('abundance', "f8", ('time',))
-        abundance.standard_name = "number_concentration_of_biological_taxon_in_sea_water"
+        abundance = dataset.createVariable("abundance", "f8", ("time",))
+        abundance.standard_name = (
+            "number_concentration_of_biological_taxon_in_sea_water"
+        )
         abundance.units = "m-3"
         abundance.coordinates = "taxon_name taxon_lsid"
-        taxon_name = dataset.createVariable('taxon_name', str, ("taxon",))
+        taxon_name = dataset.createVariable("taxon_name", str, ("taxon",))
         taxon_name.standard_name = "biological_taxon_name"
-        taxon_lsid = dataset.createVariable('taxon_lsid', str, ("taxon",))
+        taxon_lsid = dataset.createVariable("taxon_lsid", str, ("taxon",))
         taxon_lsid.standard_name = "biological_taxon_lsid"
         # This would fail if checked against an LSID or even for binomial
         # nomenclature, obviously.
@@ -2443,15 +2512,15 @@ class TestCF1_8(BaseTestCase):
         # TODO: handle scalar dimension?
         dataset.createDimension("string80", 80)
         dataset.createDimension("taxon", 1)
-        abundance = dataset.createVariable('abundance', "f8", ('time',))
-        abundance.standard_name = "number_concentration_of_biological_taxon_in_sea_water"
+        abundance = dataset.createVariable("abundance", "f8", ("time",))
+        abundance.standard_name = (
+            "number_concentration_of_biological_taxon_in_sea_water"
+        )
         abundance.units = "m-3"
         abundance.coordinates = "taxon_name taxon_lsid"
-        taxon_name = dataset.createVariable('taxon_name', "S1", ("taxon",
-                                                                "string80"))
+        taxon_name = dataset.createVariable("taxon_name", "S1", ("taxon", "string80"))
         taxon_name.standard_name = "biological_taxon_name"
-        taxon_lsid = dataset.createVariable('taxon_lsid', "S1", ("taxon",
-                                                                "string80"))
+        taxon_lsid = dataset.createVariable("taxon_lsid", "S1", ("taxon", "string80"))
         taxon_lsid.standard_name = "biological_taxon_lsid"
         fake_str = "No check"
         taxon_name[0] = stringtoarr(fake_str, 80)
@@ -2459,6 +2528,7 @@ class TestCF1_8(BaseTestCase):
         assert len(results[0].msgs) == 0
         assert results[0].value[0] == results[0].value[1]
 
+
 class TestCFUtil(BaseTestCase):
     """
     Class to test the cfutil module.
@@ -2533,8 +2603,7 @@ class TestCFUtil(BaseTestCase):
 
         # add another cf_role var, bad
         nc = MockRaggedArrayRepr("timeseries", "contiguous")
-        v = nc.createVariable("var2", "i", ("INSTANCE_DIMENSION",),
-                              fill_value=None)
+        v = nc.createVariable("var2", "i", ("INSTANCE_DIMENSION",), fill_value=None)
         v.setncattr("cf_role", "yeetyeet_id")
         self.assertFalse(
             cfutil.is_dataset_valid_ragged_array_repr_featureType(nc, "timeseries")
diff --git a/compliance_checker/tests/test_ioos_profile.py b/compliance_checker/tests/test_ioos_profile.py
index adaafea..fd23488 100644
--- a/compliance_checker/tests/test_ioos_profile.py
+++ b/compliance_checker/tests/test_ioos_profile.py
@@ -12,7 +12,8 @@ from compliance_checker.ioos import (
     NamingAuthorityValidator,
 )
 from compliance_checker.tests import BaseTestCase
-from compliance_checker.tests.helpers import MockTimeSeries, MockVariable
+from compliance_checker.tests.helpers import (MockTimeSeries, MockVariable,
+                                              MockNetCDF)
 from compliance_checker.tests.resources import STATIC_FILES
 from compliance_checker.tests.test_cf import get_results
 
@@ -761,7 +762,7 @@ class TestIOOS1_2(BaseTestCase):
         # global platform, one platform variable, pass
         temp = ds.createVariable("temp", "d", ("time"))
         temp.setncattr("platform", "platform_var")
-        plat = ds.createVariable("platform_var", np.byte)
+        ds.createVariable("platform_var", np.byte)
         result = self.ioos.check_single_platform(ds)
         self.assertTrue(result.value)
         self.assertEqual(result.msgs, [])
@@ -769,7 +770,7 @@ class TestIOOS1_2(BaseTestCase):
         # two platform variables, fail
         temp2 = ds.createVariable("temp2", "d", ("time"))
         temp2.setncattr("platform", "platform_var2")
-        plat = ds.createVariable("platform_var2", np.byte)
+        ds.createVariable("platform_var2", np.byte)
         result = self.ioos.check_single_platform(ds)
         self.assertFalse(result.value)
 
@@ -777,7 +778,7 @@ class TestIOOS1_2(BaseTestCase):
         ds = MockTimeSeries()  # time, lat, lon, depth
         temp = ds.createVariable("temp", "d", ("time"))
         temp.setncattr("platform", "platform_var")
-        plat = ds.createVariable("platform_var", np.byte)
+        ds.createVariable("platform_var", np.byte)
         result = self.ioos.check_single_platform(ds)
         self.assertFalse(result.value)
 
@@ -1002,7 +1003,7 @@ class TestIOOS1_2(BaseTestCase):
         ftype = "timeseries"
         ds = MockTimeSeries()  # time, lat, lon, depth
         ds.setncattr("featureType", ftype)
-        temp = ds.createVariable("temp", "d", ("time"))
+        ds.createVariable("temp", "d", ("time"))
 
         # no platform variables or geophys vars with cf_role=timeseries_id, fail
         result = self.ioos._check_feattype_timeseries_cf_role(ds)
@@ -1045,7 +1046,7 @@ class TestIOOS1_2(BaseTestCase):
         ds = MockTimeSeries()  # time, lat, lon, depth
         ds.createDimension("station_dim", 21)
         ds.setncattr("featureType", "timeseries")
-        temp = ds.createVariable("temp", "d", ("time"))
+        ds.createVariable("temp", "d", ("time"))
         plat = ds.createVariable("station", "|S1", dimensions=("station_dim"))
         plat.setncattr("cf_role", "timeseries_id")
         result = self.ioos._check_feattype_timeseries_cf_role(ds)
@@ -1056,7 +1057,7 @@ class TestIOOS1_2(BaseTestCase):
         ds = MockTimeSeries()  # time, lat, lon, depth
         ds.setncattr("featureType", ftype)
         ds.createDimension("station_dim", 1)
-        temp = ds.createVariable("temp", "d", ("time"))
+        ds.createVariable("temp", "d", ("time"))
 
         # no platform variables or geophys vars with cf_role=timeseries_id, fail
         result = self.ioos._check_feattype_timeseriesprof_cf_role(ds)
@@ -1088,7 +1089,7 @@ class TestIOOS1_2(BaseTestCase):
         ds.setncattr("featureType", ftype)
         ds.createDimension("station_dim", 1)
         ds.createDimension("profile_dim", 1)
-        temp = ds.createVariable("temp", "d", ("time"))
+        ds.createVariable("temp", "d", ("time"))
         plat = ds.createVariable("station", "|S1", ("station_dim"))
         plat.setncattr("cf_role", "timeseries_id")
         pf = ds.createVariable("profile", "|S1", ("profile_dim"))
@@ -1101,7 +1102,7 @@ class TestIOOS1_2(BaseTestCase):
         ds.setncattr("featureType", ftype)
         ds.createDimension("station_dim", 1)
         ds.createDimension("profile_dim", 21)
-        temp = ds.createVariable("temp", "d", ("time"))
+        ds.createVariable("temp", "d", ("time"))
         plat = ds.createVariable("station", "|S1", ("station_dim"))
         plat.setncattr("cf_role", "timeseries_id")
         pf = ds.createVariable("profile", "|S1", ("profile_dim"))
@@ -1172,7 +1173,7 @@ class TestIOOS1_2(BaseTestCase):
         ds.setncattr("featureType", "trajectoryprofile")
         ds.createDimension("trajectory_dim", 1)
         ds.createDimension("profile_dim", 1)
-        temp = ds.createVariable("temp", "d", ("time"))
+        ds.createVariable("temp", "d", ("time"))
         trj = ds.createVariable("trajectory", "|S1", ("trajectory_dim"))
         trj.setncattr("cf_role", "trajectory_id")
         pf = ds.createVariable("profile", "|S1", ("profile_dim"))
@@ -1185,7 +1186,7 @@ class TestIOOS1_2(BaseTestCase):
         ds.setncattr("featureType", "trajectoryprofile")
         ds.createDimension("trajectory_dim", 1)
         ds.createDimension("profile_dim", 21)
-        temp = ds.createVariable("temp", "d", ("time"))
+        ds.createVariable("temp", "d", ("time"))
         trj = ds.createVariable("trajectory", "|S1", ("trajectory_dim"))
         trj.setncattr("cf_role", "trajectory_id")
         pf = ds.createVariable("profile", "|S1", ("profile_dim"))
@@ -1222,6 +1223,16 @@ class TestIOOS1_2(BaseTestCase):
         result = self.ioos._check_feattype_profile_cf_role(ds)
         self.assertTrue(result.value)
 
+    def test_feattype_point(self):
+        ds = MockNetCDF()
+        ds.createDimension("obs", 1)
+        ds.createVariable("lon", "f8", ("obs",))
+        ds.createVariable("lat", "f8", ("obs",))
+        ds.createVariable("temp", "f8", ("obs",))
+        ds.setncattr("featureType", "point")
+        result = self.ioos.check_cf_role_variables(ds)
+        assert result.value
+
     def test_check_instrument_make_model_calib_date(self):
         """
         Per the IOOS-1.2 spec, instrument variables should have
diff --git a/compliance_checker/tests/test_suite.py b/compliance_checker/tests/test_suite.py
index 33d9391..617f885 100644
--- a/compliance_checker/tests/test_suite.py
+++ b/compliance_checker/tests/test_suite.py
@@ -72,8 +72,10 @@ class TestSuite(unittest.TestCase):
             score_list, points, out_of = self.cs.standard_output(
                 ds.filepath(), limit, checker, groups
             )
-            # This asserts that print is able to generate all of the unicode output
-            self.cs.standard_output_generation(groups, limit, points, out_of, checker)
+            # This asserts that print is able to generate all of the unicode
+            # output
+            self.cs.standard_output_generation(groups, limit, points, out_of,
+                                               checker)
 
     def test_generate_dataset_netCDF4(self):
         """
diff --git a/compliance_checker/tests/test_util.py b/compliance_checker/tests/test_util.py
index 6d4ea64..ee860a9 100644
--- a/compliance_checker/tests/test_util.py
+++ b/compliance_checker/tests/test_util.py
@@ -51,4 +51,4 @@ class TestUtils(unittest.TestCase):
         self.assertFalse(util.datetime_is_iso(bad_datetime)[0])
 
         bad_date = "09192017"
-        self.assertFalse(util.datetime_is_iso(bad_datetime)[0])
+        self.assertFalse(util.datetime_is_iso(bad_date)[0])