-
|
How would you go about populating a command's attributes from a config object 🤔? Here's what I'm playing with currently: # --------------------------------------------
# Declare the config stuff
# --------------------------------------------
class Unset:
"""A sentinel value for unset configuration options."""
def __repr__(self) -> str:
return "<unset>"
@dataclass(kw_only=True)
class Config:
"""Configuration for the insiders project."""
unset: ClassVar[Unset] = Unset()
sponsors_minimum_amount: int | Unset = unset
# ...more config fields
@cappa.command(name="insiders")
@dataclass(kw_only=True)
class CommandMain:
"""Command to manage your Insiders projects."""
subcommand: An[
CommandBacklog,
cappa.Subcommand(group=_GROUP_SUBCOMMANDS),
Doc("The selected subcommand."),
]
# --------------------------------------------
# Main command propagates a config arg
# --------------------------------------------
config: An[
Config | None,
cappa.Arg(
short="-c",
long=True,
parse=Config.from_file,
default=Config.from_default_location(),
group=_GROUP_GLOBAL,
propagate=True,
),
Doc("Path to the configuration file."),
] = None
@cappa.command(name="backlog")
@dataclass(kw_only=True)
class CommandBacklog:
"""Command to list the backlog of issues."""
github_namespaces: An[
list[str],
cappa.Arg(num_args=-1),
Doc("Namespaces to fetch issues from."),
]
github_org_users: An[
dict[str, list[str]],
cappa.Arg(short=False, long=True),
Doc("""A mapping of users belonging to sponsoring organizations."""),
]
github_token: An[
str,
cappa.Arg(short=False, long=True, default=cappa.Env("GITHUB_TOKEN")),
Doc("""A GitHub token. Recommended scopes: `repo`."""),
]
polar_token: An[
str,
cappa.Arg(short=False, long=True, default=cappa.Env("POLAR_TOKEN")),
Doc("""A Polar token. Recommended scopes: `read:backlog`."""),
]
# ------------------------------------------------------------
# Subcommands depend on main to fetch config values
# ------------------------------------------------------------
def __call__(self, main: CommandMain) -> int:
if main.config:
if not self.github_namespaces and main.config.backlog_namespaces is not Config.unset:
self.github_namespaces = main.config.backlog_namespaces
if not self.github_org_users and main.config.github_organization_members is not Config.unset:
self.github_org_users = main.config.github_organization_members
if not self.sort and main.config.backlog_sort is not Config.unset:
self.sort = main.config.backlog_sort
if not self.github_token and main.config.github_token_command is not Config.unset:
self.github_token = main.config.github_token_command
if not self.polar_token and main.config.polar_token_command is not Config.unset:
self.polar_token = main.config.polar_token_command
# ...actual codeI don't think this approach is the best, because required attributes like Is there a more Cappa-idiomatic way to declare such an interface? The command dataclasses should keep representing the final state of the data, while each attribute is annotated to tell how it is populated. I'm thinking about Pydantic settings, wondering if there's a way to integrate it with Cappa somehow? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 24 replies
-
|
I'm imagining something like Here we pass a tuple to github_token: An[
str,
cappa.Arg(
short=False,
long=True,
default=[
cappa.Env("GITHUB_TOKEN"),
cappa.From(Command, "config.github_token"),
],
),
Doc("A GitHub token. Recommended scopes: `repo`."),
]Here we pass it a callable directly, which expects a from functools import partial
unset = ... # sentinel
def from_config(main: Command, attribute_name: str):
if main.config and (attr := getattr(main.config, attribute_name, unset)) is not unset:
return attr
raise ValueError("whatever, just to instruct Cappa that there was no value?")
# ...in our dataclass:
github_token: An[
str,
cappa.Arg(
short=False,
long=True,
default=[
cappa.Env("GITHUB_TOKEN"),
cappa.From(partial(from_config, attribute_name="github_token")),
],
),
Doc("A GitHub token. Recommended scopes: `repo`."),
]🤔 🤔 🤔 |
Beta Was this translation helpful? Give feedback.
#180