I had a big data analysis script based on Monte Carlo simulations and wanted to try to use a GUI for it.

At the moment I have a window (will label better later) that allows the user to enter the desired type of card, number of months and how many packs are open per month. The program then makes a prediction on how many cards of that type would the user have after those months.

For now, I have the program print the result out once the start button is pressed to run it and the window is closed to end the tkinter loop. The goal would be that once the start button is pressed, a new window would open with the result.

However, after the result is printed, the window either freezes completely or closes but the icon still appears loading. My guess is that something is going on with the thread that prevents it from ending once the main loop ends. When I quit, I get this message:

Fatal Python error: PyEval_RestoreThread: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)

Python runtime state: initialized

Here is the full script:


#This is a Python code
#I have been doing this in my work breaks, so don't take it as fully finished

import numpy as np
import python_settings as st
from tkinter import * 
from tkinter import ttk 
import threading



#I am considering that a person opens 3 packs of 9 cards each every month.

win = Tk()  #Create an instance of tkinter frame or window

canvas1 = Canvas(win, width=400, height=200, relief='raised')
canvas1.pack()

#Create a label
label=Label(win, text= "What type of card?", 
            borderwidth=0, font=('Aerial 20 bold'), fg='HotPink4')
label.configure(font=('helvetica', 14))
canvas1.create_window(200, 25, window=label)


name = StringVar()

n_packs_month = IntVar()
n_packs_month.set('0')

n_months= IntVar()
n_months.set('00')


entry1 = ttk.Entry(win, width=3, font=("Arial",18,""), textvariable = n_packs_month)
entry1.config(foreground='pink')
entry2 = ttk.Entry(win, width=3, font=("Arial",18,""), textvariable = n_months)
entry2.config(foreground='pink')
entry3 = ttk.Entry(win, width=7, font=("Arial",18,""), textvariable = name)
entry3.config(foreground='pink')

canvas1.create_window(260, 100, window=entry1)
canvas1.create_window(210, 100, window=entry2)
canvas1.create_window(100, 100, window=entry3)





#x = input('What type of card? The rarities are common, rare, super, ultra, secret, ultimate or ghost. ')
total_cards = 9
n_people = 1000


def play_yg(): #possabilities when opening yugioh packs

    common_prob = (8/9) #1728
    super_prob = (1/54) #36
    ultra_prob = (1/108) #18
    secret_prob = (1/216) #9
    ultimate_prob = (1/432) #4.5
    ghost_prob = (1/1944)
    rare_prob = 1- (common_prob + super_prob + ultra_prob + secret_prob + ultimate_prob + ghost_prob)

    possible_outcomes = ['common', 'rare', 'super', 'ultra', 'secret', 'ultimate', 'ghost']
    probabilities = [common_prob, rare_prob, super_prob, ultra_prob, secret_prob, ultimate_prob, ghost_prob]

    outcome = np.random.choice(possible_outcomes,total_cards, p=probabilities)
    return outcome
 
def perform_simulation(): #simulation of one person opening packs
    n_times = int(n_packs_month.get()) * int(n_months.get())
   
    common = 0
    rare = 0
    superc = 0
    ultra = 0
    secret = 0
    ultimate = 0
    ghost = 0

    results = np.empty(9, dtype = str)
  
    for n in range(n_times):
        outcome = play_yg()
        results = np.vstack((results, outcome))
        common = round(np.count_nonzero(results == 'common'),0)
        rare = round(np.count_nonzero(results == 'rare'), 0)
        superc = round(np.count_nonzero(results == 'super'), 0)
        ultra = round(np.count_nonzero(results == 'ultra'), 0)
        secret = round(np.count_nonzero(results == 'secret'), 0)
        ultimate = round(np.count_nonzero(results == 'ultimate'), 0)
        ghost = round(np.count_nonzero(results == 'ghost'),0)
        
    return common, rare, superc, ultra, secret, ultimate, ghost, n_times

list1 = [] 
def everyone(): # simulation of a bunch of people opening packs and averaging their outcomes
    
    receive = 0
    results = 0
    x = name.get()
    
    for n in range(n_people):
        if x == 'common':
            receive = perform_simulation()[0]
        elif x == 'rare':
             receive = perform_simulation()[1]
        elif x == 'super':
             receive = perform_simulation()[2]
        elif x == 'ultra':
             receive = perform_simulation()[3]
        elif x == 'secret':
             receive = perform_simulation()[4]
        elif x == 'ultimate':
             receive = perform_simulation()[5]
        elif x == 'ghost':
             receive = perform_simulation()[6]
        
        results = results + receive

        mean = np.around(results/(n+1), 0)
       
        
        list1.append(mean)
        

    return mean, x


def start_everyone_in_bg():
     threading.Thread(target=everyone).start()
     

button2 = ttk.Button(win, text = 'Start', command= lambda: [play_yg(), perform_simulation(), start_everyone_in_bg(),])
canvas1.create_window(200, 180, window=button2)

win.mainloop()
print(everyone())

So I tried using Event but the problem remained. I did some research on the error and there's not much information on it. Some people suggested it might be a memory problem with the python version.

Any ideas on an easy fix? I'm using Python 3.9.12 on macOS Big Sur.

Thanks in advance :)

0

There are 0 best solutions below