Repository: pandas-dev/pandas-stubs (language: python)

Issue:
With the most recent pandas-stubs, mypy now complains about every call to itertuples()
With the most recent pandas-stubs, mypy now complains about every call to itertuples()
Is there a way that I'm supposed to tell the new release what my column names are?

Sample 
```python
import pandas as pd                                                                                 
                                                                                                    
df = pd.DataFrame({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]})                                           
                                                                                                    
for item in df.itertuples():                                                                        
    a = item.a                                                                                      
    b = item.b     
```

```
mypy.....................................................................Failed
- hook id: mypy
- exit code: 1

foo.py:6: error: "tuple[Any, ...]" has no attribute "a"  [attr-defined]
foo.py:7: error: "tuple[Any, ...]" has no attribute "b"  [attr-defined]
Found 2 errors in 1 file (checked 1 source file)
```

_Originally posted by @j-carson in https://github.com/pandas-dev/pandas-stubs/discussions/832_


Discussion / hints:

Fix patch:
diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi
index 759c06de..2de05988 100644
--- a/pandas-stubs/core/frame.pyi
+++ b/pandas-stubs/core/frame.pyi
@@ -249,7 +249,7 @@ class DataFrame(NDFrame, OpsMixin):
     def iterrows(self) -> Iterable[tuple[Hashable, Series]]: ...
     def itertuples(
         self, index: _bool = ..., name: _str | None = ...
-    ) -> Iterable[tuple[Any, ...]]: ...
+    ) -> Iterable[_PandasNamedTuple]: ...
     def __len__(self) -> int: ...
     @overload
     def dot(self, other: DataFrame | ArrayLike) -> DataFrame: ...
@@ -2279,3 +2279,6 @@ class DataFrame(NDFrame, OpsMixin):
     ) -> Self: ...
     def __truediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ...
     def __rtruediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ...
+
+class _PandasNamedTuple(tuple[Any, ...]):
+    def __getattr__(self, field: str) -> Scalar: ...


Test patch:
diff --git a/tests/test_frame.py b/tests/test_frame.py
index 8eb23285..46f844c5 100644
--- a/tests/test_frame.py
+++ b/tests/test_frame.py
@@ -33,7 +33,10 @@
 from pandas.core.resample import Resampler  # noqa: F401
 from pandas.core.series import Series
 import pytest
-from typing_extensions import assert_type
+from typing_extensions import (
+    TypeAlias,
+    assert_type,
+)
 import xarray as xr
 
 from pandas._typing import Scalar
@@ -47,6 +50,11 @@
 from pandas.io.formats.style import Styler
 from pandas.io.parsers import TextFileReader
 
+if TYPE_CHECKING:
+    from pandas.core.frame import _PandasNamedTuple
+else:
+    _PandasNamedTuple: TypeAlias = tuple
+
 DF = pd.DataFrame(data={"col1": [1, 2], "col2": [3, 4]})
 
 
@@ -439,9 +447,23 @@ def test_types_iterrows() -> None:
 
 def test_types_itertuples() -> None:
     df = pd.DataFrame(data={"col1": [2, 1], "col2": [3, 4]})
-    res1: Iterable[tuple[Any, ...]] = df.itertuples()
-    res2: Iterable[tuple[Any, ...]] = df.itertuples(index=False, name="Foobar")
-    res3: Iterable[tuple[Any, ...]] = df.itertuples(index=False, name=None)
+    check(
+        assert_type(df.itertuples(), Iterable[_PandasNamedTuple]),
+        Iterable,
+        _PandasNamedTuple,
+    )
+    check(
+        assert_type(
+            df.itertuples(index=False, name="Foobar"), Iterable[_PandasNamedTuple]
+        ),
+        Iterable,
+        _PandasNamedTuple,
+    )
+    check(
+        assert_type(df.itertuples(index=False, name=None), Iterable[_PandasNamedTuple]),
+        Iterable,
+        _PandasNamedTuple,
+    )
 
 
 def test_types_sum() -> None:
@@ -2962,3 +2984,12 @@ def test_frame_setitem_na() -> None:
     df["x"] = df["y"] + pd.Timedelta(days=3)
     df.loc[ind, :] = pd.NaT
     df.iloc[[0, 2], :] = pd.NaT
+
+
+def test_itertuples() -> None:
+    # GH 822
+    df = pd.DataFrame({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]})
+
+    for item in df.itertuples():
+        check(assert_type(item, _PandasNamedTuple), tuple)
+        assert_type(item.a, Scalar)