Home > Software design >  Takes 0 positional arguments but 2 were given, when it is not the case
Takes 0 positional arguments but 2 were given, when it is not the case

Time:05-15

SOLVED, answer below!

Here is the relevant fragment of the code:

def redraw() -> int:
    subprocess.call(['tput', 'reset'])
    cursor.hide()
    print(get_time())
    return 0


def main() -> int:
    """
    Main function
    """
    time_between_updates = 0.5
    signal.signal(signal.SIGWINCH, redraw)

    old = ""
    while True:
        try:
            current = get_time()
            if old != current:
                redraw()
            old = get_time()
            time.sleep(time_between_updates)
        except KeyboardInterrupt:
            cursor.show()
            return 0

And the WEIRD error from the interpreter:

$: python3 .local/my_scripts/pytime

Traceback (most recent call last):
  File "/home/omega/.local/my_scripts/pytime", line 176, in <module>
    main()
  File "/home/omega/.local/my_scripts/pytime", line 169, in main
    time.sleep(time_between_updates)
TypeError: redraw() takes 0 positional arguments but 2 were given

The higlighted line 169: time.sleep(time_between_updates) doesn't even call redraw() and I can confirm all calls to redraw() in the entire file are done with no arguments, consistent with it's definition.

I don't really get what's happening. I'd love if I could get any help on this. Thanks!

Fixed by creating the function:

def redraw_wrapper(signum, frame):
    redraw()

and using that instead of redraw() in the line:

-  signal.signal(signal.SIGWINCH, redraw)
   signal.signal(signal.SIGWINCH, redraw_wrapper)

This way redraw_wrapper is called when SIGWINCH is captured but I can still call redraw manually in any other case.

CodePudding user response:

The culprit line here is:

signal.signal(signal.SIGWINCH, redraw)

Check out the docs here for exactly why, but I'll give you the gist here.

When writing signal handlers, since the interrupt is asynchronous, we need to know where it came from, and also which thread of it comes from (since signals are handled in the main thread), so we need the stack frame.

Additionally, one signal handler could handle multiple signals, all of which share code, but branch at some later point, so we need to also know exactly which signal was called, which we'll refer to as signum.

So, in general, all user defined signal handlers need to take in a signum and frame!

In our case, we don't really care about the stack frame, nor the signum, so all we have to do is change our definition to

def redraw(signum, frame)

and you're good to go!

CodePudding user response:

Change to:

def redraw(signum, frame) -> int:
  • Related