Describe the bug
There is a class PropertyDocumenter at https://github.com/sphinx-doc/sphinx/blob/master/sphinx/ext/autodoc/__init__.py#L1380 which defines half of a Python role, the "property", which nonetheless cannot be independently accessed as it folds itself under the "method" directivetype. This causes Python descriptors which happen to use @property to be treated entirely differently from all other descriptors, which otherwise get classified as "attribute". It is based on a hardcoded check for "property" at https://github.com/sphinx-doc/sphinx/blob/master/sphinx/util/inspect.py#L220 . most importantly, it means that when I refer to an :attr: somewhere in my documentation, I now have to know that this particular attribute happened to be a @property and not any other kind of descriptor, and reference it using :method: rather than :attr:. Then, if I change the use of @property with my own caching descriptor, which occurs all the time, all my references to this attribute are now broken. It also generates an ugly "property" word in the output, which is again inconsistent from any other descriptor.
It's basically not pythonic to check the type of something using "isinstance()" when there is a widely known duck type available, that is, looking for __get__() like the descriptor protocol does. There should instead be a DescriptorDocumenter that looks for __get__() on the wrapper just like Python descriptor protocol, and then it needs to classify itself as "attribute" so that these descriptors can be swapped in and out for plain class attributes, which is the whole point of descriptors. a @property should never be considered as a "method".
I'm not sure if this object was introduced at some point and broke existing documentation, or if this was always the behavior once :attr: was supported.
To Reproduce
Steps to reproduce the behavior:
define two classes, as well as a custom descriptor class:
class Foo(object):
@property
def bar(self):
"""the bar attribute"""
return "the bar"
class _some_descriptor(object):
def __init__(self, fn):
self.fn = fn
def __get__(self, obj, cls):
if obj is None:
return self
return self.fn(obj)
class Bar(object):
@_some_descriptor
def bar(self):
"""the bar attribute"""
return "the bar"
sphinx will classify Foo.bar as a "method" which will not resolve for :attr:`.Foo.bar` and will classify Bar.bar as an "attribute" which will not resolve for :meth:`.Bar.bar`.
Expected behavior
obviously this is behavior that people are relying on by now, however it is IMO entirely wrong and I need a supported method of turning it off. I will be looking into hardcoded ways to work around it for now (this is for SQLAlchemy), likely just setting PropertyDocumenter.priority to zero. I know that :obj: is also a workaround but I have many thousands of methods and attributes and the last thing I need is more ambiguity in my documentation source.
Your project
https://docs.sqlalchemy.org/
Describe the bug
There is a class PropertyDocumenter at https://github.com/sphinx-doc/sphinx/blob/master/sphinx/ext/autodoc/__init__.py#L1380 which defines half of a Python role, the "property", which nonetheless cannot be independently accessed as it folds itself under the "method" directivetype. This causes Python descriptors which happen to use
@propertyto be treated entirely differently from all other descriptors, which otherwise get classified as "attribute". It is based on a hardcoded check for "property" at https://github.com/sphinx-doc/sphinx/blob/master/sphinx/util/inspect.py#L220 . most importantly, it means that when I refer to an:attr:somewhere in my documentation, I now have to know that this particular attribute happened to be a@propertyand not any other kind of descriptor, and reference it using:method:rather than:attr:. Then, if I change the use of@propertywith my own caching descriptor, which occurs all the time, all my references to this attribute are now broken. It also generates an ugly "property" word in the output, which is again inconsistent from any other descriptor.It's basically not pythonic to check the type of something using "isinstance()" when there is a widely known duck type available, that is, looking for
__get__()like the descriptor protocol does. There should instead be a DescriptorDocumenter that looks for__get__()on the wrapper just like Python descriptor protocol, and then it needs to classify itself as "attribute" so that these descriptors can be swapped in and out for plain class attributes, which is the whole point of descriptors. a@propertyshould never be considered as a "method".I'm not sure if this object was introduced at some point and broke existing documentation, or if this was always the behavior once
:attr:was supported.To Reproduce
Steps to reproduce the behavior:
define two classes, as well as a custom descriptor class:
sphinx will classify Foo.bar as a "method" which will not resolve for
:attr:`.Foo.bar`and will classify Bar.bar as an "attribute" which will not resolve for:meth:`.Bar.bar`.Expected behavior
obviously this is behavior that people are relying on by now, however it is IMO entirely wrong and I need a supported method of turning it off. I will be looking into hardcoded ways to work around it for now (this is for SQLAlchemy), likely just setting PropertyDocumenter.priority to zero. I know that
:obj:is also a workaround but I have many thousands of methods and attributes and the last thing I need is more ambiguity in my documentation source.Your project
https://docs.sqlalchemy.org/