2025-03-20

stdlib Protocol types

The Python stdlib has a load of useful Protocol types in typing, for example: from typing import Iterable.

I can never remember what's what. Here is a condensed version of this file (as of 2025-01-01) from the typeshed, in approximately the order I care about them in.

TypeVars ending with _co are covariant, TypeVars ending with _con are contravariant.

class Sized(Protocol):
    def __len__(self) -> int: ...

class Hashable(Protocol):
    def __hash__(self) -> int: ...

class Container(Protocol[T_co]):
    def __contains__(self, x: object, /) -> bool: ...

class Iterable(Protocol[T_co]):
    def __iter__(self) -> Iterator[T_co]: ...

class Iterator(Iterable[T_co], Protocol[T_co]):
    def __next__(self) -> T_co: ...
    def __iter__(self) -> Iterator[T_co]: ...

class Collection(Iterable[T_co], Container[T_co], Protocol[T_co]):
    def __len__(self) -> int: ...

class Reversible(Iterable[T_co], Protocol[T_co]):
    def __reversed__(self) -> Iterator[T_co]: ...

class Sequence(Reversible[T_co], Collection[T_co]):
    @overload
    def __getitem__(self, index: int) -> T_co: ...
    @overload
    def __getitem__(self, index: slice) -> Sequence[T_co]: ...
    def index(self, value: Any, start: int = 0, stop: int = ...) -> int: ...
    def count(self, value: Any) -> int: ...
    def __contains__(self, value: object) -> bool: ...
    def __iter__(self) -> Iterator[T_co]: ...
    def __reversed__(self) -> Iterator[T_co]: ...

class Generator(Iterator[U_co], Protocol[U_co, C_con, R_co]):
    def __next__(self) -> U_co: ...
    def send(self, value: C_con, /) -> U_co: ...
    @overload
    def throw(self, typ: type[BaseException], val: BaseException | object = None, tb: TracebackType | None = None, /) -> U_co: ...
    @overload
    def throw(self, typ: BaseException, val: None = None, tb: TracebackType | None = None, /) -> U_co: ...
    def close(self) -> R_co | None: ...
    def __iter__(self) -> Generator[U_co, C_con, R_co]: ...

class MutableSequence(Sequence[T]):
    def insert(self, index: int, value: T) -> None: ...
    @overload
    def __getitem__(self, index: int) -> T: ...
    @overload
    def __getitem__(self, index: slice) -> MutableSequence[T]: ...
    @overload
    def __setitem__(self, index: int, value: T) -> None: ...
    @overload
    def __setitem__(self, index: slice, value: Iterable[T]) -> None: ...
    @overload
    def __delitem__(self, index: int) -> None: ...
    @overload
    def __delitem__(self, index: slice) -> None: ...
    def append(self, value: T) -> None: ...
    def clear(self) -> None: ...
    def extend(self, values: Iterable[T]) -> None: ...
    def reverse(self) -> None: ...
    def pop(self, index: int = -1) -> T: ...
    def remove(self, value: T) -> None: ...
    def __iadd__(self, values: Iterable[T]) -> Self: ...

class AbstractSet(Collection[T_co]):
    def __contains__(self, x: object) -> bool: ...
    def _hash(self) -> int: ...
    def __le__(self, other: AbstractSet[Any]) -> bool: ...
    def __lt__(self, other: AbstractSet[Any]) -> bool: ...
    def __gt__(self, other: AbstractSet[Any]) -> bool: ...
    def __ge__(self, other: AbstractSet[Any]) -> bool: ...
    def __and__(self, other: AbstractSet[Any]) -> AbstractSet[T_co]: ...
    def __or__(self, other: AbstractSet[T]) -> AbstractSet[T_co | T]: ...
    def __sub__(self, other: AbstractSet[Any]) -> AbstractSet[T_co]: ...
    def __xor__(self, other: AbstractSet[T]) -> AbstractSet[T_co | T]: ...
    def __eq__(self, other: object) -> bool: ...
    def isdisjoint(self, other: Iterable[Any]) -> bool: ...

class MutableSet(AbstractSet[T]):
    def add(self, value: T) -> None: ...
    def discard(self, value: T) -> None: ...
    def clear(self) -> None: ...
    def pop(self) -> T: ...
    def remove(self, value: T) -> None: ...
    def __ior__(self, it: AbstractSet[T]) -> Self: ...
    def __iand__(self, it: AbstractSet[Any]) -> Self: ...
    def __ixor__(self, it: AbstractSet[T]) -> Self: ...
    def __isub__(self, it: AbstractSet[Any]) -> Self: ...

class Mapping(Collection[K], Generic[K, V_co]):
    def __getitem__(self, key: K, /) -> V_co: ...
    @overload
    def get(self, key: K, /) -> V_co | None: ...
    @overload
    def get(self, key: K, /, default: V_co | T) -> V_co | T: ...
    def items(self) -> ItemsView[K, V_co]: ...
    def keys(self) -> KeysView[K]: ...
    def values(self) -> ValuesView[V_co]: ...
    def __contains__(self, key: object, /) -> bool: ...
    def __eq__(self, other: object, /) -> bool: ...

