{"action":"created","comment":{"url":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/comments/61302618","id":61302618,"diff_hunk":"@@ -0,0 +1,689 @@\n+#!/usr/bin/env python\n+# -*- coding: utf-8 -*-\n+'''\n+cc_plugin_ncei/ncei_base.py\n+'''\n+\n+from compliance_checker.cf.cf import CFBaseCheck\n+from compliance_checker.acdd import ACDDBaseCheck, ACDD1_1Check\n+from compliance_checker.base import Result, BaseCheck, score_group, BaseNCCheck\n+from compliance_checker.cf.util import StandardNameTable, units_known\n+from cc_plugin_ncei.util import _find_platform_variables, _find_instrument_variables, getattr_check, hasattr_check, var_dtype\n+import cf_units\n+import numpy as np\n+\n+class NCEIBaseCheck(BaseNCCheck):\n+    register_checker = True\n+    @classmethod\n+    def __init__(self):\n+        self._std_names = StandardNameTable('cf-standard-name-table.xml')\n+    def setup(self, ds):\n+        pass\n+\n+    def check_required_attributes(self, dataset):\n+        '''\n+        Verifies that the dataset contains the NCEI required and highly recommended global attributes\n+        '''\n+\n+        out_of = 4\n+        score = 0\n+        messages = []\n+        \n+        for attribute in ('title', 'summary', 'keywords', 'Conventions'):\n+            test = getattr(dataset, attribute, '') != ''\n+\n+            if test:\n+                score += 1\n+            else:\n+                messages.append('Dataset is missing the global attribute {}'.format(attribute))\n+\n+        return Result(BaseCheck.HIGH, (score, out_of), 'Dataset contains NCEI required and highly recommended attributes', messages)\n+################################################################################\n+# Checks for Required Variables \n+################################################################################\n+    @score_group('Required Variables')\n+    def check_lat(self, dataset):\n+        '''\n+        float lat(time) ;//....................................... Depending on the precision used for the variable, the data type could be int or double instead of float. \n+                lat:long_name = \"\" ; //...................................... RECOMMENDED - Provide a descriptive, long name for this variable.\n+                lat:standard_name = \"latitude\" ; //.......................... REQUIRED    - Do not change.\n+                lat:units = \"degrees_north\" ; //............................. REQUIRED    - CF recommends degrees_north, but at least must use UDUNITS.\n+                lat:axis = \"Y\" ; //.......................................... REQUIRED    - Do not change.\n+                lat:valid_min = 0.0f ; //.................................... RECOMMENDED - Replace with correct value.\n+                lat:valid_max = 0.0f ; //.................................... RECOMMENDED - Replace with correct value.\n+                lat:_FillValue = 0.0f;//..................................... REQUIRED  if there could be missing values in the data.\n+                lat:ancillary_variables = \"\" ; //............................ RECOMMENDED - List other variables providing information about this variable.\n+                lat:comment = \"\" ; //........................................ RECOMMENDED - Add useful, additional information here.\n+                '''\n+        #Checks if the lat variable is formed properly\n+        msgs=[]\n+        results=[]\n+        var = u'lat'\n+       #Check 1) lat exist\n+\n+        if var in dataset.variables:\n+            exists_check = True\n+            results.append(Result(BaseCheck.HIGH, exists_check, (var,'exists'), msgs))\n+        else:\n+            msgs = ['{} does not exist'.format(var)]\n+            return Result(BaseCheck.HIGH, (0,1), (var,'exists'), msgs)\n+       \n+        #Check 2) Data Type\n+        valid_types = ['int', 'long', 'double', 'float']\n+        results.append(var_dtype(dataset, var, valid_types, BaseCheck.HIGH))\n+\n+        #Check 3,4,5 Check standard name, units, and axis\n+        get_attr_val = [\n+                ('standard_name', 'latitude'), \n+                ('units', 'degrees_north'), \n+                ('axis', 'Y')\n+                ]\n+        #Check 6,7,8,9,10,11 has these attributes\n+        has_var_attr = [\n+                '_FillValue',\n+                'valid_min',\n+                'valid_max',\n+                'ancillary_variables',\n+                'comment',\n+                'long_name'\n+                ]\n+\n+        for attr,val in get_attr_val:\n+            results.append(getattr_check(dataset, var, attr, val, BaseCheck.HIGH))\n+\n+        for attr in has_var_attr:\n+            results.append(hasattr_check(dataset, var, attr, BaseCheck.MEDIUM))\n+ \n+        return results\n+\n+    @score_group('Required Variables')\n+    def check_lon(self, dataset):\n+        '''\n+                float lat(time) ;//....................................... Depending on the precision used for the variable, the data type could be int or double instead of float. \n+                lat:long_name = \"\" ; //...................................... RECOMMENDED - Provide a descriptive, long name for this variable.\n+                lat:standard_name = \"latitude\" ; //.......................... REQUIRED    - Do not change.\n+                lat:units = \"degrees_north\" ; //............................. REQUIRED    - CF recommends degrees_north, but at least must use UDUNITS.\n+                lat:axis = \"Y\" ; //.......................................... REQUIRED    - Do not change.\n+                lat:valid_min = 0.0f ; //.................................... RECOMMENDED - Replace with correct value.\n+                lat:valid_max = 0.0f ; //.................................... RECOMMENDED - Replace with correct value.\n+                lat:_FillValue = 0.0f;//..................................... REQUIRED  if there could be missing values in the data.\n+                lat:ancillary_variables = \"\" ; //............................ RECOMMENDED - List other variables providing information about this variable.\n+                lat:comment = \"\" ; //........................................ RECOMMENDED - Add useful, additional information here.\n+                '''\n+        #Checks if the lon variable is formed properly\n+        msgs=[]\n+        results=[]\n+        var = u'lon'\n+\n+       #Check lon exist\n+        if var in dataset.variables:\n+            exists_check = True\n+            results.append(Result(BaseCheck.HIGH, exists_check, (var,'exists'), msgs))\n+        else:\n+            msgs = ['{} does not exist'.format(var)]\n+            return Result(BaseCheck.HIGH, (0,1), (var,'exists'), msgs)\n+       \n+        #Check Data Type\n+        valid_types = ['int', 'long', 'double', 'float']\n+        results.append(var_dtype(dataset, var, valid_types, BaseCheck.HIGH))\n+\n+        #Check Check standard name, units, and axis\n+        get_attr_val = [\n+                ('standard_name', 'longitude'), \n+                ('units', 'degrees_east'), \n+                ('axis', 'X')\n+                ]\n+        #Check has these attributes\n+        has_var_attr = [\n+                '_FillValue',\n+                'valid_min',\n+                'valid_max',\n+                'ancillary_variables',\n+                'comment',\n+                'long_name'\n+                ]\n+\n+        for attr,val in get_attr_val:\n+            results.append(getattr_check(dataset, var, attr, val, BaseCheck.HIGH))\n+\n+        for attr in has_var_attr:\n+            results.append(hasattr_check(dataset, var, attr, BaseCheck.MEDIUM))\n+ \n+        return results\n+\n+    @score_group('Required Variables')\n+    def check_time(self, dataset):\n+        '''\n+                double time(time) ;//........................................ Depending on the precision used for the variable, the data type could be int or double instead of float.\n+                time:long_name = \"\" ; //..................................... RECOMMENDED - Provide a descriptive, long name for this variable. \n+                time:standard_name = \"time\" ; //............................. REQUIRED    - Do not change\n+                time:units = \"seconds since 1970-01-01 00:00:00 0:00\" ; //... REQUIRED    - Use approved CF convention with approved UDUNITS.\n+                time:calendar = \"julian\" ; //................................ REQUIRED    - IF the calendar is not default calendar, which is \"gregorian\".\n+                time:axis = \"T\" ; //......................................... REQUIRED    - Do not change.\n+                time:_FillValue = 0.0f;//.................................... REQUIRED  if there could be missing values in the data.\n+                time:ancillary_variables = \"\" ; //........................... RECOMMENDED - List other variables providing information about this variable.\n+                time:comment = \"\" ; //....................................... RECOMMENDED - Add useful, additional information here. \n+                '''\n+        #Checks if the time variable is formed properly\n+        msgs=[]\n+        results=[]\n+        var = u'time'\n+       #Check time exist\n+\n+        if var in dataset.variables:\n+            exists_check = True\n+            results.append(Result(BaseCheck.HIGH, exists_check, (var,'exists'), msgs))\n+        else:\n+            msgs = ['{} does not exist'.format(var)]\n+            return Result(BaseCheck.HIGH, (0,1), (var,'exists'), msgs)\n+       \n+        #Check Data Type\n+        valid_types = ['int', 'long', 'double', 'float']\n+        results.append(var_dtype(dataset, var, valid_types, BaseCheck.HIGH))\n+\n+        #Check  Check standard name and axis\n+        get_attr_val = [\n+                ('standard_name', 'time'), \n+                ('axis', 'T')\n+                ]\n+        #Check has these attributes\n+        has_var_attr = [\n+                'ancillary_variables',\n+                'comment',\n+                'long_name',\n+                'calendar'\n+                ]\n+\n+        for attr,val in get_attr_val:\n+            results.append(getattr_check(dataset, var, attr, val, BaseCheck.HIGH))\n+\n+        for attr in has_var_attr:\n+            results.append(hasattr_check(dataset, var, attr, BaseCheck.MEDIUM))\n+ \n+        #Check Units\n+        if 'since' in getattr(dataset.variables[var], 'units', None):\n+            units_check = True\n+        else: \n+            msgs = ['units are wrong']\n+            units_check = False\n+        results.append(Result(BaseCheck.HIGH, units_check, (var,'units'), msgs))\n+        \n+        return results\n+\n+    @score_group('Required Variables')\n+    def check_height(self, dataset):\n+        #Checks if the lat variable is formed properly\n+        '''\n+                float z(time) ;//........................................ Depending on the precision used for the variable, the data type could be int or double instead of float. Also the variable \"z\" could be substituted with a more descriptive name like \"depth\", \"altitude\", \"pressure\", etc.\n+                z:long_name = \"\" ; //........................................ RECOMMENDED - Provide a descriptive, long name for this variable. \n+                z:standard_name = \"\" ; //.................................... REQUIRED    - Usually \"depth\" or \"altitude\" is used.\n+                z:units = \"\" ; //............................................ REQUIRED    - Use UDUNITS.\n+                z:axis = \"Z\" ; //............................................ REQUIRED    - Do not change.\n+                z:positive = \"\" ; //......................................... REQUIRED    - Use \"up\" or \"down\".\n+                z:valid_min = 0.0f ; //...................................... RECOMMENDED - Replace with correct value.\n+                z:valid_max = 0.0f ; //...................................... RECOMMENDED - Replace with correct value.\n+                z:_FillValue = 0.0f;//....................................... REQUIRED  if there could be missing values in the data.\n+                z:ancillary_variables = \"\" ; //.............................. RECOMMENDED - List other variables providing information about this variable.\n+                z:comment = \"\" ; //.......................................... RECOMMENDED - Add useful, additional information here.\n+                '''\n+        msgs=[]\n+        results=[]\n+        #best guess for variable name and units\n+        valid_types = ['int', 'long', 'double', 'float']\n+        valid_variable_names = [\"depth\", \"DEPTH\",\n+              \"depths\", \"DEPTHS\",\n+              \"height\", \"HEIGHT\",\n+              \"altitude\", \"ALTITUDE\",\n+              \"alt\", \"ALT\",\n+              \"Alt\", \"Altitude\",\n+              \"h\", \"H\",\n+              \"s_rho\", \"S_RHO\",\n+              \"s_w\", \"S_W\",\n+              \"z\", \"Z\",\n+              \"siglay\", \"SIGLAY\",\n+              \"siglev\", \"SIGLEV\",\n+              \"sigma\", \"SIGMA\",\n+              \"vertical\", \"VERTICAL\", \"lev\", \"LEV\", \"level\", \"LEVEL\"\n+              ]\n+        valid_units = ['m','meters','meter','metre','metres','km','kilometers','kilometer','bar','millibar','decibar','atm','atmosphere','pascal','Pa','hPa']\n+\n+        #Check  height exists and Check Axis \n+        no_height = True\n+        for var in dataset.variables:\n+            if getattr(dataset.variables[var],'axis',None) == 'Z':\n+                no_height = False\n+                results.append(Result(BaseCheck.HIGH, True, (var,'exists'), msgs))\n+                results.append(Result(BaseCheck.HIGH, True, (var,'axis'), msgs))\n+                break\n+        if no_height:\n+            return Result(BaseCheck.HIGH, (0,1), ('height_variable','exists'), msgs)\n+        \n+       #Check Height Name\n+        if var in valid_variable_names:\n+            name_check = True\n+            results.append(Result(BaseCheck.HIGH, name_check, (var,'valid_height_name'), msgs))\n+        else:\n+            msgs = ['The name of the Height Variable is not in the approved vocab list']\n+            return Result(BaseCheck.HIGH, (0,1), (var,'valid_height_name'), msgs)\n+       \n+        #Check Data Type\n+        valid_types = ['int', 'long', 'double', 'float']\n+        results.append(var_dtype(dataset, var, valid_types, BaseCheck.HIGH))\n+\n+        #Check Standard Name\n+        if getattr(dataset.variables[var], 'standard_name', None) in ['depth','altitude']:\n+            std_check = True\n+        else: \n+            msgs = ['standard name is wrong']\n+            std_check = False\n+        results.append(Result(BaseCheck.HIGH, std_check, (var,'standard_name'), msgs))\n+\n+        #Check Units\n+        if getattr(dataset.variables[var], 'units', None) in valid_units:\n+            units_check = True\n+        else: \n+            msgs = ['units are wrong']\n+            units_check = False\n+        results.append(Result(BaseCheck.HIGH, units_check, (var,'units'), msgs))\n+\n+        #Check has these attributes\n+        has_var_attr = [\n+                'ancillary_variables',\n+                'comment',\n+                'long_name',\n+                'valid_min',\n+                'valid_max',\n+                '_FillValue'\n+                ]\n+\n+        for attr in has_var_attr:\n+            results.append(hasattr_check(dataset, var, attr, BaseCheck.MEDIUM))\n+         \n+        #Check Positive\n+        if getattr(dataset.variables[var], 'positive', None) in ['up', 'down']:\n+            pos_check = True\n+        else: \n+            msgs = ['positive is incorrect']\n+            pos_check = False\n+        results.append(Result(BaseCheck.MEDIUM, pos_check, (var,'positive'), msgs))\n+        return results\n+\n+################################################################################\n+# Checks for Science Variables \n+################################################################################\n+    @score_group('Science Variables')\n+    def check_science(self, dataset):\n+        '''\n+                float geophysical_variable_1(time) ;//................................ This is an example of how each and every geophysical variable in the file should be represented. Replace the name of the variable(\"geophysical_variable_1\") with a suitable name. Replace \"float\" by data type which is appropriate for the variable. \n+                geophysical_variable_1:long_name = \"\" ; //................... RECOMMENDED - Provide a descriptive, long name for this variable. \n+                geophysical_variable_1:standard_name = \"\" ; //............... REQUIRED    - If using a CF standard name and a suitable name exists in the CF standard name table.\n+                geophysical_variable_1:nodc_name = \"\" ; //................... RECOMMENDED - From the NODC variables vocabulary, if standard_name does not exist.\n+                geophysical_variable_1:units = \"\" ; //....................... REQUIRED    - Use UDUNITS compatible units.\n+                geophysical_variable_1:scale_factor = 0.0f ; //.............. REQUIRED if the data uses a scale_factor other than 1.The data type should be the data type of the variable.\n+                geophysical_variable_1:add_offset = 0.0f ; // ............... REQUIRED if the data uses an add_offset other than 0. The data type should be the data type of the variable.\n+                geophysical_variable_1:_FillValue = 0.0f ; //................ REQUIRED  if there could be missing values in the data.\n+                geophysical_variable_1:valid_min = 0.0f ; //................. RECOMMENDED - Replace with correct value.\n+                geophysical_variable_1:valid_max = 0.0f ; //................. RECOMMENDED - Replace with correct value.\n+                geophysical_variable_1:coordinates = \"time lat lon z\" ; //... REQUIRED    - Include the auxiliary coordinate variables and optionally coordinate variables in the list. The order itself does not matter. Also, note that whenever any auxiliary coordinate variable contains a missing value, all other coordinate, auxiliary coordinate and data values corresponding to that element should also contain missing values.\n+                geophysical_variable_1:grid_mapping = \"crs\" ; //............. RECOMMENDED - It is highly recommended that the data provider put the data in a well known geographic coordinate system and provide the details of the coordinate system.\n+                geophysical_variable_1:source = \"\" ; //...................... RECOMMENDED - The method of production of the original data\n+                geophysical_variable_1:references = \"\" ; //.................. RECOMMENDED - Published or web-based references that describe the data or methods used to produce it.\n+                geophysical_variable_1: cell_methods = \"\" ; // .............. RECOMMENDED - Use the coordinate variables to define the cell values (ex., \"time: point lon: point lat: point z: point\").\n+                geophysical_variable_1:ancillary_variables = \"instrument_parameter_variable platform_variable boolean_flag_variable enumerated_flag_variable\" ; //......... RECOMMENDED - Identify the variable name(s) of the flag(s) and other ancillary variables relevant to this variable.  Use a space-separated list.\n+                geophysical_variable_1:platform = \"platform_variable\" ; //... RECOMMENDED - Refers to name of variable containing information on the platform from which this variable was collected.\n+                geophysical_variable_1:instrument = \"instrument_variable\";//..RECOMMENDED - Refers to name of variable containing information on the instrument from which this variable was collected.\n+                geophysical_variable_1:comment = \"\" ; //..................... RECOMMENDED - Add useful, additional information here.\n+                '''\n+        #Check the science variables to ensure they are good\n+        results = []\n+        msgs = []\n+        for name in dataset.variables:\n+            if hasattr(dataset.variables[name],'coordinates') and not hasattr(dataset.variables[name],'flag_meanings'):\n+                #This is a science Variable.  Start Checks.\n+                #Check  has these attributes\n+                has_var_attr = [\n+                        '_FillValue',\n+                        'valid_min',\n+                        'valid_max',\n+                        'ancillary_variables',\n+                        'comment',\n+                        'long_name',\n+                        'units',\n+                        'nodc_name',\n+                        'grid_mapping',\n+                        'source',\n+                        'references'\n+                        ]\n+                var  = name\n+\n+                for attr in has_var_attr:\n+                    results.append(hasattr_check(dataset, var, attr, BaseCheck.MEDIUM))\n+\n+                #Check Units\n+                units = getattr(dataset.variables[name],'units',None)\n+                units_check = units_known(units)\n+                if not units_check:\n+                    msgs.append('Units are wrong for {}'.format(name))\n+                results.append(Result(BaseCheck.HIGH, units_check, (name,'udunits'),msgs))\n+\n+                #Check scale_factor\n+                level = BaseCheck.MEDIUM\n+                if hasattr(dataset.variables[name], 'scale_factor'):\n+                    scale_check = (1,2)\n+                    msgs = ['scale_factor exists, but the dtype is not the same as the data']\n+                else: \n+                    msgs = ['scale_factor not present']\n+                    scale_check = False\n+                    level = BaseCheck.LOW\n+                try:\n+                    if dataset.variables[name].dtype == getattr(dataset.variables[name],'scale_factor',None).dtype:\n+                        scale_check = (2,2)\n+                        msgs = []\n+                except:\n+                    error_reached = True\n+                results.append(Result(level, scale_check, (name,'scale_factor'), msgs))\n+\n+                 #Check offset\n+                level = BaseCheck.MEDIUM\n+                if hasattr(dataset.variables[name], 'add_offset'):\n+                    msgs = ['add_offset present, but the dtype is not the same as the data']\n+                    offset_check = (1,2)\n+                else: \n+                    msgs = ['scale_factor not present']\n+                    offset_check = False\n+                    level = BaseCheck.LOW\n+                try:\n+                    if dataset.variables[name].dtype == getattr(dataset.variables[name],'add_offset',None).dtype:\n+                        offset_check = (2,2)\n+                        msgs = []\n+                except: \n+                    error_reached = True\n+                results.append(Result(level, offset_check, (name,'add_offset'), msgs))\n+ \n+\n+                #Check Platform\n+                level = BaseCheck.MEDIUM\n+                if not hasattr(dataset.variables[name], 'platform'):\n+                    plat_check = False\n+                    level = BaseCheck.LOW\n+                    msgs = ['platform attribute is missing']\n+                elif getattr(dataset.variables[name], 'platform', None) in dataset.variables:\n+                    plat_check = (2,2)\n+                else:\n+                    plat_check = (1,2)\n+                    msgs = ['platform attribute is not present in the variables']\n+                if not hasattr(dataset,'platform'):\n+                    results.append(Result(level, plat_check, (name,'platform'), msgs))\n+                msgs = []  \n+                #Check Instrument\n+                level = BaseCheck.MEDIUM\n+                if not hasattr(dataset.variables[name], 'instrument'):\n+                    inst_check = False\n+                    level = BaseCheck.LOW\n+                    msgs = ['instrument attribute is missing']\n+                elif getattr(dataset.variables[name], 'instrument', None) in dataset.variables:\n+                    inst_check = (2,2)\n+                else:\n+                    inst_check = (1,2)\n+                    msgs = ['instrument attribute is not present in the variables']\n+                if not hasattr(dataset,'instrument'):\n+                    results.append(Result(level, inst_check, (name,'instrument'), msgs)) \n+             \n+                #Check  Standard Name\n+                level = BaseCheck.HIGH\n+                if not hasattr(dataset.variables[name], 'standard_name'):\n+                    inst_check = (0,2)\n+                    msgs = ['standard_name attribute is missing']\n+                elif getattr(dataset.variables[name], 'standard_name', None) in self._std_names:\n+                    inst_check = (2,2)\n+                else:\n+                    inst_check = (1,2)\n+                    msgs = ['standard_name is not in standard name table']\n+                results.append(Result(level, inst_check, (name,'standard_name'), msgs)) \n+            else:\n+                continue\n+        return results\n+    \n+################################################################################\n+# Checks for QA/QC Variables \n+################################################################################\n+    @score_group('QA/QC Variables')\n+    def check_qaqc(self, dataset):\n+        '''\n+                byte boolean_flag_variable(timeSeries,ntimeMax); //............................. A boolean flag variable, in which each bit of the flag can be a 1 or 0.\n+                boolean_flag_variable:standard_name= \"\" ; //................. RECOMMENDED - This attribute should include the standard name of the variable which this flag contributes plus the modifier: \"status_flag\" (for example, \"sea_water_temperature status_flag\"). See CF standard name modifiers.\n+                boolean_flag_variable:long_name = \"\" ; //.................... RECOMMENDED - Provide a descriptive, long name for this variable. \n+                boolean_flag_variable:flag_masks = ; //...................... REQUIRED    - Provide a comma-separated list describing the binary condition of the flags. \n+                boolean_flag_variable:flag_meanings = \"\" ; //................ REQUIRED    - Provide a comma-separated list of flag values that map to the flag_masks.\n+                boolean_flag_variable:references = \"\" ; //................... RECOMMENDED - Published or web-based references that describe the data or methods used to produce it.\n+                boolean_flag_variable:comment = \"\" ; //...................... RECOMMENDED - Add useful, additional information here.\n+        int enumerated_flag_variable(timeSeries,ntimeMax);  //...................... An enumerated flag variable, in which numeric values refer to defined, exclusive conditions.\n+                enumerated_flag_variable:standard_name= \"\" ; //.............. RECOMMENDED - This attribute should include the standard name of the variable which this flag contributes plus the modifier: \"status_flag\" (for example, \"sea_water_temperature status_flag\"). See CF standard name modifiers.\n+                enumerated_flag_variable:long_name = \"\" ; //................. RECOMMENDED - Provide a descriptive, long name for this variable. \n+                enumerated_flag_variable:flag_values = ; //.................. REQUIRED    - Provide a comma-separated list of flag values that map to the flag_meanings.\n+                enumerated_flag_variable:flag_meanings = \"\" ; //............. REQUIRED    - Provide a space-separated list of meanings corresponding to each of the flag_values\n+                enumerated_flag_variable:references = \"\" ; //................ RECOMMENDED - Published or web-based references that describe the data or methods used to produce it.\n+                enumerated_flag_variable:comment = \"\" ; //................... RECOMMENDED - Add useful, additional information here.\n+                '''\n+        #Check the qaqc variables to ensure they are good\n+        results = []\n+        msgs = []\n+        std_name_list = [getattr(dataset.variables[var], 'standard_name', None) for var in dataset.variables]\n+        for name in dataset.variables:\n+            if hasattr(dataset.variables[name],'flag_meanings'):\n+                #Check Standard Name\n+                std_check = 0\n+                msgs = []\n+\n+                std_name = getattr(dataset.variables[name], 'standard_name', 'thereis noname')\n+                std_name_split = std_name.split(' ')\n+                if std_name_split[0] in std_name_list:\n+                    std_check = std_check + 1\n+                else:\n+                    msgs.append('Standard Name does not reference a variable in the dataset.')\n+                if std_name_split[1] == 'status_flag':\n+                    std_check = std_check + 1\n+                else:\n+                    msgs.append('Standard Name does not end in \"status_flag\"')\n+                results.append(Result(BaseCheck.HIGH, (std_check,2), (name,'standard_name'), msgs))\n+\n+                #Check Flag Mask / Flag Values\n+                msgs = []\n+                mask_val_check = False\n+                test_name = 'flag_masks_values'\n+                if 'bool' in str(dataset.variables[name].dtype):\n+                    mask_val_check = hasattr(dataset.variables[name],'flag_masks')\n+                    test_name = 'flag_masks'\n+                    mask_length = len(getattr(dataset.variables[name], 'flag_masks', None)) #Used in length check\n+                elif 'int' in str(dataset.variables[name].dtype):\n+                    mask_val_check = hasattr(dataset.variables[name], 'flag_values')\n+                    test_name = 'flag_values'\n+                    mask_length = len(getattr(dataset.variables[name], 'flag_values', None)) #Used in length check\n+                else:\n+                    mask_val_check = False\n+                    msgs = ['flag_masks or flag_values are not present']\n+                    mask_length = 0\n+                results.append(Result(BaseCheck.HIGH, mask_val_check, (name,test_name), msgs))\n+\n+                #Check Flag Meaning\n+                msgs = []\n+                if hasattr(dataset.variables[name],'flag_meanings'):\n+                    meanings_check = True\n+                    meaning_length = len(getattr(dataset.variables[name],'flag_meanings',None).split(','))","path":"cc_plugin_ncei/ncei_base.py","position":512,"original_position":512,"commit_id":"3b220af07f53d6fd0ae4e8e006f99b4e97c8b0bb","original_commit_id":"3b220af07f53d6fd0ae4e8e006f99b4e97c8b0bb","user":{"login":"lukecampbell","id":1155163,"avatar_url":"https://avatars.githubusercontent.com/u/1155163?v=3","gravatar_id":"","url":"https://api.github.com/users/lukecampbell","html_url":"https://github.com/lukecampbell","followers_url":"https://api.github.com/users/lukecampbell/followers","following_url":"https://api.github.com/users/lukecampbell/following{/other_user}","gists_url":"https://api.github.com/users/lukecampbell/gists{/gist_id}","starred_url":"https://api.github.com/users/lukecampbell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lukecampbell/subscriptions","organizations_url":"https://api.github.com/users/lukecampbell/orgs","repos_url":"https://api.github.com/users/lukecampbell/repos","events_url":"https://api.github.com/users/lukecampbell/events{/privacy}","received_events_url":"https://api.github.com/users/lukecampbell/received_events","type":"User","site_admin":false},"body":"So this is correct, it's just disappointing.","created_at":"2016-04-27T17:38:35Z","updated_at":"2016-04-27T17:38:35Z","html_url":"https://github.com/ioos/cc-plugin-ncei/pull/2#discussion_r61302618","pull_request_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2","_links":{"self":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/comments/61302618"},"html":{"href":"https://github.com/ioos/cc-plugin-ncei/pull/2#discussion_r61302618"},"pull_request":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2"}}},"pull_request":{"url":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2","id":67425252,"html_url":"https://github.com/ioos/cc-plugin-ncei/pull/2","diff_url":"https://github.com/ioos/cc-plugin-ncei/pull/2.diff","patch_url":"https://github.com/ioos/cc-plugin-ncei/pull/2.patch","issue_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/issues/2","number":2,"state":"open","locked":false,"title":"NCEI Checks Implemented","user":{"login":"DanielJMaher","id":6311839,"avatar_url":"https://avatars.githubusercontent.com/u/6311839?v=3","gravatar_id":"","url":"https://api.github.com/users/DanielJMaher","html_url":"https://github.com/DanielJMaher","followers_url":"https://api.github.com/users/DanielJMaher/followers","following_url":"https://api.github.com/users/DanielJMaher/following{/other_user}","gists_url":"https://api.github.com/users/DanielJMaher/gists{/gist_id}","starred_url":"https://api.github.com/users/DanielJMaher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DanielJMaher/subscriptions","organizations_url":"https://api.github.com/users/DanielJMaher/orgs","repos_url":"https://api.github.com/users/DanielJMaher/repos","events_url":"https://api.github.com/users/DanielJMaher/events{/privacy}","received_events_url":"https://api.github.com/users/DanielJMaher/received_events","type":"User","site_admin":false},"body":"@lukecampbell  @benjwadams\r\n\r\nI still have to add my tests, but there are example CDLs that should allow for some rational testing if you guys can.  Also, if i need to clean code, please let me know.","created_at":"2016-04-21T21:27:17Z","updated_at":"2016-04-27T17:38:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8bd474846b981c13b119c9cd6b4f14901626fef3","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2/commits","review_comments_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2/comments","review_comment_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/issues/2/comments","statuses_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/statuses/3b220af07f53d6fd0ae4e8e006f99b4e97c8b0bb","head":{"label":"DanielJMaher:master","ref":"master","sha":"3b220af07f53d6fd0ae4e8e006f99b4e97c8b0bb","user":{"login":"DanielJMaher","id":6311839,"avatar_url":"https://avatars.githubusercontent.com/u/6311839?v=3","gravatar_id":"","url":"https://api.github.com/users/DanielJMaher","html_url":"https://github.com/DanielJMaher","followers_url":"https://api.github.com/users/DanielJMaher/followers","following_url":"https://api.github.com/users/DanielJMaher/following{/other_user}","gists_url":"https://api.github.com/users/DanielJMaher/gists{/gist_id}","starred_url":"https://api.github.com/users/DanielJMaher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DanielJMaher/subscriptions","organizations_url":"https://api.github.com/users/DanielJMaher/orgs","repos_url":"https://api.github.com/users/DanielJMaher/repos","events_url":"https://api.github.com/users/DanielJMaher/events{/privacy}","received_events_url":"https://api.github.com/users/DanielJMaher/received_events","type":"User","site_admin":false},"repo":{"id":54497625,"name":"cc-plugin-ncei","full_name":"DanielJMaher/cc-plugin-ncei","owner":{"login":"DanielJMaher","id":6311839,"avatar_url":"https://avatars.githubusercontent.com/u/6311839?v=3","gravatar_id":"","url":"https://api.github.com/users/DanielJMaher","html_url":"https://github.com/DanielJMaher","followers_url":"https://api.github.com/users/DanielJMaher/followers","following_url":"https://api.github.com/users/DanielJMaher/following{/other_user}","gists_url":"https://api.github.com/users/DanielJMaher/gists{/gist_id}","starred_url":"https://api.github.com/users/DanielJMaher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DanielJMaher/subscriptions","organizations_url":"https://api.github.com/users/DanielJMaher/orgs","repos_url":"https://api.github.com/users/DanielJMaher/repos","events_url":"https://api.github.com/users/DanielJMaher/events{/privacy}","received_events_url":"https://api.github.com/users/DanielJMaher/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/DanielJMaher/cc-plugin-ncei","description":"Compliance Checker Plugin for NCEI Templates","fork":true,"url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei","forks_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/forks","keys_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/keys{/key_id}","collaborators_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/teams","hooks_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/hooks","issue_events_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/issues/events{/number}","events_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/events","assignees_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/assignees{/user}","branches_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/branches{/branch}","tags_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/tags","blobs_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/git/refs{/sha}","trees_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/git/trees{/sha}","statuses_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/statuses/{sha}","languages_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/languages","stargazers_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/stargazers","contributors_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/contributors","subscribers_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/subscribers","subscription_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/subscription","commits_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/commits{/sha}","git_commits_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/git/commits{/sha}","comments_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/comments{/number}","issue_comment_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/issues/comments{/number}","contents_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/contents/{+path}","compare_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/compare/{base}...{head}","merges_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/merges","archive_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/downloads","issues_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/issues{/number}","pulls_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/pulls{/number}","milestones_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/milestones{/number}","notifications_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/labels{/name}","releases_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/releases{/id}","deployments_url":"https://api.github.com/repos/DanielJMaher/cc-plugin-ncei/deployments","created_at":"2016-03-22T18:04:21Z","updated_at":"2016-03-22T18:04:22Z","pushed_at":"2016-04-27T16:24:27Z","git_url":"git://github.com/DanielJMaher/cc-plugin-ncei.git","ssh_url":"git@github.com:DanielJMaher/cc-plugin-ncei.git","clone_url":"https://github.com/DanielJMaher/cc-plugin-ncei.git","svn_url":"https://github.com/DanielJMaher/cc-plugin-ncei","homepage":null,"size":312,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ioos:master","ref":"master","sha":"8ea7fd1a87864041e005b8d3f7ff737ca453c4f5","user":{"login":"ioos","id":5313832,"avatar_url":"https://avatars.githubusercontent.com/u/5313832?v=3","gravatar_id":"","url":"https://api.github.com/users/ioos","html_url":"https://github.com/ioos","followers_url":"https://api.github.com/users/ioos/followers","following_url":"https://api.github.com/users/ioos/following{/other_user}","gists_url":"https://api.github.com/users/ioos/gists{/gist_id}","starred_url":"https://api.github.com/users/ioos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ioos/subscriptions","organizations_url":"https://api.github.com/users/ioos/orgs","repos_url":"https://api.github.com/users/ioos/repos","events_url":"https://api.github.com/users/ioos/events{/privacy}","received_events_url":"https://api.github.com/users/ioos/received_events","type":"Organization","site_admin":false},"repo":{"id":45073308,"name":"cc-plugin-ncei","full_name":"ioos/cc-plugin-ncei","owner":{"login":"ioos","id":5313832,"avatar_url":"https://avatars.githubusercontent.com/u/5313832?v=3","gravatar_id":"","url":"https://api.github.com/users/ioos","html_url":"https://github.com/ioos","followers_url":"https://api.github.com/users/ioos/followers","following_url":"https://api.github.com/users/ioos/following{/other_user}","gists_url":"https://api.github.com/users/ioos/gists{/gist_id}","starred_url":"https://api.github.com/users/ioos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ioos/subscriptions","organizations_url":"https://api.github.com/users/ioos/orgs","repos_url":"https://api.github.com/users/ioos/repos","events_url":"https://api.github.com/users/ioos/events{/privacy}","received_events_url":"https://api.github.com/users/ioos/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ioos/cc-plugin-ncei","description":"Compliance Checker Plugin for NCEI Templates","fork":false,"url":"https://api.github.com/repos/ioos/cc-plugin-ncei","forks_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/forks","keys_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/teams","hooks_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/hooks","issue_events_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/issues/events{/number}","events_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/events","assignees_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/assignees{/user}","branches_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/branches{/branch}","tags_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/tags","blobs_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/git/refs{/sha}","trees_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/statuses/{sha}","languages_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/languages","stargazers_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/stargazers","contributors_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/contributors","subscribers_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/subscribers","subscription_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/subscription","commits_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/commits{/sha}","git_commits_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/git/commits{/sha}","comments_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/comments{/number}","issue_comment_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/issues/comments{/number}","contents_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/contents/{+path}","compare_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/merges","archive_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/downloads","issues_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/issues{/number}","pulls_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls{/number}","milestones_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/milestones{/number}","notifications_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/labels{/name}","releases_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/releases{/id}","deployments_url":"https://api.github.com/repos/ioos/cc-plugin-ncei/deployments","created_at":"2015-10-27T22:13:15Z","updated_at":"2016-02-15T23:17:09Z","pushed_at":"2016-04-27T16:24:28Z","git_url":"git://github.com/ioos/cc-plugin-ncei.git","ssh_url":"git@github.com:ioos/cc-plugin-ncei.git","clone_url":"https://github.com/ioos/cc-plugin-ncei.git","svn_url":"https://github.com/ioos/cc-plugin-ncei","homepage":null,"size":10,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":2,"forks":2,"open_issues":2,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2"},"html":{"href":"https://github.com/ioos/cc-plugin-ncei/pull/2"},"issue":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/issues/2"},"comments":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/issues/2/comments"},"review_comments":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2/comments"},"review_comment":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/pulls/2/commits"},"statuses":{"href":"https://api.github.com/repos/ioos/cc-plugin-ncei/statuses/3b220af07f53d6fd0ae4e8e006f99b4e97c8b0bb"}}}}