sphinx icon indicating copy to clipboard operation
sphinx copied to clipboard

Napoleon: Don't use attribute type annotation for constructor parameters

Open hoodmane opened this issue 3 years ago • 3 comments

Fix a bug where if a class has an attribute and a constructor parameter with the same name, napoleon will use the type annotation from the attribute for the constructor argument.

Feature or Bugfix

  • Bugfix

Detail

Suppose we have a class that looks like

class Example:
    """
    A Class

    Parameters
    ----------
    blah:
        Description of parameter blah
    """
    def __init__(self, blah: int):
        pass

    blah: bool

The processed docstring looks like:

A Class
       
:param blah: Description of parameter blah
:type blah: bool

Note that the parameter has type int but Napoleon took the type from the attribute which has type bool. A more practical reason this would happen is that the parameter has type Optional[dict] and this is stored into an attribute of type dict where if None is passed a default dictionary is created.

I added a new parameter is_attribute to _lookup_annotation and _consume_field(s) which defaults to False. If is_attribute is False and what is "class" then we look up the type from the constructor arguments instead. With these changes it produces the correct output:

:param blah: Description of parameter blah
:type blah: int

hoodmane avatar Jan 20 '23 16:01 hoodmane

merging into this the latest master update for CI checks

jfbu avatar Jan 22 '23 17:01 jfbu

cc @cbarrick if you would have any time to look at this one?

A

AA-Turner avatar Jan 05 '25 02:01 AA-Turner

It seems that this problem arises because the docstring for the class can also be used to document the parameters of __init__.

So I think the correct behavior is for the Attributes section to refer to class attributes and for the Parameters section to refer to __init__ parameters.

Can we add a test case for this? e.g.

class OverloadedParamAttribute:
    """
    A class with both an attribute named ``blah`` and an __init__ parameter named ``blah``.
    Both are documented in this docstring, but they have different type annotations in the
    class definition. This tests that the generated docs use the correct type when using
    ``napoleon_use_param`` (for method params) and ``napoleon_attr_annotations`` (for
    attributes).

    Attributes
    ----------
    blah:
        Description of class attribute blah, of type bool.

    Parameters
    ----------
    blah:
        Description of __init__ parameter blah, of type int.
    """
    def __init__(self, blah: int):
        pass

    blah: bool

cbarrick avatar Jan 05 '25 16:01 cbarrick

Resolved conflicts.

A

AA-Turner avatar Jul 23 '25 23:07 AA-Turner