diff --git a/tools/schemacode/bidsschematools/render.py b/tools/schemacode/bidsschematools/render.py index 5971af423e..ee68e2bfa9 100644 --- a/tools/schemacode/bidsschematools/render.py +++ b/tools/schemacode/bidsschematools/render.py @@ -6,6 +6,7 @@ from collections.abc import Mapping import pandas as pd +import yaml from tabulate import tabulate from . import utils @@ -16,6 +17,19 @@ utils.set_logger_level(lgr, os.environ.get("BIDS_SCHEMA_LOG_LEVEL", logging.INFO)) logging.basicConfig(format="%(asctime)-15s [%(levelname)8s] %(message)s") +TYPE_CONVERTER = { + "associated_data": "associated data", + "columns": "column", + "common_principles": "common principle", + "datatypes": "datatype", + "entities": "entity", + "extensions": "extension", + "formats": "format", + "metadata": "metadata", + "top_level_files": "top level file", + "suffixes": "suffix", +} + def get_relpath(src_path): """Retrieve relative path to the source root from the perspective of a Markdown file. @@ -77,24 +91,29 @@ def make_entity_definitions(schema, src_path=None): text = "" for entity in entity_order: entity_info = entity_definitions[entity] - entity_shorthand = entity_info["name"] - text += "\n" - text += "## {}".format(entity_shorthand) - text += "\n\n" - text += "Full name: {}".format(entity_info["display_name"]) - text += "\n\n" - text += "Format: `{}-<{}>`".format( - entity_info["name"], - entity_info.get("format", "label"), - ) + entity_text = _make_entity_definition(entity, entity_info, src_path) + text += "\n" + entity_text + + return text + + +def _make_entity_definition(entity, entity_info, src_path): + """Describe an entity.""" + entity_shorthand = entity_info["name"] + text = "" + text += "## {}".format(entity_shorthand) + text += "\n\n" + text += f"**Full name**: {entity_info['display_name']}" + text += "\n\n" + text += f"**Format**: `{entity_info['name']}-<{entity_info.get('format', 'label')}>`" + text += "\n\n" + if "enum" in entity_info.keys(): + text += f"**Allowed values**: `{'`, `'.join(entity_info['enum'])}`" text += "\n\n" - if "enum" in entity_info.keys(): - text += "Allowed values: `{}`".format("`, `".join(entity_info["enum"])) - text += "\n\n" - description = entity_info["description"] - description = description.replace("SPEC_ROOT", get_relpath(src_path)) - text += "Definition: {}".format(description) + description = entity_info["description"] + description = description.replace("SPEC_ROOT", get_relpath(src_path)) + text += f"**Definition**: {description}" return text @@ -117,14 +136,16 @@ def make_glossary(schema, src_path=None): information about the entities in the schema. """ all_objects = {} + schema = schema.to_dict() for group, group_objects in schema["objects"].items(): group_obj_keys = list(group_objects.keys()) - # Remove private objects + + # Do not include private objects in the glossary group_obj_keys = [k for k in group_obj_keys if not k.startswith("_")] + # Identify multi-sense objects (multiple entries, indicated by __ in key) multi_sense_objects = [] - # Identify multi-sense objects (multiple entries, some with __ in them) for key in group_obj_keys: if "__" in key: temp_key = key.split("__")[0] @@ -149,6 +170,7 @@ def make_glossary(schema, src_path=None): new_name = f"{new_name} ({group})" all_objects[new_name] = {} all_objects[new_name]["key"] = f"objects.{group}.{key}" + all_objects[new_name]["type"] = TYPE_CONVERTER.get(group, group) all_objects[new_name]["definition"] = group_objects[key] text = "" @@ -156,7 +178,8 @@ def make_glossary(schema, src_path=None): obj = all_objects[obj_key] obj_marker = obj["key"] obj_def = obj["definition"] - obj_name = obj_def["display_name"] + + # Clean up the text description obj_desc = obj_def["description"] # A backslash before a newline means continue a string obj_desc = obj_desc.replace("\\\n", "") @@ -169,11 +192,31 @@ def make_glossary(schema, src_path=None): text += f'\n' text += f"\n## {obj_key}\n\n" - text += f"name: {obj_name}\n\n" - text += f"description:\n>{obj_desc}\n\n" - - temp_obj_def = {k: v for k, v in obj_def.items() if k not in ("description", "name")} - text += f"schema information:\n```yaml\n{temp_obj_def}\n```" + text += f"**Name**: {obj_def['display_name']}\n\n" + text += f"**Type**: {obj['type'].title()}\n\n" + + if obj["type"] == "suffix": + text += f"**Format**: `_{obj_def['value']}.`\n\n" + elif obj["type"] == "extension": + text += f"**Format**: `_{obj_def['value']}`\n\n" + elif obj["type"] == "format": + text += f"**Regular expression**: `{obj_def['pattern']}`\n\n" + + if "enum" in obj_def.keys(): + allowed_vals = [f"`{enum}`" for enum in obj_def["enum"]] + text += f"**Allowed values**: {', '.join(allowed_vals)}\n\n" + + text += f"**Description**:\n{obj_desc}\n\n" + + temp_obj_def = { + k: v + for k, v in obj_def.items() + if k not in ("description", "display_name", "name", "value", "enum", "pattern") + } + + if temp_obj_def: + temp_obj_def = yaml.dump(temp_obj_def) + text += f"**Schema information**:\n```yaml\n{temp_obj_def}\n```" return text diff --git a/tools/schemacode/bidsschematools/tests/test_render.py b/tools/schemacode/bidsschematools/tests/test_render.py index c321850c94..02d09f4fd6 100644 --- a/tools/schemacode/bidsschematools/tests/test_render.py +++ b/tools/schemacode/bidsschematools/tests/test_render.py @@ -11,22 +11,22 @@ def test_make_entity_definitions(schema_obj): """ schema_text = render.make_entity_definitions(schema_obj) expected_formats = [ - "Format: `sub-