diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index ef63da0c2..a754a38e5 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -141,17 +141,17 @@ class _DataFrameGroupByNonScalar(DataFrameGroupBy): class DataFrameGroupBy(GroupBy): def any(self, skipna: bool = ...) -> DataFrame: ... def all(self, skipna: bool = ...) -> DataFrame: ... - # mypy and pyright see these overloads as overlapping @overload - def apply( # type: ignore[misc] + def apply( self, func: Callable[[DataFrame], Scalar | list | dict], *args, **kwargs ) -> Series: ... @overload - def apply( # type: ignore[misc] + def apply( self, func: Callable[[DataFrame], Series | DataFrame], *args, **kwargs ) -> DataFrame: ... + # error: Overload 3 for "apply" will never be used because its parameters overlap overload 1 @overload - def apply( # type: ignore[misc] + def apply( # pyright: ignore[reportOverlappingOverload] self, func: Callable[[Iterable], float], *args, **kwargs ) -> DataFrame: ... def aggregate(self, arg: AggFuncType = ..., *args, **kwargs) -> DataFrame: ... diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index d16f6cfdf..32f9d442d 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -72,9 +72,8 @@ class DatetimeIndex(DatetimeTimedeltaMixin, DatetimeIndexProperties): def __le__(self, other: Timestamp) -> np_ndarray_bool: ... def __gt__(self, other: Timestamp) -> np_ndarray_bool: ... def __ge__(self, other: Timestamp) -> np_ndarray_bool: ... - # ignore for mypy because we know dtype of a DatetimeIndex @property - def dtype(self) -> np.dtype | DatetimeTZDtype: ... # type: ignore[misc] + def dtype(self) -> np.dtype | DatetimeTZDtype: ... def date_range( start=..., diff --git a/pandas-stubs/io/parsers.pyi b/pandas-stubs/io/parsers.pyi index 600a0493a..7b34db73a 100644 --- a/pandas-stubs/io/parsers.pyi +++ b/pandas-stubs/io/parsers.pyi @@ -516,6 +516,8 @@ class TextFileReader(abc.Iterator): def __init__(self, f, engine=..., **kwds) -> None: ... def close(self) -> None: ... def __next__(self): ... + def __enter__(self) -> TextFileReader: ... + def __exit__(self, exc_type, exc_value, traceback) -> None: ... def read(self, nrows=...): ... def get_chunk(self, size=...): ... diff --git a/pyproject.toml b/pyproject.toml index 0589763ea..0ed7daa44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,7 +138,7 @@ no_implicit_optional = true strict_optional = true # Configuring warnings warn_redundant_casts = true -warn_unused_ignores = false # Change from pandas +warn_unused_ignores = true warn_no_return = true warn_return_any = false # TODO warn_unreachable = false # GH#27396 @@ -168,6 +168,7 @@ reportMissingParameterType = false reportMissingTypeArgument = false reportMissingTypeStubs = false reportUnknownArgumentType = false +reportUnusedExpression = false reportUnknownLambdaType = false reportUnknownMemberType = false reportUnknownParameterType = false diff --git a/tests/__init__.py b/tests/__init__.py index b4108beaf..322da8cd5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,21 +1,28 @@ from __future__ import annotations +from typing import ( + TYPE_CHECKING, + Final, +) -def check( - actual: object, klass: type, dtype: type | None = None, attr: str = "left" -) -> None: +from pandas._typing import T + +TYPE_CHECKING_INVALID_USAGE: Final = TYPE_CHECKING + + +def check(actual: T, klass: type, dtype: type | None = None, attr: str = "left") -> T: if not isinstance(actual, klass): raise RuntimeError(f"Expected type '{klass}' but got '{type(actual)}'") if dtype is None: - return None + return actual # type: ignore[return-value] if hasattr(actual, "__iter__"): value = next(iter(actual)) # type: ignore[call-overload] else: assert hasattr(actual, attr) - value = getattr(actual, attr) # type: ignore[attr-defined] + value = getattr(actual, attr) if not isinstance(value, dtype): raise RuntimeError(f"Expected type '{dtype}' but got '{type(value)}'") - return None + return actual # type: ignore[return-value] diff --git a/tests/test_frame.py b/tests/test_frame.py index 862847033..8aed66021 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -1139,20 +1139,51 @@ def test_types_regressions() -> None: def test_read_csv() -> None: - if TYPE_CHECKING: # skip pytest - # https://github.com/microsoft/python-type-stubs/issues/87 - df11: pd.DataFrame = pd.read_csv("foo") - df12: pd.DataFrame = pd.read_csv("foo", iterator=False) - df13: pd.DataFrame = pd.read_csv("foo", iterator=False, chunksize=None) - df14: TextFileReader = pd.read_csv("foo", chunksize=0) - df15: TextFileReader = pd.read_csv("foo", iterator=False, chunksize=0) - df16: TextFileReader = pd.read_csv("foo", iterator=True) - df17: TextFileReader = pd.read_csv("foo", iterator=True, chunksize=None) - df18: TextFileReader = pd.read_csv("foo", iterator=True, chunksize=0) - df19: TextFileReader = pd.read_csv("foo", chunksize=0) + with ensure_clean() as path: + Path(path).write_text("A,B\n1,2") + check(assert_type(pd.read_csv(path), pd.DataFrame), pd.DataFrame) + check( + assert_type(pd.read_csv(path, iterator=False), pd.DataFrame), pd.DataFrame + ) + check( + assert_type( + pd.read_csv(path, iterator=False, chunksize=None), pd.DataFrame + ), + pd.DataFrame, + ) + + with check( + assert_type(pd.read_csv(path, chunksize=1), TextFileReader), TextFileReader + ): + pass + with check( + assert_type(pd.read_csv(path, iterator=False, chunksize=1), TextFileReader), + TextFileReader, + ): + pass + with check( + assert_type(pd.read_csv(path, iterator=True), TextFileReader), + TextFileReader, + ): + pass + with check( + assert_type( + pd.read_csv(path, iterator=True, chunksize=None), TextFileReader + ), + TextFileReader, + ): + pass + with check( + assert_type(pd.read_csv(path, iterator=True, chunksize=1), TextFileReader), + TextFileReader, + ): + pass # https://github.com/microsoft/python-type-stubs/issues/118 - pd.read_csv("foo", storage_options=None) + check( + assert_type(pd.read_csv(path, storage_options=None), pd.DataFrame), + pd.DataFrame, + ) def test_groupby_series_methods() -> None: @@ -1358,6 +1389,7 @@ def test_set_columns() -> None: df = pd.DataFrame({"a": [1, 2, 3], "b": [0.0, 1, 1]}) # Next line should work, but it is a mypy bug # https://github.com/python/mypy/issues/3004 + # pyright doesn't need the ignore df.columns = ["c", "d"] # type: ignore[assignment] diff --git a/tests/test_interval.py b/tests/test_interval.py index cc47a8964..5c23f3e00 100644 --- a/tests/test_interval.py +++ b/tests/test_interval.py @@ -1,11 +1,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING - import pandas as pd from typing_extensions import assert_type -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) def test_interval_init() -> None: @@ -49,8 +50,8 @@ def test_interval_length() -> None: idres = i1 + pd.Timedelta(seconds=20) check(assert_type(idres, "pd.Interval[pd.Timestamp]"), pd.Interval, pd.Timestamp) - if TYPE_CHECKING: - 20 in i1 # type: ignore[operator] + if TYPE_CHECKING_INVALID_USAGE: + 20 in i1 # TODO both: ignore[operator] i1 + pd.Timestamp("2000-03-03") # type: ignore[operator] i1 * 3 # type: ignore[operator] i1 * pd.Timedelta(seconds=20) # type: ignore[operator] @@ -68,9 +69,13 @@ def test_interval_length() -> None: check(assert_type(i2 * 4, "pd.Interval[int]"), pd.Interval, int) check(assert_type(i2 * 4.2, "pd.Interval[float]"), pd.Interval, float) - if TYPE_CHECKING: - pd.Timestamp("2001-01-02") in i2 # type: ignore[operator] - i2 + pd.Timedelta(seconds=20) # type: ignore[operator] + if TYPE_CHECKING_INVALID_USAGE: + pd.Timestamp( + "2001-01-02" + ) in i2 # pyright: ignore[reportGeneralTypeIssues] # TODO mypy: ignore[operator] + i2 + pd.Timedelta( + seconds=20 + ) # pyright: ignore[reportGeneralTypeIssues] # TODO mypy: ignore[operator] i3 = pd.Interval(13.2, 19.5) check(assert_type(i3.length, float), float) @@ -82,6 +87,10 @@ def test_interval_length() -> None: check(assert_type(i3inres, bool), bool) check(assert_type(i3 + 3, "pd.Interval[float]"), pd.Interval, float) check(assert_type(i3 * 3, "pd.Interval[float]"), pd.Interval, float) - if TYPE_CHECKING: - pd.Timestamp("2001-01-02") in i3 # type: ignore[operator] - i3 + pd.Timedelta(seconds=20) # type: ignore[operator] + if TYPE_CHECKING_INVALID_USAGE: + pd.Timestamp( + "2001-01-02" + ) in i3 # pyright: ignore[reportGeneralTypeIssues] # TODO mypy: ignore[operator] + i3 + pd.Timedelta( + seconds=20 + ) # pyright: ignore[reportGeneralTypeIssues] # TODO mypy: ignore[operator] diff --git a/tests/test_series.py b/tests/test_series.py index 4a6841f73..322c5bd44 100644 --- a/tests/test_series.py +++ b/tests/test_series.py @@ -25,7 +25,10 @@ from pandas._typing import Scalar -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) if TYPE_CHECKING: from pandas._typing import np_ndarray_int # noqa: F401 @@ -661,7 +664,7 @@ def add1(x: int) -> int: # inplace s6: None = pd.Series([1, 2, 3]).rename("A", inplace=True) - if TYPE_CHECKING: + if TYPE_CHECKING_INVALID_USAGE: s7 = pd.Series([1, 2, 3]).rename({1: [3, 4, 5]}) # type: ignore[dict-item] diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 786d4c35d..3e082e7da 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -18,7 +18,10 @@ from pandas._libs import NaTType from pandas._libs.tslibs import BaseOffset -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) if TYPE_CHECKING: from pandas.core.series import ( @@ -201,10 +204,10 @@ def test_iso_calendar() -> None: def fail_on_adding_two_timestamps() -> None: s1 = pd.Series(pd.to_datetime(["2022-05-01", "2022-06-01"])) s2 = pd.Series(pd.to_datetime(["2022-05-15", "2022-06-15"])) - if TYPE_CHECKING: - ssum: pd.Series = s1 + s2 # type: ignore[operator] + if TYPE_CHECKING_INVALID_USAGE: + ssum: pd.Series = s1 + s2 # TODO both: ignore[operator] ts = pd.Timestamp("2022-06-30") - tsum: pd.Series = s1 + ts # type: ignore[operator] + tsum: pd.Series = s1 + ts # TODO both: ignore[operator] def test_dtindex_tzinfo() -> None: