Skip to content

Commit

Permalink
Enhance validation to handle custom data structures.
Browse files Browse the repository at this point in the history
  • Loading branch information
dharvey-consbio committed Oct 27, 2016
1 parent 9861892 commit 8db03d4
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 16 deletions.
16 changes: 13 additions & 3 deletions gis_metadata/metadata_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
from gis_metadata.utils import DATES, DATE_TYPE, DATE_VALUES
from gis_metadata.utils import DATE_TYPE_RANGE, DATE_TYPE_RANGE_BEGIN, DATE_TYPE_RANGE_END
from gis_metadata.utils import parse_complex, parse_complex_list, parse_dates, parse_property
from gis_metadata.utils import update_complex, update_complex_list, update_property, validate_any, validate_properties
from gis_metadata.utils import _supported_props, ParserError
from gis_metadata.utils import update_complex, update_complex_list, update_property
from gis_metadata.utils import validate_any, validate_complex_list, validate_properties
from gis_metadata.utils import _complex_definitions, _supported_props, ParserError


# Place holders for lazy, one-time FGDC & ISO imports
Expand Down Expand Up @@ -394,6 +395,15 @@ def validate(self):
validate_properties(self._data_map, self._metadata_props)

for prop in self._data_map:
validate_any(prop, getattr(self, prop))
try:
validate_any(prop, getattr(self, prop))
except ParserError:
if prop in _complex_definitions:
raise # Enforce basic validation for established structures
if prop not in self._data_structures:
raise # Enforce validation for simple properties

# Validate custom data structures according to configured structure
validate_complex_list(prop, getattr(self, prop), self._data_structures[prop])

return self
43 changes: 30 additions & 13 deletions gis_metadata/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def parse_complex(tree_to_parse, xpath_root, xpath_map, complex_key):

complex_struct = {}

for prop in _complex_definitions[complex_key]:
for prop in _complex_definitions.get(complex_key, xpath_map):
parsed = parse_property(tree_to_parse, xpath_root, xpath_map, prop)
complex_struct[prop] = reduce_value(
flatten_items(v.split(_COMPLEX_DELIM) for v in wrap_value(parsed))
Expand Down Expand Up @@ -497,18 +497,18 @@ def update_complex_list(tree_to_update, xpath_root, xpath_map, prop, values):
return complex_list


def validate_any(prop, value):
def validate_any(prop, value, xpath_map=None):
""" Validates any metadata property, complex or simple (string or array) """

if value is not None:
if prop in [ATTRIBUTES, CONTACTS, DIGITAL_FORMS]:
validate_complex_list(prop, value)
if prop in (ATTRIBUTES, CONTACTS, DIGITAL_FORMS):
validate_complex_list(prop, value, xpath_map)

elif prop in [BOUNDING_BOX, LARGER_WORKS]:
validate_complex(prop, value)
elif prop in (BOUNDING_BOX, LARGER_WORKS):
validate_complex(prop, value, xpath_map)

elif prop == DATES:
validate_dates(prop, value)
validate_dates(prop, value, xpath_map)

elif prop == PROCESS_STEPS:
validate_process_steps(prop, value)
Expand All @@ -518,13 +518,18 @@ def validate_any(prop, value):
validate_type(prop, val, string_types)


def validate_complex(prop, value):
def validate_complex(prop, value, xpath_map=None):
""" Default validation for single complex data structure """

if value is not None:
validate_type(prop, value, dict)

complex_keys = set(_complex_definitions[prop])
if prop in _complex_definitions:
complex_keys = _complex_definitions[prop]
elif xpath_map is None:
complex_keys = {}
else:
complex_keys = xpath_map

for complex_prop, complex_val in iteritems(value):
complex_key = '.'.join((prop, complex_prop))
Expand All @@ -535,13 +540,18 @@ def validate_complex(prop, value):
validate_type(complex_key, complex_val, (string_types, list))


def validate_complex_list(prop, value):
def validate_complex_list(prop, value, xpath_map=None):
""" Default validation for Attribute Details data structure """

if value is not None:
validate_type(prop, value, (dict, list))

complex_keys = set(_complex_definitions[prop])
if prop in _complex_definitions:
complex_keys = _complex_definitions[prop]
elif xpath_map is None:
complex_keys = {}
else:
complex_keys = xpath_map

for idx, complex_struct in enumerate(wrap_value(value)):
cs_idx = prop + '[' + str(idx) + ']'
Expand All @@ -561,7 +571,7 @@ def validate_complex_list(prop, value):
validate_type(list_prop, list_val, string_types)


def validate_dates(prop, value):
def validate_dates(prop, value, xpath_map=None):
""" Default validation for Date Types data structure """

if value is not None:
Expand All @@ -571,7 +581,14 @@ def validate_dates(prop, value):

if date_keys:
if DATE_TYPE not in date_keys or DATE_VALUES not in date_keys:
_validation_error(prop, None, value, ('keys: {0}'.format(','.join(_complex_definitions[prop]))))
if prop in _complex_definitions:
complex_keys = _complex_definitions[prop]
elif xpath_map is None:
complex_keys = _complex_definitions[DATES]
else:
complex_keys = xpath_map

_validation_error(prop, None, value, ('keys: {0}'.format(','.join(complex_keys))))

date_type = value[DATE_TYPE]

Expand Down

0 comments on commit 8db03d4

Please sign in to comment.