TLDR: how to check if thread is alive when I used the thread function as a decorator on another function?
I'm creating a GUI using PyQt6 (other recommendations will be accepted in case its a bad choice). my issue is when I click the Connect button, I want to verify the connection thread is not running.
i marked with ** what is relevant due to the long code
So I created self.ecMaster attribute in the main init and im trying to check if ecConnection is up using is_alive method on which is decorated with @threaded.
i'm getting an error : AttributeError: 'function' object has no attribute 'is_alive'
How should i do it properly? Thank you
from threading import thread
import pysoem
import ecAPI as ec
from PyQt6.QtWidgets import *
from PyQt6.QtCore import *
from PyQt6.QtGui import *
class mainWindow(QMainWindow):
exitSignal = Signal() # Define the custom exit signal
def __init__(self,*args, **kwargs):
super().__init__(*args, **kwargs)
self.exitSignal.connect(app.quit)
self.central_widget = QWidget(self)
self.test_widget = QWidget(self)
self.modeSignal = ''
self.operatorSignal = ''
self.setCentralWidget(self.central_widget)
self.connectionWindowLayout()
**self.master = ec.ecMaster()**
def connectButtonClicked(self):
self.connect_button.clickable = False
# here i ran into trouble
**if self.master.ecConnection.is_alive:** # If thread is active
self.master.ecConnection.terminate()
logger.info('Connection thread was already active, terminated')
logger.info('Starting connection thread')
**self.master.ecConnection()** # Start connection thread
time.sleep(0.1)
if __name__ == '__main__':
logger = logging.getLogger(__name__)
logging.getLogger().setLevel(logging.INFO)
app = QApplication(sys.argv)
ModernStyle.apply(app)
window = mainWindow()
window.show()
sys.exit(app.exec())
import pysoem, logging
from threading import Thread
def threaded(fn):
# To use as decorator to make a function call threaded
def wrapper(*args, **kwargs):
thread = Thread(target=fn, args=args, kwargs=kwargs)
thread.start()
return thread
return wrapper
class ecMaster(pysoem.Master):
def __init__(self):
self.connectionSignal = 0
super().__init__()
def findAdapters(self):
nicName = 'PCIe' # Change based on PC --- 'PCIe
network_adapters = pysoem.find_adapters()
for adapter in network_adapters:
if nicName in str(adapter[1]):
networkAdapterID = adapter[0]
self.open(networkAdapterID)
logging.info('Found network adapter\n'+str(networkAdapterID))
return len(network_adapters)>0 # True if found
@threaded
def ecConnection(self):
if self.findAdapters():
print('Searching for EC devices ... ')
self.connectionSignal = self.config_init() # Initilize connection
if self.slaves:
print(f'Found {len(self.slave_list)} devices')
for i,slave in enumerate(self.slaves):
# ven = slave.sdo_read(0x1018, 1)
print(f'Found Device {slave.name},{slave.id},{slave.man}') #,{slave.sdo_read()}
logging.info(f'Found {self.connectionSignal} EC devices')
else:
logging.info('No salves were found')
print('Slaves not found')
else:
logging.warning('No network adapter found')
print('No network adapter found')
Tried to remove wrapper and leave only thread. searched online. Expected the function I decorated to have Thread attribute but could't get it right.
found a solution.
self.master.ecConnection()
isn't a thread but a function. only when running it, it becomes a thread (due to @threaded
decorator).
therefore I added
con_thread = self.master.ecConnection()
and then con_thread was indeed a thread object and I could access con_thread.is_alive()