Returns a generator that produces (x, y) tuples for a rectangle.

    The `left` and `top` arguments are the x and y coordinates for the topleft corner of the square.

    If `filled` is `True`, the interior points are also returned.

    NOTE: The `thickness` argument is not yet implemented.

    >>> list(rectangle(0, 0, 10, 4))
    [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0), (9, 1), (9, 2), (9, 3), (8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3), (0, 3), (0, 2), (0, 1)]
    >>> drawPoints(rectangle(0, 0, 10, 4))
    OOOOOOOOOO
    O,,,,,,,,O
    O,,,,,,,,O
    OOOOOOOOOO
    >>> drawPoints(rectangle(0, 0, 10, 4, filled=True))
    OOOOOOOOOO
    OOOOOOOOOO
    OOOOOOOOOO
    OOOOOOOOOO

def rectangle(left, top, width, height, filled=False, thickness=1):
    """
    Returns a generator that produces (x, y) tuples for a rectangle.

    The `left` and `top` arguments are the x and y coordinates for the topleft corner of the square.

    If `filled` is `True`, the interior points are also returned.

    NOTE: The `thickness` argument is not yet implemented.

    >>> list(rectangle(0, 0, 10, 4))
    [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0), (9, 1), (9, 2), (9, 3), (8, 3), (7, 3), (6, 3), (5, 3), (4, 3), (3, 3), (2, 3), (1, 3), (0, 3), (0, 2), (0, 1)]
    >>> drawPoints(rectangle(0, 0, 10, 4))
    OOOOOOOOOO
    O,,,,,,,,O
    O,,,,,,,,O
    OOOOOOOOOO
    >>> drawPoints(rectangle(0, 0, 10, 4, filled=True))
    OOOOOOOOOO
    OOOOOOOOOO
    OOOOOOOOOO
    OOOOOOOOOO
    """

    # Note: For perfomance, this function does not rely on line() to generate its points.

    if thickness != 1:
        # TODO - should the original left and top be for the thick border, or should thick borders go to the left and above of the left and top coordinates?
        raise NotImplementedError('The pybresenham module is under development and the filled, thickness, and endcap parameters are not implemented. You can contribute at https://github.com/asweigart/pybresenham')

    # Validate arguments
    _checkForIntOrFloat(left)
    _checkForIntOrFloat(top)
    _checkForIntOrFloat(width)
    _checkForIntOrFloat(height)

    left, top, width, height = int(left), int(top), int(width), int(height)

    if width < 1 or height < 1:
        raise PyBresenhamException('width and height must be positive integers')

    # Generate all the points.
    if filled:
        for y in range(top, top + height):
            for x in range(left, left + width):
                yield (x, y)
    else:
        # Note: The `- 1` adjustments here are to prevent duplicate coordinates of the corners being returned.

        # Top side.
        y = top
        for x in range(left, left + width - 1):
            yield (x, y)

        # Right side.
        x = left + width - 1
        for y in range(top, top + height - 1):
            yield (x, y)

        # Bottom side.
        y = top + height - 1
        for x in range(left + width - 1, left, -1):
            yield (x, y)

        # Left side.
        x = left
        for y in range(top + height - 1, top, -1):
            yield (x, y)