Skip to content

🐛 False positive DOC503 when Exception is created via class method #201

@s-weigand

Description

@s-weigand

When creating an Exeption from a class constructor method a DOC503 is raised saying <class name> does not match <class name>.<method name>.

Example

def ensure_unique_tuple(value: tuple[int, ...]):
    """Ensure that all values in the tuple are unique.

    Parameters
    ----------
    value : tuple[int,...]
        Tuple to check

    Raises
    ------
    TupleDuplicateException
        If the tuple contains duplicate values.
    """
    if len(value) != len(set(value)):
        raise TupleDuplicateException.from_tuple(value)

will result in

DOC503: Function `ensure_unique_tuple` exceptions in the "Raises" section in the docstring do not
match those in the function body Raises values in the docstring: ['TupleDuplicateException'].
Raised exceptions in the body: ['TupleDuplicateException.from_tuple'].

Reproduction

I was preparing a ninja PR to fix this bug (see full reproducible example on my fork).

However, the problem seems to me that at the point where the visitor comes around there isn't enough information to determine is it of style module.Exception() or Exception.method() (but might just be my AST skill issues 😅).

Here is the AST representation of raise TupleDuplicateException.from_tuple(value) (thanks astpretty to make it more readable 😅)

Raise(
    lineno=45,
    col_offset=8,
    end_lineno=45,
    end_col_offset=55,
    exc=Call(
        lineno=45,
        col_offset=14,
        end_lineno=45,
        end_col_offset=55,
        func=Attribute(
            lineno=45,
            col_offset=14,
            end_lineno=45,
            end_col_offset=48,
            value=Name(lineno=45, col_offset=14, end_lineno=45, end_col_offset=37, id='TupleDuplicateException', ctx=Load()),
            attr='from_tuple',
            ctx=Load(),
        ),
        args=[Name(lineno=45, col_offset=49, end_lineno=45, end_col_offset=54, id='value', ctx=Load())],
        keywords=[],
    ),
    cause=None,
),

Possible solutions

The only thing that comes to my mind currently would be a remapping configuration option to run a string replace the output of getRaisedExceptions (creating an exception from a class method is pretty much an edge case, my actual use case is ValidationError.from_exception_data to concatenate validations).

Env

  • pydoclint==0.5.15
  • py310

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions