Skip to content

[Feature] Detect if an argument has been parsed from the command line or if it is a default. #254

@emcd

Description

@emcd

The motivating use case is to determine whether to override a corresponding piece of configuration or not. Judging from Stack Overflow, it is clear that this has been a thorn in the side of argparse users for years. The most robust solution that I see is to parse twice, once with the "normal" defaults and one with default = argparse.SUPPRESS, and then look at the diff in the arguments namespaces. I don't know how much work this would be to implement in Tyro, but it would allow for simpler CLIs generated by it. Take, for example, a situation that I currently face:

    clip: Annotated[
        Optional[ bool ],
        tyro.conf.arg( # pyright: ignore
            aliases = ( '--clipboard', '--to-clipboard' ),
            help = "Copy to clipboard." ),
    ] = None
    edit: Annotated[
        bool,
        tyro.conf.arg( # pyright: ignore
            aliases = ( '-e', '--edit-message' ),
            help = "Spawn editor to capture an introductory message." ),
    ] = False

The resulting CLI is awkward in the sense that a user can choose --edit/--no-edit, but if they want to override the configuration for clip, then they must use --clip True or --clip False. (The default clip = None means to defer to configuration.)

What I would like to do is:

    clip: Annotated[
        Optional[ bool ],
        tyro.conf.arg( # pyright: ignore
            aliases = ( '--clipboard', '--to-clipboard' ),
            help = "Copy to clipboard." ),
        tyro.conf.SuppressDefault,
    ] = None
    edit: Annotated[
        bool,
        tyro.conf.arg( # pyright: ignore
            aliases = ( '-e', '--edit-message' ),
            help = "Spawn editor to capture an introductory message." ),
    ] = False

where the behavior from tyro.conf.SuppressDefault would be to allow --clip/--no-clip without explicitly specifying the boolean value. If neither --clip nor --no-clip is given by the user, then the default (None) would be the value of the argument. The default would not be displayed as a possible value to the user. This behavior also potentially paves a way to mitigate the enable/disable/retain tristate enum hack that I mentioned in #171.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions