from typediter.classes import _FrozenTypedIter, Item_T

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

    It can be used exactly like the built-in frozenset but its items are type-restricted,
    if the type restriction is broken, it fails with a TypeRestrictionError
    
    Inherits from frozenset, 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 frozenset,
    not a typed frozenset like in the 'complete' version (TypedFrozenset)

    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
            - or is not a hashable 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 'frozenset'
        for a given operation

    Usage Example
    -------------
    >>> # importing the class
    >>> from typediter import TypedFrozenset_lt
    >>>
    >>> # creating an instance
    >>> string_frozenset = TypedFrozenset_lt( ('A', 'B', 'C'), i_type=str )
    >>>
    >>> # supports all frozenset operations
    >>> new_frozenset = string_frozenset & { 'D', 'E', 'F' }
    >>>
    >>> # new instances generated by non-mutating
    >>> # operations are built-ins
    >>> type( new_frozenset ) # -> frozenset
    >>>
    >>> # trying to insert an incompatible item in the instance,
    >>> # will raise a TypeRestrictionError
    >>> invalid_instance = TypedFrozenset_lt( ( 1, 2, 3 ), i_type=str ) # will raise TypeRestrictionError
    >>>
    >>> # Remark:
    >>> # Operations returning new instances are not type-restricted:
    >>> mixed_frozenset = string_frozenset & { 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 = set(self)
        return f"(lt)Frozenset[{typename}]:{default_representation}"
    
    def __str__( self ) -> str:
        return self.__repr__()

    # -------------------- Overriding --------------------
    # -> Everything that could introduce an item of another type

    def copy( self ): # do not type hint return (allows to have correct return type on child classes)
        """ Returns a shallow copy of the typed frozenset """
        new_set = super().copy()
        return self.__class__( new_set, i_type=self.i_type, _skip_type_check=True )