import abc
from typing import (Mapping, MutableMapping, List, Union, Iterable,
                    Iterator, TypeVar, Generic, Tuple, Dict)


class istr(str):
    pass


upstr = istr

_S = Union[str, istr]

_T = TypeVar('_T')


class MultiMapping(Mapping[_S, _T], Generic[_T]):
    @abc.abstractmethod
    def getall(self, key: _S, default: _T = ...) -> List[_T]: ...

    @abc.abstractmethod
    def getone(self, key: _S, default: _T = ...) -> _T: ...


_Arg = Union[Mapping[_S, _T],
             Dict[_S, _T],
             MultiMapping[_T],
             Iterable[Tuple[_S, _T]]]


class MutableMultiMapping(MultiMapping[_T],
                          MutableMapping[_S, _T],
                          Generic[_T]):

    @abc.abstractmethod
    def add(self, key: _S, value: _T) -> None: ...

    @abc.abstractmethod
    def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...

    @abc.abstractmethod
    def popone(self, key: _S, default: _T = ...) -> _T: ...

    @abc.abstractmethod
    def popall(self, key: _S, default: _T = ...) -> List[_T]: ...


class MultiDict(MutableMultiMapping[_T], Generic[_T]):
    def __init__(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...

    def copy(self) -> MultiDict[_T]: ...

    def __getitem__(self, k: _S) -> _T: ...

    def __setitem__(self, k: _S, v: _T) -> None: ...

    def __delitem__(self, v: _S) -> None: ...

    def __iter__(self) -> Iterator[_S]: ...

    def __len__(self) -> int: ...

    def getall(self, key: _S, default: _T = ...) -> List[_T]: ...

    def getone(self, key: _S, default: _T = ...) -> _T: ...

    def add(self, key: _S, value: _T) -> None: ...

    def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...

    def popone(self, key: _S, default: _T = ...) -> _T: ...

    def popall(self, key: _S, default: _T = ...) -> List[_T]: ...


class CIMultiDict(MutableMultiMapping[_T], Generic[_T]):
    def __init__(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...

    def copy(self) -> MultiDict[_T]: ...

    def __getitem__(self, k: _S) -> _T: ...

    def __setitem__(self, k: _S, v: _T) -> None: ...

    def __delitem__(self, v: _S) -> None: ...

    def __iter__(self) -> Iterator[_S]: ...

    def __len__(self) -> int: ...

    def getall(self, key: _S, default: _T = ...) -> List[_T]: ...

    def getone(self, key: _S, default: _T = ...) -> _T: ...

    def add(self, key: _S, value: _T) -> None: ...

    def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...

    def popone(self, key: _S, default: _T = ...) -> _T: ...

    def popall(self, key: _S, default: _T = ...) -> List[_T]: ...


class MultiDictProxy(MultiMapping[_T], Generic[_T]):
    def __init__(self, arg: Union[MultiMapping[_T],
                                  MutableMultiMapping[_T]]) -> None: ...

    def copy(self) -> MultiDict[_T]: ...

    def __getitem__(self, k: _S) -> _T: ...

    def __iter__(self) -> Iterator[_S]: ...

    def __len__(self) -> int: ...

    def getall(self, key: _S, default: _T = ...) -> List[_T]: ...

    def getone(self, key: _S, default: _T = ...) -> _T: ...


class CIMultiDictProxy(MultiMapping[_T], Generic[_T]):
    def __init__(self, arg: Union[MultiMapping[_T],
                                  MutableMultiMapping[_T]]) -> None: ...

    def __getitem__(self, k: _S) -> _T: ...

    def __iter__(self) -> Iterator[_S]: ...

    def __len__(self) -> int: ...

    def getall(self, key: _S, default: _T = ...) -> List[_T]: ...

    def getone(self, key: _S, default: _T = ...) -> _T: ...

    def copy(self) -> CIMultiDict[_T]: ...


def getversion(md: Union[MultiDict[_T],
                         CIMultiDict[_T],
                         MultiDictProxy[_T],
                         CIMultiDictProxy[_T]]) -> int: ...
