Source code for hed.schema.schema_compliance

""" Utilities for HED schema checking. """

from hed.errors.error_types import ErrorContext, SchemaErrors, ErrorSeverity, SchemaAttributeErrors, SchemaWarnings
from hed.errors.error_reporter import ErrorHandler
from hed.schema.hed_schema import HedSchema, HedKey
from hed.schema import schema_attribute_validators
from hed.schema.schema_validation_util import validate_schema_term, validate_schema_description


[docs]def check_compliance(hed_schema, check_for_warnings=True, name=None, error_handler=None): """ Check for hed3 compliance of a schema object. Parameters: hed_schema (HedSchema): HedSchema object to check for hed3 compliance. check_for_warnings (bool): If True, check for formatting issues like invalid characters, capitalization, etc. name (str): If present, will use as filename for context. error_handler (ErrorHandler or None): Used to report errors. Uses a default one if none passed in. Returns: list: A list of all warnings and errors found in the file. Each issue is a dictionary. :raises ValueError: - Trying to validate a HedSchemaGroup directly """ if not isinstance(hed_schema, HedSchema): raise ValueError("To check compliance of a HedGroupSchema, call self.check_compliance on the schema itself.") error_handler = error_handler if error_handler else ErrorHandler(check_for_warnings) validator = SchemaValidator(hed_schema, check_for_warnings, error_handler) issues_list = [] if not name: name = hed_schema.filename error_handler.push_error_context(ErrorContext.FILE_NAME, name) issues_list += validator.check_unknown_attributes() issues_list += validator.check_attributes() issues_list += validator.check_duplicate_names() issues_list += validator.check_invalid_chars() error_handler.pop_error_context() return issues_list
[docs]class SchemaValidator: """Validator class to wrap some code. In general, just call check_compliance.""" attribute_validators = { HedKey.SuggestedTag: [schema_attribute_validators.tag_exists_check], HedKey.RelatedTag: [schema_attribute_validators.tag_exists_check], HedKey.UnitClass: [schema_attribute_validators.tag_is_placeholder_check, schema_attribute_validators.unit_class_exists], HedKey.ValueClass: [schema_attribute_validators.tag_is_placeholder_check, schema_attribute_validators.value_class_exists], # Rooted tag is implicitly verified on loading # HedKey.Rooted: [schema_attribute_validators.tag_exists_base_schema_check], HedKey.DeprecatedFrom: [schema_attribute_validators.tag_is_deprecated_check], HedKey.TakesValue: [schema_attribute_validators.tag_is_placeholder_check], HedKey.DefaultUnits: [schema_attribute_validators.unit_exists], HedKey.ConversionFactor: [schema_attribute_validators.conversion_factor], HedKey.AllowedCharacter: [schema_attribute_validators.allowed_characters_check], HedKey.InLibrary: [schema_attribute_validators.in_library_check] }
[docs] def __init__(self, hed_schema, check_for_warnings=True, error_handler=None): self.hed_schema = hed_schema self._check_for_warnings = check_for_warnings self.error_handler = error_handler
[docs] def check_unknown_attributes(self): """Returns issues for any unknown attributes in any section""" unknown_attributes = self.hed_schema.get_unknown_attributes() issues_list = [] if unknown_attributes: for attribute_name, source_tags in unknown_attributes.items(): for tag in source_tags: issues_list += self.error_handler.format_error_with_context(SchemaAttributeErrors.SCHEMA_ATTRIBUTE_INVALID, attribute_name, source_tag=tag) return issues_list
[docs] def check_attributes(self): """Returns issues from validating known attributes in all sections""" issues_list = [] for section_key in self.hed_schema._sections: self.error_handler.push_error_context(ErrorContext.SCHEMA_SECTION, section_key) for tag_entry in self.hed_schema[section_key].values(): self.error_handler.push_error_context(ErrorContext.SCHEMA_TAG, tag_entry.name) for attribute_name in tag_entry.attributes: validators = self.attribute_validators.get(attribute_name, []) for validator in validators: self.error_handler.push_error_context(ErrorContext.SCHEMA_ATTRIBUTE, attribute_name) new_issues = validator(self.hed_schema, tag_entry, attribute_name) for issue in new_issues: issue['severity'] = ErrorSeverity.WARNING self.error_handler.add_context_and_filter(new_issues) issues_list += new_issues self.error_handler.pop_error_context() self.error_handler.pop_error_context() self.error_handler.pop_error_context() return issues_list
[docs] def check_duplicate_names(self): """Return issues for any duplicate names in all sections.""" issues_list = [] for section_key in self.hed_schema._sections: for name, duplicate_entries in self.hed_schema[section_key].duplicate_names.items(): values = set(entry.has_attribute(HedKey.InLibrary) for entry in duplicate_entries) error_code = SchemaErrors.SCHEMA_DUPLICATE_NODE if len(values) == 2: error_code = SchemaErrors.SCHEMA_DUPLICATE_FROM_LIBRARY issues_list += self.error_handler.format_error_with_context(error_code, name, duplicate_tag_list=[entry.name for entry in duplicate_entries], section=section_key) return issues_list
[docs] def check_invalid_chars(self): """Returns issues for bad chars in terms or descriptions.""" issues_list = [] if self._check_for_warnings: hed_terms = self.hed_schema.get_all_schema_tags(True) for hed_term in hed_terms: issues_list += validate_schema_term(hed_term) for tag_name, desc in self.hed_schema.get_desc_iter(): issues_list += validate_schema_description(tag_name, desc) return issues_list