python-3.xheapq

Python heapq pushed task is missing a parameter


With the below declared class:

runner_pq = []
p_count = 0

class RunThread(threading.Thread):
    def __init__(self, func, **kwargs):
        self._func = func
        self._kwargs = kwargs
        threading.Thread.__init__(self, name="IVU")

    def run(self):
        self._func(**self._kwargs)

And, the below function to push the task to be run into the heapq runner_pq:

def add_task_runner(deviceName, actionTime, func, args):
    global runner_pq
    global p_count
    t = RunThread(func, **args)
    t.name = deviceName
    task = [actionTime, p_count, t]
    p_count += 1
    heapq.heappush(runner_pq, task)

The below call is made to add the task to the runner_pq:

RunThread.add_task_runner(device.name, device.getTime(), Tool.send_instructions, {'device': device})

To run the task the below call is used:

priority, p_count, task = heapq.heappop(runner_pq)

However, the below error is seen:

Exception in thread Device1:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/home/user/ivu/robot/libraries/RunThread.py", line 41, in run
    self._func(**self._kwargs)
TypeError: send_instructions() missing 1 required positional argument: 'device'
20221031 06:10:57.005 - FAIL - OSError: [Errno 5] Input/output error
20221031 06:10:57.005 - DEBUG - Traceback (most recent call last):
  None
20221031 06:10:57.006 - INFO - +--- END KW: Interactive.Run Events (6126064)

Could you plz review and let me know why the needed 'device' parameter is missing from the "send_instructions()" call?

PS: This was working with python2.7 where the above task (to be pushed) assignment under add_task_runner() was: "task = [actionTime, t]" & reversely, when the task was being popped, this assignment was used: "priority, task = heapq.heappop(runner_pq)". I suspect something in the new python3 param sequence assignment is not correct.


Solution

  • The problem was under the "init" function of the class. Specifically: "threading.Thread.init(self, name="IVU")" needed to be repositioned before the assignments of the class data parameters:

    class RunThread(threading.Thread):
    def __init__(self, func, **kwargs):
        threading.Thread.__init__(self, name="IVU")
        self._func = func
        self._kwargs = kwargs
    
    def run(self):
        self._func(**self._kwargs)
    

    This to avoid the class's data parameters be set to None as these were before the change. Not sure if this is a change that python3 introduced compared to python2; likely the case.