from typing import Any, Callable, Iterable, Iterator, TypeVar, overload

_T = TypeVar("_T")

# Note, all classes "defined" here require special handling.

class NoneType: ...

TypeType = type
ObjectType = object

IntType = int
LongType = int  # Really long, but can't reference that due to a mypy import cycle
FloatType = float
BooleanType = bool
ComplexType = complex
StringType = str
UnicodeType = unicode
StringTypes: tuple[type[StringType], type[UnicodeType]]
BufferType = buffer
TupleType = tuple
ListType = list
DictType = dict
DictionaryType = dict

class _Cell:
    cell_contents: Any

class FunctionType:
    func_closure: tuple[_Cell, ...] | None = ...
    func_code: CodeType = ...
    func_defaults: tuple[Any, ...] | None = ...
    func_dict: dict[str, Any] = ...
    func_doc: str | None = ...
    func_globals: dict[str, Any] = ...
    func_name: str = ...
    __closure__ = func_closure
    __code__ = func_code
    __defaults__ = func_defaults
    __dict__ = func_dict
    __globals__ = func_globals
    __name__ = func_name
    def __init__(
        self,
        code: CodeType,
        globals: dict[str, Any],
        name: str | None = ...,
        argdefs: tuple[object, ...] | None = ...,
        closure: tuple[_Cell, ...] | None = ...,
    ) -> None: ...
    def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
    def __get__(self, obj: object | None, type: type | None) -> UnboundMethodType: ...

LambdaType = FunctionType

class CodeType:
    co_argcount: int
    co_cellvars: tuple[str, ...]
    co_code: str
    co_consts: tuple[Any, ...]
    co_filename: str
    co_firstlineno: int
    co_flags: int
    co_freevars: tuple[str, ...]
    co_lnotab: str
    co_name: str
    co_names: tuple[str, ...]
    co_nlocals: int
    co_stacksize: int
    co_varnames: tuple[str, ...]
    def __init__(
        self,
        argcount: int,
        nlocals: int,
        stacksize: int,
        flags: int,
        codestring: str,
        constants: tuple[Any, ...],
        names: tuple[str, ...],
        varnames: tuple[str, ...],
        filename: str,
        name: str,
        firstlineno: int,
        lnotab: str,
        freevars: tuple[str, ...] = ...,
        cellvars: tuple[str, ...] = ...,
    ) -> None: ...

class GeneratorType:
    gi_code: CodeType
    gi_frame: FrameType
    gi_running: int
    def __iter__(self) -> GeneratorType: ...
    def close(self) -> None: ...
    def next(self) -> Any: ...
    def send(self, __arg: Any) -> Any: ...
    @overload
    def throw(self, __typ: type[BaseException], __val: BaseException | object = ..., __tb: TracebackType | None = ...) -> Any: ...
    @overload
    def throw(self, __typ: BaseException, __val: None = ..., __tb: TracebackType | None = ...) -> Any: ...

class ClassType: ...

class UnboundMethodType:
    im_class: type = ...
    im_func: FunctionType = ...
    im_self: object = ...
    __name__: str
    __func__ = im_func
    __self__ = im_self
    def __init__(self, func: Callable[..., Any], obj: object) -> None: ...
    def __call__(self, *args: Any, **kwargs: Any) -> Any: ...

class InstanceType(object): ...

MethodType = UnboundMethodType

class BuiltinFunctionType:
    __self__: object | None
    def __call__(self, *args: Any, **kwargs: Any) -> Any: ...

BuiltinMethodType = BuiltinFunctionType

class ModuleType:
    __doc__: str | None
    __file__: str | None
    __name__: str
    __package__: str | None
    __path__: Iterable[str] | None
    __dict__: dict[str, Any]
    def __init__(self, name: str, doc: str | None = ...) -> None: ...

FileType = file
XRangeType = xrange

class TracebackType:
    tb_frame: FrameType
    tb_lasti: int
    tb_lineno: int
    tb_next: TracebackType

class FrameType:
    f_back: FrameType
    f_builtins: dict[str, Any]
    f_code: CodeType
    f_exc_type: None
    f_exc_value: None
    f_exc_traceback: None
    f_globals: dict[str, Any]
    f_lasti: int
    f_lineno: int | None
    f_locals: dict[str, Any]
    f_restricted: bool
    f_trace: Callable[[], None]
    def clear(self) -> None: ...

SliceType = slice

class EllipsisType: ...

class DictProxyType:
    # TODO is it possible to have non-string keys?
    # no __init__
    def copy(self) -> dict[Any, Any]: ...
    def get(self, key: str, default: _T = ...) -> Any | _T: ...
    def has_key(self, key: str) -> bool: ...
    def items(self) -> list[tuple[str, Any]]: ...
    def iteritems(self) -> Iterator[tuple[str, Any]]: ...
    def iterkeys(self) -> Iterator[str]: ...
    def itervalues(self) -> Iterator[Any]: ...
    def keys(self) -> list[str]: ...
    def values(self) -> list[Any]: ...
    def __contains__(self, key: str) -> bool: ...
    def __getitem__(self, key: str) -> Any: ...
    def __iter__(self) -> Iterator[str]: ...
    def __len__(self) -> int: ...

class NotImplementedType: ...

class GetSetDescriptorType:
    __name__: str
    __objclass__: type
    def __get__(self, obj: Any, type: type = ...) -> Any: ...
    def __set__(self, obj: Any) -> None: ...
    def __delete__(self, obj: Any) -> None: ...

# Same type on Jython, different on CPython and PyPy, unknown on IronPython.
class MemberDescriptorType:
    __name__: str
    __objclass__: type
    def __get__(self, obj: Any, type: type = ...) -> Any: ...
    def __set__(self, obj: Any) -> None: ...
    def __delete__(self, obj: Any) -> None: ...
