Skip to content

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

Closed

Description

@EzioHelios

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?

Activity

  1. EzioHelios commented on Sep 1, 2022

    @EzioHelios
    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): ...
  2. WeilerMarcel commented on Jul 10, 2023

    @WeilerMarcel
    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.

  3. added a commit that references this issue on Jan 8, 2024
    35f402c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions