Commands¶
A command can be as simple as a dataclass-like object, with no additional annotations. Supported object-types include:
dataclasses
from cappa import parse
from dataclasses import dataclass
@dataclass
class Dataclass:
name: str
value = parse(Dataclass)
assert isinstance(value, Dataclass)
Pydantic models
from cappa import parse
from pydantic import BaseModel
class PydanticModel(BaseModel):
name: str
value = parse(PydanticModel)
assert isinstance(value, PydanticModel)
Pydantic dataclasses
from cappa import parse
from pydantic.dataclasses import dataclass as pydantic_dataclass
@pydantic_dataclass
class PydanticDataclass:
name: str
value = parse(PydanticDataclass)
assert isinstance(value, PydanticDataclass)
Attrs classes
from cappa import parse
from attr import define
@define
class AttrsClass:
name: str
value = parse(AttrsClass)
assert isinstance(value, AttrsClass)
cattrs classes
from cappa import parse
from attr import define
@define
class CAttrsClass:
name: str
value = parse(CAttrsClass)
assert isinstance(value, CAttrsClass)
An undecorated dataclass-class will receive all the default cappa.command
behavior. In order to customize or change the default behavior, you would
begin by wrapping the class in the @cappa.command decorator like so:
@cappa.command()
@dataclass
class Dataclass:
name: str
Note
The wrapped class is directly returned from the decorator. So unlike click,
the resultant object can be directly used in the same way that you’d have been
able to do sans decorator.
Note
All arguments to cappa.command directly translate to cappa.Command
attributes. When annotating an object with @command(), you are essentially pre-configuring
the generated cappa.Command for that particular command.
Subcommands¶
See Subcommands for details.
In short, any supported dataclass-like class that can be a top-level command is also compatible with being a subcommand. The only difference is that subcommands are attached to parent commands in a tree by way of having the parent define which subcommands are available options.
from cappa import Subcommands
@dataclass
class Command:
subcommand: Subcommands[SubcmdOne | SubcmdTwo]
@command(name=...) / Command.name¶
By default, the name of the command is inferred from the name of the containing
class, and converted to dash-case. For example Example would become example,
and SomeLongName would become some-long-name.
The name field can be used to override this behavior.
@command(help=...) / Command.help¶
See Help Text Inference for details.
Essentially this replaces any inferred (from docstring) short help text for the command.
@command(description=...) / Command.description¶
See Help Text Inference for details.
Essentially this replaces any inferred (from docstring) extended help text for the command.
@command(invoke=...) / Command.invoke¶
See Invoke documentation for more details.
Essentially this invokes a function upon a command/subcommand being selected during parsing,
corresponds to use of the cappa.invoke API rather than cappa.parse.
This API is roughly comparable to how click maps subcommands to functions.
@command(default_short=...) / Command.default_short¶
By default unannotated arguments are considered to be ordered positional aruguments.
This option controls whether un-annotated arguments default to implying Arg(short=True).
For example:
@command(default_short=True)
@dataclass
class Foo:
bar: int
# which is then called like:
# `foo -b 4`
@command(default_long=...) / Command.default_long¶
By default unannotated arguments are considered to be ordered positional aruguments.
This option controls whether un-annotated arguments default to implying Arg(long=True).
For example:
@command(default_long=True)
@dataclass
class Foo:
bar: int
# which is then called like:
# `foo --bar 4`
@command(deprecated=...) / Command.deprecated¶
This generates a warning if the command in question is used at runtime.
If True is supplied, a default deprecation message is generated. Alternatively
it accepts the string message that should be emitted.