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

stubgenc.py does not generate correct lines for staticmethods #13574

Closed
EzioHelios opened this issue Sep 1, 2022 · 2 comments · Fixed by #14934
Closed

stubgenc.py does not generate correct lines for staticmethods #13574

EzioHelios opened this issue Sep 1, 2022 · 2 comments · Fixed by #14934
Labels
bug mypy got something wrong topic-stubgen

Comments

@EzioHelios
Copy link

Bug Report

When I use stubgen to generate stub file for a pybind11 module

klass
.def_static("some_static_method", &A::some_static_method,
    R"#(None)#", py::arg("a"), py::arg("b")
    );

where pybind11::class_ klass is bound to C++ class A

the result line is like:

class A:
    def some_static_method(self, *args, **kwargs): ...

which should be like:

class A:
    @static_method
    def some_static_method(a: T, b: T): ...

The issue here is related to a pybind11 discussion: [https://github.com/pybind/pybind11/issues/2403].
which says "a static method of class Foo, Foo.dict['f_static'] points to the static method decorator around the function object instead, not the function object itself"

So, I temporarily fixed this issue for my own project by appending a staticmethod checker right after the is_c_classmethod in file stubgenc.py:

def is_c_staticmethod(obj: object) -> bool:
    return type(obj).__name__ in ('staticmethod')
def generate_c_type_stub(module: ModuleType,
                         class_name: str,
                         obj: type,
                         output: List[str],
                         imports: List[str],
                         sigs: Optional[Dict[str, str]] = None,
                         class_sigs: Optional[Dict[str, str]] = None) -> None:
                ...
                if is_c_classmethod(value):
                    methods.append('@classmethod')
                    self_var = 'cls'
                elif is_c_staticmethod(value):
                    methods.append('@staticmethod')
                    value = value.__func__
                    self_var = None
                else:
                    self_var = 'self'
                ...

The result turns out correct with my pybind11 code. But I guess it may not work for other conditions?

@EzioHelios EzioHelios added the bug mypy got something wrong label Sep 1, 2022
@EzioHelios
Copy link
Author

For overloaded static methods the @staticmethod decorator is added to the output only once at the top, because multiple overloads are inferred in value.__func__ and their stubs appended in a loop in function generate_c_function_stub:

class A:
    @staticmethod
    @overload
    def some_static_method(a: A1, b: B1): ...
    @overload
    def some_static_method(a: A2, b: B2): ...
    @overload
    def some_static_method(a: A3, b: B3): ...

Passing an additional decorator string argument to generate_c_function_stub, and use it in that loop can fix this problem:

class A:
    @overload
    @staticmethod
    def some_static_method(a: A1, b: B1): ...
    @overload
    @staticmethod
    def some_static_method(a: A2, b: B2): ...
    @overload
    @staticmethod
    def some_static_method(a: A3, b: B3): ...

@WeilerMarcel
Copy link
Contributor

I created #14934 to fix this issue, but he pull request seems to have gone cold. I don't get any response from the reviewers and I can't merge it since I don't have the necessary permissions. How should I proceed? I would like to have this bug fixed.

hauntsaninja pushed a commit that referenced this issue Jan 8, 2024
Fixes #13574

This PR fixes the generation of type hints for static methods of
pybind11 classes. The code changes are based on the suggestions in
#13574.

The fix introduces an additional check if the property under inspection
is of type `staticmethod`. If it is, the type information is read from
the staticmethod's `__func__` attribute, instead of the staticmethod
instance itself.

I added a test for C++ classes with static methods bound using pybind11.
Both, an overloaded and a non-overloaded static method are tested.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-stubgen
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants