Skip to content

Not preserving low level signature metadada #148

@prusse-martin

Description

@prusse-martin

(Sorry if the title is somewhat misleading or I did get some jargon wrong)

In version 5.1.1 methods decorated by decorate created with the decorator lib stopped working with qt(pyqt?) signals that inspect the signature of the connected slot (also tested with 4.0.2 with a slight different error).

Failing snippet:

@decorator
def dummy_decorator(f, *args, **kwargs):
    return f(*args, **kwargs)

 class Foo:
    def __init__(self):
        self.action = QAction()
        self.action.triggered.connect(self.ActionCallbackNoArg)
    @dummy_decorator
    def ActionCallbackNoArg(self):
        pass

foo = Foo()
foo.action.trigger()

This was not an issue in 4.4.2.
While porting our code base to python 3.10 the decorator version also got upgraded, decorator version prior to this was 4.4.2.
We will probably be able to downgrade back for now.

I created a test to reproduce the error.
add_qt_test_patch.txt

Create env and install decorator in editable mode:

conda create -n decorator python=3.6 pyqt
conda activate decorator
pip install --editable .

Test with 4.4.2 (pass):

W:\my\Projects\decorator (master -> origin)
(decorator) λ git checkout -- src/tests/test.py

W:\my\Projects\decorator (master -> origin)
(decorator) λ git checkout 4.4.2
Note: switching to '4.4.2'.
...
HEAD is now at 55a68b5 Updated setup.py [skip CI]

W:\my\Projects\decorator (HEAD detached at 55a68b5)
(decorator) λ patch -i add_qt_test_patch.txt -p 1
patching file src/tests/test.py
Hunk #1 succeeded at 18 with fuzz 1 (offset 6 lines).

W:\my\Projects\decorator (HEAD detached at 55a68b5)
(decorator) λ python src/tests/test.py -v QtActionTestCase.test_qt_decorator_signature_preserving_interaction_methods
test_qt_decorator_signature_preserving_interaction_methods (__main__.QtActionTestCase) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Test with 5.1.1 (fail, at the time of this writing origin/master will also fail):

W:\my\Projects\decorator (HEAD detached at 55a68b5)
(decorator) λ git checkout -- src/tests/test.py

W:\my\Projects\decorator (HEAD detached at 55a68b5)
(decorator) λ git checkout 5.1.1
Previous HEAD position was 55a68b5 Updated setup.py [skip CI]
HEAD is now at ad013a2 Updated changelog and bumped version to 5.1.1

W:\my\Projects\decorator (HEAD detached at ad013a2)
(decorator) λ patch -i add_qt_test_patch.txt -p 1
patching file src/tests/test.py

W:\my\Projects\decorator (HEAD detached at ad013a2)
(decorator) λ python src/tests/test.py -v QtActionTestCase.test_qt_decorator_signature_preserving_interaction_methods
test_qt_decorator_signature_preserving_interaction_methods (__main__.QtActionTestCase) ... Traceback (most recent call last):
  File "w:\my\projects\decorator\src\decorator.py", line 231, in fun
    args, kw = fix(args, kw, sig)
  File "w:\my\projects\decorator\src\decorator.py", line 203, in fix
    ba = sig.bind(*args, **kwargs)
  File "W:\my\envs\decorator\lib\inspect.py", line 2997, in bind
    return args[0]._bind(args[1:], kwargs)
  File "W:\my\envs\decorator\lib\inspect.py", line 2918, in _bind
    raise TypeError('too many positional arguments') from None
TypeError: too many positional arguments

I also was somewhat curious.
"Plain" functions:

>>> plain.ActionCallbackNoArg.__func__.__code__.co_argcount
1
>>> plain.ActionCallbackNoArg.__func__.__code__.co_varnames
('self',)
>>> plain.ActionCallbackAnyArgs.__func__.__code__.co_argcount
1
>>> plain.ActionCallbackAnyArgs.__func__.__code__.co_varnames
('self', 'args', 'kwargs')

Decorated with 4.4.2:

>>> decorated.ActionCallbackNoArg.__func__.__code__.co_argcount
1
>>> decorated.ActionCallbackNoArg.__func__.__code__.co_varnames
('self',)
>>> decorated.ActionCallbackAnyArgs.__func__.__code__.co_argcount
1
>>> decorated.ActionCallbackAnyArgs.__func__.__code__.co_varnames
('self', 'args', 'kwargs')

Decorated with 5.1.1:

>>> decorated.ActionCallbackNoArg.__func__.__code__.co_argcount
0
>>> decorated.ActionCallbackNoArg.__func__.__code__.co_varnames
('args', 'kw')
>>> decorated.ActionCallbackAnyArgs.__func__.__code__.co_argcount
0
>>> decorated.ActionCallbackAnyArgs.__func__.__code__.co_varnames
('args', 'kw')

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions