diff --git a/tests/test_type_eval.py b/tests/test_type_eval.py index c7d52fd..136ba6b 100644 --- a/tests/test_type_eval.py +++ b/tests/test_type_eval.py @@ -24,6 +24,7 @@ import pytest from typemap.type_eval import _ensure_context, eval_typing +from typemap.type_eval._eval_operators import TypeMapError from typemap.typing import _BoolLiteral from typemap_extensions import ( @@ -414,8 +415,8 @@ def test_getmember_01(): Member[Literal["x"], int, Never, Never, TA] | Member[Literal["x"], str, Never, Never, TB] ) - d = eval_typing(GetMember[TA | TB, Literal[""]]) - assert d == Never + with pytest.raises(TypeMapError): + eval_typing(GetMember[TA | TB, Literal[""]]) type OnlyIntToSet[T] = set[T] if IsAssignable[T, int] else T @@ -727,6 +728,8 @@ class B(A): def test_getarg_never(): + # Never decomposes to an empty union, so the operator never runs + # and _mk_union returns Never d = eval_typing(GetArg[Never, object, Literal[0]]) assert d is Never @@ -830,8 +833,8 @@ def test_eval_getarg_callable_02(): gc = GenericCallable[tuple[T], f] t = eval_typing(GetArg[gc, GenericCallable, Literal[0]]) assert t == tuple[T] - gc_f = eval_typing(GetArg[gc, GenericCallable, Literal[1]]) - assert gc_f == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[gc, GenericCallable, Literal[1]]) # Params wrapped f = Callable[ @@ -848,8 +851,8 @@ def test_eval_getarg_callable_02(): ] t = eval_typing(GetArg[gc, GenericCallable, Literal[0]]) assert t == tuple[T] - gc_f = eval_typing(GetArg[gc, GenericCallable, Literal[1]]) - assert gc_f == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[gc, GenericCallable, Literal[1]]) type IndirectProtocol[T] = NewProtocol[*[m for m in Iter[Members[T]]],] @@ -996,8 +999,8 @@ def f[T](self, x: T, /, y: T, *, z: T) -> T: ... _T = eval_typing( GetArg[GetArg[gc, GenericCallable, Literal[0]], tuple, Literal[0]] ) - f = eval_typing(GetArg[gc, GenericCallable, Literal[1]]) - assert f is Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[gc, GenericCallable, Literal[1]]) def test_eval_getarg_callable_08(): @@ -1010,8 +1013,8 @@ def f[T](cls, x: T, /, y: T, *, z: T) -> T: ... _T = eval_typing( GetArg[GetArg[gc, GenericCallable, Literal[0]], tuple, Literal[0]] ) - f = eval_typing(GetArg[gc, GenericCallable, Literal[1]]) - assert f is Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[gc, GenericCallable, Literal[1]]) def test_eval_getarg_callable_09(): @@ -1024,8 +1027,8 @@ def f[T](x: T, /, y: T, *, z: T) -> T: ... _T = eval_typing( GetArg[GetArg[gc, GenericCallable, Literal[0]], tuple, Literal[0]] ) - f = eval_typing(GetArg[gc, GenericCallable, Literal[1]]) - assert f is Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[gc, GenericCallable, Literal[1]]) def test_eval_getarg_tuple(): @@ -1108,37 +1111,10 @@ def test_eval_getarg_list(): assert arg == Any # indexing with 1 always fails - t = list[int] - arg = eval_typing(GetArg[t, list, Literal[1]]) - assert arg == Never - - t = List[int] - arg = eval_typing(GetArg[t, list, Literal[1]]) - assert arg == Never - - t = list - arg = eval_typing(GetArg[t, list, Literal[1]]) - assert arg == Never - - t = List - arg = eval_typing(GetArg[t, list, Literal[1]]) - assert arg == Never - - t = list[int] - arg = eval_typing(GetArg[t, List, Literal[1]]) - assert arg == Never - - t = List[int] - arg = eval_typing(GetArg[t, List, Literal[1]]) - assert arg == Never - - t = list - arg = eval_typing(GetArg[t, List, Literal[1]]) - assert arg == Never - - t = List - arg = eval_typing(GetArg[t, List, Literal[1]]) - assert arg == Never + for t in [list[int], List[int], list, List]: + for base in [list, List]: + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, base, Literal[1]]) @pytest.mark.xfail(reason="Should this work?") @@ -1160,12 +1136,14 @@ class A[T]: t = A[int] assert eval_typing(GetArg[t, A, Literal[0]]) is int assert eval_typing(GetArg[t, A, Literal[-1]]) is int - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) t = A assert eval_typing(GetArg[t, A, Literal[0]]) == Any assert eval_typing(GetArg[t, A, Literal[-1]]) == Any - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) def test_eval_getarg_custom_02(): @@ -1177,12 +1155,14 @@ class A(Generic[T]): t = A[int] assert eval_typing(GetArg[t, A, Literal[0]]) is int assert eval_typing(GetArg[t, A, Literal[-1]]) is int - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) t = A assert eval_typing(GetArg[t, A, Literal[0]]) == Any assert eval_typing(GetArg[t, A, Literal[-1]]) == Any - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) def test_eval_getarg_custom_03(): @@ -1192,12 +1172,14 @@ class A[T = str]: t = A[int] assert eval_typing(GetArg[t, A, Literal[0]]) is int assert eval_typing(GetArg[t, A, Literal[-1]]) is int - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) t = A assert eval_typing(GetArg[t, A, Literal[0]]) is str assert eval_typing(GetArg[t, A, Literal[-1]]) is str - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) def test_eval_getarg_custom_04(): @@ -1209,12 +1191,14 @@ class A(Generic[T]): t = A[int] assert eval_typing(GetArg[t, A, Literal[0]]) is int assert eval_typing(GetArg[t, A, Literal[-1]]) is int - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) t = A assert eval_typing(GetArg[t, A, Literal[0]]) is str assert eval_typing(GetArg[t, A, Literal[-1]]) is str - assert eval_typing(GetArg[t, A, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, A, Literal[1]]) TestTypeVar = TypeVar("TestTypeVar") @@ -1228,12 +1212,14 @@ class ATree(Generic[TestTypeVar]): t = ATree[int] assert eval_typing(GetArg[t, ATree, Literal[0]]) is int assert eval_typing(GetArg[t, ATree, Literal[-1]]) is int - assert eval_typing(GetArg[t, ATree, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, ATree, Literal[1]]) t = ATree assert eval_typing(GetArg[t, ATree, Literal[0]]) is Any assert eval_typing(GetArg[t, ATree, Literal[-1]]) is Any - assert eval_typing(GetArg[t, ATree, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, ATree, Literal[1]]) def test_eval_getarg_custom_06(): @@ -1246,12 +1232,14 @@ class ATree(Generic[A]): t = ATree[int] assert eval_typing(GetArg[t, ATree, Literal[0]]) is int assert eval_typing(GetArg[t, ATree, Literal[-1]]) is int - assert eval_typing(GetArg[t, ATree, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, ATree, Literal[1]]) t = ATree assert eval_typing(GetArg[t, ATree, Literal[0]]) is Any assert eval_typing(GetArg[t, ATree, Literal[-1]]) is Any - assert eval_typing(GetArg[t, ATree, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, ATree, Literal[1]]) # Doubly recursive generic types @@ -1275,12 +1263,14 @@ def test_eval_getarg_custom_07(): t = ABTree[int, str] assert eval_typing(GetArg[t, ABTree, Literal[0]]) is int assert eval_typing(GetArg[t, ABTree, Literal[1]]) is str - assert eval_typing(GetArg[t, ABTree, Literal[2]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, ABTree, Literal[2]]) t = ABTree assert eval_typing(GetArg[t, ABTree, Literal[0]]) is Any assert eval_typing(GetArg[t, ABTree, Literal[1]]) is Any - assert eval_typing(GetArg[t, ABTree, Literal[2]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, ABTree, Literal[2]]) T = TypeVar("T") @@ -1302,12 +1292,14 @@ def test_eval_getarg_custom_08(): t = Container[int] assert eval_typing(GetArg[t, Container, Literal[0]]) is int assert eval_typing(GetArg[t, Container, Literal[-1]]) is int - assert eval_typing(GetArg[t, Container, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, Container, Literal[1]]) t = Container assert eval_typing(GetArg[t, Container, Literal[0]]) is Any assert eval_typing(GetArg[t, Container, Literal[-1]]) is Any - assert eval_typing(GetArg[t, Container, Literal[1]]) == Never + with pytest.raises(TypeMapError): + eval_typing(GetArg[t, Container, Literal[1]]) def test_eval_getargs_generic_callable_01(): @@ -1796,10 +1788,10 @@ def test_eval_slice_02(): def test_eval_slice_03(): - d = eval_typing(Slice[int, Literal[1], Literal[2]]) - assert d == Never - d = eval_typing(Slice[dict[int, str], Literal[1], Literal[2]]) - assert d == Never + with pytest.raises(TypeMapError): + eval_typing(Slice[int, Literal[1], Literal[2]]) + with pytest.raises(TypeMapError): + eval_typing(Slice[dict[int, str], Literal[1], Literal[2]]) def test_eval_literal_idempotent_01(): @@ -2679,7 +2671,6 @@ def test_type_eval_annotated_04(): # RaiseError tests from typemap_extensions import RaiseError -from typemap.type_eval import TypeMapError def test_raise_error_basic(): diff --git a/typemap/type_eval/_eval_operators.py b/typemap/type_eval/_eval_operators.py index 48f1bd2..9e75601 100644 --- a/typemap/type_eval/_eval_operators.py +++ b/typemap/type_eval/_eval_operators.py @@ -879,7 +879,7 @@ def _eval_GetMember(tp, prop, *, ctx): if name in hints: return _hint_to_member(name, *hints[name], ctx=ctx) else: - return typing.Never + raise TypeMapError(f"GetMember: {name!r} not found in {tp!r}") ################################################################## @@ -1077,18 +1077,20 @@ def _eval_GetArg(tp, base, idx, *, ctx) -> typing.Any: base_head = _typing_inspect.get_head(base) args = _get_args(tp, base_head, ctx) if args is None: - return typing.Never + raise TypeMapError(f"GetArg: {tp!r} is not a subclass of {base!r}") try: idx_val = _eval_literal(idx, ctx) if base_head is GenericCallable and idx_val >= 1: # Disallow access to callable lambda - return typing.Never + raise TypeMapError( + f"GetArg: cannot access index {idx_val} of GenericCallable" + ) return _fix_type(args[idx_val]) except IndexError: - return typing.Never + raise TypeMapError(f"GetArg: index out of range for {tp!r} as {base!r}") @type_eval.register_evaluator(GetArgs) @@ -1097,7 +1099,7 @@ def _eval_GetArgs(tp, base, *, ctx) -> typing.Any: base_head = _typing_inspect.get_head(base) args = _get_args(tp, base_head, ctx) if args is None: - return typing.Never + raise TypeMapError(f"GetArgs: {tp!r} is not a subclass of {base!r}") if base_head is GenericCallable: # Disallow access to callable lambda @@ -1125,7 +1127,9 @@ def _eval_GetSpecialAttr(tp, attr, *, ctx) -> typing.Any: elif attr.__args__[0] == "__qualname__": return typing.Literal[tp.__qualname__] else: - return typing.Never + raise TypeMapError( + f"GetSpecialAttr: {attr.__args__[0]!r} is not a valid attribute" + ) @type_eval.register_evaluator(GetAnnotations) @@ -1178,7 +1182,7 @@ def _eval_Slice(tp, start, end, *, ctx): ): return tp.__origin__[tp.__args__[0][start:end]] else: - return typing.Never + raise TypeMapError(f"Slice: {tp!r} is not a tuple or string Literal") # String literals