Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inspect.signature returns incorrect result on a @staticmethod and a @classmethod #101293

Closed
heckad opened this issue Jan 24, 2023 · 3 comments
Closed
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@heckad
Copy link
Contributor

heckad commented Jan 24, 2023

Bug report

import inspect


def test_1():
    class FooStaticmethod:
        @staticmethod
        def __call__(cls, s, l, t):
            return t

    instance = FooStaticmethod()
    instance(1, 2, 3, 4) # Success call with 4 args

    assert list(inspect.signature(instance).parameters.keys()) == ['cls', 's', 'l', 't']


def test_2():
    class FooClassmethod:
        @classmethod
        def __call__(cls, s, l, t):
            return t

    instance = FooClassmethod()
    instance(1, 2, 3) # Success call with 4 args

    assert list(inspect.signature(instance).parameters.keys()) == ['s', 'l', 't']

def test_3():
    class FooStaticmethod:
        @staticmethod
        def __call__():
            return None

    instance = FooStaticmethod()
    instance()

    assert list(inspect.signature(instance).parameters.keys()) == []

Your environment

CPython versions tested on:

  • Python 3.10.9 (tags/v3.10.9:1dd9be6, Dec 6 2022, 20:01:21) [MSC v.1934 64 bit (AMD64)] on win32
  • Python 3.11.1 (tags/v3.11.1:a7a450f, Dec 6 2022, 19:58:39) [MSC v.1934 64 bit (AMD64)] on win32

Possible fix

The problem is that we are calling _signature_from_callable twice with skip_bound_arg=True.
A simple solution is to call _get_signature_of with skip_bound_arg=False on

sig = _get_signature_of(call)

That fix the test_2 but not the test_1. I need to think about how to do better. I will be glad to your suggestions.

Р.S I would like to submit a pull request.

Linked PRs

@heckad heckad added the type-bug An unexpected behavior, bug, or error label Jan 24, 2023
@hugovk hugovk added the stdlib Python modules in the Lib dir label Jan 24, 2023
@sobolevn
Copy link
Member

I don't think that __call__ should ever be @staticmethod or @classmethod. It is designed to be an instance method. Do you have examples with other methods?

@heckad
Copy link
Contributor Author

heckad commented Jan 28, 2023

It is from pyparsing, Here is the test suite. I want to do this and got a bug in inspect module.

Is there a way to find out which descriptor wrapped a method?

heckad added a commit to heckad/cpython that referenced this issue Mar 9, 2023
heckad added a commit to heckad/cpython that referenced this issue Mar 9, 2023
heckad added a commit to heckad/cpython that referenced this issue Mar 9, 2023
serhiy-storchaka pushed a commit to serhiy-storchaka/cpython that referenced this issue Feb 15, 2024
….Signature.from_callable()

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of methods and
descriptors.

Add tests for numerous types of callables and descriptors.
@serhiy-storchaka
Copy link
Member

serhiy-storchaka commented Feb 15, 2024

__call__() can be an arbitrary callable or descriptor.

This is an interesting issue, and it is larger that what #102564 covers.

  • It does not handle classmethod or statimethod decorated __call__() for types. It is more rare case, but __call__() can be overridden in metaclasses, and this case is supported.
  • Standard type.__call__() calls __new__() and __init__(), which also can be not only pure Python functions.
  • There are more types of callables and descriptors that can be used here: bound methods, partial(), and various builtin methods and descriptors.

#115530 is more general, and supports more different cases.

It does not support all cases. There is an explicit exclusion for builtin methods and descriptors in the current code, and I keep it for now. It can be significantly weakened (allowing to support more weird cases), but this can also break some Cython generated classes, so we should be careful. More general approach would ignore signatures like (*args, **kwargs), but it requires large changes.

serhiy-storchaka added a commit that referenced this issue Mar 1, 2024
…ture.from_callable() (GH-115530)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Mar 1, 2024
….Signature.from_callable() (pythonGH-115530)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
(cherry picked from commit 59167c9)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Mar 1, 2024
….Signature.from_callable() (pythonGH-115530)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
(cherry picked from commit 59167c9)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
serhiy-storchaka added a commit that referenced this issue Mar 1, 2024
…t.Signature.from_callable() (GH-115530) (GH-116197)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
(cherry picked from commit 59167c9)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
serhiy-storchaka added a commit that referenced this issue Mar 1, 2024
…t.Signature.from_callable() (GH-115530) (GH-116198)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
(cherry picked from commit 59167c9)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
woodruffw pushed a commit to woodruffw-forks/cpython that referenced this issue Mar 4, 2024
….Signature.from_callable() (pythonGH-115530)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
adorilson pushed a commit to adorilson/cpython that referenced this issue Mar 25, 2024
….Signature.from_callable() (pythonGH-115530)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
diegorusso pushed a commit to diegorusso/cpython that referenced this issue Apr 17, 2024
….Signature.from_callable() (pythonGH-115530)

Support callables with the __call__() method and types with
__new__() and __init__() methods set to class methods, static
methods, bound methods, partial functions, and other types of
methods and descriptors.

Add tests for numerous types of callables and descriptors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants