Skip to content

Add docstrings for static fields and properties#308

Open
markuspi wants to merge 4 commits intopybind:mainfrom
markuspi:attribute-docstrings
Open

Add docstrings for static fields and properties#308
markuspi wants to merge 4 commits intopybind:mainfrom
markuspi:attribute-docstrings

Conversation

@markuspi
Copy link
Copy Markdown

This PR extracts docstrings from static fields defined via def_property_readonly_static and def_property_static.
This is based on the observation that the docstring for these fields is reachable from Python:

>>> demo._bindings.properties.WithPropDoc.def_property_readonly_static
0
>>> demo._bindings.properties.WithPropDoc.__dict__['def_property_readonly_static']
<pybind11_builtins.pybind11_static_property object at 0x7bd623d73a70>
>>> demo._bindings.properties.WithPropDoc.__dict__['def_property_readonly_static'].__doc__
'prop doc token'

For each Field detected by pybind11-stubgen, FixMissingFieldDocString checks whether __dict__[...] is different from obj, which should only be the case for static properties. It then tries to use the dcostring in __doc__.

Version compatibility

This approach requires cpython 3.12+ as it relies on python/cpython#23205 and pybind11 2.10.1+ due to pybind/pybind11#4168

@markuspi markuspi marked this pull request as ready for review April 21, 2026 10:06
self, path: QualifiedName, class_: type, obj: Any
) -> Docstring | Alias | Class | list[Method] | Field | Property | None:
result = super().handle_class_member(path, class_, obj)
if isinstance(result, Field):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any specific reason static properties fall under Field in the class processor? Without too much in-depth analysis, this looks like a bug that we are trying to circumvent here.

Copy link
Copy Markdown
Author

@markuspi markuspi Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess since class-level/static properties don't really exist in plain python, pybind11-stubgen's Property might not be suited since it is rendered using @property. So Field might be the next-best choice.

ParserDispatchMixin._iter_module_members mimics inspect.getmembers (before #238 it directly used inspect.getmembers), which already resolves def_property_readonly_static and def_property_static to their final values, thus losing the information about a descriptor. Presumably, we could change the logic of ParserDispatchMixin._iter_module_members to mimic inspect.getmembers_static, but I don't know which problems this will cause with other function types.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are usually done as a combo of @classmethod and @Property decorators in plain Python. I don't know what pybind11 uses internally for those (as alternatively, this can be a metaclass as well). I think we can leave this as is, but a comment in the code explaining this logic (why we check against Field) would be nice.

skarndev
skarndev previously approved these changes Apr 25, 2026
@skarndev
Copy link
Copy Markdown
Contributor

This approach requires cpython 3.12+
what do you mean by requirement for cpython3.12+? I see it works in tests with earlier versions based on CI jobs, and we aim to support compatibility with Python versions that have not yet reached their end of life.

@markuspi
Copy link
Copy Markdown
Author

@skarndev

This approach requires cpython 3.12+ what do you mean by requirement for cpython3.12+? I see it works in tests with earlier versions based on CI jobs, and we aim to support compatibility with Python versions that have not yet reached their end of life.

Before cpython 3.12, the documentation for static properties is not accessiblethrough pybind. In those cases, my code would just skip the inner if-statement and effectively be a no-op.
The CI jobs are passing because there are separate checked-in results per python version, and I only updated those that met the version requirements.

Is this behavior in line with this project's policy on version compatibility?

@skarndev
Copy link
Copy Markdown
Contributor

@skarndev

This approach requires cpython 3.12+ what do you mean by requirement for cpython3.12+? I see it works in tests with earlier versions based on CI jobs, and we aim to support compatibility with Python versions that have not yet reached their end of life.

Before cpython 3.12, the documentation for static properties is not accessiblethrough pybind. In those cases, my code would just skip the inner if-statement and effectively be a no-op. The CI jobs are passing because there are separate checked-in results per python version, and I only updated those that met the version requirements.

Is this behavior in line with this project's policy on version compatibility?

Yes, it is clear now. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants