Skip to content

Commit 9f8ff8d

Browse files
authored
Merge pull request #224 from DanCardin/dc/docs
fix: Improve docs.
2 parents c362820 + da92fb8 commit 9f8ff8d

13 files changed

Lines changed: 2576 additions & 86 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# Changelog
22

3-
### 0.29.0
3+
## 0.29.0
44

55
## Unreleased: 0.29.0
66

7+
- docs: Add argument validation documentation.
78
- feat: Test against python 3.14.
89
- fix: Apply pyright strict typing.
910
- fix: Function callables ability to depend on implicit Deps.
1011
- docs: Improve docs relating to `Output`.
12+
1113
## 0.28
1214

1315
### 0.28.1

docs/poetry.lock

Lines changed: 1799 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dependencies = [
1818
"sphinx-copybutton",
1919
"sphinx-pyproject >= 0.3.0",
2020
"sphinx-togglebutton >= 0.3.2",
21+
"sphinx-toolbox (>=3.9.0,<4.0.0)",
2122
]
2223

2324
[tool.poetry.dev-dependencies]

docs/source/arg.md

Lines changed: 137 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,98 @@ By default:
2323

2424
However, by using `Arg`, with syntax like
2525
`name: Annotated[str, cappa.Arg(...)]`, you can customize the behavior of the
26-
field.
27-
28-
- `short=True` (equivalent to `short='-n'` for this example) turns the option
29-
from a positional argument into a flag.
30-
- `long` works the same way as short (and can be used together), but for `--`
31-
flags, like `--name`.
32-
- `count=True` counts the number of flag instance. Frequently used for `-v`,
33-
`-vv`, `-vvv` verbosity handling.
34-
- `help='...'` allows customizing the help text outside the docstring.
35-
- `parse=<callable>` allows parsing of more complex input values the cannot be
36-
handled through the type annotation system directly.
26+
field. For each field of customization, there is a default inferred value, based
27+
on the particulars of the dataclass and/or other configured fields.
28+
29+
Below we document when configuring a given field might **imply** some other field by default
30+
(e.g. `count=True` **implies** `num_args=0`), however in all cases, an explicitly
31+
provided value will take precedence over the default inference.
3732

3833
```{note}
3934
See the [annotation docs](./annotation.md) for more details on how annotations
4035
can be used and are interpreted to handle different kinds of CLI input.
4136
```
4237

