1from itertools import filterfalse
2
3from typing import (
4    Callable,
5    Iterable,
6    Iterator,
7    Optional,
8    Set,
9    TypeVar,
10    Union,
11)
12
13# Type and type variable definitions
14_T = TypeVar('_T')
15_U = TypeVar('_U')
16
17
18def unique_everseen(
19    iterable: Iterable[_T], key: Optional[Callable[[_T], _U]] = None
20) -> Iterator[_T]:
21    "List unique elements, preserving order. Remember all elements ever seen."
22    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
23    # unique_everseen('ABBCcAD', str.lower) --> A B C D
24    seen: Set[Union[_T, _U]] = set()
25    seen_add = seen.add
26    if key is None:
27        for element in filterfalse(seen.__contains__, iterable):
28            seen_add(element)
29            yield element
30    else:
31        for element in iterable:
32            k = key(element)
33            if k not in seen:
34                seen_add(k)
35                yield element
36