import logging import xml.etree.ElementTree as ET from fiona.env import require_gdal_version from fiona.ogrext import _get_metadata_item log = logging.getLogger(__name__) class MetadataItem: # since GDAL 2.0 CREATION_FIELD_DATA_TYPES = "DMD_CREATIONFIELDDATATYPES" # since GDAL 2.3 CREATION_FIELD_DATA_SUB_TYPES = "DMD_CREATIONFIELDDATASUBTYPES" CREATION_OPTION_LIST = "DMD_CREATIONOPTIONLIST" LAYER_CREATION_OPTION_LIST = "DS_LAYER_CREATIONOPTIONLIST" # since GDAL 2.0 DATASET_OPEN_OPTIONS = "DMD_OPENOPTIONLIST" # since GDAL 2.0 EXTENSIONS = "DMD_EXTENSIONS" EXTENSION = "DMD_EXTENSION" VIRTUAL_IO = "DCAP_VIRTUALIO" # since GDAL 2.0 NOT_NULL_FIELDS = "DCAP_NOTNULL_FIELDS" # since gdal 2.3 NOT_NULL_GEOMETRY_FIELDS = "DCAP_NOTNULL_GEOMFIELDS" # since GDAL 3.2 UNIQUE_FIELDS = "DCAP_UNIQUE_FIELDS" # since GDAL 2.0 DEFAULT_FIELDS = "DCAP_DEFAULT_FIELDS" OPEN = "DCAP_OPEN" CREATE = "DCAP_CREATE" def _parse_options(xml): """Convert metadata xml to dict""" options = {} if len(xml) > 0: root = ET.fromstring(xml) for option in root.iter('Option'): option_name = option.attrib['name'] opt = {} opt.update((k, v) for k, v in option.attrib.items() if not k == 'name') values = [] for value in option.iter('Value'): values.append(value.text) if len(values) > 0: opt['values'] = values options[option_name] = opt return options @require_gdal_version('2.0') def dataset_creation_options(driver): """ Returns dataset creation options for driver Parameters ---------- driver : str Returns ------- dict Dataset creation options """ xml = _get_metadata_item(driver, MetadataItem.CREATION_OPTION_LIST) if xml is None: return {} if len(xml) == 0: return {} return _parse_options(xml) @require_gdal_version('2.0') def layer_creation_options(driver): """ Returns layer creation options for driver Parameters ---------- driver : str Returns ------- dict Layer creation options """ xml = _get_metadata_item(driver, MetadataItem.LAYER_CREATION_OPTION_LIST) if xml is None: return {} if len(xml) == 0: return {} return _parse_options(xml) @require_gdal_version('2.0') def dataset_open_options(driver): """ Returns dataset open options for driver Parameters ---------- driver : str Returns ------- dict Dataset open options """ xml = _get_metadata_item(driver, MetadataItem.DATASET_OPEN_OPTIONS) if xml is None: return {} if len(xml) == 0: return {} return _parse_options(xml) @require_gdal_version('2.0') def print_driver_options(driver): """ Print driver options for dataset open, dataset creation, and layer creation. Parameters ---------- driver : str """ for option_type, options in [("Dataset Open Options", dataset_open_options(driver)), ("Dataset Creation Options", dataset_creation_options(driver)), ("Layer Creation Options", layer_creation_options(driver))]: print(f"{option_type}:") if len(options) == 0: print("\tNo options available.") else: for option_name in options: print(f"\t{option_name}:") if 'description' in options[option_name]: print("\t\tDescription: {description}".format(description=options[option_name]['description'])) if 'type' in options[option_name]: print("\t\tType: {type}".format(type=options[option_name]['type'])) if 'values' in options[option_name] and len(options[option_name]['values']) > 0: print("\t\tAccepted values: {values}".format(values=",".join(options[option_name]['values']))) for attr_text, attribute in [('Default value', 'default'), ('Required', 'required'), ('Alias', 'aliasOf'), ('Min', 'min'), ('Max', 'max'), ('Max size', 'maxsize'), ('Scope', 'scope'), ('Alternative configuration option', 'alt_config_option')]: if attribute in options[option_name]: print("\t\t{attr_text}: {attribute}".format(attr_text=attr_text, attribute=options[option_name][attribute])) print("") @require_gdal_version('2.0') def extensions(driver): """ Returns file extensions supported by driver Parameters ---------- driver : str Returns ------- list List with file extensions or None if not specified by driver """ exts = _get_metadata_item(driver, MetadataItem.EXTENSIONS) if exts is None: return None return [ext for ext in exts.split(" ") if len(ext) > 0] def extension(driver): """ Returns file extension of driver Parameters ---------- driver : str Returns ------- str File extensions or None if not specified by driver """ return _get_metadata_item(driver, MetadataItem.EXTENSION) @require_gdal_version('2.0') def supports_vsi(driver): """ Returns True if driver supports GDAL's VSI*L API Parameters ---------- driver : str Returns ------- bool """ virutal_io = _get_metadata_item(driver, MetadataItem.VIRTUAL_IO) return virutal_io is not None and virutal_io.upper() == "YES" @require_gdal_version('2.0') def supported_field_types(driver): """ Returns supported field types Parameters ---------- driver : str Returns ------- list List with supported field types or None if not specified by driver """ field_types_str = _get_metadata_item(driver, MetadataItem.CREATION_FIELD_DATA_TYPES) if field_types_str is None: return None return [field_type for field_type in field_types_str.split(" ") if len(field_type) > 0] @require_gdal_version('2.3') def supported_sub_field_types(driver): """ Returns supported sub field types Parameters ---------- driver : str Returns ------- list List with supported field types or None if not specified by driver """ field_types_str = _get_metadata_item(driver, MetadataItem.CREATION_FIELD_DATA_SUB_TYPES) if field_types_str is None: return None return [field_type for field_type in field_types_str.split(" ") if len(field_type) > 0]