Skip to content

Discriminative union helper and errors are hard to understand #695

@julien-blanchon

Description

@julien-blanchon

I'm using a lot the following discriminative union pattern:

from dataclasses import dataclass
from typing import Annotated, Literal
from jsonargparse import auto_cli
from pydantic import Field

@dataclass
class DatasetImage:
    type: Literal["image"]
    path: str


@dataclass
class DatasetVideo:
    type: Literal["video"]
    path: str
    fps: int


@dataclass
class Config:
    dataset: Annotated[DatasetImage | DatasetVideo, Field(discriminator="type")]


def main(conf: Config):
    print(conf)


if __name__ == "__main__":
    auto_cli(main)

It's working with cyclopts (but still need pydantic for the discriminator field).

With jsonargparse it's working

❯ python main.py --conf.dataset.type="video" --conf.dataset.path="." --conf.dataset.fps=24 
Config(dataset=DatasetVideo(type='video', path='.', fps=24))

But the helper is not very helpful and the error message are very hard to understand

❯ python main.py --conf.dataset.type="video" --conf.dataset.path="."        
usage: main.py [-h] [--config CONFIG] [--print_config[=flags]] [--conf CONFIG] --conf.dataset DATASET
               [--print_shtab {bash,zsh,tcsh}]
error: Parser key "conf.dataset":
  Does not validate against any of the Union subtypes
  Subtypes: [<class '__main__.DatasetImage'>, <class '__main__.DatasetVideo'>]
  Errors:
    - No action for key "fps" to set its default.
    - Validation failed: Key "fps" is required but not included in config object or its value is None.
  Given value type: <class 'jsonargparse._namespace.Namespace'>
  Given value: Namespace(type='video', path='.', fps=None)


❯ python main.py --help              
usage: main.py [-h] [--config CONFIG] [--print_config[=flags]] [--conf CONFIG] --conf.dataset DATASET
               [--print_shtab {bash,zsh,tcsh}]

<function main at 0x10491d8a0>

options:
  -h, --help            Show this help message and exit.
  --config CONFIG       Path to a configuration file.
  --print_config[=flags]
                        Print the configuration after applying all other arguments and exit. The optional flags customizes the
                        output and are one or more keywords separated by comma. The supported flags are: comments, skip_default,
                        skip_null.
  --print_shtab {bash,zsh,tcsh}
                        Print shtab shell completion script.

Config(dataset: Annotated[__main__.DatasetImage | __main__.DatasetVideo, FieldInfo(annotation=NoneType, required=True, discriminator='type')]):
  --conf CONFIG         Path to a configuration file.
  --conf.dataset DATASET
                        (required, type: Annotated[DatasetImage | DatasetVideo, FieldInfo(annotation=null, required=True,
                        discriminator='type')])

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions