Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- General: Give `ParseError` the `problems` of the whole docstring and the `result` parsed despite them, and mention how many more there are in its message
- General: Show a docstring and its metas with the fields they have set in `repr()`, as in `DocstringParam(kind=Kind.PARAM, arg_name='x', ...)`
- General: Add `raw_type_name` to params, the type as written, such as `int, optional`, before its optional mark and default are split off
- General: Keep a class attribute in `parse_from_object()` when the class docstring documents a param of the same name, instead of dropping it
- General: Return the docstring of a built-in class or module from `parse_from_object()` instead of raising `TypeError`, and ignore a `__doc__` that is not a string
- ReST: Stop the last field from absorbing text after the field list; that text now goes to the long description (thanks to @apoorvdarshan)
- ReST: Raise `ParseError` instead of `IndexError` for a field with no name
Expand Down
6 changes: 4 additions & 2 deletions docstring_parser/attrdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,13 @@ def add_attribute_docstrings(
:param docstring: Docstring object where found attributes are added
:returns: list with names of added attributes
"""
params = set(p.arg_name for p in [*docstring.params, *docstring.attrs])
# An attribute the docstring documents already wins. A param of the
# same name, such as one ``__init__`` stores, is no attribute.
documented = set(a.arg_name for a in docstring.attrs)
for arg_name, (description, type_name, default) in (
AttributeDocstrings().get_attr_docs(obj).items()
):
if arg_name not in params:
if arg_name not in documented:
param = DocstringParam(
key="attribute",
description=description,
Expand Down
40 changes: 40 additions & 0 deletions docstring_parser/tests/test_parse_from_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,46 @@ class StandardCase:
assert docstring.attrs[1].description == "Description for attr_two"


def test_from_class_attribute_named_like_param() -> None:
"""Test that an attribute named like a documented param is kept."""

class WithParam:
"""Short description

:param x: The param x.
"""

x: int = 1
"""The attribute x."""

docstring = parse_from_object(WithParam)

assert len(docstring.params) == 1
assert docstring.params[0].arg_name == "x"
assert docstring.params[0].description == "The param x."
assert len(docstring.attrs) == 1
assert docstring.attrs[0].arg_name == "x"
assert docstring.attrs[0].description == "The attribute x."


def test_from_class_documented_attribute_wins() -> None:
"""Test that an attribute the docstring documents is not added twice."""

class WithAttribute:
"""Short description

:attribute x: From the docstring.
"""

x: int = 1
"""From the source."""

docstring = parse_from_object(WithAttribute)

assert len(docstring.attrs) == 1
assert docstring.attrs[0].description == "From the docstring."


def test_from_class_attribute_docstrings_without_type() -> None:
"""Test the parse of untyped attribute docstrings."""

Expand Down
Loading