0

I am trying to retrieve the evaluation scores of each move from the perspective of white in a PGN file by analyzing the positions using the Stockfish chess engine in Python. I am using the python-chess library to interact with the Stockfish engine.

I am running into an error when trying to analyze the position with the Stockfish engine. The error message is "object NoneType can't be used in 'await' expression" which suggests that something in the expression await engine._position(board) is returning None which is not a valid object for the await statement.

Here's my minimal reporducible example:

import chess
import chess.pgn
import chess.engine
import logging
import asyncio
import numpy as np

logging.basicConfig(filename='debug.log', level=logging.DEBUG)

file_path = r"C:\Users\iftik\Downloads\libase\New folder\ex_game.pgn"
stockfish = r"C:\Users\iftik\Downloads\stockfish\stockfish-windows-2022-x86-64-avx2.exe"

async def get_eval(file_path):
    """
    Function that retrieves the evaluation scores of each move in a PGN file
    by analyzing the position using Stockfish chess engine.
    """
# create an empty numpy array to store evaluation scores    
evaluation_scores = np.array([])
    board = chess.Board()
    transport, engine = await chess.engine.popen_uci(stockfish)
    try:
        with open(file_path, 'r') as file:
            game = chess.pgn.read_game(file)
            # iterate through every move in the game
            for move in game.mainline_moves():
                # make the move on the board
                board.push(move)
                await engine._position(board)
                with await engine.analysis(board) as analysis:
                    async for info in analysis:
                        # don't stop until analysis reaches depth 30
                        if info.get("seldepth", 0) > 30:
                            evaluation_scores = np.append(evaluation_scores, info.get("score").white().cp)
                            break
                #undo the move
                board.pop()
    except Exception as e:
        logging.error("An error occurred while analyzing position: %s", e)
    finally:
        await engine.quit()
    return evaluation_scores

async def main():
    position_evaluations = await get_eval(file_path)
    print(position_evaluations)

asyncio.run(main())

I have tried using a try-except block to handle any errors that occur during the analysis and logging the error message using the logging module. But the error still persists.

I was expecting to be able to analyze the position and retrieve the evaluation scores without any errors. However, the error "object NoneType can't be used in 'await' expression" is preventing me from doing so. I've looked at communicate with stockfish with python and How to Communicate with a Chess engine in Python? and will soon try this to interact with the engine using python stockfish module as suggested by Pranav Hosangadi . I've also look at UCI/XBoard engine communication:Analysing and evaluating a position , but it doesn't talk about analyzing the position for moves I already have based on a game that's already been played in the documentation.

I am looking for any suggestions on how to fix this error and successfully analyze the position with the Stockfish engine. After writing this post I am now thinking about how would I use stockfish.make_moves_from_curent_position() (from stockfish import Stockfish) or stockfish.set_position() from (from stockfish import Stockfish) to retrieve the evaluation scores of each move in a PGN file from the perspective of white. Any help on the logic would be great considering the time I took to write the post.

Here's the the debugging log output from my actual code -- not the minimal reporducible example:

DEBUG:asyncio:Using proactor: IocpProactor
DEBUG:root:Starting main function
DEBUG:root:Getting evaluation scores
DEBUG:root:Opening file
DEBUG:root:Starting iteration over moves
DEBUG:root:Starting Stockfish
DEBUG:chess.engine:<UciProtocol (pid=6840)>: Connection made
DEBUG:chess.engine:<UciProtocol (pid=6840)>: << uci
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> Stockfish 15.1 by the Stockfish developers (see AUTHORS file)
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> id name Stockfish 15.1
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> id author the Stockfish developers (see AUTHORS file)
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> 
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Debug Log File type string default 
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Threads type spin default 1 min 1 max 1024
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Hash type spin default 16 min 1 max 33554432
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Clear Hash type button
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Ponder type check default false
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name MultiPV type spin default 1 min 1 max 500
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Skill Level type spin default 20 min 0 max 20
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Move Overhead type spin default 10 min 0 max 5000
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Slow Mover type spin default 100 min 10 max 1000
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name nodestime type spin default 0 min 0 max 10000
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name UCI_Chess960 type check default false
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name UCI_AnalyseMode type check default false
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name UCI_LimitStrength type check default false
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name UCI_Elo type spin default 1350 min 1350 max 2850
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name UCI_ShowWDL type check default false
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name SyzygyPath type string default <empty>
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name SyzygyProbeDepth type spin default 1 min 1 max 100
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Syzygy50MoveRule type check default true
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name SyzygyProbeLimit type spin default 7 min 0 max 7
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name Use NNUE type check default true
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> option name EvalFile type string default nn-ad9b42354671.nnue
DEBUG:chess.engine:<UciProtocol (pid=6840)>: >> uciok
DEBUG:root:Setting position
DEBUG:chess.engine:<UciProtocol (pid=6840)>: << position startpos moves e2e4
ERROR:root:An error occurred while analyzing position: object NoneType can't be used in 'await' expression
DEBUG:root:Closing Stockfish
DEBUG:chess.engine:<UciProtocol (pid=6840)>: << quit
DEBUG:chess.engine:<UciProtocol (pid=6840)>: Process exited
DEBUG:chess.engine:<UciProtocol (pid=6840)>: Connection lost (exit code: 0, error: None)
DEBUG:root:Starting Stockfish
'''
  • After rummaging around in the [documentation](https://python-chess.readthedocs.io/en/latest/engine.html#chess.engine.SimpleEngine): I found out that you don't need 'engine.position(board)' because 'chess.analysis(board:Board)' sends the entire move stack to the engine. – Iftikhar Ramnandan Jan 21 '23 at 13:59

0 Answers0