Investigating an ambigous add-on error

There’s an error that has been bothering me for quite some time, but I have no idea how to get rid of it. When I open the editor window, bring up the context menu and press “Paste”, the following error occurs.

Debug info:
Anki 2.1.47 (dc156f34) Python 3.9.6 Qt 5.15.2 PyQt 5.15.4
Platform: Linux
Flags: frz=False ao=True sv=3
Add-ons, last update check: 2021-08-31 09:16:47

Caught exception:
Traceback (most recent call last):
  File "/home/ren/.local/lib/python3.9/site-packages/decorator.py", line 231, in fun
    args, kw = fix(args, kw, sig)
  File "/home/ren/.local/lib/python3.9/site-packages/decorator.py", line 203, in fix
    ba = sig.bind(*args, **kwargs)
  File "/usr/lib/python3.9/inspect.py", line 3062, in bind
    return self._bind(args, kwargs)
  File "/usr/lib/python3.9/inspect.py", line 2983, in _bind
    raise TypeError('too many positional arguments') from None
TypeError: too many positional arguments

This error wasn’t present in earlier Anki versions. It started occurring maybe around version 2.1.44, but I can’t say for sure.

It is related to an add-on I’m developing, but no add-on code is shown in the traceback, which leaves me clueless. If instead of using the context menu I press Ctrl+v instead, this error doesn’t occur.

I tried cleaning the code to pin-point the issue. Most likely it triggers by a snippet like this:

from anki.hooks import wrap
from aqt.editor import EditorWebView

def paste_event(self: EditorWebView):
    print('wrap works?')
    pass

EditorWebView.onPaste = wrap(EditorWebView.onPaste, paste_event, 'after')

or like this:

from anki.hooks import wrap
from aqt.editor import EditorWebView


def paste_event(self: EditorWebView, _old):
    print('wrap works?')
    return _old(self)


EditorWebView.onPaste = wrap(EditorWebView.onPaste, paste_event, 'around')

Is there a way to fix this?

I think the signature must be def paste_event(self, _old).

1 Like

Yes, you’re right. I’ll edit the example in the opening post. Unfortunately, it doesn’t fix the error.

1 Like

I’m guessing it’s a similar issue to what @no_arg_trigger tries to prevent. If you bisect the change history, maybe the cause will become more apparent. Or you could just submit a PR that adds a hook instead of monkey patching. :slight_smile:

1 Like

Maybe using the recently added editor_did_paste hook instead could work:

1 Like

At first I wanted to try editor_did_paste, but it gets called after EditorWebView._processMime and there’s no way to tell whether the event got triggered by drag-and-drop or copy-paste. For my purposes, only a new hook could solve this.

As a workaround, you can decorate onPaste() function with a decorator that ignores an argument (False, which is the default value of checked argument of QAction::triggered signal) that is passed to the function only when it is called from the context menu.

from functools import wraps
from aqt.editor import EditorWebView


def my_decorator(f):
    @wraps(f)
    def wrapper(*args):
        # args[0]: EditorWebView instance

        # Do something here

        # discard args[1](=False) when called from context menu
        return f(args[0])

    return wrapper


EditorWebView.onPaste = my_decorator(EditorWebView.onPaste)
3 Likes

Thank you for the workaround! I’m going to apply it until I figure out how to submit a new hook.

1 Like

I have created a pull request with the new hook.

1 Like