Get parameter info for constructor from class docstring
Description
Some libraries document constructor parameters in the class' docstring as opposed to the constructor's docstring. This is mentioned in PEP-257:
The class constructor should be documented in the docstring for its
__init__method.
However, this is still done. For example, Click: https://github.com/pallets/click/blob/309ce9178707e1efaf994f191d062edbdffd5ce6/src/click/types.py#L879-L934
This is also used in Sphinx's docs:
class SimpleBleDevice(object): """This is a conceptual class representation of a simple BLE device (GATT Server). It is essentially an extended combination of the :class:`bluepy.btle.Peripheral` and :class:`bluepy.btle.ScanEntry` classes :param client: A handle to the :class:`simpleble.SimpleBleClient` client object that detected the device :type client: class:`simpleble.SimpleBleClient` :param addr: Device MAC address, defaults to None :type addr: str, optional :param addrType: Device address type - one of ADDR_TYPE_PUBLIC or ADDR_TYPE_RANDOM, defaults to ADDR_TYPE_PUBLIC :type addrType: str, optional :param iface: Bluetooth interface number (0 = /dev/hci0) used for the connection, defaults to 0 :type iface: int, optional :param data: A list of tuples (adtype, description, value) containing the AD type code, human-readable description and value for all available advertising data items, defaults to None :type data: list, optional :param rssi: Received Signal Strength Indication for the last received broadcast from the device. This is an integer value measured in dB, where 0 dB is the maximum (theoretical) signal strength, and more negative numbers indicate a weaker signal, defaults to 0 :type rssi: int, optional :param connectable: `True` if the device supports connections, and `False` otherwise (typically used for advertising ‘beacons’)., defaults to `False` :type connectable: bool, optional :param updateCount: Integer count of the number of advertising packets received from the device so far, defaults to 0 :type updateCount: int, optional """ def __init__(self, client, addr=None, addrType=None, iface=0, data=None, rssi=0, connectable=False, updateCount=0): """Constructor method """ super().__init__(deviceAddr=None, addrType=addrType, iface=iface) self.addr = addr self.addrType = addrType self.iface = iface self.rssi = rssi self.connectable = connectable self.updateCount = updateCount self.data = data self._connected = False self._services = [] self._characteristics = [] self._client = client
When the docstring is on the class, hover info for constructor parameters no longer works.
-
Class docstring
- If you hover over
fooon line 9, no documentation is shown, only the type
- If you hover over
-
Constructor docstring
- If you hover over
fooon line 8, documentation is shown
- If you hover over
It would be great if parameter docs were inherited from the class docstring if they weren't provided in a constructor's docstring.
Related:
- #1096
- More related to what is displayed rather than getting parsed exclusive information like parameter docs
- https://github.com/microsoft/pylance-release/issues/7613
I think this is more of an issue with the library if its parameter documentation is in the wrong spot. While unlike other type checkers I don't treat PEPs as gospel, in this case I think it makes sense that the parameters for the constructor should be documented on the constructor
I think this is an example of the standard being whatever people tend to do. This might also have been caused by doc generator defaults, for example Sphinx defaults to only using the class' docstring. Enough (popular) projects do this that I think it's an expectation that people will do both and both should be treated the same.
I quickly went through some of the top PyPI packages to try to get a rough idea of which was more popular (and very roughly see which approach most LSP users would be interacting with, but this doesn't exclusively include libraries, look at public classes, consider downloads are inflated etc.):
- boto3
- urllib3
- Couldn't find class parameter docs
- requests
- aiobotocore
- charset-normalizer
- idna
- Couldn't find class parameter docs
- setuptools
- Couldn't find class parameter docs
- gprc
- Couldn't find class parameter docs
- packaging
- Couldn't find class parameter docs
- python-dateutil
- s3transfer
- pyyaml
- Couldn't find class parameter docs
- six
- Couldn't find class parameter docs
- s3fs
- pydantic
- Couldn't find class parameter docs
- cryptography
- Couldn't find class parameter docs
- numpy
Someone could try to PR every library they use to update this and their docs config and check their docs are unaffected, but I think it would be easier to adapt to how people currently write docstrings, which as far as I can tell is a mix of documenting the class and the constructor, and in the meantime people are stuck with a subpar experience due to no fault of their own.
Docstrings seem to be very inconsistent across the Python ecosystem which is why Pyright currently supports 3 different formats (and Pylance supports 4, #1558), and while I'm not aware of a PEP that explicitly mentions one of the popular parameter docstring conventions, I personally see supporting parameter docstrings on classes similar to supporting all the popular docstring conventions as opposed to whatever the single most popular one that the community is trying to converge on is. I also don't see a movement of people trying to encourage libraries to "fix" this.
i guess we could support it if it's a common pattern among popular libraries. but i think we shouldn't show them when hovering over the class itself unless you're instantiating it (similar to the current behavior where it only shows the constructor's docstring when instantiating)