brentyi / tyro

CLI interfaces & config objects, from types
https://brentyi.github.io/tyro
MIT License
467 stars 23 forks source link

Optional Literal argument with None default does not generate tab completion #158

Closed KolinGuo closed 2 weeks ago

KolinGuo commented 2 weeks ago

It seemed like Optional[Literal] argument with None as its default value does not generate tab completion correctly.

This might be related to #156

See the minimal example below where the preset argument fails to generate choices for tab completion while the frame argument works.

#!/usr/bin/env python3
from typing import Annotated, Literal, Optional

import tyro

def start_device(
    preset: Annotated[
        Optional[Literal["rgb", "depth", "ir"]], tyro.conf.arg(aliases=["-p"])
    ] = None,
    frame: Annotated[Literal["world", "base"], tyro.conf.arg(aliases=["-f"])] = "world",
) -> None:
    """
    Start device with the given preset.

    :param preset: device preset to use.
    :param frame: coordinate frame to use.
    """
    print(f"{preset=} {frame=}")

if __name__ == "__main__":
    tyro.cli(start_device)

Below is the first few lines of the generated completion file:

# AUTOMATICALLY GENERATED by `shtab`

_shtab_tyro_test_py_option_strings=('-h' '--help' '--preset' '-p' '--frame' '-f')

_shtab_tyro_test_py___frame_choices=('world' 'base')
_shtab_tyro_test_py__f_choices=('world' 'base')

_shtab_tyro_test_py__h_nargs=0
_shtab_tyro_test_py___help_nargs=0

# $1=COMP_WORDS[1]
_shtab_compgen_files() {
  compgen -f -- $1  # files
}

# $1=COMP_WORDS[1]
_shtab_compgen_dirs() {
  compgen -d -- $1  # recurse into subdirs
}

# $1=COMP_WORDS[1]
_shtab_replace_nonword() {
  echo "${1//[^[:word:]]/_}"
}
brentyi commented 2 weeks ago

Thanks @KolinGuo! I just pushed a change to main that should fix this. If you have a chance could you double-check?

KolinGuo commented 2 weeks ago

Hi @brentyi, thanks for your update! However, it seems to generate the same completion script when I run python3 test.py --tyro-write-completion bash /etc/bash_completion.d/test Below is the first few lines of the generated completion script

# AUTOMATICALLY GENERATED by `shtab`
_shtab_tyro_test_py_option_strings=('-h' '--help' '--preset' '-p' '--frame' '-f')

_shtab_tyro_test_py___frame_choices=('world' 'base')
_shtab_tyro_test_py__f_choices=('world' 'base')

_shtab_tyro_test_py__h_nargs=0
_shtab_tyro_test_py___help_nargs=0

# $1=COMP_WORDS[1]
_shtab_compgen_files() {
  compgen -f -- $1  # files
}

# $1=COMP_WORDS[1]
_shtab_compgen_dirs() {
  compgen -d -- $1  # recurse into subdirs
}

# $1=COMP_WORDS[1]
_shtab_replace_nonword() {
  echo "${1//[^[:word:]]/_}"
}

Does it work on your end?

brentyi commented 2 weeks ago

Are you installing from source? I didn't do a release, sorry for not clarifying.

Here's a pip command:

pip install git+https://github.com/brentyi/tyro.git

The output I get from your command:

# AUTOMATICALLY GENERATED by `shtab`
_shtab_tyro_test_py_option_strings=('-h' '--help' '--preset' '-p' '--frame' '-f')

_shtab_tyro_test_py___preset_choices=('ir' 'rgb' 'None' 'depth')
_shtab_tyro_test_py__p_choices=('ir' 'rgb' 'None' 'depth')
_shtab_tyro_test_py___frame_choices=('world' 'base')
_shtab_tyro_test_py__f_choices=('world' 'base')

_shtab_tyro_test_py__h_nargs=0
_shtab_tyro_test_py___help_nargs=0

# $1=COMP_WORDS[1]
_shtab_compgen_files() {
  compgen -f -- $1  # files
}

# $1=COMP_WORDS[1]
_shtab_compgen_dirs() {
  compgen -d -- $1  # recurse into subdirs
}
KolinGuo commented 2 weeks ago

Sorry my bad, the main branch worked. I wasn't installing your main branch before

KolinGuo commented 2 weeks ago

Thank you very much! Do you plan to publish a quick release to PyPI?

brentyi commented 2 weeks ago

Done!