basedpyright icon indicating copy to clipboard operation
basedpyright copied to clipboard

Get parameter info for constructor from class docstring

Open nihaals opened this issue 5 months ago • 3 comments

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.

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

nihaals avatar Oct 06 '25 16:10 nihaals

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

DetachHead avatar Oct 06 '25 21:10 DetachHead

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.):

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.

nihaals avatar Oct 08 '25 12:10 nihaals

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)

DetachHead avatar Oct 09 '25 09:10 DetachHead