0

I am getting error after running code with below class. Clueless right now, please help

from __future__ import division
from threading import Thread
from pubsub import pub
import os
import glob

########################################################################
class process_csv_thread(Thread):
    """Test Worker Thread Class."""
user2774120
  • 139
  • 3
  • 16
  • 1
    You haven't posted enough code to tell but `TextCtrl has been deleted` i.e. `self.outputMessages` is quite specific. – Rolf of Saxony May 24 '20 at 09:35
  • Hey Thanks.. I just included complete code .. can you please check.. – user2774120 May 24 '20 at 16:57
  • 1
    It's still a collection of code bits but I don't see any `pub.unsubscribe(self.updateDisplay, "update")` in there, So I assume that a message is received after you started closing down. It's difficult to tell. – Rolf of Saxony May 24 '20 at 17:58
  • yes i didnt include pub.unsubscribe.. could that be causing problem ? if yes where should i include this unsubscribe ? Thanks – user2774120 May 24 '20 at 18:12
  • 1
    It's difficult to say without all the code but `onExit` seems like a contender. – Rolf of Saxony May 25 '20 at 07:59
  • 1
    I think the guts of the issue is that you have no method to stop the thread. If you don't stop the thread or `join` it, it will keep processing. Therefore it will attempt to send messages which you haven't `unsubcribed` from. – Rolf of Saxony May 25 '20 at 16:38
  • Hey it worked after I added unsubscribed to onExit :) :).. Thanks alot for helping me on this.. Much appreciate :) – user2774120 May 26 '20 at 05:27

1 Answers1

1

