Skip to content

Commit 46f532a

Browse files
fohrlooprossbar
andauthored
fix 'Alias for field number X' problem with NamedTuples (#527)
* fix 'Alias for field number X' problem with NamedTuples * TST: Add test for duplicated attrs w/ namedtuples. * TST: Add test of explicitly documented namedtuple params. --------- Co-authored-by: Ross Barnowski <[email protected]>
1 parent 8e2d545 commit 46f532a

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

numpydoc/docscrape.py

+14
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ def properties(self):
706706
for name, func in inspect.getmembers(self._cls)
707707
if (
708708
not name.startswith("_")
709+
and not self._should_skip_member(name, self._cls)
709710
and (
710711
func is None
711712
or isinstance(func, (property, cached_property))
@@ -715,6 +716,19 @@ def properties(self):
715716
)
716717
]
717718

719+
@staticmethod
720+
def _should_skip_member(name, klass):
721+
if (
722+
# Namedtuples should skip everything in their ._fields as the
723+
# docstrings for each of the members is: "Alias for field number X"
724+
issubclass(klass, tuple)
725+
and hasattr(klass, "_asdict")
726+
and hasattr(klass, "_fields")
727+
and name in klass._fields
728+
):
729+
return True
730+
return False
731+
718732
def _is_show_member(self, name):
719733
if self.show_inherited_members:
720734
return True # show all class members

numpydoc/tests/test_docscrape.py

+57
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,63 @@ def val(self):
16411641
assert class_docstring["Attributes"][0].name == "val"
16421642

16431643

1644+
def test_namedtuple_no_duplicate_attributes():
1645+
"""
1646+
Ensure that attributes of namedtuples are not duplicated in the docstring.
1647+
1648+
See gh-257
1649+
"""
1650+
from collections import namedtuple
1651+
1652+
foo = namedtuple("Foo", ("bar", "baz"))
1653+
1654+
# Create the SphinxClassDoc object via get_doc_object
1655+
sds = get_doc_object(foo)
1656+
assert sds["Attributes"] == []
1657+
1658+
1659+
def test_namedtuple_class_docstring():
1660+
"""Ensure that class docstring is preserved when inheriting from namedtuple.
1661+
1662+
See gh-257
1663+
"""
1664+
from collections import namedtuple
1665+
1666+
foo = namedtuple("Foo", ("bar", "baz"))
1667+
1668+
class MyFoo(foo):
1669+
"""MyFoo's class docstring"""
1670+
1671+
# Create the SphinxClassDoc object via get_doc_object
1672+
sds = get_doc_object(MyFoo)
1673+
assert sds["Summary"] == ["MyFoo's class docstring"]
1674+
1675+
# Example dataclass where constructor params are documented explicit.
1676+
# Parameter names/descriptions should be included in the docstring, but
1677+
# should not result in a duplicated `Attributes` section
1678+
class MyFooWithParams(foo):
1679+
"""
1680+
MyFoo's class docstring
1681+
1682+
Parameters
1683+
----------
1684+
bar : str
1685+
The bar attribute
1686+
baz : str
1687+
The baz attribute
1688+
"""
1689+
1690+
bar: str
1691+
baz: str
1692+
1693+
sds = get_doc_object(MyFooWithParams)
1694+
assert "MyFoo's class docstring" in sds["Summary"]
1695+
assert len(sds["Attributes"]) == 0
1696+
assert len(sds["Parameters"]) == 2
1697+
assert sds["Parameters"][0].desc[0] == "The bar attribute"
1698+
assert sds["Parameters"][1].desc[0] == "The baz attribute"
1699+
1700+
16441701
if __name__ == "__main__":
16451702
import pytest
16461703

0 commit comments

Comments
 (0)