diff --git a/packages/typemap/src/typemap/type_eval/_eval_operators.py b/packages/typemap/src/typemap/type_eval/_eval_operators.py index 137e645..26e2591 100644 --- a/packages/typemap/src/typemap/type_eval/_eval_operators.py +++ b/packages/typemap/src/typemap/type_eval/_eval_operators.py @@ -1089,6 +1089,11 @@ def _eval_GetArgs(tp, base, *, ctx) -> typing.Any: return tuple[*args] # type: ignore[valid-type] +# NOTE: GenericCallable does NOT have an evaluator. +# It is handled via GetArg/GetArgs which extract the typevars and callable. +# This is by design per PEP 827 which restricts GenericCallable to Member type arguments. + + @type_eval.register_evaluator(GetSpecialAttr) @_lift_over_unions def _eval_GetSpecialAttr(tp, attr, *, ctx) -> typing.Any: diff --git a/packages/typemap/tests/test_type_eval.py b/packages/typemap/tests/test_type_eval.py index 171df9c..0203f16 100644 --- a/packages/typemap/tests/test_type_eval.py +++ b/packages/typemap/tests/test_type_eval.py @@ -2785,6 +2785,69 @@ def test_template_empty_parameterization(): assert result is not None +############### +# GenericCallable tests + + +def test_generic_callable_basic(): + """Test GenericCallable with a single TypeVar.""" + + T = TypeVar("T") + + gc = GenericCallable[tuple[T], lambda T: Callable[[T], T]] + result = eval_typing(gc) + # GenericCallable returns as-is when evaluated (no transformation) + assert result is not typing.Never + assert "GenericCallable" in repr(result) + + +def test_generic_callable_in_member(): + """Test GenericCallable used within a Member type.""" + + T = TypeVar("T") + + # Create a Member with GenericCallable as the type + member = Member[ + Literal["process"], + GenericCallable[tuple[T], lambda T: Callable[[T], T]], + ] + result = eval_typing(member) + assert result is not typing.Never + + +def test_generic_callable_getarg_typevars(): + """Test GetArg on GenericCallable returns typevars tuple.""" + + T = TypeVar("T") + + gc = GenericCallable[tuple[T], lambda T: Callable[[T], T]] + typevars = eval_typing(GetArg[gc, GenericCallable, Literal[0]]) + # Should return the typevars tuple + assert typevars is not typing.Never + + +def test_generic_callable_getarg_callable(): + """Test GetArg on GenericCallable returns Never for callable (as per existing behavior).""" + + T = TypeVar("T") + + gc = GenericCallable[tuple[T], lambda T: Callable[[T], T]] + callable_part = eval_typing(GetArg[gc, GenericCallable, Literal[1]]) + # This returns Never per existing implementation + assert callable_part is typing.Never + + +def test_generic_callable_getargs(): + """Test GetArgs on GenericCallable returns typevars tuple.""" + + T = TypeVar("T") + + gc = GenericCallable[tuple[T], lambda T: Callable[[T], T]] + args = eval_typing(GetArgs[gc, GenericCallable]) + # Should return tuple containing the typevars + assert args is not typing.Never + + ############## # DeepPartial tests