diff --git a/hed/errors/error_messages.py b/hed/errors/error_messages.py
index 5cded3402..b5dfb6060 100644
--- a/hed/errors/error_messages.py
+++ b/hed/errors/error_messages.py
@@ -5,8 +5,7 @@
"""
from hed.errors.error_reporter import hed_error, hed_tag_error
-from hed.errors.error_types import ValidationErrors, SchemaErrors, \
- SidecarErrors, SchemaWarnings, ErrorSeverity, DefinitionErrors, OnsetErrors, ColumnErrors
+from hed.errors.error_types import ValidationErrors, SidecarErrors, ErrorSeverity, DefinitionErrors, OnsetErrors, ColumnErrors
@hed_tag_error(ValidationErrors.UNITS_INVALID)
@@ -231,57 +230,6 @@ def val_warning_default_units_used(tag, default_unit):
return f"No unit specified. Using '{default_unit}' as the default - '{tag}'"
-@hed_error(SchemaErrors.HED_SCHEMA_DUPLICATE_NODE)
-def schema_error_hed_duplicate_node(tag, duplicate_tag_list, section):
- tag_join_delimiter = "\n\t"
- return f"Duplicate term '{str(tag)}' used {len(duplicate_tag_list)} places in '{section}' section schema as:" + \
- f"{tag_join_delimiter}{tag_join_delimiter.join(duplicate_tag_list)}"
-
-
-@hed_error(SchemaErrors.HED_SCHEMA_DUPLICATE_FROM_LIBRARY)
-def schema_error_hed_duplicate_node(tag, duplicate_tag_list, section):
- tag_join_delimiter = "\n\t"
- return f"Duplicate term '{str(tag)}' was found in the library and in the standard schema in '{section}' section schema as:" + \
- f"{tag_join_delimiter}{tag_join_delimiter.join(duplicate_tag_list)}"
-
-
-@hed_error(SchemaErrors.SCHEMA_ATTRIBUTE_INVALID)
-def schema_error_unknown_attribute(attribute_name, source_tag):
- return f"Attribute '{attribute_name}' used by '{source_tag}' was not defined in the schema, " \
- f"or was used outside of it's defined class."
-
-
-@hed_error(SchemaWarnings.INVALID_CHARACTERS_IN_DESC, default_severity=ErrorSeverity.WARNING,
- actual_code=SchemaWarnings.HED_SCHEMA_CHARACTER_INVALID)
-def schema_warning_invalid_chars_desc(desc_string, tag_name, problem_char, char_index):
- return f"Invalid character '{problem_char}' in desc for '{tag_name}' at position {char_index}. '{desc_string}"
-
-
-@hed_error(SchemaWarnings.INVALID_CHARACTERS_IN_TAG, default_severity=ErrorSeverity.WARNING,
- actual_code=SchemaWarnings.HED_SCHEMA_CHARACTER_INVALID)
-def schema_warning_invalid_chars_tag(tag_name, problem_char, char_index):
- return f"Invalid character '{problem_char}' in tag '{tag_name}' at position {char_index}."
-
-
-@hed_error(SchemaWarnings.INVALID_CAPITALIZATION, default_severity=ErrorSeverity.WARNING)
-def schema_warning_invalid_capitalization(tag_name, problem_char, char_index):
- return "First character must be a capital letter or number. " + \
- f"Found character '{problem_char}' in tag '{tag_name}' at position {char_index}."
-
-
-@hed_error(SchemaWarnings.NON_PLACEHOLDER_HAS_CLASS, default_severity=ErrorSeverity.WARNING)
-def schema_warning_non_placeholder_class(tag_name, invalid_attribute_name):
- return "Only placeholder nodes('#') can have a unit or value class." + \
- f"Found {invalid_attribute_name} on {tag_name}"
-
-
-@hed_error(SchemaWarnings.INVALID_ATTRIBUTE, default_severity=ErrorSeverity.ERROR)
-def schema_error_invalid_attribute(tag_name, invalid_attribute_name):
- return f"'{invalid_attribute_name}' should not be present in a loaded schema, found on '{tag_name}'." \
- f"Something went very wrong."
-
-
-
@hed_error(SidecarErrors.BLANK_HED_STRING)
def sidecar_error_blank_hed_string():
return "No HED string found for Value or Category column."
diff --git a/hed/errors/error_reporter.py b/hed/errors/error_reporter.py
index 6eebe38f3..596882e37 100644
--- a/hed/errors/error_reporter.py
+++ b/hed/errors/error_reporter.py
@@ -167,8 +167,11 @@ def wrapper(tag, *args, severity=default_severity, **kwargs):
# Import after hed_error decorators are defined.
from hed.errors import error_messages
+from hed.errors import schema_error_messages
+
# Intentional to make sure tools don't think the import is unused
error_messages.mark_as_used = True
+schema_error_messages.mark_as_used = True
class ErrorHandler:
@@ -545,6 +548,8 @@ def _add_single_error_to_dict(items, root=None, issue_to_add=None):
def _error_dict_to_string(print_dict, add_link=True, level=0):
output = ""
+ if print_dict is None:
+ return output
for context, value in print_dict.items():
if context == "children":
for child in value:
diff --git a/hed/errors/error_types.py b/hed/errors/error_types.py
index 18418a4f2..1fa43c8b1 100644
--- a/hed/errors/error_types.py
+++ b/hed/errors/error_types.py
@@ -106,19 +106,32 @@ class SidecarErrors:
class SchemaErrors:
- HED_SCHEMA_DUPLICATE_NODE = 'HED_SCHEMA_DUPLICATE_NODE'
+ SCHEMA_DUPLICATE_NODE = 'SCHEMA_DUPLICATE_NODE'
SCHEMA_ATTRIBUTE_INVALID = 'SCHEMA_ATTRIBUTE_INVALID'
- HED_SCHEMA_DUPLICATE_FROM_LIBRARY = "SCHEMA_LIBRARY_INVALID"
+ SCHEMA_DUPLICATE_FROM_LIBRARY = "SCHEMA_LIBRARY_INVALID"
class SchemaWarnings:
- INVALID_CHARACTERS_IN_DESC = "INVALID_CHARACTERS_IN_DESC"
- INVALID_CHARACTERS_IN_TAG = "INVALID_CHARACTERS_IN_TAG"
+ SCHEMA_INVALID_CHARACTERS_IN_DESC = "SCHEMA_INVALID_CHARACTERS_IN_DESC"
+ SCHEMA_INVALID_CHARACTERS_IN_TAG = "SCHEMA_INVALID_CHARACTERS_IN_TAG"
+
# The actual reported error for the above two
- HED_SCHEMA_CHARACTER_INVALID = "HED_SCHEMA_CHARACTER_INVALID"
- INVALID_CAPITALIZATION = 'invalidCaps'
- NON_PLACEHOLDER_HAS_CLASS = 'NON_PLACEHOLDER_HAS_CLASS'
- INVALID_ATTRIBUTE = "INVALID_ATTRIBUTE"
+ SCHEMA_CHARACTER_INVALID = "SCHEMA_CHARACTER_INVALID"
+ SCHEMA_INVALID_CAPITALIZATION = 'invalidCaps'
+ SCHEMA_NON_PLACEHOLDER_HAS_CLASS = 'SCHEMA_NON_PLACEHOLDER_HAS_CLASS'
+ SCHEMA_INVALID_ATTRIBUTE = "SCHEMA_INVALID_ATTRIBUTE"
+
+
+class SchemaAttributeErrors:
+ SCHEMA_DEPRECATED_INVALID = "SCHEMA_DEPRECATED_INVALID"
+ SCHEMA_SUGGESTED_TAG_INVALID = "SCHEMA_SUGGESTED_TAG_INVALID"
+ SCHEMA_RELATED_TAG_INVALID = "SCHEMA_RELATED_TAG_INVALID"
+
+ SCHEMA_UNIT_CLASS_INVALID = "SCHEMA_UNIT_CLASS_INVALID"
+ SCHEMA_VALUE_CLASS_INVALID = "SCHEMA_VALUE_CLASS_INVALID"
+
+ SCHEMA_DEFAULT_UNITS_INVALID = "SCHEMA_DEFAULT_UNITS_INVALID"
+ SCHEMA_CHILD_OF_DEPRECATED = "SCHEMA_CHILD_OF_DEPRECATED" # Reported as SCHEMA_DEPRECATED_INVALID
class DefinitionErrors:
diff --git a/hed/errors/schema_error_messages.py b/hed/errors/schema_error_messages.py
new file mode 100644
index 000000000..b7fda9d50
--- /dev/null
+++ b/hed/errors/schema_error_messages.py
@@ -0,0 +1,84 @@
+from hed.errors.error_types import SchemaErrors, SchemaWarnings, ErrorSeverity, SchemaAttributeErrors
+from hed.errors.error_reporter import hed_error
+
+
+@hed_error(SchemaErrors.SCHEMA_DUPLICATE_NODE)
+def schema_error_hed_duplicate_node(tag, duplicate_tag_list, section):
+ tag_join_delimiter = "\n\t"
+ return f"Duplicate term '{str(tag)}' used {len(duplicate_tag_list)} places in '{section}' section schema as:" + \
+ f"{tag_join_delimiter}{tag_join_delimiter.join(duplicate_tag_list)}"
+
+
+@hed_error(SchemaErrors.SCHEMA_DUPLICATE_FROM_LIBRARY)
+def schema_error_hed_duplicate_from_library(tag, duplicate_tag_list, section):
+ tag_join_delimiter = "\n\t"
+ return f"Duplicate term '{str(tag)}' was found in the library and in the standard schema in '{section}' section schema as:" + \
+ f"{tag_join_delimiter}{tag_join_delimiter.join(duplicate_tag_list)}"
+
+
+@hed_error(SchemaErrors.SCHEMA_ATTRIBUTE_INVALID)
+def schema_error_unknown_attribute(attribute_name, source_tag):
+ return f"Attribute '{attribute_name}' used by '{source_tag}' was not defined in the schema, " \
+ f"or was used outside of it's defined class."
+
+
+@hed_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_DESC, default_severity=ErrorSeverity.WARNING,
+ actual_code=SchemaWarnings.SCHEMA_CHARACTER_INVALID)
+def schema_warning_invalid_chars_desc(desc_string, tag_name, problem_char, char_index):
+ return f"Invalid character '{problem_char}' in desc for '{tag_name}' at position {char_index}. '{desc_string}"
+
+
+@hed_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_TAG, default_severity=ErrorSeverity.WARNING,
+ actual_code=SchemaWarnings.SCHEMA_CHARACTER_INVALID)
+def schema_warning_invalid_chars_tag(tag_name, problem_char, char_index):
+ return f"Invalid character '{problem_char}' in tag '{tag_name}' at position {char_index}."
+
+
+@hed_error(SchemaWarnings.SCHEMA_INVALID_CAPITALIZATION, default_severity=ErrorSeverity.WARNING)
+def schema_warning_SCHEMA_INVALID_CAPITALIZATION(tag_name, problem_char, char_index):
+ return "First character must be a capital letter or number. " + \
+ f"Found character '{problem_char}' in tag '{tag_name}' at position {char_index}."
+
+
+@hed_error(SchemaWarnings.SCHEMA_NON_PLACEHOLDER_HAS_CLASS, default_severity=ErrorSeverity.WARNING)
+def schema_warning_non_placeholder_class(tag_name, invalid_attribute_name):
+ return "Only placeholder nodes('#') can have a unit class, value class, or takes value." + \
+ f"Found {invalid_attribute_name} on {tag_name}"
+
+
+@hed_error(SchemaWarnings.SCHEMA_INVALID_ATTRIBUTE, default_severity=ErrorSeverity.ERROR)
+def schema_error_SCHEMA_INVALID_ATTRIBUTE(tag_name, invalid_attribute_name):
+ return f"'{invalid_attribute_name}' should not be present in a loaded schema, found on '{tag_name}'." \
+ f"Something went very wrong."
+
+
+@hed_error(SchemaAttributeErrors.SCHEMA_DEPRECATED_INVALID)
+def schema_error_SCHEMA_DEPRECATED_INVALID(tag_name, invalid_deprecated_version):
+ return f"'{tag_name}' has invalid or unknown value in attribute deprecatedFrom: '{invalid_deprecated_version}'."
+
+
+@hed_error(SchemaAttributeErrors.SCHEMA_CHILD_OF_DEPRECATED,
+ actual_code=SchemaAttributeErrors.SCHEMA_DEPRECATED_INVALID)
+def schema_error_SCHEMA_CHILD_OF_DEPRECATED(deprecated_tag, non_deprecated_child):
+ return f"Deprecated tag '{deprecated_tag}' has a child that is not deprecated: '{non_deprecated_child}'."
+
+
+@hed_error(SchemaAttributeErrors.SCHEMA_SUGGESTED_TAG_INVALID)
+def schema_error_SCHEMA_SUGGESTED_TAG_INVALID(suggestedTag, invalidSuggestedTag, attribute_name):
+ return f"Tag '{suggestedTag}' has an invalid {attribute_name}: '{invalidSuggestedTag}'."
+
+
+@hed_error(SchemaAttributeErrors.SCHEMA_UNIT_CLASS_INVALID)
+def schema_error_SCHEMA_UNIT_CLASS_INVALID(tag, unit_class, attribute_name):
+ return f"Tag '{tag}' has an invalid {attribute_name}: '{unit_class}'."
+
+
+@hed_error(SchemaAttributeErrors.SCHEMA_VALUE_CLASS_INVALID)
+def schema_error_SCHEMA_VALUE_CLASS_INVALID(tag, unit_class, attribute_name):
+ return f"Tag '{tag}' has an invalid {attribute_name}: '{unit_class}'."
+
+
+@hed_error(SchemaAttributeErrors.SCHEMA_DEFAULT_UNITS_INVALID)
+def schema_error_SCHEMA_DEFAULT_UNITS_INVALID(tag, bad_unit, valid_units):
+ valid_units = ",".join(valid_units)
+ return f"Tag '{tag}' has an invalid defaultUnit '{bad_unit}'. Valid units are: '{valid_units}'."
diff --git a/hed/models/hed_tag.py b/hed/models/hed_tag.py
index 56bb20d9b..9d470002b 100644
--- a/hed/models/hed_tag.py
+++ b/hed/models/hed_tag.py
@@ -270,7 +270,7 @@ def expanded(self):
@property
def expandable(self):
- """Returns if this is expandable
+ """Returns what this expands to
This is primarily used for Def/Def-expand tags at present.
diff --git a/hed/schema/hed_cache.py b/hed/schema/hed_cache.py
index 793cd6d85..299af6f66 100644
--- a/hed/schema/hed_cache.py
+++ b/hed/schema/hed_cache.py
@@ -60,13 +60,14 @@ def get_cache_directory():
return HED_CACHE_DIRECTORY
-def get_hed_versions(local_hed_directory=None, library_name=None, get_libraries=False):
+def get_hed_versions(local_hed_directory=None, library_name=None):
""" Get the HED versions in the hed directory.
Parameters:
local_hed_directory (str): Directory to check for versions which defaults to hed_cache.
library_name (str or None): An optional schema library name.
- get_libraries (bool): If true, return a dictionary of version numbers, with an entry for each library name.
+ None retrieves the standard schema only.
+ Pass "all" to retrieve all standard and library schemas as a dict.
Returns:
list or dict: List of version numbers or dictionary {library_name: [versions]}.
@@ -89,18 +90,16 @@ def get_hed_versions(local_hed_directory=None, library_name=None, get_libraries=
if expression_match is not None:
version = expression_match.group(3)
found_library_name = expression_match.group(2)
- if not get_libraries and found_library_name != library_name:
+ if library_name != "all" and found_library_name != library_name:
continue
if found_library_name not in all_hed_versions:
all_hed_versions[found_library_name] = []
all_hed_versions[found_library_name].append(version)
for name, hed_versions in all_hed_versions.items():
all_hed_versions[name] = _sort_version_list(hed_versions)
- if get_libraries:
- return all_hed_versions
if library_name in all_hed_versions:
return all_hed_versions[library_name]
- return []
+ return all_hed_versions
def cache_specific_url(hed_xml_url, xml_version=None, library_name=None, cache_folder=None):
diff --git a/hed/schema/hed_schema_constants.py b/hed/schema/hed_schema_constants.py
index d747c2148..0cecc4ab6 100644
--- a/hed/schema/hed_schema_constants.py
+++ b/hed/schema/hed_schema_constants.py
@@ -41,6 +41,7 @@ class HedKey:
RelatedTag = "relatedTag"
SuggestedTag = "suggestedTag"
Rooted = "rooted"
+ DeprecatedFrom = "deprecatedFrom"
# All known properties
BoolProperty = 'boolProperty'
diff --git a/hed/schema/schema_attribute_validators.py b/hed/schema/schema_attribute_validators.py
index 47dc7410b..d1d7f5ecb 100644
--- a/hed/schema/schema_attribute_validators.py
+++ b/hed/schema/schema_attribute_validators.py
@@ -9,9 +9,11 @@
bool
"""
-from hed.errors.error_types import SchemaWarnings, ValidationErrors
+from hed.errors.error_types import SchemaWarnings, ValidationErrors, SchemaAttributeErrors
from hed.errors.error_reporter import ErrorHandler
from hed.schema.hed_schema import HedSchema
+from hed.schema.hed_cache import get_hed_versions
+from hed.schema.hed_schema_constants import HedKey
def tag_is_placeholder_check(hed_schema, tag_entry, attribute_name):
@@ -28,12 +30,13 @@ def tag_is_placeholder_check(hed_schema, tag_entry, attribute_name):
"""
issues = []
if not tag_entry.name.endswith("/#"):
- issues += ErrorHandler.format_error(SchemaWarnings.NON_PLACEHOLDER_HAS_CLASS, tag_entry.name,
+ issues += ErrorHandler.format_error(SchemaWarnings.SCHEMA_NON_PLACEHOLDER_HAS_CLASS, tag_entry.name,
attribute_name)
return issues
+# todo: This needs to be refactored, these next several functions are near identical
def tag_exists_check(hed_schema, tag_entry, attribute_name):
""" Check if the list of possible tags exists in the schema.
@@ -51,14 +54,55 @@ def tag_exists_check(hed_schema, tag_entry, attribute_name):
split_tags = possible_tags.split(",")
for org_tag in split_tags:
if org_tag and org_tag not in hed_schema.tags:
- issues += ErrorHandler.format_error(ValidationErrors.NO_VALID_TAG_FOUND,
+ issues += ErrorHandler.format_error(SchemaAttributeErrors.SCHEMA_SUGGESTED_TAG_INVALID,
+ tag_entry.name,
org_tag,
- index_in_tag=0,
- index_in_tag_end=len(org_tag))
+ attribute_name)
return issues
+def unit_class_exists(hed_schema, tag_entry, attribute_name):
+ issues = []
+ possible_unit_classes = tag_entry.attributes.get(attribute_name, "")
+ split_tags = possible_unit_classes.split(",")
+ for org_tag in split_tags:
+ if org_tag and org_tag not in hed_schema.unit_classes:
+ issues += ErrorHandler.format_error(SchemaAttributeErrors.SCHEMA_UNIT_CLASS_INVALID,
+ tag_entry.name,
+ org_tag,
+ attribute_name)
+
+ return issues
+
+
+def value_class_exists(hed_schema, tag_entry, attribute_name):
+ issues = []
+ possible_value_classes = tag_entry.attributes.get(attribute_name, "")
+ split_tags = possible_value_classes.split(",")
+ for org_tag in split_tags:
+ if org_tag and org_tag not in hed_schema.value_classes:
+ issues += ErrorHandler.format_error(SchemaAttributeErrors.SCHEMA_VALUE_CLASS_INVALID,
+ tag_entry.name,
+ org_tag,
+ attribute_name)
+
+ return issues
+
+
+def unit_exists(hed_schema, tag_entry, attribute_name):
+ issues = []
+ default_unit = tag_entry.attributes.get(attribute_name, "")
+ if default_unit and default_unit not in tag_entry.derivative_units:
+ issues += ErrorHandler.format_error(SchemaAttributeErrors.SCHEMA_DEFAULT_UNITS_INVALID,
+ tag_entry.name,
+ default_unit,
+ tag_entry.units)
+
+ return issues
+
+
+# This is effectively unused and can never fail - The schema would catch these errors and refuse to load
def tag_exists_base_schema_check(hed_schema, tag_entry, attribute_name):
""" Check if the single tag is a partnered schema tag
@@ -78,4 +122,32 @@ def tag_exists_base_schema_check(hed_schema, tag_entry, attribute_name):
index_in_tag=0,
index_in_tag_end=len(rooted_tag))
+ return issues
+
+
+def tag_is_deprecated_check(hed_schema, tag_entry, attribute_name):
+ """ Check if the tag has a valid deprecatedFrom attribute, and that any children have it
+
+ Parameters:
+ hed_schema (HedSchema): The schema to use for validation
+ tag_entry (HedSchemaEntry): The schema entry for this tag.
+ attribute_name (str): The name of this attribute
+
+ Returns:
+ list: A list of issues. Each issue is a dictionary.
+ """
+ issues = []
+ deprecated_version = tag_entry.attributes.get(attribute_name, "")
+ library_name = tag_entry.has_attribute(HedKey.InLibrary, return_value=True)
+ all_versions = get_hed_versions(library_name=library_name)
+ if deprecated_version and deprecated_version not in all_versions:
+ issues += ErrorHandler.format_error(SchemaAttributeErrors.SCHEMA_DEPRECATED_INVALID,
+ tag_entry.name,
+ deprecated_version)
+
+ for child in tag_entry.children.values():
+ if not child.has_attribute(attribute_name):
+ issues += ErrorHandler.format_error(SchemaAttributeErrors.SCHEMA_CHILD_OF_DEPRECATED,
+ tag_entry.name,
+ child.name)
return issues
\ No newline at end of file
diff --git a/hed/schema/schema_compliance.py b/hed/schema/schema_compliance.py
index 59770e6b2..c75c11de3 100644
--- a/hed/schema/schema_compliance.py
+++ b/hed/schema/schema_compliance.py
@@ -1,6 +1,6 @@
""" Utilities for HED schema checking. """
-from hed.errors.error_types import ErrorContext, SchemaErrors, ErrorSeverity
+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
@@ -45,12 +45,29 @@ def check_compliance(hed_schema, check_for_warnings=True, name=None, error_handl
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,
- HedKey.ValueClass: schema_attribute_validators.tag_is_placeholder_check,
- HedKey.Rooted: schema_attribute_validators.tag_exists_base_schema_check,
+ HedKey.SuggestedTag: [(schema_attribute_validators.tag_exists_check,
+ SchemaAttributeErrors.SCHEMA_SUGGESTED_TAG_INVALID)],
+ HedKey.RelatedTag: [(schema_attribute_validators.tag_exists_check,
+ SchemaAttributeErrors.SCHEMA_RELATED_TAG_INVALID)],
+ HedKey.UnitClass: [(schema_attribute_validators.tag_is_placeholder_check,
+ SchemaWarnings.SCHEMA_NON_PLACEHOLDER_HAS_CLASS),
+ (schema_attribute_validators.unit_class_exists,
+ SchemaAttributeErrors.SCHEMA_UNIT_CLASS_INVALID)],
+ HedKey.ValueClass: [(schema_attribute_validators.tag_is_placeholder_check,
+ SchemaWarnings.SCHEMA_NON_PLACEHOLDER_HAS_CLASS),
+ (schema_attribute_validators.value_class_exists,
+ SchemaAttributeErrors.SCHEMA_VALUE_CLASS_INVALID)],
+ # Rooted tag is implicitly verified on loading
+ # HedKey.Rooted: [(schema_attribute_validators.tag_exists_base_schema_check,
+ # SchemaAttributeErrors.SCHEMA_ROOTED_TAG_INVALID)],
+ HedKey.DeprecatedFrom: [(schema_attribute_validators.tag_is_deprecated_check,
+ SchemaAttributeErrors.SCHEMA_DEPRECATED_INVALID)],
+ HedKey.TakesValue: [(schema_attribute_validators.tag_is_placeholder_check,
+ SchemaWarnings.SCHEMA_NON_PLACEHOLDER_HAS_CLASS)],
+ HedKey.DefaultUnits: [(schema_attribute_validators.unit_exists,
+ SchemaAttributeErrors.SCHEMA_DEFAULT_UNITS_INVALID)]
}
+
def __init__(self, hed_schema, check_for_warnings=True, error_handler=None):
self.hed_schema = hed_schema
self._check_for_warnings = check_for_warnings
@@ -76,14 +93,16 @@ def check_attributes(self):
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:
- validator = self.attribute_validators.get(attribute_name)
- if validator:
- 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
+ validators = self.attribute_validators.get(attribute_name, None)
+ if validators:
+ for validator, error_code 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['code'] = error_code
+ 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()
@@ -95,11 +114,12 @@ def check_duplicate_names(self):
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.HED_SCHEMA_DUPLICATE_NODE
+ error_code = SchemaErrors.SCHEMA_DUPLICATE_NODE
if len(values) == 2:
- error_code = SchemaErrors.HED_SCHEMA_DUPLICATE_FROM_LIBRARY
+ 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],
+ duplicate_tag_list=[entry.name for entry in
+ duplicate_entries],
section=section_key)
return issues_list
@@ -114,5 +134,3 @@ def check_invalid_chars(self):
for tag_name, desc in self.hed_schema.get_desc_iter():
issues_list += validate_schema_description(tag_name, desc)
return issues_list
-
-
diff --git a/hed/schema/schema_validation_util.py b/hed/schema/schema_validation_util.py
index 7805a3977..8404970e7 100644
--- a/hed/schema/schema_validation_util.py
+++ b/hed/schema/schema_validation_util.py
@@ -169,12 +169,12 @@ def validate_schema_term(hed_term):
for i, char in enumerate(hed_term):
if i == 0 and not (char.isdigit() or char.isupper()):
- issues_list += ErrorHandler.format_error(SchemaWarnings.INVALID_CAPITALIZATION,
+ issues_list += ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CAPITALIZATION,
hed_term, char_index=i, problem_char=char)
continue
if char in ALLOWED_TAG_CHARS or char.isalnum():
continue
- issues_list += ErrorHandler.format_error(SchemaWarnings.INVALID_CHARACTERS_IN_TAG,
+ issues_list += ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_TAG,
hed_term, char_index=i, problem_char=char)
return issues_list
@@ -199,6 +199,6 @@ def validate_schema_description(tag_name, hed_description):
continue
if char in ALLOWED_DESC_CHARS:
continue
- issues_list += ErrorHandler.format_error(SchemaWarnings.INVALID_CHARACTERS_IN_DESC,
+ issues_list += ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_DESC,
hed_description, tag_name, char_index=i, problem_char=char)
return issues_list
diff --git a/spec_tests/test_errors.py b/spec_tests/test_errors.py
index 2ee73fc9e..ac817fa81 100644
--- a/spec_tests/test_errors.py
+++ b/spec_tests/test_errors.py
@@ -10,9 +10,6 @@
import json
from hed import HedFileError
from hed.errors import ErrorHandler, get_printable_issue_string
-import shutil
-from hed import schema
-from hed.schema import hed_cache
# To be removed eventually once all errors are being verified.
@@ -48,7 +45,14 @@
"SIDECAR_BRACES_INVALID",
"SCHEMA_LIBRARY_INVALID",
- "SCHEMA_ATTRIBUTE_INVALID"
+ "SCHEMA_ATTRIBUTE_INVALID",
+ "SCHEMA_UNIT_CLASS_INVALID",
+ "SCHEMA_VALUE_CLASS_INVALID",
+ "SCHEMA_DEPRECATED_INVALID",
+ "SCHEMA_SUGGESTED_TAG_INVALID",
+ "SCHEMA_RELATED_TAG_INVALID",
+ "SCHEMA_NON_PLACEHOLDER_HAS_CLASS",
+ "SCHEMA_DEFAULT_UNITS_INVALID"
]
skip_tests = {
@@ -68,21 +72,9 @@ def setUpClass(cls):
cls.fail_count = []
cls.default_sidecar = Sidecar(os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_sidecar.json')))
- # this is just to make sure 8.2.0 is in the cache(as you can't find it online yet) and could be cleaned up
- cls.hed_cache_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_errors_cache/')
- base_schema_dir = '../tests/data/schema_tests/merge_tests/'
- cls.saved_cache_folder = hed_cache.HED_CACHE_DIRECTORY
- schema.set_cache_directory(cls.hed_cache_dir)
- cls.full_base_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), base_schema_dir)
- cls.source_schema_path = os.path.join(cls.full_base_folder, "HED8.2.0.xml")
- cls.cache_folder = hed_cache.get_cache_directory()
- cls.schema_path_in_cache = os.path.join(cls.cache_folder, "HED8.2.0.xml")
- shutil.copy(cls.source_schema_path, cls.schema_path_in_cache)
-
@classmethod
def tearDownClass(cls):
- shutil.rmtree(cls.hed_cache_dir)
- schema.set_cache_directory(cls.saved_cache_folder)
+ pass
def run_single_test(self, test_file):
with open(test_file, "r") as fp:
diff --git a/tests/data/schema_tests/merge_tests/issues_tests/overlapping_units.mediawiki b/tests/data/schema_tests/merge_tests/issues_tests/overlapping_units.mediawiki
index 8f98fc80b..b7c4d5aa7 100644
--- a/tests/data/schema_tests/merge_tests/issues_tests/overlapping_units.mediawiki
+++ b/tests/data/schema_tests/merge_tests/issues_tests/overlapping_units.mediawiki
@@ -31,7 +31,7 @@ For more information see https://hed-schema-library.readthedocs.io/en/latest/ind
!# end schema
'''Unit classes'''
-* weightUnitsNew {defaultUnits=testUnit}
+* weightUnitsNew {defaultUnits=g}
** g {conversionFactor=100}
diff --git a/tests/errors/test_error_reporter.py b/tests/errors/test_error_reporter.py
index bec45f60e..c5f850aa9 100644
--- a/tests/errors/test_error_reporter.py
+++ b/tests/errors/test_error_reporter.py
@@ -69,7 +69,7 @@ def test_pop_error_context(self):
def test_filter_issues_by_severity(self):
error_list = self.error_handler.format_error_with_context(ValidationErrors.TAG_NOT_UNIQUE, "")
- error_list += self.error_handler.format_error_with_context(SchemaWarnings.INVALID_CAPITALIZATION,
+ error_list += self.error_handler.format_error_with_context(SchemaWarnings.SCHEMA_INVALID_CAPITALIZATION,
"dummy", problem_char="#", char_index=0)
self.assertTrue(len(error_list) == 2)
filtered_list = self.error_handler.filter_issues_by_severity(issues_list=error_list,
@@ -79,7 +79,7 @@ def test_filter_issues_by_severity(self):
def test_printable_issue_string(self):
self.error_handler.push_error_context(ErrorContext.CUSTOM_TITLE, "Default Custom Title")
error_list = self.error_handler.format_error_with_context(ValidationErrors.TAG_NOT_UNIQUE, "")
- error_list += self.error_handler.format_error_with_context(SchemaWarnings.INVALID_CAPITALIZATION,
+ error_list += self.error_handler.format_error_with_context(SchemaWarnings.SCHEMA_INVALID_CAPITALIZATION,
"dummy", problem_char="#", char_index=0)
printable_issues = get_printable_issue_string(error_list)
@@ -99,7 +99,7 @@ def test_printable_issue_string_with_filenames(self):
self.error_handler.push_error_context(ErrorContext.CUSTOM_TITLE, "Default Custom Title")
self.error_handler.push_error_context(ErrorContext.FILE_NAME, myfile)
error_list = self.error_handler.format_error_with_context(ValidationErrors.TAG_NOT_UNIQUE, "")
- error_list += self.error_handler.format_error_with_context(SchemaWarnings.INVALID_CAPITALIZATION,
+ error_list += self.error_handler.format_error_with_context(SchemaWarnings.SCHEMA_INVALID_CAPITALIZATION,
"dummy", problem_char="#", char_index=0)
printable_issues = get_printable_issue_string(error_list, skip_filename=False)
diff --git a/tests/schema/test_hed_cache.py b/tests/schema/test_hed_cache.py
index 55a343a26..3a33155bf 100644
--- a/tests/schema/test_hed_cache.py
+++ b/tests/schema/test_hed_cache.py
@@ -82,7 +82,7 @@ def test_cache_specific_url(self):
self.assertTrue(local_filename)
def test_get_hed_versions_all(self):
- cached_versions = hed_cache.get_hed_versions(self.hed_cache_dir, get_libraries=True)
+ cached_versions = hed_cache.get_hed_versions(self.hed_cache_dir, library_name="all")
self.assertIsInstance(cached_versions, dict)
self.assertTrue(len(cached_versions) > 1)
diff --git a/tests/schema/test_hed_schema.py b/tests/schema/test_hed_schema.py
index f1b992511..9344df988 100644
--- a/tests/schema/test_hed_schema.py
+++ b/tests/schema/test_hed_schema.py
@@ -141,7 +141,7 @@ def test_short_tag_mapping(self):
def test_schema_compliance(self):
warnings = self.hed_schema_group.check_compliance(True)
- self.assertEqual(len(warnings), 10)
+ self.assertEqual(len(warnings), 14)
def test_bad_prefixes(self):
schema = load_schema_version(xml_version="8.0.0")
diff --git a/tests/schema/test_hed_schema_group.py b/tests/schema/test_hed_schema_group.py
index 891dfc2b1..83e062ce6 100644
--- a/tests/schema/test_hed_schema_group.py
+++ b/tests/schema/test_hed_schema_group.py
@@ -15,7 +15,7 @@ def setUpClass(cls):
def test_schema_compliance(self):
warnings = self.hed_schema_group.check_compliance(True)
- self.assertEqual(len(warnings), 10)
+ self.assertEqual(len(warnings), 14)
def test_get_tag_entry(self):
tag_entry = self.hed_schema_group.get_tag_entry("Event", schema_namespace="tl:")
diff --git a/tests/schema/test_hed_schema_io.py b/tests/schema/test_hed_schema_io.py
index 85f860b29..f3591ead3 100644
--- a/tests/schema/test_hed_schema_io.py
+++ b/tests/schema/test_hed_schema_io.py
@@ -287,7 +287,7 @@ def test_saving_merged2(self):
os.remove(path2)
def test_bad_schemas(self):
- """These should all have one HED_SCHEMA_DUPLICATE_NODE issue"""
+ """These should all have one SCHEMA_DUPLICATE_NODE issue"""
files = [
load_schema(os.path.join(self.full_base_folder, "issues_tests/overlapping_tags1.mediawiki")),
load_schema(os.path.join(self.full_base_folder, "issues_tests/overlapping_tags2.mediawiki")),
@@ -304,7 +304,7 @@ def test_bad_schemas(self):
HedExceptions.SCHEMA_LIBRARY_INVALID,
HedExceptions.SCHEMA_LIBRARY_INVALID,
HedExceptions.SCHEMA_LIBRARY_INVALID,
- SchemaErrors.HED_SCHEMA_DUPLICATE_NODE,
+ SchemaErrors.SCHEMA_DUPLICATE_NODE,
]
for schema, expected_code in zip(files, expected_code):
# print(schema.filename)
diff --git a/tests/schema/test_schema_compliance.py b/tests/schema/test_schema_compliance.py
index 49f6afe02..9a73248cb 100644
--- a/tests/schema/test_schema_compliance.py
+++ b/tests/schema/test_schema_compliance.py
@@ -17,3 +17,8 @@ def test_validate_schema(self):
self.assertTrue(isinstance(issues, list))
self.assertTrue(len(issues) > 1)
+ def test_validate_schema_deprecated(self):
+ hed_schema = schema.load_schema_version("score_1.1.0")
+ issues = hed_schema.check_compliance()
+ self.assertTrue(isinstance(issues, list))
+ self.assertTrue(len(issues) > 1)
diff --git a/tests/schema/test_schema_converters.py b/tests/schema/test_schema_converters.py
index 5f7c1d121..30cacaba6 100644
--- a/tests/schema/test_schema_converters.py
+++ b/tests/schema/test_schema_converters.py
@@ -79,7 +79,7 @@ class TestComplianceBase(unittest.TestCase):
xml_file = '../data/schema_tests/HED8.0.0t.xml'
wiki_file = '../data/schema_tests/HED8.0.0.mediawiki'
can_compare = True
- expected_issues = 5
+ expected_issues = 7
@classmethod
def setUpClass(cls):
diff --git a/tests/schema/test_schema_validation_util.py b/tests/schema/test_schema_validation_util.py
index 3c9494aac..7476a3733 100644
--- a/tests/schema/test_schema_validation_util.py
+++ b/tests/schema/test_schema_validation_util.py
@@ -28,13 +28,13 @@ def test_validate_schema_term(self):
"@invalidcharatstart",
]
expected_issues = [
- ErrorHandler.format_error(SchemaWarnings.INVALID_CAPITALIZATION, test_terms[0], char_index=0,
+ ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CAPITALIZATION, test_terms[0], char_index=0,
problem_char="i"),
[],
[],
- ErrorHandler.format_error(SchemaWarnings.INVALID_CHARACTERS_IN_TAG, test_terms[3], char_index=11,
+ ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_TAG, test_terms[3], char_index=11,
problem_char="#"),
- ErrorHandler.format_error(SchemaWarnings.INVALID_CAPITALIZATION, test_terms[4], char_index=0,
+ ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CAPITALIZATION, test_terms[4], char_index=0,
problem_char="@"),
]
self.validate_term_base(test_terms, expected_issues)
@@ -50,13 +50,13 @@ def test_validate_schema_description(self):
[],
[],
[],
- ErrorHandler.format_error(SchemaWarnings.INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
+ ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
char_index=60, problem_char="@")
- + ErrorHandler.format_error(SchemaWarnings.INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
+ + ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
char_index=61, problem_char="$")
- + ErrorHandler.format_error(SchemaWarnings.INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
+ + ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
char_index=62, problem_char="%")
- + ErrorHandler.format_error(SchemaWarnings.INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
+ + ErrorHandler.format_error(SchemaWarnings.SCHEMA_INVALID_CHARACTERS_IN_DESC, test_descs[3], "dummy",
char_index=63, problem_char="*")
]