Skip to content

CI: check for some unused ignore comments #213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 22, 2022
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
8 changes: 4 additions & 4 deletions pandas-stubs/core/groupby/generic.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
3 changes: 1 addition & 2 deletions pandas-stubs/core/indexes/datetimes.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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=...,
Expand Down
2 changes: 2 additions & 0 deletions pandas-stubs/io/parsers.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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=...): ...

Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -168,6 +168,7 @@ reportMissingParameterType = false
reportMissingTypeArgument = false
reportMissingTypeStubs = false
reportUnknownArgumentType = false
reportUnusedExpression = false
reportUnknownLambdaType = false
reportUnknownMemberType = false
reportUnknownParameterType = false
Expand Down
19 changes: 13 additions & 6 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -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]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a mypy error to me: I think it is of type object because of the instance call where class is just type without a specification which type. Might fallback to object.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


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]
56 changes: 44 additions & 12 deletions tests/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is almost the only ignore in the tests that is not needed by pyright (there are many in the stubs that are not "needed").

The other two ignores are in tests/__init__.py.

If pyright had no unnecessary ignore comments in the tests, we could have a second pyright config for the installed stub check (it only checks the tests using the stubs, but not the stubs).

df.columns = ["c", "d"] # type: ignore[assignment]


Expand Down
31 changes: 20 additions & 11 deletions tests/test_interval.py
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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]
Expand All @@ -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)
Expand All @@ -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]
7 changes: 5 additions & 2 deletions tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]


Expand Down
11 changes: 7 additions & 4 deletions tests/test_timefuncs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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:
Expand Down