Skip to content

Commit

Permalink
Merge pull request #293 from BrianPugh/bugfix-converter-validator-wro…
Browse files Browse the repository at this point in the history
…ng-nested-type

Fix  converters/validators getting the wrong type for nested Annotated[Parameter(...)]
  • Loading branch information
BrianPugh authored Jan 10, 2025
2 parents 139d12d + 709d7b4 commit 6284a12
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 17 deletions.
7 changes: 6 additions & 1 deletion cyclopts/_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ def _convert(
convert_tuple = partial(_convert_tuple, converter=converter, name_transform=name_transform)

origin_type = get_origin(type_)
inner_types = [resolve(x) for x in get_args(type_)]
# Inner types **may** be ``Annotated``
inner_types = get_args(type_)

if type_ is dict:
out = convert(dict[str, str], token)
Expand Down Expand Up @@ -285,6 +286,10 @@ def _convert(
out = type_(*pos_values)

if cparam:
# An inner type may have an independent Parameter annotation;
# e.g.:
# Uint8 = Annotated[int, ...]
# rgb: tuple[Uint8, Uint8, Uint8]
try:
for validator in cparam.validator: # pyright: ignore
validator(type_, out)
Expand Down
16 changes: 0 additions & 16 deletions cyclopts/argument.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import cyclopts.utils
from cyclopts._convert import (
ITERABLE_TYPES,
convert,
token_count,
)
Expand Down Expand Up @@ -220,21 +219,6 @@ def _from_type(
hint, hint_parameters = _get_parameters(hint)
cyclopts_parameters_no_group.extend(hint_parameters)

# Handle annotations where ``Annotated`` is not at the root level; e.g. ``list[Annotated[...]]``.
# Multiple inner Parameter Annotations only make sense if providing specific converter/validators.
origin = get_origin(hint)
if origin is tuple:
# handled in _convert.py
pass
elif origin in ITERABLE_TYPES:
inner_hints = get_args(hint)
if len(inner_hints) > 1:
raise NotImplementedError(f"Did not expect multiple inner type arguments: {inner_hints}.")
elif len(inner_hints) == 1:
inner_hint = inner_hints[0]
_, hint_parameters = _get_parameters(inner_hint)
cyclopts_parameters_no_group.extend(hint_parameters)

if not keys: # root hint annotation
if field_info.kind is field_info.VAR_KEYWORD:
hint = dict[str, hint]
Expand Down
10 changes: 10 additions & 0 deletions tests/types/test_types_path.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from pathlib import Path
from typing import Tuple

import pytest
Expand Down Expand Up @@ -93,6 +94,15 @@ def test_types_resolved_existing_path(convert, tmp_path, action):
assert src.resolve() == convert(ct.ResolvedExistingPath, src)


def test_types_resolved_existing_path_list(app, assert_parse_args):
@app.default
def main(f: list[ct.ResolvedFile]):
pass

expected = Path("foo.bin").resolve()
assert_parse_args(main, "foo.bin", [expected])


def test_types_resolved_existing_path_validation_error(convert, tmp_path):
with pytest.raises(ValidationError):
convert(ct.ResolvedExistingPath, tmp_path / "foo")
Expand Down

0 comments on commit 6284a12

Please sign in to comment.