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
18 changes: 17 additions & 1 deletion tests/test_type_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ def test_never_is():
assert d is True


def test_eval_iter():
def test_eval_iter_01():
d = eval_typing(Iter[tuple[int, str]])
assert tuple(d) == (int, str)

Expand All @@ -654,6 +654,22 @@ def test_eval_iter():
assert tuple(d) == ()


type DuplicateTuple[T] = tuple[*[x for x in Iter[T]], *[x for x in Iter[T]]]
type ConcatTupleWithSelf[T] = ConcatTuples[T, T]


def test_eval_iter_02():
# ensure iterating duplicate tuples can be iterated multiple times
d = eval_typing(ConcatTuples[tuple[int, str], tuple[int, str]])
assert d == tuple[int, str, int, str]

d = eval_typing(DuplicateTuple[tuple[int, str]])
assert d == tuple[int, str, int, str]

d = eval_typing(ConcatTupleWithSelf[tuple[int, str]])
assert d == tuple[int, str, int, str]


def test_eval_length_01():
d = eval_typing(Length[tuple[int, str]])
assert d == Literal[2]
Expand Down
6 changes: 5 additions & 1 deletion typemap/type_eval/_eval_typing.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import annotationlib

import collections.abc
import contextlib
import contextvars
import dataclasses
Expand Down Expand Up @@ -231,7 +232,10 @@ def _eval_types(obj: typing.Any, ctx: EvalContext):
ctx.resolved |= {x: x for x in child_ctx.known_recursive_types.keys()}
ctx.known_recursive_types |= child_ctx.known_recursive_types

ctx.resolved[obj] = evaled
# Don't cache iterators as they are stateful and can only be consumed once.
# This is important for Iter results that may be used multiple times.
if not isinstance(evaled, collections.abc.Iterator):
ctx.resolved[obj] = evaled
return evaled


Expand Down