9

I have this small example:

"""Sandbox module"""

class Toto:
    """
    This class is an example

    Attributes:
        class_attribute (str): The class attribute #Unresolved reference
        instance_attribute (str): The instance attribute #OK
    """

    class_attribute = ""

    def __init__(self):
        self.instance_attribute = ""
        pass

This triggers an unresolved reference warning How should I properly document the class attribute ?

mzjn
  • 48,958
  • 13
  • 128
  • 248
Milan
  • 1,547
  • 1
  • 24
  • 47

2 Answers2

4

Assuming you would like to use napoleon to render your docstrings into docs, the sphinx developers are working towards a way to add custom sections to class-level docstrings (see Issue #33).

Currently, in the Google Style Docstrings Example, the class ExamplePEP526Class example states

If the class has public attributes, they may be documented here in an Attributes section and follow the same formatting as a function's Args section. If napoleon_attr_annotations is True, types can be specified in the class body using PEP 526 annotations.

PEP 526 added variable annotations to type hints. Hence, your code could now be written:

"""Sandbox module"""

class Toto:
    """ This class is an example

    Attributes:
        class_attribute (str): (class attribute) The class attribute
        instance_attribute (str): The instance attribute
    """

    class_attribute: str = ""

    def __init__(self):
        self.instance_attribute: str = ""

For one thing, it seems you forgot to put the type hint str after class_attribute when defining it, so mypy (if using an external type checker) probably couldn't discover its type.

Ironically, the reverse situation would have worked: in napoleon version 3.4, if napoleon_attr_attributes is set to True, then

If an attribute is documented in the docstring without a type and has an annotation in the class body, that type is used.

Second, the pass at the end of your __init__ method is allowed, but unnecessary since you define instance_attribute there.

I mention Issue #33 because, personally, I would rather call the heading "Class Variables" as "Attributes" by itself doesn't distinguish between instance vs. class attributes/variables. For the time being, you may want to put your own notation in the attribute description like I have done.

For me, I either have fewer class attributes than instance attributes or none at all, so I only note if an attribute is a class attribute (otherwise, it is an instance attribute). That way, I don't have to write (instance attribute) next to all my instance attributes. Alternatively, you could try putting class in the parentheses with the type the same what that optional is listed:

class_attribute (str, class): The class attribute

I'm not sure if that will work or break. If it breaks, it would certainly be nice to have added to the docstring syntax in the future (I think this looks cleaner).

Lastly, you could document the class variable as an attribute docstring as defined in PEP 257 as well as this SO answer by putting a docstring directly underneath the assignment like so:

"""Sandbox module"""

class Toto:

    class_attribute: str = ""
    """class_attribute (str): (class attribute) The class attribute"""

    def __init__(self):
        """ This class is an example
    
        Attributes:
            instance_attribute (str): The instance attribute
        """
        self.instance_attribute: str = ""
adam.hendry
  • 4,458
  • 5
  • 24
  • 51
-1

Try this:

"""
    Sandbox module
    ~~~~~~~~~~~~~~
"""

class Toto:
    """This class is an example

    Attributes:
        instance_attribute (str): The instance attribute #OK
    """
    
    #: str: The class attribute #Unresolved reference
    class_attribute = ""

    def __init__(self):
        self.instance_attribute = ""
        pass

This works fine for me using sphinx.

agittarius
  • 619
  • 6
  • 10