Skip to content

Commit

Permalink
Remove inapplicable XML constants, and support metadata defaults.
Browse files Browse the repository at this point in the history
  • Loading branch information
dharvey-consbio committed Sep 13, 2016
1 parent 87acce5 commit 05db927
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 46 deletions.
4 changes: 2 additions & 2 deletions gis_metadata/iso_metadata_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,12 +686,12 @@ def _update_report_item(self, **update_props):

return update_property(xpath_root=self._data_map['_dataqual_report'], **update_props)

def update(self, use_template=False):
def update(self, use_template=False, **metadata_defaults):
""" OVERRIDDEN: Prevents writing multiple CharacterStrings per XPATH property """

self.validate()

tree_to_update = self._xml_tree if not use_template else self._get_template()
tree_to_update = self._xml_tree if not use_template else self._get_template(**metadata_defaults)

# Iterate over keys, and extract non-primitive root for all XPATHs
# xroot = identificationInfo/MD_DataIdentification/abstract/
Expand Down
28 changes: 13 additions & 15 deletions gis_metadata/metadata_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from gis_metadata.parser_utils import DATE_TYPE, DATE_VALUES
from gis_metadata.parser_utils import DATE_TYPE_RANGE, DATE_TYPE_RANGE_BEGIN, DATE_TYPE_RANGE_END
from gis_metadata.parser_utils import filter_property, get_required_keys, get_xml_constants
from gis_metadata.parser_utils import filter_property, get_required_keys
from gis_metadata.parser_utils import update_property, validate_any, validate_keyset
from gis_metadata.parser_utils import ParserException

Expand Down Expand Up @@ -43,7 +43,7 @@ def convert_parser_to(parser, parser_or_type):
return new_parser


def get_metadata_parser(metadata_container):
def get_metadata_parser(metadata_container, **metadata_defaults):
"""
:return: an appropriate instance of MetadataParser depending on what is passed in. If metadata_container
is a type, an instance of it must contain an update method that returns parsable content.
Expand All @@ -53,16 +53,16 @@ def get_metadata_parser(metadata_container):
"""

if isinstance(metadata_container, type):
metadata_container = metadata_container().update()
metadata_container = metadata_container().update(**metadata_defaults)

xml_root, xml_tree = get_parsed_content(metadata_container)

# The get_parsed_content method ensures only these roots will be returned

if xml_root == FGDC_ROOT:
return FgdcParser(xml_tree)
return FgdcParser(xml_tree, **metadata_defaults)
elif xml_root in ISO_ROOTS:
return IsoParser(xml_tree)
return IsoParser(xml_tree, **metadata_defaults)


def get_parsed_content(metadata_content):
Expand Down Expand Up @@ -174,7 +174,7 @@ class MetadataParser(object):
"""

def __init__(self, metadata_to_parse=None, out_file_or_path=None):
def __init__(self, metadata_to_parse=None, out_file_or_path=None, **metadata_defaults):
"""
Initialize new parser with valid content as defined by get_parsed_content
:see: get_parsed_content(metdata_content) for more on what constitutes valid content
Expand All @@ -187,7 +187,7 @@ def __init__(self, metadata_to_parse=None, out_file_or_path=None):
self._xml_tree = None

if metadata_to_parse is None:
self._xml_tree = self._get_template()
self._xml_tree = self._get_template(**metadata_defaults)
self._xml_root = self._data_map['root']
else:
self._xml_root, self._xml_tree = get_parsed_content(metadata_to_parse)
Expand Down Expand Up @@ -227,11 +227,9 @@ def _init_data_map(self):

if self._data_map is None:
self._data_map = {'root': None}

self._data_map.update({}.fromkeys(get_required_keys()))
self._data_map.update({}.fromkeys(get_xml_constants()))

def _get_template(self, root=None):
def _get_template(self, root=None, **metadata_defaults):
""" Iterate over items retrieved from _get_template_paths to populate template """

if root is None:
Expand All @@ -242,21 +240,21 @@ def _get_template(self, root=None):

template = create_element_tree(root)

for path, val in iteritems(self._get_template_paths()):
for path, val in iteritems(self._get_template_paths(**metadata_defaults)):
if path and val:
insert_element(template, 0, path, val)

return template

def _get_template_paths(self):
def _get_template_paths(self, **metadata_defaults):
"""
Default template XPATHs: MAY be overridden in children.
:return: a dict containing at least the distribution contact info: {xpath: value}
"""

if not hasattr(self, '_template_paths'):
self._template_paths = {
self._data_map[key]: val for key, val in iteritems(get_xml_constants())
self._data_map[key]: val for key, val in iteritems(metadata_defaults)
}

