Skip to content

Commit c77b7cb

Browse files
Merge pull request #3 from neuromechanist/feat/generic-root-template-macro
Add generic root-level template macro for non-datatype directories
2 parents 239b67f + 5725810 commit c77b7cb

File tree

5 files changed

+64
-14
lines changed

5 files changed

+64
-14
lines changed

src/appendices/entity-table.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,3 @@ while entity definitions are in the [Entities Appendix](entities.md).
6161
## Motion
6262

6363
{{ MACROS___make_entity_table(datatypes=["motion"]) }}
64-
65-
## Stimulus Files
66-
67-
{{ MACROS___make_entity_table(datatypes=["stimuli"]) }}

tools/mkdocs_macros_bids/macros.py

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,18 @@ def make_root_filename_template(
112112
if src_path is None:
113113
src_path = _get_source_path()
114114

115-
schema_obj = schema.load_schema()
115+
# Load schema with explicit path to avoid caching issues
116+
import os
117+
118+
schema_path = os.path.join(
119+
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
120+
"src",
121+
"schema.json",
122+
)
123+
if os.path.exists(schema_path):
124+
schema_obj = schema.load_schema(schema_path)
125+
else:
126+
schema_obj = schema.load_schema()
116127

117128
# Look for rules that have a specific path (root-level organization)
118129
target_path = kwargs.get("path", "stimuli") # Default to stimuli
@@ -147,17 +158,30 @@ def make_root_filename_template(
147158
template_lines.append(f" {rule.stem}{ext}")
148159

149160
elif hasattr(rule, "suffixes"):
150-
# Handle entity-based files (like stim-<label>_audio.wav)
161+
# Handle entity-based files generically using entity definitions from schema
151162
entities_part = ""
152163
if hasattr(rule, "entities"):
153164
entity_parts = []
154165
for entity_name, requirement in rule.entities.items():
155-
if entity_name == "stimulus":
156-
entity_parts.append("stim-<label>")
157-
elif entity_name == "part":
158-
entity_parts.append("[_part-<label>]")
159-
elif entity_name == "annotation":
160-
entity_parts.append("_annot-<label>")
166+
# Look up the entity in the schema to get its prefix and format
167+
if entity_name in schema_obj.objects.entities:
168+
entity_def = schema_obj.objects.entities[entity_name]
169+
entity_prefix = entity_def.get("name", entity_name)
170+
entity_format = entity_def.get("format", "label")
171+
172+
# Format based on requirement (required vs optional)
173+
if requirement == "optional":
174+
entity_parts.append(f"[_{entity_prefix}-<{entity_format}>]")
175+
else:
176+
# First entity doesn't need underscore prefix
177+
if not entity_parts:
178+
entity_parts.append(
179+
f"{entity_prefix}-<{entity_format}>"
180+
)
181+
else:
182+
entity_parts.append(
183+
f"_{entity_prefix}-<{entity_format}>"
184+
)
161185
entities_part = "".join(entity_parts)
162186

163187
for suffix in rule.suffixes:
@@ -353,7 +377,18 @@ def make_sidecar_table(table_name, src_path=None):
353377
if src_path is None:
354378
src_path = _get_source_path()
355379

356-
schema_obj = schema.load_schema()
380+
# Load schema with explicit path to avoid caching issues
381+
import os
382+
383+
schema_path = os.path.join(
384+
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
385+
"src",
386+
"schema.json",
387+
)
388+
if os.path.exists(schema_path):
389+
schema_obj = schema.load_schema(schema_path)
390+
else:
391+
schema_obj = schema.load_schema()
357392
table = render.make_sidecar_table(schema_obj, table_name, src_path=src_path)
358393
return table
359394

@@ -412,7 +447,18 @@ def make_columns_table(table_name, src_path=None):
412447
if src_path is None:
413448
src_path = _get_source_path()
414449

415-
schema_obj = schema.load_schema()
450+
# Load schema with explicit path to avoid caching issues
451+
import os
452+
453+
schema_path = os.path.join(
454+
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
455+
"src",
456+
"schema.json",
457+
)
458+
if os.path.exists(schema_path):
459+
schema_obj = schema.load_schema(schema_path)
460+
else:
461+
schema_obj = schema.load_schema()
416462
table = render.make_columns_table(schema_obj, table_name, src_path=src_path)
417463
return table
418464

tools/schemacode/src/bidsschematools/render/tables.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,10 @@ def make_entity_table(schema, tablefmt="github", src_path=None, **kwargs):
309309
if not suffixes:
310310
continue
311311

312+
# Skip rules that don't have datatypes (e.g., stimuli rules with path-based organization)
313+
if not hasattr(rule, "datatypes"):
314+
continue
315+
312316
entities = []
313317
for ent in schema.rules.entities:
314318
val = rule.entities.get(ent, "")

tools/schemacode/src/bidsschematools/render/text.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ def make_filename_template(
324324
file_rules = schema.rules.files[dstype]
325325
file_groups = {}
326326
for rule in file_rules.values(level=2):
327+
# Skip rules that don't have datatypes (e.g., stimuli rules with path-based organization)
328+
if not hasattr(rule, "datatypes"):
329+
continue
327330
for datatype in rule.datatypes:
328331
file_groups.setdefault(datatype, []).append(rule)
329332

tools/schemacode/src/bidsschematools/tests/test_render_text.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ def test_make_filename_template(schema_obj, schema_dir, placeholders):
9393
datatypes = {
9494
datatype
9595
for rule in schema_obj.rules.files.raw.values(level=2)
96+
if hasattr(rule, "datatypes") # Skip rules without datatypes (e.g., stimuli)
9697
for datatype in rule.datatypes
9798
}
9899

0 commit comments

Comments
 (0)