diff --git a/pybind11_stubgen/__init__.py b/pybind11_stubgen/__init__.py index 2e96bec..02adaed 100644 --- a/pybind11_stubgen/__init__.py +++ b/pybind11_stubgen/__init__.py @@ -32,6 +32,7 @@ FixMissing__all__Attribute, FixMissing__future__AnnotationsImport, FixMissingEnumMembersAnnotation, + FixMissingFieldDocString, FixMissingFixedSizeImport, FixMissingImports, FixMissingNoneHashFieldAnnotation, @@ -270,6 +271,7 @@ class Parser( FixPEP585CollectionNames, FixTypingTypeNames, FixScipyTypeArguments, + FixMissingFieldDocString, FixMissingFixedSizeImport, FixMissingEnumMembersAnnotation, OverridePrintSafeValues, diff --git a/pybind11_stubgen/parser/mixins/fix.py b/pybind11_stubgen/parser/mixins/fix.py index 595c15e..57ade35 100644 --- a/pybind11_stubgen/parser/mixins/fix.py +++ b/pybind11_stubgen/parser/mixins/fix.py @@ -964,6 +964,27 @@ def handle_class_member( return result +class FixMissingFieldDocString(IParser): + """Extracts docstrings for `def_property_readonly_static` and `def_property_static`.""" + + def handle_class_member( + self, path: QualifiedName, class_: type, obj: Any + ) -> Docstring | Alias | Class | list[Method] | Field | Property | None: + result = super().handle_class_member(path, class_, obj) + + # `ParserDispatchMixin.handle_class_member` classifies static properties as `Field` instead of `Property`. + if isinstance(result, Field): + obj2 = class_.__dict__[path[-1]] + doc = getattr(obj2, "__doc__", None) + + # If the current item is a static property, `obj` contains the fully resolved value, + # but `obj2` contains a `pybind11_builtins.pybind11_static_property` proxy object. + # In Python 3.12+, this proxy object has a `__doc__` attribute. + if obj is not obj2 and isinstance(doc, str): + result.attribute.doc = Docstring(doc) + return result + + class FixMissingFixedSizeImport(IParser): def parse_annotation_str( self, annotation_str: str diff --git a/pybind11_stubgen/printer.py b/pybind11_stubgen/printer.py index cb1bf90..2361500 100644 --- a/pybind11_stubgen/printer.py +++ b/pybind11_stubgen/printer.py @@ -166,7 +166,10 @@ def print_attribute(self, attr: Attribute) -> list[str]: if attr.value is not None and self.print_value_comments: parts.append(f" # value = {self.print_value(attr.value)}") - return ["".join(parts)] + result = ["".join(parts)] + if attr.doc: + result.extend(self.print_docstring(attr.doc)) + return result def print_argument(self, arg: Argument) -> str: parts = [] diff --git a/pybind11_stubgen/structs.py b/pybind11_stubgen/structs.py index 79ad65c..7669066 100644 --- a/pybind11_stubgen/structs.py +++ b/pybind11_stubgen/structs.py @@ -108,6 +108,7 @@ class Attribute: name: Identifier value: Value | None annotation: Annotation | None = field_(default=None) + doc: Docstring | None = field_(default=None) @dataclass diff --git a/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi b/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi index f19453b..e47254e 100644 --- a/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.11/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi @@ -29,7 +29,13 @@ class WithPropDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ @@ -61,7 +67,13 @@ class WithGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ @property def def_property(self) -> int: """ @@ -84,7 +96,13 @@ class WithPropAndGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ diff --git a/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi b/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi index f19453b..e47254e 100644 --- a/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.12/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi @@ -29,7 +29,13 @@ class WithPropDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ @@ -61,7 +67,13 @@ class WithGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ @property def def_property(self) -> int: """ @@ -84,7 +96,13 @@ class WithPropAndGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ diff --git a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/properties.pyi b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/properties.pyi index f19453b..e47254e 100644 --- a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/properties.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-use-type-var/demo/_bindings/properties.pyi @@ -29,7 +29,13 @@ class WithPropDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ @@ -61,7 +67,13 @@ class WithGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ @property def def_property(self) -> int: """ @@ -84,7 +96,13 @@ class WithPropAndGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ diff --git a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi index f19453b..e47254e 100644 --- a/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi +++ b/tests/stubs/python-3.12/pybind11-v2.13/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi @@ -29,7 +29,13 @@ class WithPropDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ @@ -61,7 +67,13 @@ class WithGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ @property def def_property(self) -> int: """ @@ -84,7 +96,13 @@ class WithPropAndGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ diff --git a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/properties.pyi b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/properties.pyi index e24ef6a..eb99e55 100644 --- a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/properties.pyi +++ b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-use-type-var/demo/_bindings/properties.pyi @@ -37,7 +37,13 @@ class WithPropDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ @@ -71,7 +77,13 @@ class WithGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ @property def def_property(self) -> int: """ @@ -94,7 +106,13 @@ class WithPropAndGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ diff --git a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi index e24ef6a..eb99e55 100644 --- a/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi +++ b/tests/stubs/python-3.12/pybind11-v3.0/numpy-array-wrap-with-annotated/demo/_bindings/properties.pyi @@ -37,7 +37,13 @@ class WithPropDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """ @@ -71,7 +77,13 @@ class WithGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + getter doc token + """ @property def def_property(self) -> int: """ @@ -94,7 +106,13 @@ class WithPropAndGetterSetterDoc: """ def_property_readonly_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ def_property_static: typing.ClassVar[int] = 0 + """ + prop doc token + """ @property def def_property(self) -> int: """