3

For example, for:

def foo(a):
    if a == 10:
        raise FooError
    return 1 / a

Should the docstring for foo contain something like:

"""Raises:
    FooError: if a is equal to 10.
    ZeroDivisionError: if a is equal to 0.
"""

Or should it just list the exceptions that the function itself raises, i. e. FooError? Any insights as to what's better are welcome, thanks.

LoneCodeRanger
  • 413
  • 6
  • 18

1 Answers1

3

TLDR: List all exceptions relevant to users of your code, regardless of implementation.


A docstring is directed at the user of a function/class. Just like a proper class interface, a docstring should not be concerned with implementation details of a function/class. The content of a docstring should only reflect the what, not the how.

This means that whether an error is documented should not differ between different implementations of the same thing.


Consider moving the error-raising code to a helper:

class Bar:
    def foo(self, a):
        if a == 10:
            raise FooBarError
        return 1 / a

    def bar(self, a):
        self._reject(a, 10)
        return 1 / a

    def _reject(self, value, forbidden):
        if value == forbidden:
            raise FooBarError

Both foo and bar are functionally equivalent to client code. Their internal validation logic is a mere implementation detail that does not change how to use them.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
  • I see your point, and it makes sense. However, I was wondering, being new to docstrings (yeah... ) if there wasn't already an automatic way in which, having raises be documented for functions called in `bar` (ie `_reject`), those wouldn't also surface in `bar`. I guess that depends on how you access the documentation. And I'm not really fixated on that. – LoneCodeRanger Oct 17 '20 at 15:02
  • I made a little test with the `help` function and, from what I can see, it doesn't surface info found in the docstrings of functions called in the implementation of the function passed to it. So calling `help(bar)` wouldn't tell you about what's in `_reject`'s docstring. – LoneCodeRanger Oct 17 '20 at 15:07
  • But then again, I don't know if tools like Sphinx do. – LoneCodeRanger Oct 17 '20 at 15:08
  • 2
    @AndreiToroplean Resolving the call graph in Python is highly complex, moreso inferring types and exceptions from this. Sphinx does not attempt to do so. – MisterMiyagi Oct 17 '20 at 15:25