Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better help message with optional dataclasses #368

Open
bilelomrani1 opened this issue Sep 2, 2023 · 3 comments
Open

Better help message with optional dataclasses #368

bilelomrani1 opened this issue Sep 2, 2023 · 3 comments
Labels
enhancement New feature or request

Comments

@bilelomrani1
Copy link

bilelomrani1 commented Sep 2, 2023

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!

@mauvilsa
Copy link
Member

mauvilsa commented Sep 4, 2023

@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.

@bilelomrani1
Copy link
Author

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

@mauvilsa mauvilsa added the enhancement New feature or request label Sep 6, 2023
@jerrymatjila
Copy link

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants