diff --git a/src/pygeometadata/mcf.py b/src/pygeometadata/mcf.py index 2fa8fd6..fb74280 100644 --- a/src/pygeometadata/mcf.py +++ b/src/pygeometadata/mcf.py @@ -239,7 +239,7 @@ def set_abstract(self, abstract): self.mcf['identification']['abstract'] = abstract def set_keywords(self, keywords, section='default', keywords_type='theme', - vocabulary=None): + vocabulary=None): """Describe a dataset with a list of keywords. Keywords are grouped into sections for the purpose of complying with @@ -299,6 +299,7 @@ def describe_band(self, band_number, name=None, title=None, abstract=None, def describe_field(self, name, title=None, abstract=None, units=None): """Define metadata for a tabular field. + Args: name (str): name and unique identifier of the field title (str): title for the field @@ -324,7 +325,16 @@ def get_attr(attribute_list): self.mcf['content_info']['attributes'][idx] = attribute def write(self): - """Write MCF to disk.""" + """Write MCF and ISO-19139 XML to disk. + + This creates sidecar files with '.yml' and '.xml' extensions + appended to the full filename of the data source. For example, + + - 'myraster.tif' + - 'myraster.tif.yml' + - 'myraster.tif.xml' + + """ with open(self.mcf_path, 'w') as file: file.write(yaml.dump(self.mcf, Dumper=_NoAliasDumper)) # TODO: allow user to override the iso schema choice @@ -347,8 +357,9 @@ def to_string(self): def _set_spatial_info(self): """Populate the MCF using properties of the dataset.""" - gis_type = pygeoprocessing.get_gis_type(self.datasource) - if gis_type == pygeoprocessing.UNKNOWN_TYPE: + try: + gis_type = pygeoprocessing.get_gis_type(self.datasource) + except ValueError: self.mcf['metadata']['hierarchylevel'] = 'nonGeographicDataset' return @@ -388,7 +399,8 @@ def _set_spatial_info(self): attribute['title'] = '' attribute['abstract'] = '' attributes.append(attribute) - self.mcf['content_info']['attributes'] = attributes + if len(attributes): + self.mcf['content_info']['attributes'] = attributes vector = None layer = None @@ -412,7 +424,8 @@ def _set_spatial_info(self): attribute['title'] = '' attribute['abstract'] = band.GetDescription() attributes.append(attribute) - self.mcf['content_info']['attributes'] = attributes + if len(attributes): + self.mcf['content_info']['attributes'] = attributes raster = None gis_info = pygeoprocessing.get_raster_info(self.datasource) diff --git a/tests/test_mcf.py b/tests/test_mcf.py index 25dfec6..61592d7 100644 --- a/tests/test_mcf.py +++ b/tests/test_mcf.py @@ -29,11 +29,13 @@ } -def create_vector(target_filepath, field_map): - attribute_list = [{ - k: _OGR_TYPES_VALUES_MAP[v] - for k, v in field_map.items() - }] +def create_vector(target_filepath, field_map=None): + attribute_list = None + if field_map: + attribute_list = [{ + k: _OGR_TYPES_VALUES_MAP[v] + for k, v in field_map.items() + }] projection = osr.SpatialReference() projection.ImportFromEPSG(3116) pygeoprocessing.shapely_geometry_to_vector( @@ -112,6 +114,22 @@ def test_vector_MCF(self): f'{e}') mcf.write() + def test_vector_no_fields(self): + """MCF: validate MCF for basic vector with no fields.""" + from pygeometadata.mcf import MCF + + datasource_path = os.path.join(self.workspace_dir, 'vector.geojson') + create_vector(datasource_path, None) + + mcf = MCF(datasource_path) + try: + mcf.validate() + except (MCFValidationError, SchemaError) as e: + self.fail( + 'unexpected validation error occurred\n' + f'{e}') + mcf.write() + def test_raster_MCF(self): """MCF: validate basic raster MCF.""" from pygeometadata.mcf import MCF