Skip to content

Commit

Permalink
Merge pull request #175 from DanCardin/dc/non-variadic-tuple-fixes
Browse files Browse the repository at this point in the history
Dc/non variadic tuple fixes
  • Loading branch information
DanCardin authored Nov 12, 2024
2 parents fd2fb92 + 3fc5e39 commit 721687a
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 3 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## 0.24

### 0.24.2

- fix: Literal contained inside non-variadic tuple should not imply "choices".
- fix: Optional non-variadic tuple should be allowed (None shouldn't fail arity check).

### 0.24.1

- feat: Add Group.section to enable ordering of groups separately from the items within them.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "cappa"
version = "0.24.1"
version = "0.24.2"
description = "Declarative CLI argument parser."

urls = {repository = "https://github.com/dancardin/cappa"}
Expand Down
3 changes: 3 additions & 0 deletions src/cappa/arg.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,9 @@ def infer_num_args(
distinct_num_args = set()
num_args_variants = []
for type_arg in type_view.inner_types:
if type_arg.is_none_type:
continue

num_args = infer_num_args(
arg,
type_arg,
Expand Down
2 changes: 1 addition & 1 deletion src/cappa/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def detect_choices(type_view: TypeView) -> list[str] | None:
if type_view.is_subclass_of(enum.Enum):
return [v.value for v in type_view.annotation]

if type_view.is_subclass_of((tuple, list, set)):
if type_view.is_subclass_of((list, set)) or type_view.is_variadic_tuple:
type_view = type_view.inner_types[0]

if type_view.is_union:
Expand Down
30 changes: 30 additions & 0 deletions tests/arg/test_choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,33 @@ class ArgTest:

result = capsys.readouterr().out
assert "Valid options: one, two." in result


@backends
def test_variadic_tuple_choices(backend, capsys):
@dataclass
class ArgTest:
choice: Annotated[
tuple[Literal["one", "two"], ...] | None, cappa.Arg(short=True)
] = None

with pytest.raises(cappa.HelpExit):
parse(ArgTest, "--help", backend=backend)

result = capsys.readouterr().out
assert "Valid options: one, two." in result


@backends
def test_tuple_choices(backend, capsys):
@dataclass
class ArgTest:
choice: Annotated[
tuple[Literal["one", "two"], int] | None, cappa.Arg(short=True)
] = None

with pytest.raises(cappa.HelpExit):
parse(ArgTest, "--help", backend=backend)

result = capsys.readouterr().out
assert "Valid options: one, two." not in result
35 changes: 35 additions & 0 deletions tests/arg/test_tuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,38 @@ class Example:
parse(Example, "-s", "1", "2", "3", backend=backend)
assert e.value.code == 2
assert str(e.value.message).lower() == "unrecognized arguments: 3"


@backends
def test_optional_tuple_option(backend):
@dataclass
class Example:
start_project: Annotated[
tuple[int, float] | None,
cappa.Arg(short=True, required=False),
] = None

test = parse(Example, backend=backend)
assert test == Example(start_project=None)

test = parse(Example, "-s", "2", "2.4", backend=backend)
assert test == Example(start_project=(2, 2.4))

# Missing values
with pytest.raises(cappa.Exit) as e:
parse(Example, "-s", "1", backend=backend)

assert e.value.code == 2

if backend:
assert str(e.value.message).lower() == "argument -s: expected 2 arguments"
else:
assert (
e.value.message == "Argument '-s' requires 2 values, found 1 ('1' so far)"
)

# Extra values
with pytest.raises(cappa.Exit) as e:
parse(Example, "-s", "1", "2", "3", backend=backend)
assert e.value.code == 2
assert str(e.value.message).lower() == "unrecognized arguments: 3"
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 721687a

Please sign in to comment.