Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 119 additions & 21 deletions tests/test_type_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from typemap.typing import (
Attrs,
FromUnion,
GenericCallable,
GetArg,
GetArgs,
GetAttr,
Expand Down Expand Up @@ -451,6 +452,41 @@ def test_eval_getarg_callable_01():
assert args == Any


def test_eval_getarg_callable_02():
# GenericCallable
T = TypeVar("T")

# Params not wrapped
f = Callable[[T], T]
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 == f
t = eval_typing(GetArg[gc_f, Callable, Literal[0]])
assert t == tuple[Param[Literal[None], T, Never]]
t = eval_typing(GetArg[gc_f, Callable, Literal[1]])
assert t is T

# Params wrapped
f = Callable[
[
Param[Literal[None], T, Literal["positional"]],
Param[Literal["y"], T],
Param[Literal["z"], T, Literal["keyword"]],
],
T,
]
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 == f


type IndirectProtocol[T] = NewProtocol[*[m for m in Iter[Members[T]]],]
type GetMethodLike[T, Name] = GetArg[
tuple[
Expand All @@ -461,6 +497,7 @@ def test_eval_getarg_callable_01():
IsSub[GetType[p], Callable]
or IsSub[GetType[p], staticmethod]
or IsSub[GetType[p], classmethod]
or IsSub[GetType[p], GenericCallable]
)
and IsSub[Name, GetName[p]]
],
Expand All @@ -470,7 +507,8 @@ def test_eval_getarg_callable_01():
]


def test_eval_getarg_callable_02a():
def test_eval_getarg_callable_03():
# member function
class C:
def f(self, x: int, /, y: int, *, z: int) -> int: ...

Expand All @@ -488,11 +526,6 @@ def f(self, x: int, /, y: int, *, z: int) -> int: ...
t = eval_typing(GetArg[f, Callable, Literal[1]])
assert t is int


def test_eval_getarg_callable_02b():
class C:
def f(self, x: int, /, y: int, *, z: int) -> int: ...

f = eval_typing(GetMethodLike[IndirectProtocol[C], Literal["f"]])
t = eval_typing(GetArg[f, Callable, Literal[0]])
assert (
Expand All @@ -508,7 +541,8 @@ def f(self, x: int, /, y: int, *, z: int) -> int: ...
assert t is int


def test_eval_getarg_callable_03a():
def test_eval_getarg_callable_04():
# classmethod
class C:
@classmethod
def f(cls, x: int, /, y: int, *, z: int) -> int: ...
Expand All @@ -528,12 +562,6 @@ def f(cls, x: int, /, y: int, *, z: int) -> int: ...
t = eval_typing(GetArg[f, classmethod, Literal[2]])
assert t is int


def test_eval_getarg_callable_03b():
class C:
@classmethod
def f(cls, x: int, /, y: int, *, z: int) -> int: ...

f = eval_typing(GetMethodLike[IndirectProtocol[C], Literal["f"]])
t = eval_typing(GetArg[f, classmethod, Literal[0]])
t = eval_typing(GetArg[f, classmethod, Literal[1]])
Expand All @@ -549,7 +577,8 @@ def f(cls, x: int, /, y: int, *, z: int) -> int: ...
assert t is int


def test_eval_getarg_callable_04a():
def test_eval_getarg_callable_05():
# staticmethod
class C:
@staticmethod
def f(x: int, /, y: int, *, z: int) -> int: ...
Expand All @@ -567,12 +596,6 @@ def f(x: int, /, y: int, *, z: int) -> int: ...
t = eval_typing(GetArg[f, staticmethod, Literal[1]])
assert t is int


def test_eval_getarg_callable_04b():
class C:
@staticmethod
def f(x: int, /, y: int, *, z: int) -> int: ...

f = eval_typing(GetMethodLike[IndirectProtocol[C], Literal["f"]])
t = eval_typing(GetArg[f, staticmethod, Literal[0]])
assert (
Expand All @@ -587,7 +610,8 @@ def f(x: int, /, y: int, *, z: int) -> int: ...
assert t is int


def test_eval_getarg_callable_05():
def test_eval_getarg_callable_06():
# member callable attr
class C:
f: Callable[[int], int]

Expand All @@ -598,6 +622,80 @@ class C:
assert t is int


def test_eval_getarg_callable_07():
# generic member function
class C:
def f[T](self, x: T, /, y: T, *, z: T) -> T: ...

gc = eval_typing(GetMethodLike[C, Literal["f"]])
_T = eval_typing(
GetArg[GetArg[gc, GenericCallable, Literal[0]], tuple, Literal[0]]
)
f = eval_typing(GetArg[gc, GenericCallable, Literal[1]])
t = eval_typing(GetArg[f, Callable, Literal[0]])
assert (
t
== tuple[
Param[Literal["self"], C, Literal["positional"]],
Param[Literal["x"], _T, Literal["positional"]],
Param[Literal["y"], _T],
Param[Literal["z"], _T, Literal["keyword"]],
]
)
t = eval_typing(GetArg[f, Callable, Literal[1]])
assert t is _T


def test_eval_getarg_callable_08():
# generic classmethod
class C:
@classmethod
def f[T](cls, x: T, /, y: T, *, z: T) -> T: ...

gc = eval_typing(GetMethodLike[C, Literal["f"]])
_T = eval_typing(
GetArg[GetArg[gc, GenericCallable, Literal[0]], tuple, Literal[0]]
)
f = eval_typing(GetArg[gc, GenericCallable, Literal[1]])
t = eval_typing(GetArg[f, classmethod, Literal[0]])
assert t is C
t = eval_typing(GetArg[f, classmethod, Literal[1]])
assert (
t
== tuple[
Param[Literal["x"], _T, Literal["positional"]],
Param[Literal["y"], _T],
Param[Literal["z"], _T, Literal["keyword"]],
]
)
t = eval_typing(GetArg[f, classmethod, Literal[2]])
assert t is _T


def test_eval_getarg_callable_09():
# generic staticmethod
class C:
@staticmethod
def f[T](x: T, /, y: T, *, z: T) -> T: ...

gc = eval_typing(GetMethodLike[C, Literal["f"]])
_T = eval_typing(
GetArg[GetArg[gc, GenericCallable, Literal[0]], tuple, Literal[0]]
)
f = eval_typing(GetArg[gc, GenericCallable, Literal[1]])
t = eval_typing(GetArg[f, staticmethod, Literal[0]])
assert (
t
== tuple[
Param[Literal["x"], _T, Literal["positional"]],
Param[Literal["y"], _T],
Param[Literal["z"], _T, Literal["keyword"]],
]
)
t = eval_typing(GetArg[f, staticmethod, Literal[1]])
assert t is _T


def test_eval_getarg_tuple():
t = tuple[int, ...]
args = eval_typing(GetArg[t, tuple, Literal[1]])
Expand Down
2 changes: 1 addition & 1 deletion typemap/type_eval/_eval_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ def _get_raw_args(tp, base_head, ctx) -> typing.Any:

if tp_head is base_head:
args = typing.get_args(evaled)
if _is_method_like(tp):
if _is_method_like(tp) and base_head is not GenericCallable:
args = _fix_callable_args(base_head, args)

return args
Expand Down