Skip to content

Commit 126aab7

Browse files
committed
Addressed copilot reviews
1 parent 22790bb commit 126aab7

3 files changed

Lines changed: 48 additions & 17 deletions

File tree

docs/search_implementation.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,18 @@ It parses each raw HED string into a lightweight {class}`~hed.models.string_sear
5353
Key characteristics:
5454

5555
- Input is a raw string (or a `pd.Series` via {func}`~hed.models.string_search.search_series`).
56-
- Schema is **optional**: pass a `schema_lookup` dict (see {mod}`hed.models.schema_lookup`) to enable ancestor matching for long-form strings; omit it for purely literal matching.
56+
- Schema is **optional**: pass a `schema_lookup` dict (see {mod}`hed.models.schema_lookup`) to enable ancestor matching for short-form strings (e.g. `Event` matching `Sensory-event`); omit it for purely literal matching.
5757
- Output is a list (truthy/falsy) — row-filtering only, no object references.
5858
- Supports the same full query syntax as `QueryHandler` (`&&`, `||`, `~`, `@`, `{}`, etc.).
5959
- `@A` carries the same semantics as `QueryHandler` — A must **not** be present.
60-
- Without a schema lookup, `Event` does **not** match `Sensory-event` (short-form strings). With a schema lookup, ancestor matching works for long-form strings (`Event/Sensory-event`).
60+
- Long-form strings (`Event/Sensory-event`) support ancestor matching via slash-splitting even without a lookup. Short-form strings (`Sensory-event`) require a `schema_lookup` for ancestor matching; without one, matching is purely literal.
6161
- Parse cost is a lightweight recursive split — much cheaper than a full HedString + schema parse.
6262

6363
Use `StringQueryHandler` when you have raw strings (not `HedString` objects), need the full `QueryHandler` query syntax, and either don't have a schema available or want faster processing at the cost of losing full schema-aware ancestor matching. See {class}`hed.models.string_search.StringQueryHandler`.
6464

6565
### Generating a schema lookup
6666

67-
If you want `StringQueryHandler` to resolve ancestors for long-form strings without a full schema parse per row, you can pre-generate a lookup dictionary from a `HedSchema`:
67+
If you want `StringQueryHandler` to resolve ancestors for short-form strings (e.g. query `Event` matching `Sensory-event`) without a full schema parse per row, you can pre-generate a lookup dictionary from a `HedSchema`:
6868

6969
```python
7070
from hed import load_schema_version

hed/models/schema_lookup.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
import json
3838
from pathlib import Path
3939

40-
from hed.schema.hed_schema_constants import HedSectionKey
41-
4240

4341
def generate_schema_lookup(schema):
4442
"""Build a schema lookup table mapping short tag names to their ``tag_terms``.
@@ -69,7 +67,7 @@ def generate_schema_lookup(schema):
6967
# Handle HedSchemaGroup by iterating component schemas
7068
schemas = _iter_schemas(schema)
7169
for sch in schemas:
72-
tags_section = sch._sections.get(HedSectionKey.Tags)
70+
tags_section = sch.tags
7371
if tags_section is None:
7472
continue
7573
for name, entry in tags_section.items():
@@ -98,13 +96,9 @@ def _iter_schemas(schema):
9896
Yields:
9997
HedSchema: Individual schema objects.
10098
"""
101-
# HedSchemaGroup has a 'schemas' dict or list attribute
102-
if hasattr(schema, "schemas"):
103-
schemas_attr = schema.schemas
104-
if isinstance(schemas_attr, dict):
105-
yield from schemas_attr.values()
106-
else:
107-
yield from schemas_attr
99+
# HedSchemaGroup stores member schemas in _schemas (a dict keyed by namespace)
100+
if hasattr(schema, "_schemas"):
101+
yield from schema._schemas.values()
108102
else:
109103
yield schema
110104

tests/models/test_schema_lookup.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,45 @@ def test_round_trip_preserves_tag_terms(self):
189189
os.unlink(tmp_path)
190190

191191

192+
class TestGenerateSchemaLookupGroup(unittest.TestCase):
193+
"""Verify that generate_schema_lookup works correctly with HedSchemaGroup."""
194+
195+
@classmethod
196+
def setUpClass(cls):
197+
base_data_dir = os.path.realpath(os.path.join(os.path.dirname(__file__), "../data/"))
198+
hed_xml_file = os.path.join(base_data_dir, "schema_tests/HED8.0.0t.xml")
199+
try:
200+
from hed import schema as hed_schema
201+
from hed.schema.hed_schema_group import HedSchemaGroup
202+
203+
single = hed_schema.load_schema(hed_xml_file)
204+
cls.group = HedSchemaGroup([single])
205+
cls.single_lookup = generate_schema_lookup(single)
206+
cls.group_lookup = generate_schema_lookup(cls.group)
207+
except Exception as exc:
208+
cls.group = None
209+
cls.single_lookup = None
210+
cls.group_lookup = None
211+
cls._setup_error = str(exc)
212+
213+
def _require_group(self):
214+
if self.group_lookup is None:
215+
self.skipTest(f"Schema not available: {getattr(self, '_setup_error', 'unknown error')}")
216+
217+
def test_group_returns_dict(self):
218+
self._require_group()
219+
self.assertIsInstance(self.group_lookup, dict)
220+
221+
def test_group_lookup_non_empty(self):
222+
self._require_group()
223+
self.assertGreater(len(self.group_lookup), 0)
224+
225+
def test_group_lookup_matches_single_lookup(self):
226+
"""A group wrapping a single schema should produce the same lookup as that schema alone."""
227+
self._require_group()
228+
self.assertEqual(self.group_lookup, self.single_lookup)
229+
230+
192231
class TestSchemaLookupUsedInSearch(TestSchemaLookupBase):
193232
"""Integration tests: lookup dict plugged into StringQueryHandler."""
194233

@@ -241,11 +280,9 @@ def items(self):
241280
return []
242281

243282
class _FakeSchema:
244-
_sections = {}
245-
246283
@property
247-
def schemas(self):
248-
return []
284+
def tags(self):
285+
return _FakeSection()
249286

250287
result = generate_schema_lookup(_FakeSchema())
251288
self.assertIsInstance(result, dict)

0 commit comments

Comments
 (0)