An answer, just for the record. (Bare in mind, I'm no Thread wizard.)
If the Thread is not stopped and you don't unsubscribe from the messages, there is the possibility of messages being received from a still running Thread, which will attempt to update a widget that no longer exists.

I've adapted your code to include a Stop method for the Thread.
I also join the thread to ensure that it has terminated, before destroying the GUI.
Obviously, this Thread is simply spinning, you would need to ensure that a working Thread has a means of checking the running variable.

Thread code process_csv_class.py

from __future__ import division
from threading import Thread
from pubsub import pub
import os
import glob
import time

########################################################################
class process_csv_thread(Thread):
    """Test Worker Thread Class."""

    #----------------------------------------------------------------------
    def __init__(self,csv_path,rnti_value):
        """Init Worker Thread Class."""
        self.csv_path = csv_path
        self.rnti_value = rnti_value

        Thread.__init__(self)
        self.running = True
        self.start()    # start the thread i.e. run()

    #----------------------------------------------------------------------
    def run(self):
        all_files_list = glob.glob(self.csv_path+'/*.csv')
        output_excel_file='Parsed_output.xlsx'
        os.chdir(self.csv_path)
        pub.sendMessage("update", msg="Currently loading")
        while self.running == True:
            time.sleep(1)
            pub.sendMessage("update", msg="Processing files")
        pub.sendMessage("finish", msg="Thread Stopped")
        pub.sendMessage("finish", msg="Processing Terminated")

    def stop(self):
        self.running = False

Main program:

import time
import wx
import os
import configparser

from pubsub import pub

#from extract_class import TestThread
from process_csv_class import process_csv_thread

########################################################################
class MyForm(wx.Frame):

    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Nokia 5G TTI Parser",size=(560,460))

        # Add a panel so it looks the correct on all platforms

        self.config = configparser.ConfigParser()
        self.config.read("config_setup.ini")

        panel = wx.Panel(self, wx.ID_ANY)

        self.load_csv_btn=load_csv_btn= wx.Button(panel, label="Load 5G TTI CSV")
        load_csv_btn.Bind(wx.EVT_BUTTON, self.selectLogsFolder)

        self.def_opening_text = wx.TextCtrl ( panel, size = (122, 17),value = "Default Load Location:",style = wx.TE_READONLY | wx.NO_BORDER | wx.TE_CENTRE )
        self.def_opening_location = wx.TextCtrl ( panel, size = (300, -1),value = self.config.get('PrevConfig','defaultLoad') )

        self.process_btn=process_btn= wx.Button(panel, label="Process CSV Files")
        process_btn.Bind(wx.EVT_BUTTON, self.processCSVs)

        self.chart_btn=chart_btn= wx.Button(panel, label="Generate Chart Slides")
        chart_btn.Bind(wx.EVT_BUTTON, self.generateSlides)

        self.rnti_value = wx.TextCtrl ( panel, size = (45, -1),value = "RNTI:",style = wx.TE_READONLY | wx.NO_BORDER | wx.TE_LEFT )
        self.rnti_value_var = wx.TextCtrl(panel,value=self.config.get('PrevConfig','rnti_value_default'))

        self.outputMessages = wx.TextCtrl(parent = panel, id = -1, size = (530, 200), style = wx.TE_MULTILINE)

        self.load_fold_btn=load_fold_btn= wx.Button(panel, label="Results Folder")
        load_fold_btn.Bind(wx.EVT_BUTTON, self.LoadFold)

        self.exit_btn=exit_btn= wx.Button(panel, label="Exit")
        exit_btn.Bind(wx.EVT_BUTTON, self.onExit)

        self.about_btn=about_btn= wx.Button(panel, label="About")
        about_btn.Bind(wx.EVT_BUTTON, self.onAbout)

        topSizer = wx.BoxSizer(wx.VERTICAL)

        load_sizer = wx.BoxSizer(wx.HORIZONTAL)
        load_sizer.Add(load_csv_btn, 0, wx.ALL, 5)
        load_sizer.Add(self.def_opening_text, 0, wx.ALL, 8)
        load_sizer.Add(self.def_opening_location, 0, wx.ALL, 5)

        process_csv_sizer = wx.BoxSizer(wx.HORIZONTAL)
        process_csv_sizer.Add(process_btn, 0, wx.ALL|wx.EXPAND, 5)
        process_csv_sizer.Add(chart_btn, 0, wx.ALL|wx.EXPAND, 5)

        rnti_val_sizer = wx.BoxSizer(wx.HORIZONTAL)
        rnti_val_sizer.Add(self.rnti_value, 0, wx.ALL|wx.EXPAND, 5)
        rnti_val_sizer.Add(self.rnti_value_var, 0, wx.ALL|wx.EXPAND, 5)

        display_msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
        display_msg_sizer.Add(self.outputMessages, 0, wx.ALL, 5)

        exit_row_sizer = wx.BoxSizer(wx.HORIZONTAL)
        exit_row_sizer.Add(self.load_fold_btn, 0, wx.ALL, 5)
        exit_row_sizer.Add(self.exit_btn, 0, wx.ALL, 5)
        exit_row_sizer.Add(self.about_btn, 0, wx.ALL, 5)

        topSizer.Add(load_sizer, 0, wx.LEFT)
        #topSizer.Add(extract_sizer, 0, wx.RIGHT)
        topSizer.Add(process_csv_sizer, 0, wx.RIGHT)
        topSizer.Add(rnti_val_sizer, 0, wx.RIGHT)
        topSizer.Add(display_msg_sizer, 0, wx.CENTER)
        topSizer.Add(exit_row_sizer, 0, wx.RIGHT)


        panel.SetSizer(topSizer)

        # create a pubsub receiver
        pub.subscribe(self.updateDisplay, "update")
        pub.subscribe(self.ThreadStopped, "finish")

        self.updateDisplay("Please load csv file")

    #----------------------------------------------------------------------
    def updateDisplay(self, msg):
        """
        Receives data from thread and updates the display
        """
        self.outputMessages.write("\n>>>%s" % str(msg))
        print("\n>>>%s" % str(msg))

    #----------------------------------------------------------------------
    def ThreadStopped(self, msg):
        """
        Receives finish from thread and updates the display
        """
        self.outputMessages.write("\n>>>%s" % str(msg))
        print("\n>>>%s" % str(msg))

    def selectLogsFolder(self, event):
        openDirDialog = wx.DirDialog(self,"Choose a directory:",size=(300,400),style=wx.DD_DEFAULT_STYLE)
        openDirDialog.SetPath(self.def_opening_location.GetValue())
        openDirDialog.ShowModal()
        self.csv_folder = openDirDialog.GetPath()
        self.updateDisplay("File Location: "+self.csv_folder)

        self.def_opening_location.SetValue(self.csv_folder)
        openDirDialog.Destroy()


    def processCSVs(self, event):
        try:

            self.pst = process_csv_thread(self.csv_folder,self.rnti_value_var.GetValue())

        except:
            self.updateDisplay("Error: Please check if CSV File is loaded")

    def generateSlides(self, event):

        try:
            cqi_sinr_thread(self.csv_folder,self.cells_list_input.GetValue(),self.rnti_value_var.GetValue())
        except:
            self.updateDisplay("Error: Please check if CSV File is loaded")


    def LoadFold(self, event):
        try:
            os.startfile(os.path.dirname(self.csv_folder))
        except:
            self.updateDisplay("Error: First Load File ")


    def onExit(self, event):

        try:
            self.pst.stop()
            self.pst.join()
        except:
            pass
        pub.unsubscribe(self.updateDisplay, "update")
        pub.unsubscribe(self.ThreadStopped, "finish")
        wx.GetApp().Yield()
        time.sleep(4)

        #self.config.set('PrevConfig', 'CellsList', self.cells_list_input.GetValue())
        self.config.set('PrevConfig', 'rnti_value_default', self.rnti_value_var.GetValue())
        self.config.set('PrevConfig', 'defaultLoad', self.def_opening_location.GetValue())
        with open('config_setup.ini', 'w') as configfile:
            self.config.write(configfile)
        configfile.close()
        self.Close()

    def onAbout(self, event):
        info = wx.AboutDialogInfo()
        info.Name = "KPI Parser"
        info.Version = "v13.0"
        info.AddDeveloper("***an \n**nan.**sir@*****.com")
        wx.AboutBox(info)

#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm()
    frame.Show()
    app.MainLoop()

config_setup.ini file

[PrevConfig]
defaultload = /home/rolf
rnti_value_default = abc
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60