From 6247e7b3efc40219c62ce97e00313d1e7d50c8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 24 Dec 2023 00:13:11 -0500 Subject: [PATCH 1/5] Fix itertuples --- pandas-stubs/core/frame.pyi | 2 +- tests/test_frame.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index f413e6110..2eebdd6c2 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -250,7 +250,7 @@ class DataFrame(NDFrame, OpsMixin): def iterrows(self) -> Iterable[tuple[Hashable, Series]]: ... def itertuples( self, index: _bool = ..., name: _str | None = ... - ) -> Iterable[tuple[Any, ...]]: ... + ) -> Iterable[Any]: ... def __len__(self) -> int: ... @overload def dot(self, other: DataFrame | ArrayLike) -> DataFrame: ... diff --git a/tests/test_frame.py b/tests/test_frame.py index bdd9bf491..8dcbcec93 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -2949,3 +2949,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, Any), tuple) + assert_type(item.a, Any) From 1bea598c365d7899403a2555b92ad43c8af7f4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Tue, 26 Dec 2023 12:23:16 -0500 Subject: [PATCH 2/5] _PandasNamedTuple --- pandas-stubs/core/frame.pyi | 5 ++++- tests/test_frame.py | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index 2eebdd6c2..ddaa03469 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -250,7 +250,7 @@ class DataFrame(NDFrame, OpsMixin): def iterrows(self) -> Iterable[tuple[Hashable, Series]]: ... def itertuples( self, index: _bool = ..., name: _str | None = ... - ) -> Iterable[Any]: ... + ) -> Iterable[_PandasNamedTuple]: ... def __len__(self) -> int: ... @overload def dot(self, other: DataFrame | ArrayLike) -> DataFrame: ... @@ -2280,3 +2280,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) -> Any: ... diff --git a/tests/test_frame.py b/tests/test_frame.py index 8dcbcec93..7558348af 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -20,6 +20,7 @@ Any, Callable, Generic, + TypeAlias, TypedDict, TypeVar, Union, @@ -47,6 +48,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]}) @@ -2956,5 +2962,5 @@ def test_itertuples() -> None: df = pd.DataFrame({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]}) for item in df.itertuples(): - check(assert_type(item, Any), tuple) + check(assert_type(item, _PandasNamedTuple), tuple) assert_type(item.a, Any) From 6e6c96aed1daf0020986c33d50030ffc15900ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Tue, 26 Dec 2023 12:45:08 -0500 Subject: [PATCH 3/5] 3.9 --- tests/test_frame.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_frame.py b/tests/test_frame.py index 6062e0cc2..e46a3f069 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -20,7 +20,6 @@ Any, Callable, Generic, - TypeAlias, TypedDict, TypeVar, Union, @@ -34,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 From cef89adc7f09a6234470cd665f41230da668ec2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Tue, 26 Dec 2023 13:18:46 -0500 Subject: [PATCH 4/5] adjust old test --- tests/test_frame.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/test_frame.py b/tests/test_frame.py index e46a3f069..c372a3877 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -447,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: From 9bc7d429f3672ce11df531d0d72b453bc3933d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Tue, 26 Dec 2023 14:11:57 -0500 Subject: [PATCH 5/5] return Scalar --- pandas-stubs/core/frame.pyi | 2 +- tests/test_frame.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index f3e28739a..2de05988a 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -2281,4 +2281,4 @@ class DataFrame(NDFrame, OpsMixin): def __rtruediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ... class _PandasNamedTuple(tuple[Any, ...]): - def __getattr__(self, field: str) -> Any: ... + def __getattr__(self, field: str) -> Scalar: ... diff --git a/tests/test_frame.py b/tests/test_frame.py index c372a3877..46f844c58 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -2992,4 +2992,4 @@ def test_itertuples() -> None: for item in df.itertuples(): check(assert_type(item, _PandasNamedTuple), tuple) - assert_type(item.a, Any) + assert_type(item.a, Scalar)