@@ -434,7 +434,12 @@ def __eq__(self, other):
434434
435435 def find_tags (self , search_tags , recursive = False , include_groups = 2 ) -> list :
436436 """Find the base tags and their containing groups.
437- This searches by short_base_tag, ignoring any ancestors or extensions/values.
437+
438+ Comparison property: ``short_base_tag`` (schema short name without any extension or value).
439+ Rationale: callers pass bare tag names such as ``"Event"`` or ``"Def"`` and must
440+ match regardless of any extension or value the tag carries in the source string.
441+ Using ``short_base_tag`` strips the extension/value so ``"Def/MyDef"`` is found
442+ by searching for ``"Def"``.
438443
439444 Parameters:
440445 search_tags (container): A container of short_base_tags to locate.
@@ -462,11 +467,16 @@ def find_tags(self, search_tags, recursive=False, include_groups=2) -> list:
462467 return found_tags
463468
464469 def find_wildcard_tags (self , search_tags , recursive = False , include_groups = 2 ) -> list :
465- """Find the tags and their containing groups.
466-
467- This searches tag.short_tag.casefold(), with an implicit wildcard on the end.
470+ """Find tags whose short form starts with a given prefix (implicit trailing wildcard).
468471
469- e.g. "Eve" will find Event, but not Sensory-event.
472+ Comparison property: ``short_tag`` (schema short name *including* any extension or value).
473+ Rationale: the query is a prefix such as ``"Def/"`` or ``"Eve"``; the match must cover
474+ the extension/value as well so that ``"Def/MyDef"`` is found by ``"Def/"`` but not by
475+ an unrelated tag that merely shares the same base. ``short_tag`` is used (not
476+ ``short_base_tag``) so that value-bearing tags like ``"Duration/3 s"`` can be matched
477+ by a prefix query such as ``"Duration/"``.
478+ Note: prefix matching is anchored to the start of ``short_tag`` only, so ``"Eve"``
479+ finds ``"Event"`` but not ``"Sensory-event"``.
470480
471481 Parameters:
472482 search_tags (container): A container of the starts of short tags to search.
@@ -499,15 +509,27 @@ def find_wildcard_tags(self, search_tags, recursive=False, include_groups=2) ->
499509 return found_tags
500510
501511 def find_exact_tags (self , exact_tags , recursive = False , include_groups = 1 ) -> list :
502- """Find the given tags. This will only find complete matches, any extension or value must also match.
512+ """Find tags that match exactly, including any extension or value.
513+
514+ Comparison property: ``HedTag.__eq__`` which compares ``short_tag.casefold()``
515+ (falling back to ``org_tag.casefold()`` for unrecognised tags).
516+ Rationale: callers pass a slash-path string such as ``"def/mydef"`` and need an
517+ exact full-path match — the extension/value is part of the identity (``"Def/Foo"``
518+ must not match ``"Def/Bar"``). Because ``HedTag.__str__`` returns ``short_tag`` when
519+ the tag is schema-identified, a tag written in long form in the source HED string
520+ (e.g. ``"Event/Sensory-event"``) will still be found by a short-form query
521+ (``"Sensory-event"``); the schema normalises them to the same ``short_tag``.
522+ Unrecognised tags fall back to a case-insensitive comparison of the original text.
503523
504524 Parameters:
505- exact_tags (list of HedTag): A container of tags to locate.
525+ exact_tags (list of str or HedTag): Tags to locate; each is compared via
526+ ``HedTag.__eq__``, which accepts both ``str`` and ``HedTag`` operands.
506527 recursive (bool): If true, also check subgroups.
507- include_groups (bool): 0, 1 or 2.
528+ include_groups (0, 1 or 2):
508529 If 0: Return only tags
509530 If 1: Return only groups
510531 If 2 or any other value: Return both
532+
511533 Returns:
512534 list: A list of tuples. The contents depend on the values of the include_group.
513535 """
@@ -564,12 +586,21 @@ def _get_def_tags_from_group(group):
564586 return def_tags
565587
566588 def find_tags_with_term (self , term , recursive = False , include_groups = 2 ) -> list :
567- """Find any tags that contain the given term.
568-
569- Note: This can only find identified tags.
589+ """Find tags whose schema ancestry includes the given term.
590+
591+ Comparison property: ``tag_terms`` — a tuple of all path components in the tag's
592+ long-form schema path, all casefolded (e.g. ``("event", "sensory-event")`` for the
593+ ``Sensory-event`` tag).
594+ Rationale: this implements HED's *ancestor search* — a bare query term such as
595+ ``"Event"`` must match not only the ``Event`` tag itself but also every descendant
596+ (``Sensory-event``, ``Agent-action``, etc.) because those descendants inherit the
597+ ``Event`` parent. ``tag_terms`` encodes the full ancestry, so membership testing
598+ (``term in tag.tag_terms``) handles all descendants in O(k) time where k is the
599+ schema depth. This requires a schema-identified tag; unidentified tags have an
600+ empty ``tag_terms`` tuple and will not be found.
570601
571602 Parameters:
572- term (str): A single term to search for.
603+ term (str): A single term to search for (compared case-insensitively) .
573604 recursive (bool): If true, recursively check subgroups.
574605 include_groups (0, 1 or 2): Controls return values
575606 If 0: Return only tags.
@@ -579,6 +610,7 @@ def find_tags_with_term(self, term, recursive=False, include_groups=2) -> list:
579610 Returns:
580611 list: A list of tuples. The contents depend on the values of the include_group.
581612 """
613+ # Note: unidentified tags (tag_terms == ()) are silently skipped.
582614 found_tags = []
583615 if recursive :
584616 tags = self .get_all_tags ()
0 commit comments