Skip to content
11 changes: 9 additions & 2 deletions tests/test_qblike.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import textwrap

from typing import Literal

from typemap.type_eval import eval_call, eval_typing
from typemap.typing import (
NewProtocol,
Expand Down Expand Up @@ -106,10 +108,15 @@ def test_qblike_3():
class select[...]:
x: tests.test_qblike.Property[int]
w: tests.test_qblike.Property[list[str]]
z: tests.test_qblike.Link[PropsOnly[tests.test_qblike.Tgt]]
z: tests.test_qblike.Link[PropsOnly[typemap.typing.GetArg[\
tests.test_qblike.Link[tests.test_qblike.Tgt], tests.test_qblike.Link, 0]]]
""")
# z: tests.test_qblike.Link[PropsOnly[tests.test_qblike.Tgt]]

tgt = eval_typing(GetAttr[ret, "z"].__args__[0])
res = eval_typing(GetAttr[ret, Literal["z"]])
tgt = res.__args__[0]
# XXX: this should probably be pre-evaluated already?
tgt = eval_typing(tgt)
fmt = format_helper.format_class(tgt)

assert fmt == textwrap.dedent("""\
Expand Down
4 changes: 3 additions & 1 deletion tests/test_type_dir.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,9 @@ class NoLiterals2[tests.test_type_dir.Final]:

def test_type_dir_7():
d = eval_typing(Members[Final])
foo = next(iter(m for m in Iter[d] if m.__args__[0].__args__[0] == "foo"))
foo = next(
iter(m for m in d.__args__ if m.__args__[0].__args__[0] == "foo")
)
# XXX: drop self?
assert (
str(foo)
Expand Down
17 changes: 14 additions & 3 deletions tests/test_type_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ def test_eval_types_1():
def test_eval_types_2():
evaled = eval_typing(MapRecursive[Recursive])

# Validate that recursion worked properly and "Recursive" was only walked once
assert evaled.__annotations__["a"].__args__[0] is evaled
# FIXME, or think about: this doesn't work, we currently evaluate it to an
# *unexpanded* type alias.
# # Validate that recursion worked properly and "Recursive" was only walked once
# assert evaled.__annotations__["a"].__args__[0] is evaled

assert format_helper.format_class(evaled) == textwrap.dedent("""\
class MapRecursive[tests.test_type_eval.Recursive]:
n: int | typing.Literal['gotcha!']
m: str | typing.Literal['gotcha!']
t: typing.Literal[False] | typing.Literal['gotcha!']
a: tests.test_type_eval.MapRecursive[tests.test_type_eval.Recursive] | typing.Literal['gotcha!']
a: MapRecursive[tests.test_type_eval.Recursive] | typing.Literal['gotcha!']
fff: int | typing.Literal['gotcha!']
control: float
""")
Expand Down Expand Up @@ -159,3 +161,12 @@ def test_type_strings_5():
def test_type_strings_6():
d = eval_typing(StrSlice[Literal["abcd"], Literal[1], Literal[None]])
assert d == Literal["bcd"]


def test_type_asdf():
from typemap.typing import FromUnion

d = eval_typing(FromUnion[int | bool])
arg = FromUnion[int | str]
d = eval_typing(arg)
assert d == tuple[int, str] or d == tuple[str, int]
13 changes: 12 additions & 1 deletion typemap/type_eval/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
from ._eval_typing import (
eval_typing,
_get_current_context,
register_evaluator,
_EvalProxy,
)

# XXX: this needs to go second due to nasty circularity -- try to fix that!!
from ._eval_call import eval_call
from ._eval_typing import eval_typing, _get_current_context, _EvalProxy
from ._subtype import issubtype
from ._subsim import issubsimilar

# This one is imported for registering handlers
from . import _eval_operators # noqa


__all__ = (
"eval_typing",
"register_evaluator",
"eval_call",
"issubtype",
"issubsimilar",
Expand Down
4 changes: 3 additions & 1 deletion typemap/type_eval/_eval_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ def _eval_call(
params = func.__type_params__
for p in params:
if hasattr(p, "__bound__") and p.__bound__ is next.CallSpec:
vars[p.__name__] = next._CallSpecWrapper(args, kwargs, func)
vars[p.__name__] = next._CallSpecWrapper(
args, tuple(kwargs.items()), func
)
else:
vars[p.__name__] = p

Expand Down
Loading