Better help message with optional dataclasses
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!
@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.
Thank you @mauvilsa, great idea, adding an argument seems very reasonable to me indeed.
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)