Skip to content

Commit 9ea292f

Browse files
docs(annotated): list frozenset in collection messages and changelog
Address review feedback on #1691: frozenset[T] was functionally supported but the error messages and docstrings enumerating the supported collection types still only mentioned list/set/tuple. Update those strings so exceptions and docs accurately list frozenset, and add a CHANGELOG entry for the new collection type.
1 parent cba60f5 commit 9ea292f

2 files changed

Lines changed: 10 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
- **complete_in_thread**: (boolean) if `True`, then completion will run in a separate
66
thread. If `False` then completion runs in the main thread and causes it to block if slow.
77
Defaults to `True`.
8+
- Experimental features
9+
- `@with_annotated` now supports `frozenset[T]` collection parameters, alongside the existing
10+
`list[T]`, `set[T]`, and `tuple[T, ...]` collection types.
811

912
## 4.0.0 (June 5, 2026)
1013

cmd2/annotated.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -588,11 +588,11 @@ def _resolve_element(tp: Any) -> _TypeResult:
588588

589589

590590
def _make_collection_resolver(collection_type: type) -> Callable[..., _TypeResult]:
591-
"""Create a resolver for single-arg collections (list[T], set[T])."""
591+
"""Create a resolver for single-arg collections (list[T], set[T], frozenset[T])."""
592592

593593
def _resolve(_tp: Any, args: tuple[Any, ...], **_ctx: Any) -> _TypeResult:
594594
if len(args) == 0:
595-
# Bare list/set without type args -- treat as list[str]/set[str].
595+
# Bare list/set/frozenset without type args -- treat as list[str]/set[str]/frozenset[str].
596596
return _TypeResult(is_collection=True, container_factory=collection_type)
597597
if len(args) != 1:
598598
raise TypeError(
@@ -722,7 +722,7 @@ def _resolve_base_type(tp: Any, *, is_positional: bool = False) -> _TypeResult:
722722
f"Unsupported parameter type {_type_name(tp)!r} for @with_annotated: there is no converter "
723723
f"for it, so command-line values would silently arrive as plain strings. Supported scalar types "
724724
f"are str, int, float, bool, decimal.Decimal, pathlib.Path, enum.Enum subclasses, and Literal[...]; "
725-
f"use one of these (optionally in list/set/tuple) or a subclass of one."
725+
f"use one of these (optionally in list/set/frozenset/tuple) or a subclass of one."
726726
)
727727

728728

@@ -912,7 +912,7 @@ def omittable(self) -> bool:
912912
def _is_list(self) -> bool:
913913
"""Whether the declared type is ``list``/``list[T]`` -- the shape the list actions need.
914914
915-
Distinct from :attr:`is_collection` (also true for ``set``/``tuple``): ``append``/``extend``/
915+
Distinct from :attr:`is_collection` (also true for ``set``/``frozenset``/``tuple``): ``append``/``extend``/
916916
``append_const`` accumulate specifically into a ``list``.
917917
"""
918918
return get_origin(self.inner_type) is list or self.inner_type is list
@@ -1288,7 +1288,7 @@ def add_to(self, target: _ArgumentTarget) -> None:
12881288
_NARGS_RULES: list[_Rule[_ArgparseArgument, _NargsValue | None]] = [
12891289
(lambda a: a._meta_nargs is not None, lambda a: a._meta_nargs), # an explicit Argument(nargs=) wins
12901290
(lambda a: a.fixed_arity is not None, lambda a: a.fixed_arity), # tuple[T, T] pins nargs to its arity
1291-
(lambda a: a.is_collection and a.omittable, _const("*")), # list/set/tuple[T, ...] that may be empty
1291+
(lambda a: a.is_collection and a.omittable, _const("*")), # list/set/frozenset/tuple[T, ...] that may be empty
12921292
(lambda a: a.is_collection, _const("+")), # collection requiring >= 1 value
12931293
(lambda a: a.is_positional and a.omittable, _const("?")), # an optional scalar positional
12941294
(_always, _const(None)), # required scalar / any option scalar
@@ -1572,12 +1572,12 @@ def _const_mismatches_type(a: _ArgparseArgument) -> bool:
15721572
lambda a: TypeError(
15731573
f"nargs={a._meta_nargs!r} produces a list of values, but the annotation "
15741574
f"'{_type_name(a.inner_type)}' is not a collection type. "
1575-
f"Use list[T], tuple[T, ...], or set[T] (optionally with | None) to match."
1575+
f"Use list[T], tuple[T, ...], set[T], or frozenset[T] (optionally with | None) to match."
15761576
),
15771577
),
15781578
(
15791579
# An explicit '?' / (0, 1) on a collection yields a single value (or None), which the
1580-
# collection-casting action cannot wrap into the declared list/set/tuple.
1580+
# collection-casting action cannot wrap into the declared list/set/frozenset/tuple.
15811581
lambda a: a.is_collection and a._meta_nargs_yields_optional_single,
15821582
lambda a: TypeError(
15831583
f"parameter '{a.name}' in {a.func_qualname} sets nargs={a._meta_nargs!r} on the collection "

0 commit comments

Comments
 (0)