from __future__ import annotations
from typing import TYPE_CHECKING, Any, List, Protocol, Sequence, Tuple, TypeVar, Union

if TYPE_CHECKING:
    from typing_extensions import ParamSpec

    import numpy as np
    import numpy.typing as npt


    T_con = TypeVar('T_con', contravariant=True)
    U_con = TypeVar('U_con', contravariant=True)
    V_con = TypeVar('V_con', contravariant=True)
    T_co = TypeVar('T_co', covariant=True)

    S = TypeVar('S')
    T = TypeVar('T')
    O = ParamSpec('O')

    class Array(Protocol):
        def __array__(self) -> np.ndarray: ...


    TensorLike = Union[Array, Sequence, float]

    AxesPermutation = List[Union[int, None]]
    '''
    A list of integers or None that represents a permutation of a set of axes. None
    means that a new axis of length 1 is to be created at the corresponding index.
    '''

    class HasDimName(Protocol):
        def __get_dimname__(self) -> str: ...

    DimLike = Union[str,int,Tuple[str,int],HasDimName]
    DimsLike = List[DimLike]

    Dims = List[Union[str,None]]
    Coords = List[Union[npt.NDArray[Any],None]]




    class Function_1Arg(Protocol[T_con, O, T_co]):
        def __call__(self, X: T_con, /, *args: O.args, **kwargs: O.kwargs) -> T_co: ...


    class Function_2Args(Protocol[T_con, U_con, O, T_co]):
        def __call__(self, X: T_con, Y: U_con, /, *args: O.args, **kwargs: O.kwargs) -> T_co: ...


    class Function_3Args(Protocol[T_con, U_con, V_con, O, T_co]):
        def __call__(self, X: T_con, Y: U_con, Z: V_con, /, *args: O.args, **kwargs: O.kwargs) -> T_co: ...


    class BinaryOperator(Protocol[T]):
        def __call__(self, X: T, Y: T) -> T: ...


    class TernaryOperator(Protocol[T]):
        def __call__(self, X: T, Y: T, Z: T) -> T: ...



