class ILedStringMeta(type):
    """
    Metaclass for the ILedString interface
    """
    def __instancecheck__(cls, instance):
        return cls.__subclasscheck__(type(instance))

    def __subclasscheck__(cls, subclass):
        return hasattr(subclass, 'set_led') and callable(subclass.set_led) and \
               hasattr(subclass, 'fill_leds') and callable(subclass.fill_leds) and \
               hasattr(subclass, 'set_leds_color') and callable(subclass.set_leds_color) and \
               hasattr(subclass, 'set_leds_colors') and callable(subclass.set_leds_colors)

class ILedString(metaclass=ILedStringMeta):
    """
    Interface for an LED string
    """
    def __init__(self, location, length: int):
        """
        Constructor for the ILedString interface
        :param location: the physical location of the LED string on the device
        :param length: the number of LEDs in the string
        """
        self.num_leds = length
        pass
    def set_led(self, color: tuple[int, int, int], index: int):
        """
        Set the colour of a single LED
        :param color: the colour to set the LED to (as a tuple of (r, g, b))
        :param index: the index of the LED to set
        """
        pass
    def fill_leds(self, color: tuple[int, int, int]):
        """
        Sets all LEDs in the string to the same colour
        :param color: the colour to set the LEDs to (as a tuple of (r, g, b))
        """
        pass
    def set_leds_color(self, color: tuple[int, int, int], start_index, end_index, step=1):
        """
        Set the colour of a range of LEDs to a single colour
        :param color: the colour to set the LEDs to (as a tuple of (r, g, b))
        :param start_index: the index of the first LED to set (inclusive)
        :param end_index: the index of the last LED to set (inclusive)
        :param step: the step between LEDs to set
        """
        pass
    def set_leds_colors(self, colors: list[tuple[int, int, int]], start_index=0):
        """
        Set the colour of a range of LEDs to a list of colours.
        If the list of colours is longer than the number of LEDs, the extra colours are ignored.
        :param colors: the list of colours to set the LEDs to (as a list of tuples of (r, g, b))
        :param start_index: the index of the first LED to set (inclusive)
        """
        pass
    def show(self):
        """
        Writes the current LED state to the physical LEDs.
        """
        pass
