diff --git a/src/dolphin/workflows/config/_yaml_model.py b/src/dolphin/workflows/config/_yaml_model.py index 2bd44527..55658632 100644 --- a/src/dolphin/workflows/config/_yaml_model.py +++ b/src/dolphin/workflows/config/_yaml_model.py @@ -171,15 +171,30 @@ def _add_comments( subsequent_indent=" " * indent_per_level, ) ) - if "anyOf" in val: + if "anyOf" in val or "oneOf" in val: # 'anyOf': [{'type': 'string'}, {'type': 'null'}], - # Join the options with a pipe, like Python types - type_str = " | ".join(d["type"] for d in val["anyOf"]) + # or for a Union of submodels (plain or discriminated): + # 'anyOf': [{'$ref': '#/$defs/A'}, {'$ref': '#/$defs/B'}] + # 'oneOf': [{'$ref': '#/$defs/A'}, {'$ref': '#/$defs/B'}] + # `oneOf` shows up when the field uses + # `Annotated[Union[...], Field(discriminator=...)]`. Join the + # options with a pipe, like Python types; fall back to the + # sub-model name for `$ref` entries that have no primitive + # `type` key. + def _union_label(d: dict) -> str: + if "type" in d: + return d["type"] + if "$ref" in d: + return d["$ref"].rsplit("/", 1)[-1] + return "object" + + entries = val.get("anyOf") or val.get("oneOf") or [] + type_str = " | ".join(_union_label(d) for d in entries) type_str.replace("null", "None") elif "const" in val: type_str = val["const"] else: - type_str = val["type"] + type_str = val.get("type", "object") type_line = f"\n Type: {type_str}." choices = f"\n Options: {val['enum']}." if "enum" in val else ""