from typediter.classes import _FrozenTypedIter, Item_T


class TypedTuple_lt( _FrozenTypedIter[Item_T], tuple[Item_T, ...] ):
    """ Class based on tuple, insuring the type safety of its items

    It can be used exactly like the built-in tuple but its items are type-restricted,
    if the type restriction is broken, it fails with a TypeRestrictionError

    Inherits from tuple, but overriding methods:
        - That could insert an incompatible item

    (i) All operations returning a new instance will return a new instance of the built-in tuple,
    not a typed tuple like in the 'complete' version (TypedTuple)

    Attributes
    ----------
    - **i_type**
        The type restriction for the items

    Raises
    ------
    - **typediter.exceptions.TypeRestrictionError**
        Raised by a typed-checked operation to prevent
        it from inserting incompatible items in a type-safe iterable.
        (At instance creation only)
    
    - **typediter.exceptions.InvalidTypeRestrictionError**
        Raised at instance creation if the provided 'i_type':
            - is not a type
    
    - **typediter.exceptions.IterableExpectedError**
        Raised by a type-checked operation if it expected an iterable
        but received something else
        (At instance creation only)
    
    - **other exceptions**
        Any exception that can be raised by a built-in 'tuple'
        for a given operation

    Usage Example
    -------------
    >>> # importing the class
    >>> from typediter import TypedTuple_lt
    >>>
    >>> # creating an instance
    >>> string_tuple = TypedTuple_lt( ('A', 'B', 'C'), i_type=str )
    >>>
    >>> # supports all tuple operations
    >>> new_tuple = string_tuple + ('D', 'E', 'F')
    >>>
    >>> # new instances generated by non-mutating
    >>> # operations are built-ins
    >>> type( new_tuple ) # -> tuple
    >>>
    >>> # trying to insert an incompatible item in the instance,
    >>> # will raise a TypeRestrictionError
    >>> invalid_instance = TypedTuple_lt( ( 1, 2, 3 ), i_type=str ) # will raise TypeRestrictionError
    >>>
    >>> # Remark:
    >>> # Operations returning new instances are not type-restricted:
    >>> mixed_tuple = string_tuple + ( 1, 2, 3 ) # -> will not fail
    """
    __module__ = 'typediter.light' # shorten class 'print' name

    # -------------------- Representation --------------------
    
    def __repr__( self ) -> str:
        typename = self.i_type.__name__
        default_representation = tuple(self)
        return f"(lt)Tuple[{typename}]:{default_representation}"
    
    def __str__( self ) -> str:
        return self.__repr__()
    
    # -------------------- Overriding --------------------
    # -> Everything that could introduce an item of another type

    # nothing is overriten because the instance is immutable