return self._template_paths
Expand Down Expand Up @@ -334,15 +332,15 @@ def write(self, use_template=False, out_file_or_path=None, encoding=DEFAULT_ENCO

write_element(self.update(use_template), out_file_or_path, encoding)

def update(self, use_template=False):
def update(self, use_template=False, **metadata_defaults):
"""
Validates instance properties and updates either a template or the original XML tree with them.
:param use_template: if True, updates a new template XML tree; otherwise the original XML tree
"""

self.validate()

tree_to_update = self._xml_tree if not use_template else self._get_template()
tree_to_update = self._xml_tree if not use_template else self._get_template(**metadata_defaults)

for prop, xpath in iteritems(self._data_map):
if not prop.startswith('_'): # Update only non-private properties
Expand Down
24 changes: 0 additions & 24 deletions gis_metadata/parser_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,6 @@
}
}

# A map of default XML values by property name

_xml_constants = {
'dist_contact_org': 'Data Basin',
'dist_contact_person': 'Data Basin Administrator',
'dist_address_type': 'physical address',
'dist_address': '136 SW Washington Ave, Suite 202',
'dist_city': 'Corvallis',
'dist_state': 'OR',
'dist_postal': '97333',
'dist_country': 'USA',
'dist_phone': '541-757-0687',
'dist_email': 'databasin_admin@consbio.org',
}


def format_xpath(xpath, *args, **kwargs):
""" :return: an XPATH formatted with the ordered or keyword values """
Expand Down Expand Up @@ -163,15 +148,6 @@ def get_required_keys():
return deepcopy(_required_keys)


def get_xml_constants():
"""
Get a deep copy of the XML constants Dictionary, which contains a map of
default XML values by property name (used to pre-populate XML templates)
"""

return deepcopy(_xml_constants)


def get_xpath_root(xpath):
""" :return: the base of an XPATH: the part preceding any formattable segments """

Expand Down
24 changes: 19 additions & 5 deletions gis_metadata/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from gis_metadata.iso_metadata_parser import IsoParser, ISO_ROOTS, _iso_tag_formats
from gis_metadata.metadata_parser import MetadataParser, get_metadata_parser, get_parsed_content

from gis_metadata.parser_utils import get_complex_definitions, get_required_keys, get_xml_constants
from gis_metadata.parser_utils import get_complex_definitions, get_required_keys
from gis_metadata.parser_utils import DATE_TYPE, DATE_VALUES
from gis_metadata.parser_utils import DATE_TYPE_SINGLE, DATE_TYPE_RANGE, DATE_TYPE_MISSING, DATE_TYPE_MULTIPLE
from gis_metadata.parser_utils import ATTRIBUTES, CONTACTS, DIGITAL_FORMS, PROCESS_STEPS
Expand All @@ -21,6 +21,20 @@
from gis_metadata.parser_utils import ParserException, ParserProperty


TEST_TEMPLATE_CONSTANTS = {
'dist_contact_org': 'ORG',
'dist_contact_person': 'PERSON',
'dist_address_type': 'PHYSICAL ADDRESS',
'dist_address': 'ADDRESS LOCATION',
'dist_city': 'CITY',
'dist_state': 'STATE',
'dist_postal': '12345',
'dist_country': 'USA',
'dist_phone': '123-456-7890',
'dist_email': 'EMAIL@DOMAIN.COM',
}


class MetadataParserTestCase(unittest.TestCase):

valid_complex_values = ('one', ['before', 'after'], ['first', 'next', 'last'])
Expand Down Expand Up @@ -118,7 +132,7 @@ def assert_template_after_write(self, parser_type, out_file_path):
parser = parser_type(out_file_or_path=out_file_path)

# Reverse each value and read the file in again
for prop, val in iteritems(get_xml_constants()):
for prop, val in iteritems(TEST_TEMPLATE_CONSTANTS):
setattr(parser, prop, val[::-1])

parser.write()
Expand Down Expand Up @@ -191,7 +205,7 @@ def assert_valid_template(self, parser, exclude=()):

parser_type = type(parser.validate()).__name__

for prop, val in iteritems(get_xml_constants()):
for prop, val in iteritems(TEST_TEMPLATE_CONSTANTS):
if prop not in exclude:
parsed_val = getattr(parser, prop)

Expand All @@ -202,10 +216,10 @@ def assert_valid_template(self, parser, exclude=()):
))

def test_fgdc_template_values(self):
self.assert_valid_template(FgdcParser())
self.assert_valid_template(FgdcParser(**TEST_TEMPLATE_CONSTANTS))

def test_iso_template_values(self):
self.assert_valid_template(IsoParser(), exclude=('dist_address_type'))
self.assert_valid_template(IsoParser(**TEST_TEMPLATE_CONSTANTS), exclude=('dist_address_type'))

def test_template_conversion(self):
fgdc_template = FgdcParser()
Expand Down

0 comments on commit 05db927

Please sign in to comment.