Source code for hed.models.query_util

"""Classes representing HED search results and tokens."""


[docs] class SearchResult: """Holder for and manipulation of search results. Represents a query match result consisting of: - group: The containing HedGroup where matches were found. - children: The specific matched elements (tags/groups) within that group (NOT all children of the group — only those that satisfied the query). Example: When searching for "Red" in the HED string "(Red, Blue, Green)": - group = the containing group (Red, Blue, Green) - children = [Red] (only the matched tag) """ def __init__(self, group, children): """Initialize a search result. Parameters: group (HedGroup): The group where the children were found. children (HedTag, HedGroup, or list): The matched child elements (tags or groups) that satisfied the query condition. Can be: - Single tag/group that matched - List of tags/groups that matched - Empty list (for negation or when group matched but no specific children) """ self.group = group if not isinstance(children, list): new_children = [children] else: new_children = children.copy() self.children = new_children
[docs] def merge_and_result(self, other): """Returns a new result with the combined children from this and other. Parameters: other (SearchResult): Another search result to merge with this one. Returns: SearchResult: A new SearchResult containing unique children from both results. Raises: ValueError: If the groups are not the same. """ new_children = self.children.copy() for child in other.children: if any(child is this_child for this_child in self.children): continue new_children.append(child) new_children.sort(key=str) if self.group is not other.group: raise ValueError("Internal error") return SearchResult(self.group, new_children)
[docs] def has_same_children(self, other): """Checks if these two results have the same children by identity (not equality). Parameters: other (SearchResult): Another search result to compare with this one. Returns: bool: True if both results have the same group and identical children. """ if self.group is not other.group: return False if len(self.children) != len(other.children): return False return all(child is child2 for child, child2 in zip(self.children, other.children, strict=False))
def __eq__(self, other): if not isinstance(other, SearchResult): return NotImplemented return ( self.group is other.group and len(self.children) == len(other.children) and all(c is c2 for c, c2 in zip(self.children, other.children, strict=False)) ) def __hash__(self): return hash((id(self.group), tuple(id(c) for c in self.children))) # Backward compatibility alias has_same_tags = has_same_children def __str__(self): return str(self.group) + " Children: " + "---".join([str(child) for child in self.children])
class Token: """Represents a single term/character""" And = 0 Tag = 1 DescendantGroup = 4 DescendantGroupEnd = 5 Or = 6 LogicalGroup = 7 LogicalGroupEnd = 8 LogicalNegation = 9 Wildcard = 10 ExactMatch = 11 ExactMatchEnd = 12 ExactMatchOptional = 14 def __init__(self, text): """Initialize a token for query parsing. Parameters: text (str): The text representation of the token. """ tokens = { ",": Token.And, "&&": Token.And, "||": Token.Or, "[": Token.DescendantGroup, "]": Token.DescendantGroupEnd, "(": Token.LogicalGroup, ")": Token.LogicalGroupEnd, "~": Token.LogicalNegation, "?": Token.Wildcard, # Any tag or group "??": Token.Wildcard, # Any tag "???": Token.Wildcard, # Any Group "{": Token.ExactMatch, # Nothing else "}": Token.ExactMatchEnd, # Nothing else ":": Token.ExactMatchOptional, } self.kind = tokens.get(text, Token.Tag) self.text = text def __str__(self): return self.text def __eq__(self, other): if self.kind == other: return True return False