From 216e4972822b3e228fbe15b2e2fdf8c88ff76449 Mon Sep 17 00:00:00 2001 From: Kristian Hartikainen Date: Thu, 1 Oct 2026 20:05:12 -0400 Subject: [PATCH] Preserve Ellipsis in postponed variadic tuple annotations Optional variadic tuples with postponed annotations fail during union conversion because Ellipsis is not recognized. Preserve the sentinel and cover omitted, single-value, and multiple-value arguments. --- .../annotation_utils/get_field_annotations.py | 3 +++ .../test_postponed_annotations.py | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/simple_parsing/annotation_utils/get_field_annotations.py b/simple_parsing/annotation_utils/get_field_annotations.py index 81935730..cb3529c5 100644 --- a/simple_parsing/annotation_utils/get_field_annotations.py +++ b/simple_parsing/annotation_utils/get_field_annotations.py @@ -74,6 +74,9 @@ def _replace_UnionType_with_typing_Union(annotation): # Therefore just return the annotation as-is. return annotation + if annotation is Ellipsis: + return annotation + if isinstance(annotation, types.UnionType): # type: ignore union_args = typing.get_args(annotation) new_union_args = tuple(_replace_UnionType_with_typing_Union(arg) for arg in union_args) diff --git a/test/postponed_annotations/test_postponed_annotations.py b/test/postponed_annotations/test_postponed_annotations.py index 7d0a9053..9d207040 100644 --- a/test/postponed_annotations/test_postponed_annotations.py +++ b/test/postponed_annotations/test_postponed_annotations.py @@ -1,11 +1,12 @@ from __future__ import annotations +import sys from dataclasses import dataclass from pathlib import Path import pytest -from simple_parsing import Serializable +from simple_parsing import ArgumentParser, Serializable from ..test_utils import TestSetup from .b import B @@ -81,3 +82,25 @@ def test_overwrite_field(): assert instance == overwrite_attribute.Subclass( attribute=overwrite_attribute.ParamClsSubclass(True) ), "parsed attribute value is correct" + + +@pytest.mark.skipif(sys.version_info < (3, 10), reason="Union syntax requires Python 3.10.") +@pytest.mark.parametrize( + "argv, objects", + [ + ([], None), + (["--objects", "cube"], ("cube",)), + (["--objects", "cube", "cylinder"], ("cube", "cylinder")), + ], +) +def test_postponed_annotations_with_optional_variadic_tuple( + argv: list[str], objects: tuple[str, ...] | None +): + @dataclass + class Arguments: + objects: tuple[str, ...] | None = None + + parser = ArgumentParser() + parser.add_arguments(Arguments, dest="args") + + assert parser.parse_args(argv).args == Arguments(objects=objects)