43-
```{eval-rst}
44-
.. autoapiclass:: cappa.Arg
45-
:noindex:
38+
(arg-value-name)=
39+
## `Arg.value_name`
40+
41+
This field controls the name of the field in helptext/errors. By default it matches
42+
the dataclass' field name.
43+
44+
```python
45+
@dataclass
46+
class Command:
47+
foo: Annotated[int, cappa.Arg(value_name="bar")]
48+
happy: Annotated[int, cappa.Arg(value_name="sad", long=True)] = 1
4649
```
4750

51+
Would yield help text like:
52+
53+
```
54+
Options
55+
[--happy SAD]
56+
57+
Arguments
58+
BAR
59+
```
60+
61+
(arg-short)=
62+
## `Arg.short`
63+
64+
By default, unannotated dataclass fields are assumed to be positional arguments.
65+
66+
An `Arg.short` argument is a non-positional argument which can be selected by a
67+
single `-` followed by the short name.
68+
69+
The value can be supplied in a few different ways:
70+
71+
* `foo: Annotated[int, Arg(short=True)]`: Rendered as `-f`. If there are more than one
72+
field starting with "f" with `short=True`, at least one will need to be disambiguated.
73+
* `foo: Annotated[int, Arg(short='-b')]`: Rendered as-is
74+
* `foo: Annotated[int, Arg(short='b')]`: Rendered as `-b`.
75+
* `foo: Annotated[int, Arg(short=['-b', '-f'])]`: Rendered as **both/either** `-b` and `-f`.
76+
* `foo: Annotated[int, Arg(short='-b/-f')]`: Rendered as **both/either** `-b` and `-f`.
77+
78+
(arg-long)=
79+
## `Arg.long`
80+
81+
By default, unannotated dataclass fields are assumed to be positional arguments.
82+
83+
An `Arg.long` argument is a non-positional argument which can be selected by a
84+
single `--` followed by the long name.
85+
86+
```{note}
87+
`snake_case` field names will be converted to `dash-case` by default.
88+
```
89+
90+
The value can be supplied in a few different ways:
91+
92+
* `foo: Annotated[int, Arg(long=True)]`: Rendered as `--foo`.
93+
field starting with "f" with `long=True`, at least one will need to be disambiguated.
94+
* `foo: Annotated[int, Arg(long='--bar')]`: Rendered as-is
95+
* `foo: Annotated[int, Arg(long='bar')]`: Rendered as `--bar`.
96+
* `foo: Annotated[int, Arg(long=['--bar', '-foo'])]`: Rendered as **both/either** `--bar` and `--foo`.
97+
* `foo: Annotated[int, Arg(long='--bar/--foo')]`: Rendered as **both/either** `--bar` and `--foo`.
98+
99+
(arg-count)=
100+
## `Arg.count`
101+
102+
Counts instances of the argument in question. This implies `num_args=0` and `action=ArgAction.count` by default.
103+
104+
The canonical example of this is counting verbosity flags.
105+
```python
106+
@dataclass
107+
class Example:
108+
verbose: Annotated[int, cappa.Arg(short="-v", count=True),
109+
```
110+
111+
(arg-help)=
112+
## `Arg.help`
113+
Controls the per-argument help text.
114+
115+
See [Help](./help.md) for more details, but in short help text is inferred by
116+
default from a few different sources, including docstrings and "attribute docstrings".
117+
48118
(arg-action)=
49119
## `Arg.action`
50120

@@ -299,7 +369,7 @@ class Example:
299369
value: Annotated[int, cappa.Arg(default=cappa.ValueFrom(load_default, key='value'))]
300370
```
301371
302-
This construct is able to be automatically supplied with [cappa.State](State), in the even shared
372+
This construct is able to be automatically supplied with [cappa.State](State), in the event shared
303373
parse state is required to evaluate a field's default.
304374
305375
As noted above, a value produced by `ValueFrom` **does not** invoke the `Arg.parse` parser. This is
@@ -635,6 +705,37 @@ More injectable dependencies **could** be supported. In particular the `Arg` ins
635705
it's just not immediately obvious what that would be. File an issue if you have a usecase!
636706
```
637707
708+
## `Arg.choices`
709+
710+
This can be used to limit the set of valid inputs to one of a few literal values,
711+
for example, `Arg(choices=['a', 'b', 'c']`.
712+
713+
Both `Literal`s (and literal unions) and `Enum`s automatically infer `choices`.
714+
715+
## `Arg.completion`
716+
717+
This is an optional function which, if provided will be called during CLI (typically TAB)
718+
completion events in the shell. You can supply a function which accepts the partial
719+
input and returns an optional list of completions for that input.
720+
721+
```{note}
722+
`Arg.choices` has a default completion implementation.
723+
```
724+
725+
```python
726+
def complete_file(raw: str) -> list[cappa.Completion]:
727+
return [filename for filename in os.listdir() if filename.startswith(raw)]
728+
729+
@dataclass
730+
class Foo:
731+
file: Annotated[str, cappa.Arg(completion=complete_file)
732+
```
733+
734+
```{note}
735+
Filename completion is actually natively supported by the shells, so this example is
736+
somewhat unnecessary to **actually** implement yourself.
737+
```
738+
638739
## `Arg.has_value`
639740
640741
`Arg(has_value=True/False)` can be used to explicitly control whether the argument in question
@@ -798,3 +899,24 @@ Would yield:
798899
Note, this is no different from use of `Arg.group` in any other context, except in that
799900
the argument only exists at the declaration point, so any grouping configuration will
800901
also propagate down into the way child commands render those arguments as well.
902+
903+
## `Arg.hidden`
904+
905+
Controls whether an argument is displayed in help text.
906+
907+
## `Arg.required`
908+
909+
Controls whether an argument is required.
910+
911+
## `Arg.deprecated`
912+
913+
When truthy, will emit a deprecation message upon use of an argument. There is
914+
a default message generated, but supplying a string will yield **that** as the
915+
deprecation message.
916+
917+
## API
918+
919+
```{eval-rst}
920+
.. autoapiclass:: cappa.Arg
921+
:noindex:
922+
```

0 commit comments

Comments
 (0)