While loop continues once more than necessary

Hello,
I am currently working on a tac tac toe project for the first portfolio project and am close to finishing besides one issue.
I have a while loop that checks the game state after each turn to see if anyone has won the game.
This while loop will terminate just one loop after a winner is found.

I just wanted to have a working script first, so the code is probably longer than necessary.
Any help would be very much appreciated, the comments should explain my thought process.
If anyone is willing to pore through my work, I would be extremely grateful.

# ================================|
#                                 |
# Tic Tac Toe Portfolio Project.  |
#                                 |
# ================================|


# Import necessary libraries.
from random import choice # choice is used to select a random choice if a player wants to play against a bot.
import logging # Using logging and sys to debug
import sys




print('Testing, 1, 2, 3...')



# Logging config
logger = logging.getLogger(__name__)
stream_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(stream_handler)
logger.setLevel(logging.INFO)

# Possible outputs for logging debuging
logger.info('message')
logger.log(logging.INFO, 'message')


# This class will be the main object that keeps track of game states.
class PlayGame:


    # __init__ stores the name of the player, the name of the bot and the state of the board.
    def __init__(self):
        self.player = None # This variable will later be updated to the user input.
        self.bot = 'Tacky' # Name of bot
        self.board = [[0, 1, 2], [3, 4, 5], [6, 7, 8]] # Each sublist represents a row on the tic-tac-toe board.
        self.options = [0, 1, 2, 3, 4, 5, 6, 7, 8] # Keeps track of remaining options to place either an 'X' or an 'O'.


    def __repr__(self):
        pass


    # introduction welcomes the player and collects user input for their name.
    def introduction(self):
        intro = """
================================
WELCOME TO TIC TAC TOE!
================================

What is the name of your player?    
"""
        print(intro)
        self.player = input()
        welcome = f'\nHello {self.player}!'
        print(welcome)


    # player_input collects player input.
    def player_input(self):
        print('\nPlease enter an option, corresponding to one of the numbers shown.\n')
        # The current state of the board is printed to show what options are available.
        self.print_board()
        select = int(input()) # select collects user's choice and converts it into an integer.

        # Function is recursively called if user's option is not available.
        if select not in self.options:
            print('\nOption not available.')
            self.player_input()

        # Once the user selects a valid option, a loop searches each cell
        # until it finds the cell value that matches the choice.
        for row in range(len(self.board)):
            for cell in range(len(self.board)):
                if self.board[row][cell] == select:
                    self.board[row][cell] = 'X'
                    # The selected choice is removed from self.options to ensure it
                    # is not picked again.
                    self.options.remove(select)
                    return self.board
                
    
    # tacky_input randomly chooses an available option and updates the board.
    def tacky_input(self):
        print("\nIt is now the Tacky's turn to choose.")
        # Randomly selects choice.
        select = choice(self.options)

        # Updates board in same loop that was used for the user.
        for row in range(len(self.board)):
            for cell in range(len(self.board)):
                if self.board[row][cell] == select:
                    self.board[row][cell] = 'O'
                    # self.options is updated.
                    self.options.remove(select)
                    return self.board

                
    # print_board just prints the board in the arrangement
    # of a tic-tac-toe board.
    def print_board(self):
        print('')
        for row in self.board:
            print(row)


    # The goal of check_winner should be able to see if the use with the assigned letter has
    # the game, based on the orientation of the board (config): rows, columns, diagonals.
    def check_winner(self, letter, config): # For some reason, sometimes the winner is not noticed.
        log = 0 # log keeps track of the current run of letters. If log reaches 3, then the player with that letter wins.
        index = 0 # index keeps track of either each row, column, or diagonal depending on config.
        while index <= len(config)-1: # Stays in loop while index is a useable index of the config.
            for cell in config[index]:
                print(f'Checking if {cell} is equal to the player {letter}.')
                if cell == letter:
                    log += 1 # 1 is added to log to show that the current cell in the config is equal to the letter.
                else:
                    print('\nMoving on to the next index for the board...')
                    log = 0 # log is redefined to 0 to indicate that there was a cell that did not equal the letter.
                    index = index + 1 # 1 is added to index to move on to the next sublist of the config.
                if log == 3: # A log with a value of 3 shows a run of 3 of the letter.
                    print(f'{letter} has WON the game!')
                    self.print_board()
                    return True # return True means a winner was found
        return False
    
    
    # check_rows returns the board as it is already
    # oriented in rows.
    def check_rows(self):
        
        return self.board


    # check_columns creates a new board with the current state of the board, with each sublist containing a column.
    def check_columns(self):

        columns = [] # columns will hold the new board config.
        current_column = [] # Stores the current sublist that we are looping through.
        current_index = 0 # Keeps track of the current index of the sublist we are looping through.
        while len(columns) < 3: # Loop stops once there are three sublists in columns, representing the three columns of the board.
            for row in self.board:
                if current_index > 2: # Loop is broken if current_index is larger than the largest index of cells.
                    break

                # The current cell is appended to the current_column
                current_column.append(row[current_index])
                if len(current_column) == 3: # once the column reached a length of 3, it is appended to the columns config.
                    current_index += 1 # We move onto the next index
                    columns.append(current_column)
                    current_column = [] # current_column is redefined to make room for next column.
        return columns
    

    # check_diagonals creates a new board with the current state of the board, with each sublist containing a diagonal.
    def check_diagonals(self):
        
        diagonals = [] # diagonals will hold the new board config.
        current_diagonal = [] # Stores the current sublist that we are looping through.
        current_index = 0 # Keeps track of the current index of the sublist we are looping through.
        while len(diagonals) < 2: # Loop stops once there are two sublists in diagonals, representing the two diagonals of the board.
            for row in self.board:
                current_diagonal.append(row[current_index]) # The loop begins at the first index for the first row, then the second index for the second row... up until we have
                # visited all of the rows.
                current_index += 1
            diagonals.append(current_diagonal)
            current_diagonal = [] # Once the first diagonal is looped through, it is redefined to an empty list for the second diagonal.
            current_index -= 1 # We update the current index in reverse for the second loop.
            for row in self.board:
                current_diagonal.append(row[current_index])
                current_index -= 1
            diagonals.append(current_diagonal)
        return diagonals
                

    # check_all checks every board iteration for the current state to see if there is a winner.
    def check_all(self):
        checking = [self.check_winner('X', self.check_rows()),
        self.check_winner('O', self.check_rows()),
        self.check_winner('X', self.check_columns()),
        self.check_winner('O', self.check_columns()),
        self.check_winner('X', self.check_diagonals()),
        self.check_winner('O', self.check_diagonals())]
        # Loops through the list of board configs to see if any return True.
        for check in checking:
            if check == True:
                return True
        return False

    # round collects player input checks if there is a winner, collects tacky input and checks if there is a winner.
    # If there is a winner True is returned.
    def round(self):
        self.player_input()
        self.print_board()
        self.check_all()
        if self.check_all() == True:
            return True
        self.tacky_input()
        self.print_board()
        self.check_all()
        if self.check_all() == True:
            return True
        return False
    
        # For some reason, there is one more instance of player input even after the player wins. Unsure why.

        





# =========|
# TESTING  |
# =========|

test_game = PlayGame()
test_game.introduction()
test_game.round() # The first test_game.round() is needed to initiate the while loop.
while test_game.round() != True: # Rounds are played until a winner is found.
    test_game.round()



# DEBUGGING NOTES
# Check loop for checking winner, winner is found 1 round after it should be.