4

I am trying to write a function in micropython that takes the name of another function along with arguments and keyword arguments, creates a thread to run that function and automatically exits the thread after the function returns.

The requirement is that the functions that have to be run in this thread might not have arguments/keyword arguments at all or might have them in variable numbers.

So far, I tried:

import _thread

def run_main_software():
    while True:
        pass


def run_function(function, arguments, kwarguments):
    def run_function_thread(function, args, kwargs):
        function(*args, **kwargs)
        _thread.exit()

    _thread.start_new_thread(run_function_thread, (function, arguments, kwarguments))


_thread.start_new_thread(run_main_software, ())


def test_func(thingtoprint):
    print(thingtoprint)

However, when I try to run this, I get:

>>> run_function(test_func, "thingtoprint")
>>> Unhandled exception in thread started by <function run_function_thread at 0x2000fb20>
Traceback (most recent call last):
  File "<stdin>", line 44, in run_function_thread
AttributeError: 'NoneType' object has no attribute 'keys'

If I pass all three arguments:

>>> run_function(test_func, "Print this!", None)
>>> Unhandled exception in thread started by <function run_function_thread at 0x20004cf0>
Traceback (most recent call last):
  File "<stdin>", line 48, in run_function_thread
TypeError: function takes 1 positional arguments but 11 were given

What am I doing wrong here?

Thank you!

EDIT: I tried to run with ("Print this!", ) by suggestion from Giacomo Alzetta and I get this:

>>> run_function(test_func, ("Print this!", ), None)
>>> Unhandled exception in thread started by <function run_function_thread at 0x20003d80>
Traceback (most recent call last):
  File "<stdin>", line 44, in run_function_thread
AttributeError: 'NoneType' object has no attribute 'keys'

EDIT 2: It works if I do this:

>>> run_function(test_func, ("Print this!", ), {})
>>> Print this!

1 Answers1

1

The problem was that in the first case, I was missing a non-optional argument (kwarguments). So **kwargs cannot find any keys to iterate over, resulting in the error:

AttributeError: 'NoneType' object has no attribute 'keys'

In the second case, I explicitly passed None to **kwargs instead of a dictionary. Here, however, it notices that I passed a string to *args rather than a tuple. So *args essentially iterates over the string and take each character in the string as a different argument. This results in:

TypeError: function takes 1 positional arguments but 11 were given

In the third case, I did pass a tuple to *args but the mistake is essentially the same as the first case.

The solution is to pass a tuple to *args and an empty dictionary to **kwargs, like so:

>>> run_function(test_func, ("Print this!", ), {})
>>> Print this!