brentyi / tyro

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

Common shared CLI flags for different scripts? #143

Closed mainrs closed 3 months ago

mainrs commented 3 months ago

Basically I have a dataclass that contains arguments that all my script files should support. Is it somehow possible to tell tyro that I want to include all the fields of a dataclass as if I defined them inside the current dataclass? Basically, flattening.

@dataclass
class CommonConfig:
    seed: int = 0,

@dataclass
class CustomConfig1:
     common: CommonConfig
    flag1: int = 1

@dataclass
class CustomConfig2:
     common: CommonConfig2
    flag2: int = 2

def cli1(cfg: CustomConfig1):
    print(cfg.common.seed)
    print(cfg.flag1)

def cli2(cfg: CustomConfig2):
    print(cfg.common.seed)
    print(cfg.flag2)

Now, calling python script1.py --seed 1 that holds cli1 should work as well as python script2.py --seed 2. The first prints one as the seed, the second 2.

brentyi commented 3 months ago

Hi @mainrs!

Here are some runnable options for getting --seed INT and --flag1 INT. Do any of them help?

(1) Standard dataclass inheritance might be the easiest:

from dataclasses import dataclass
import tyro

@dataclass
class CommonConfig:
    seed: int = 0

@dataclass
class CustomConfig(CommonConfig):
    flag1: int = 1

tyro.cli(CustomConfig)

(2) tyro.conf.OmitArgPrefixes will flatten all of the arguments:

from dataclasses import dataclass
import tyro

@dataclass
class CommonConfig:
    seed: int = 0

@dataclass
class CustomConfig:
    common: CommonConfig
    flag1: int = 1

tyro.cli(tyro.conf.OmitArgPrefixes[CustomConfig])

(3) You can "erase" the name of the common field, which will remove the common. prefix. This is the most cryptic option (and frankly not well-documented), but it's in the tyro tests:

from dataclasses import dataclass
import tyro
from typing import Annotated

@dataclass
class CommonConfig:
    seed: int = 0

@dataclass
class CustomConfig:
    common: Annotated[CommonConfig, tyro.conf.arg(name="")]
    flag1: int = 1

tyro.cli(CustomConfig)
mainrs commented 3 months ago

I didn't think about inheritance, sorry! Thanks for helping me out!