Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hed/errors/error_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def schema_error_hed_duplicate_node(tag, duplicate_tag_list, section):
f"{tag_join_delimiter}{tag_join_delimiter.join(duplicate_tag_list)}"


@hed_error(SchemaErrors.HED_SCHEMA_ATTRIBUTE_INVALID)
@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."
Expand Down
2 changes: 1 addition & 1 deletion hed/errors/error_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class SidecarErrors:

class SchemaErrors:
HED_SCHEMA_DUPLICATE_NODE = 'HED_SCHEMA_DUPLICATE_NODE'
HED_SCHEMA_ATTRIBUTE_INVALID = 'HED_SCHEMA_ATTRIBUTE_INVALID'
SCHEMA_ATTRIBUTE_INVALID = 'SCHEMA_ATTRIBUTE_INVALID'
HED_SCHEMA_DUPLICATE_FROM_LIBRARY = "SCHEMA_LIBRARY_INVALID"


Expand Down
9 changes: 0 additions & 9 deletions hed/models/hed_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ def append(self, tag_or_group):

Parameters:
tag_or_group (HedTag or HedGroup): The new object to add to this group.

:raises ValueError:
If a HedGroupFrozen.

"""
tag_or_group._parent = self
self._children.append(tag_or_group)
Expand Down Expand Up @@ -469,11 +465,6 @@ def find_exact_tags(self, tags_or_groups, recursive=False, include_groups=1):
- This can only find identified tags.
- By default, definition, def, def-expand, onset, and offset are identified, even without a schema.
- If this is a HedGroup, order matters. (b, a) != (a, b)
- If this is a HedGroupFrozen:
if "(a, b)" in tags_or_groups, then it will match 1 and 2, but not 3.
1. (a, b)
2. (b, a)
3. (a, b, c)

"""
found_tags = []
Expand Down
4 changes: 3 additions & 1 deletion hed/schema/hed_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ def cache_xml_versions(hed_base_urls=DEFAULT_URL_LIST, skip_folders=DEFAULT_SKIP
_cache_hed_version(version, library_name, version_info, cache_folder=cache_folder)

_write_last_cached_time(current_timestamp, cache_folder)
except portalocker.exceptions.LockException:
except portalocker.exceptions.LockException or ValueError:
return -1

return 0
Expand Down Expand Up @@ -303,6 +303,8 @@ def _write_last_cached_time(new_time, cache_folder):
new_time (float): The time this was updated.
cache_folder (str): The folder used for caching the hed schema.

:raises ValueError:
- something went wrong writing to the file
"""
timestamp_filename = os.path.join(cache_folder, TIMESTAMP_FILENAME)
try:
Expand Down
4 changes: 2 additions & 2 deletions hed/schema/hed_schema_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def __init__(self, schema_list):
HedSchemaGroup: the container created.

:raises HedFileError:
- If multiple schemas have the same library prefixes.

- Multiple schemas have the same library prefixes.
- Empty list passed
"""
if len(schema_list) == 0:
raise HedFileError(HedExceptions.BAD_PARAMETERS, "Empty list passed to HedSchemaGroup constructor.",
Expand Down
20 changes: 11 additions & 9 deletions hed/schema/hed_schema_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def from_string(schema_string, file_type=".xml", schema_namespace=None):

:raises HedFileError:
- If empty string or invalid extension is passed.
- Other fatal formatting issues with file

Notes:
- The loading is determined by file type.
Expand Down Expand Up @@ -79,7 +80,9 @@ def load_schema(hed_path=None, schema_namespace=None):
HedSchema: The loaded schema.

:raises HedFileError:
- If there are any fatal issues when loading the schema.
- Empty path passed
- Unknown extension
- Any fatal issues when loading the schema.

"""
if not hed_path:
Expand Down Expand Up @@ -114,6 +117,8 @@ def get_hed_xml_version(xml_file_path):
Returns:
str: The version number of the HED XML file.

:raises HedFileError:
- There is an issue loading the schema
"""
root_node = HedSchemaXMLParser._parse_hed_xml(xml_file_path)
return root_node.attrib[hed_schema_constants.VERSION_ATTRIBUTE]
Expand All @@ -130,10 +135,9 @@ def _load_schema_version(xml_version=None, xml_folder=None):
HedSchema or HedSchemaGroup: The requested HedSchema object.

:raises HedFileError:
- If the xml_version is not valid.

Notes:
- The library schema files have names of the form HED_(LIBRARY_NAME)_(version).xml.
- The xml_version is not valid.
- The specified version cannot be found or loaded
- Other fatal errors loading the schema (These are unlikely if you are not editing them locally)
"""
schema_namespace = ""
library_name = None
Expand Down Expand Up @@ -179,10 +183,8 @@ def load_schema_version(xml_version=None, xml_folder=None):
HedSchema or HedSchemaGroup: The schema or schema group extracted.

:raises HedFileError:
- If the xml_version is not valid.

Notes:
- Loads the latest schema value if an empty version is given (string or list).
- The xml_version is not valid.
- A fatal error was encountered in parsing
"""
if xml_version and isinstance(xml_version, list):
schemas = [_load_schema_version(xml_version=version, xml_folder=xml_folder) for version in xml_version]
Expand Down
87 changes: 28 additions & 59 deletions hed/schema/schema_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ def check_compliance(hed_schema, check_for_warnings=True, name=None, error_handl
Returns:
list: A list of all warnings and errors found in the file. Each issue is a dictionary.

Notes:
- Useful for temp filenames in support of web services.

: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.")
Expand All @@ -40,7 +39,7 @@ def check_compliance(hed_schema, check_for_warnings=True, name=None, error_handl
if unknown_attributes:
for attribute_name, source_tags in unknown_attributes.items():
for tag in source_tags:
issues_list += error_handler.format_error_with_context(SchemaErrors.HED_SCHEMA_ATTRIBUTE_INVALID,
issues_list += error_handler.format_error_with_context(SchemaErrors.SCHEMA_ATTRIBUTE_INVALID,
attribute_name,
source_tag=tag)

Expand All @@ -62,7 +61,10 @@ def check_compliance(hed_schema, check_for_warnings=True, name=None, error_handl
validator = schema_attribute_validators.get(attribute_name)
if validator:
error_handler.push_error_context(ErrorContext.SCHEMA_ATTRIBUTE, attribute_name)
new_issues = validator(hed_schema, tag_entry, tag_entry.attributes[attribute_name])
new_issues = validator(hed_schema, tag_entry, attribute_name)
# if force_issues_as_warnings:
for issue in new_issues:
issue['severity'] = ErrorSeverity.WARNING
error_handler.add_context_and_filter(new_issues)
issues_list += new_issues
error_handler.pop_error_context()
Expand All @@ -75,8 +77,7 @@ def check_compliance(hed_schema, check_for_warnings=True, name=None, error_handl
if len(values) == 2:
error_code = SchemaErrors.HED_SCHEMA_DUPLICATE_FROM_LIBRARY
issues_list += 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)

error_handler.pop_error_context()
Expand All @@ -92,15 +93,19 @@ def check_compliance(hed_schema, check_for_warnings=True, name=None, error_handl
error_handler.pop_error_context()
return issues_list

# attribute_checker_template(hed_schema, tag_entry, attribute_name, possible_values):
# 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


def tag_is_placeholder_check(hed_schema, tag_entry, possible_tags, force_issues_as_warnings=True):
def tag_is_placeholder_check(hed_schema, tag_entry, attribute_name):
""" Check if comma separated list has valid HedTags.

Parameters:
hed_schema (HedSchema): The schema to check if the tag exists.
hed_schema (HedSchema): The schema to use for validation
tag_entry (HedSchemaEntry): The schema entry for this tag.
possible_tags (str): Comma separated list of tags. Short long or mixed form valid.
force_issues_as_warnings (bool): If True sets all the severity levels to warning.
attribute_name (str): The name of this attribute

Returns:
list: A list of issues. Each issue is a dictionary.
Expand All @@ -109,91 +114,55 @@ def tag_is_placeholder_check(hed_schema, tag_entry, possible_tags, force_issues_
issues = []
if not tag_entry.name.endswith("/#"):
issues += ErrorHandler.format_error(SchemaWarnings.NON_PLACEHOLDER_HAS_CLASS, tag_entry.name,
possible_tags)

if force_issues_as_warnings:
for issue in issues:
issue['severity'] = ErrorSeverity.WARNING

return issues


def attribute_does_not_exist_check(hed_schema, tag_entry, attribute_name, force_issues_as_warnings=True):
""" Throws an error saying this is a bad attribute if found.

Parameters:
hed_schema (HedSchema): The schema to check if the tag exists.
tag_entry (HedSchemaEntry): The schema entry for this tag.
attribute_name (str): the attribute name we're looking for
force_issues_as_warnings (bool): If True sets all the severity levels to warning.

Returns:
list: A list of issues. Each issue is a dictionary.

"""
issues = []
issues += ErrorHandler.format_error(SchemaWarnings.INVALID_ATTRIBUTE, tag_entry.name,
attribute_name)

if force_issues_as_warnings:
for issue in issues:
issue['severity'] = ErrorSeverity.WARNING
attribute_name)

return issues


def tag_exists_check(hed_schema, tag_entry, possible_tags, force_issues_as_warnings=True):
""" Check if comma separated list are valid HedTags.
def tag_exists_check(hed_schema, tag_entry, attribute_name):
""" Check if the list of possible tags exists in the schema.

Parameters:
hed_schema (HedSchema): The schema to check if the tag exists.
hed_schema (HedSchema): The schema to use for validation
tag_entry (HedSchemaEntry): The schema entry for this tag.
possible_tags (str): Comma separated list of tags. Short long or mixed form valid.
force_issues_as_warnings (bool): If True, set all the severity levels to warning.
attribute_name (str): The name of this attribute

Returns:
list: A list of issues. Each issue is a dictionary.

"""
issues = []
possible_tags = tag_entry.attributes.get(attribute_name, "")
split_tags = possible_tags.split(",")
for org_tag in split_tags:
if org_tag not in hed_schema.all_tags:
if org_tag and org_tag not in hed_schema.all_tags:
issues += ErrorHandler.format_error(ValidationErrors.NO_VALID_TAG_FOUND,
org_tag,
index_in_tag=0,
index_in_tag_end=len(org_tag))

if force_issues_as_warnings:
for issue in issues:
issue['severity'] = ErrorSeverity.WARNING
return issues


def tag_exists_base_schema_check(hed_schema, tag_entry, tag_name, force_issues_as_warnings=True):
def tag_exists_base_schema_check(hed_schema, tag_entry, attribute_name):
""" Check if the single tag is a partnered schema tag

Parameters:
hed_schema (HedSchema): The schema to check if the tag exists.
hed_schema (HedSchema): The schema to use for validation
tag_entry (HedSchemaEntry): The schema entry for this tag.
tag_name (str): The tag to verify, can be any form.
force_issues_as_warnings (bool): If True, set all the severity levels to warning.
attribute_name (str): The name of this attribute

Returns:
list: A list of issues. Each issue is a dictionary.

"""
issues = []
rooted_tag = tag_name.lower()
if rooted_tag not in hed_schema.all_tags:
rooted_tag = tag_entry.attributes.get(attribute_name, "")
if rooted_tag and rooted_tag not in hed_schema.all_tags:
issues += ErrorHandler.format_error(ValidationErrors.NO_VALID_TAG_FOUND,
rooted_tag,
index_in_tag=0,
index_in_tag_end=len(rooted_tag))

if force_issues_as_warnings:
for issue in issues:
issue['severity'] = ErrorSeverity.WARNING
return issues


Expand Down
26 changes: 21 additions & 5 deletions hed/schema/schema_validation_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ def is_hed3_version_number(version_string):


def validate_present_attributes(attrib_dict, filename):
""" Validate combinations of attributes

Parameters:
attrib_dict (dict): Dictionary of attributes to be evaluated.
filename (str): File name to use in reporting errors.

Returns:
list: List of issues. Each issue is a dictionary.

:raises HedFileError:
- withStandard is found in th header, but a library attribute is not specified
"""
if constants.WITH_STANDARD_ATTRIBUTE in attrib_dict and constants.LIBRARY_ATTRIBUTE not in attrib_dict:
raise HedFileError(HedExceptions.BAD_WITH_STANDARD,
"withStandard header attribute found, but no library attribute is present",
Expand All @@ -81,8 +93,9 @@ def validate_attributes(attrib_dict, filename):
list: List of issues. Each issue is a dictionary.

:raises HedFileError:
- If invalid or version not found in the dictionary.

- Invalid library name
- Version not present
- Invalid combinations of attributes in header
"""
validate_present_attributes(attrib_dict, filename)

Expand Down Expand Up @@ -111,9 +124,12 @@ def find_rooted_entry(tag_entry, schema, loading_merged):
rooted_tag(HedTagEntry or None): The base tag entry from the standard schema
Returns None if this tag isn't rooted

:raises HedValueError:
- If the tag doesn't exist or similar

:raises HedFileError:
- A rooted attribute is found in a non-paired schema
- A rooted attribute is not a string
- A rooted attribute was found on a non-root node in an unmerged schema.
- A rooted attribute is found on a root node in a merged schema.
- A rooted attribute indicates a tag that doesn't exist in the base schema.
"""
rooted_tag = tag_entry.has_attribute(constants.HedKey.Rooted, return_value=True)
if rooted_tag is not None:
Expand Down
Loading