[Feature Request] Dataclasses as commands
dominikandreas opened this issue ยท 3 comments
Given some existing config dataclass, I would like to parse arguments to create the config.
Example:
import sys
from cyclopts import App
@dataclass
class MyConfig:
a: int = 1
b: int = 2
config = object.__new__(MyConfig)
app = App()
app.default(config.__init__)
sys.argv = [__file__, "--a", "3", "--b", "4"]
app()
print(config)
MyConfig(a=3, b=4)
This already works as is, but I was wondering if a prettier solution already exists, either currently working or planned for version 3?
Generally, I would prefer defining a CLI around dataclasses rather than function implementations (one reason being that it's easier to extend something based on classes using inheritance).
I assume someone else has already thought about this, so before I start reinventing the wheel, I thought I should ask here.
Thanks for the great work, really like it so far ๐
This will kind of work in v3; not exactly as you describe, but the main big feature of v3 is that dataclasses/pydantic/attrs/typeddict will all be allowed as type-hints.
In v3 your example will look like:
from dataclasses import dataclass
from typing import Annotated
from cyclopts import App, Parameter
app = App(name="issue-228")
@dataclass
class Config:
a: int = 1
"""Docstring for a."""
b: Annotated[int, Parameter(name="bar")] = 2
"""This is the docstring for python parameter "b"."""
@app.default
def my_default_command(config: Annotated[Config, Parameter(name="*")]):
# The name "*" is special and means "squash this name"
# Without this, items would have to be identified as "--config.a" instead of "--a"
print(f"{config=}")
if __name__ == "__main__":
app()
And then invoking the program from the CLI:
$ python issue-228.py --help
Usage: issue-228 COMMAND [ARGS] [OPTIONS]
โญโ Commands โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ --help,-h Display this message and exit. โ
โ --version Display application version. โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
โญโ Parameters โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ A,--a Docstring for a. โ
โ BAR,--bar This is the docstring for python parameter "b". โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
$ python issue-228.py --a=100 --bar=200
config=Config(a=100, b=200)
You can play around with v3 in the dev-3.0.0 branch. Everything is mostly working, and the primary work that remains is:
- polishing everything up
- finishing up a few edge-case-TODOs
- reconsider what elements/attributes/classes should be public
- update documentation.
For this specific example, it actually demonstrates that as of right now, positional arguments are not correctly being passed into Config
, so I'll have to fix that! If you end up giving it a try, just know that things may change. If you have feedback, I would also be very open to it!
Thanks for the great work, really like it so far ๐
Thank you!
ok, the positional arguments should now work on dev-3.0.0
. The example provided above now fully works as expected.
v3.0.0 has been released! Please let me know if you run into any issues, thanks!