class MutableMapping(Mapping[K, V]):
    def __setitem__(self, key: K, value: V, /) -> None: ...
    def __delitem__(self, key: K, /) -> None: ...
    def clear(self) -> None: ...
    @overload
    def pop(self, key: K, /) -> V: ...
    @overload
    def pop(self, key: K, /, default: V) -> V: ...
    @overload
    def pop(self, key: K, /, default: T) -> V | T: ...
    def popitem(self) -> tuple[K, V]: ...
    @overload
    def setdefault(self: MutableMapping[K, T | None], key: K, default: None = None, /) -> T | None: ...
    @overload
    def setdefault(self, key: K, default: V, /) -> V: ...
    @overload
    def update(self, m: typeshed.SupportsKeysAndGetItem[K, V], /, **kwargs: V) -> None: ...
    @overload
    def update(self, m: Iterable[tuple[K, V]], /, **kwargs: V) -> None: ...
    @overload
    def update(self, **kwargs: V) -> None: ...

class SupportsInt(Protocol):
    def __int__(self) -> int: ...
class SupportsFloat(Protocol):
    def __float__(self) -> float: ...
class SupportsComplex(Protocol):
    def __complex__(self) -> complex: ...
class SupportsBytes(Protocol):
    def __bytes__(self) -> bytes: ...
class SupportsIndex(Protocol):
    def __index__(self) -> int: ...
class SupportsAbs(Protocol[T_co]):
    def __abs__(self) -> T_co: ...

class SupportsRound(Protocol[T_co]):
    @overload
    def __round__(self) -> int: ...
    @overload
    def __round__(self, ndigits: int, /) -> T_co: ...

class Awaitable(Protocol[T_co]):
    def __await__(self) -> Generator[Any, Any, T_co]: ...

class Coroutine(Awaitable[R_co], Generic[U_co, C_con, R_co]):
    __name__: str
    __qualname__: str
    def send(self, value: C_con, /) -> U_co: ...
    @overload
    def throw(self, typ: type[BaseException], val: BaseException | object = None, tb: TracebackType | None = None, /) -> U_co: ...
    @overload
    def throw(self, typ: BaseException, val: None = None, tb: TracebackType | None = None, /) -> U_co: ...
    def close(self) -> None: ...

class AsyncIterable(Protocol[T_co]):
    def __aiter__(self) -> AsyncIterator[T_co]: ...

class AsyncIterator(AsyncIterable[T_co], Protocol[T_co]):
    def __anext__(self) -> Awaitable[T_co]: ...
    def __aiter__(self) -> AsyncIterator[T_co]: ...

class AsyncGenerator(AsyncIterator[U_co], Protocol[U_co, C_con]):
    def __anext__(self) -> Coroutine[Any, Any, U_co]: ...
    def asend(self, value: C_con, /) -> Coroutine[Any, Any, U_co]: ...
    @overload
    def athrow(self, typ: type[BaseException], val: BaseException | object = None, tb: TracebackType | None = None, /) -> Coroutine[Any, Any, U_co]: ...
    @overload
    def athrow(self, typ: BaseException, val: None = None, tb: TracebackType | None = None, /) -> Coroutine[Any, Any, U_co]: ...
    def aclose(self) -> Coroutine[Any, Any, None]: ...

class MappingView(Sized):
    def __init__(self, mapping: Mapping[Any, Any]) -> None: ...
    def __len__(self) -> int: ...

class ItemsView(MappingView, AbstractSet[tuple[K_co, V_co]], Generic[K_co, V_co]):
    def __init__(self, mapping: Mapping[K_co, V_co]) -> None: ...
    def __and__(self, other: Iterable[Any]) -> set[tuple[K_co, V_co]]: ...
    def __rand__(self, other: Iterable[T]) -> set[T]: ...
    def __contains__(self, item: object) -> bool: ...
    def __iter__(self) -> Iterator[tuple[K_co, V_co]]: ...
    def __or__(self, other: Iterable[T]) -> set[tuple[K_co, V_co] | T]: ...
    def __ror__(self, other: Iterable[T]) -> set[tuple[K_co, V_co] | T]: ...
    def __sub__(self, other: Iterable[Any]) -> set[tuple[K_co, V_co]]: ...
    def __rsub__(self, other: Iterable[T]) -> set[T]: ...
    def __xor__(self, other: Iterable[T]) -> set[tuple[K_co, V_co] | T]: ...
    def __rxor__(self, other: Iterable[T]) -> set[tuple[K_co, V_co] | T]: ...

class KeysView(MappingView, AbstractSet[K_co]):
    def __init__(self, mapping: Mapping[K_co, Any]) -> None: ...
    def __and__(self, other: Iterable[Any]) -> set[K_co]: ...
    def __rand__(self, other: Iterable[T]) -> set[T]: ...
    def __contains__(self, key: object) -> bool: ...
    def __iter__(self) -> Iterator[K_co]: ...
    def __or__(self, other: Iterable[T]) -> set[K_co | T]: ...
    def __ror__(self, other: Iterable[T]) -> set[K_co | T]: ...
    def __sub__(self, other: Iterable[Any]) -> set[K_co]: ...
    def __rsub__(self, other: Iterable[T]) -> set[T]: ...
    def __xor__(self, other: Iterable[T]) -> set[K_co | T]: ...
    def __rxor__(self, other: Iterable[T]) -> set[K_co | T]: ...

class ValuesView(MappingView, Collection[V_co]):
    def __init__(self, mapping: Mapping[Any, V_co]) -> None: ...
    def __contains__(self, value: object) -> bool: ...
    def __iter__(self) -> Iterator[V_co]: ...