Skip to content

Better help message with optional dataclasses #368

Closed

Description

@bilelomrani1

In the following example

from dataclasses import dataclass
from typing import Optional

from jsonargparse import ArgumentParser


@dataclass
class Config:
    a: int
    b: float = 2.0


if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument("--config", type=Optional[Config], default=None, required=False)
    print(parser.parse_args())

the help message looks like this:

$ python main.py --help
usage: main.py [-h] [--config CONFIG]

options:
  -h, --help       Show this help message and exit.
  --config CONFIG  (type: Optional[Config], default: null)

I haven't figured out a way but is there a way to show the dataclasses arguments in the help message (even when the dataclass is optional) and mark the group as optional?

$ python main.py --help
usage: main.py [-h] [--config CONFIG] --config.a A [--config.b B]

options:
  -h, --help       Show this help message and exit.

Config docstring (optional):
  --config CONFIG  Path to a configuration file.
  --config.a A     (required, type: int)
  --config.b B     (type: float, default: 2.0)

The goal is to give the user more clues about what's expected but still yield Namespace(config=None) when nothing is passed from the CLI.

Thank you for your help!

Activity

  1. mauvilsa commented on Sep 4, 2023

    @mauvilsa
    Owner

    @bilelomrani1 thanks for pointing this out. Certainly there should be a way to get the details of the dataclass. This should be similar to how it is being done for subclasses. Though there are two cases to handle:

    • Optional dataclasses, e.g. Optional[DataClass]
    • Mixture of classes, e.g. Union[int, DataClass1, DataClass2, BaseForSubclasses1]

    In the first case it could be an argument --*.help that does not expect any value and would print the details for the dataclass. This means that for the example above, people would need to call the CLI as python main.py --config.help. Would be nicer if it were shown in the normal help, though this might be overly complicated to implement, since the parser wouldn't really have these arguments.

    For the second case, for certain it would be a --*.help that expects a class name or class import path. So the behavior would be just like it is now for subclasses.

  2. bilelomrani1 commented on Sep 4, 2023

    @bilelomrani1
    Author

    Thank you @mauvilsa, great idea, adding an argument seems very reasonable to me indeed.

  3. jerrymatjila commented on Nov 17, 2023

    @jerrymatjila

    Here is the solution

    from dataclasses import dataclass
    from jsonargparse import ArgumentParser
    
    
    @dataclass
    class Config:
        a: int
        b: float = 2.0
    
    
    if __name__ == "__main__":
        parser = ArgumentParser()
        parser.add_argument("--config", type=Config)
        print(parser.parse_args())
    $ python example.py  -h
    usage: example.py [-h] [--config CONFIG] --config.a A [--config.b B]
    
    options:
      -h, --help       Show this help message and exit.
    
    Config(a: int, b: float = 2.0):
      --config CONFIG  Path to a configuration file.
      --config.a A     (required, type: int)
      --config.b B     (type: float, default: 2.0)

    To make meaningful help messages use docstrings as shown below

    from dataclasses import dataclass
    from jsonargparse import ArgumentParser
    from jsonargparse import set_docstring_parse_options
    set_docstring_parse_options(attribute_docstrings=True)
    
    @dataclass
    class Config:
        a: int
        """Number of integers."""
    
        b: float = 2.0
        """Number of floats."""
    
    
    if __name__ == "__main__":
        parser = ArgumentParser()
        parser.add_argument("--config", type=Config)
        print(parser.parse_args())
    $ python example.py  -h
    usage: example.py [-h] [--config CONFIG] --config.a A [--config.b B]
    
    options:
      -h, --help       Show this help message and exit.
    
    Config(a: int, b: float = 2.0):
      --config CONFIG  Path to a configuration file.
      --config.a A     Number of integers. (required, type: int)
      --config.b B     Number of floats. (type: float, default: 2.0)
  4. mauvilsa commented on Oct 9, 2025

    @mauvilsa
    Owner

    With pull request #783 just merged, the behavior is as proposed in #368 (comment). If there is a single nested dataclass, then there will be a --*.help option that doesn't expect any value. For multiple nested dataclasses, the --*.help option expects a class name or class path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions