Skip to content

updater

chessapp.controller.updater.Updater

Bases: LogModule

Update the ChessTree from the sources folder.

Source code in chessapp\controller\updater.py
class Updater(LogModule):
    """ Update the ChessTree from the sources folder.
    """

    def __init__(self, app, tree: ChessTree):
        """ initialize the Updater with the action "Update Openings" which updates the ChessTree from the sources folder.

        Args:
            app (ChessApp): the main application
            tree (ChessTree): the ChessTree to update
        """
        super().__init__(app, "Update", [create_method_action(
            app, "Update Openings", self.update_openings)])
        self.tree = tree
        self.app = app

    def update_openings(self):
        """ update the ChessTree from the sources folder.
        """
        self.log_message("updating...")
        for key in SourceType._member_map_:
            path = join(get_openings_folder(), "sources", key)
            Path(path).mkdir(parents=True, exist_ok=True)
            import_pgn_from_folder_path(self.app, self.tree, SourceType.from_str(
                key), path, self.about_to_close, False)
        self.log_message("updating done")

__init__(app, tree)

initialize the Updater with the action "Update Openings" which updates the ChessTree from the sources folder.

Parameters:

Name Type Description Default
app ChessApp

the main application

required
tree ChessTree

the ChessTree to update

required
Source code in chessapp\controller\updater.py
def __init__(self, app, tree: ChessTree):
    """ initialize the Updater with the action "Update Openings" which updates the ChessTree from the sources folder.

    Args:
        app (ChessApp): the main application
        tree (ChessTree): the ChessTree to update
    """
    super().__init__(app, "Update", [create_method_action(
        app, "Update Openings", self.update_openings)])
    self.tree = tree
    self.app = app

update_openings()

update the ChessTree from the sources folder.

Source code in chessapp\controller\updater.py
def update_openings(self):
    """ update the ChessTree from the sources folder.
    """
    self.log_message("updating...")
    for key in SourceType._member_map_:
        path = join(get_openings_folder(), "sources", key)
        Path(path).mkdir(parents=True, exist_ok=True)
        import_pgn_from_folder_path(self.app, self.tree, SourceType.from_str(
            key), path, self.about_to_close, False)
    self.log_message("updating done")

Source

from chessapp.model.chesstree import ChessTree
from chessapp.model.sourcetype import SourceType
from pathlib import Path
from chess import Board, IllegalMoveError
from chess.pgn import read_game
import io
from chessapp.model.move import Move
from chessapp.view.module import LogModule, create_method_action
from os.path import join, isfile, isdir
from chessapp.util.paths import get_openings_folder
from chessapp.model.node import Node
from os import listdir
from chessapp.util.fen import get_reduced_fen_from_board


class Updater(LogModule):
    """ Update the ChessTree from the sources folder.
    """

    def __init__(self, app, tree: ChessTree):
        """ initialize the Updater with the action "Update Openings" which updates the ChessTree from the sources folder.

        Args:
            app (ChessApp): the main application
            tree (ChessTree): the ChessTree to update
        """
        super().__init__(app, "Update", [create_method_action(
            app, "Update Openings", self.update_openings)])
        self.tree = tree
        self.app = app

    def update_openings(self):
        """ update the ChessTree from the sources folder.
        """
        self.log_message("updating...")
        for key in SourceType._member_map_:
            path = join(get_openings_folder(), "sources", key)
            Path(path).mkdir(parents=True, exist_ok=True)
            import_pgn_from_folder_path(self.app, self.tree, SourceType.from_str(
                key), path, self.about_to_close, False)
        self.log_message("updating done")


def import_from_file(app, tree: ChessTree, file_path: str | Path, source: SourceType, about_to_close, count_frequency: bool = False):
    """import lines from a pgn file into the ChessTree


    Args:
        app (ChessApp): the main apllication
        tree (ChessTree): the ChessTree to import into
        file_path (str | Path): the path to the pgn file
        source (SourceType): the source of the moves
        about_to_close (callable): callable that returns True if the module closes
        count_frequency (bool, optional): Defaults to False. if True, the frequency of the moves will be counted
    """
    app.show_status_message(
        "importing pgn from file \"" + file_path + "\"")
    pgn = ""
    with open(file_path, "r", encoding="utf-8") as file:
        pgn = file.read()
    import_pgn(app, tree, pgn, source, about_to_close, count_frequency)


def import_pgn_from_folder_path(app, tree, source: SourceType, folder_path: str, about_to_close, count_frequency: bool = False):
    """import all .pgn files from a folder into the ChessTree

    Args:
        app (ChessApp): the main application
        tree (ChessTree): the ChessTree to import into
        source (SourceType): the source of the moves
        folder_path (str): the path to the folder
        about_to_close (_type_): callable that returns True if the module closes
        count_frequency (bool, optional): Defaults to False. if True, the frequency of the moves will be counted
    """
    for name in listdir(folder_path):
        path: str = join(folder_path, name)
        if isdir(path):
            import_pgn_from_folder_path(
                app, tree, source, path, about_to_close, count_frequency)
        elif isfile(path) and path.endswith(".pgn"):
            import_from_file(app, tree, path, source,
                             about_to_close, count_frequency)


def import_pgn(app, tree: ChessTree, pgn: str, source: SourceType, about_to_close, count_frequency: bool = False):
    """ import a pgn string into the ChessTree

    Args:
        app (ChessApp): the main application
        tree (ChessTree): the ChessTree to import into
        pgn (str): the pgn string
        source (SourceType): the source of the moves
        about_to_close (_type_): callable that returns True if the module closes
        count_frequency (bool, optional): Defaults to False. if True, the frequency of the moves will be counted
    """
    lines = extract_lines(pgn, about_to_close)
    for line in lines:
        app.show_status_message("found line: " + str(line))
        board = Board()
        for san in line:
            fen = get_reduced_fen_from_board(board)
            tree.assure(fen)
            try:
                board.push_san(san)
            except IllegalMoveError:
                print(
                    "cannot perform board.push_san(san) because an illegal move was performed")
                return
            move = Move(tree, san, get_reduced_fen_from_board(
                board), source=source)
            equivalent_move = tree.get(fen).get_equivalent_move(move)
            if equivalent_move == None:
                tree.get(fen).add(move)
                equivalent_move = move
            elif equivalent_move.source.value < source.value:
                equivalent_move.source = source
            if count_frequency:
                equivalent_move.frequency += 1
        fen = get_reduced_fen_from_board(board)
        tree.assure(fen)


def extract_lines_from_node(base_line: list[str], board: Board, node: Node, about_to_close):
    """ extract all lines from a node

    Args:
        base_line (list[str]): the base line is a list of moves that was played before to reach this specific board state
        board (Board): the board having the specific board state and all the desired variations
        node (Node): the node that represents the board state
        about_to_close (callable): callable that returns True if the module closes

    Returns:
        list[list[str]]: list of lines (variations) of chess moves extracted from the board
    """
    move_line: list[str] = base_line.copy()
    move_line.append(board.san(node.move))
    if len(node.variations) == 0:
        return [move_line]
    board.push(node.move)
    lines = []
    for n in node.variations:
        if about_to_close():
            break
        for line in extract_lines_from_node(move_line, board, n, about_to_close):
            if about_to_close():
                break
            lines.append(line)
    board.pop()
    return lines


def extract_lines(pgn: str, about_to_close):
    """ extract all lines from a pgn string

    Args:
        pgn (str): the pgn string
        about_to_close (callable): callable that returns True if the module closes

    Returns:
        list[list[str]]: list of lines (variations) of chess moves extracted from the pgn string
    """
    input_str = io.StringIO(pgn)
    game = read_game(input_str)
    lines = []
    while game != None and not about_to_close():
        for node in game.variations:
            for line in extract_lines_from_node([], Board(), node, about_to_close):
                lines.append(line)
        game = read_game(input_str)
    return lines