Skip to content

TYP: Use Self instead of class-bound TypeVar in pyi files (remove Y019) #51480

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 2 commits into from
Mar 13, 2023
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
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,4 @@ dependencies:

- pip:
- sphinx-toggleprompt
- typing_extensions; python_version<"3.11"
Copy link
Member

Choose a reason for hiding this comment

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

I think we don't need to add it, as it is only used during type checking (and typing_extensions is, I think, a dependency of mypy).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, typing_extension is a dependency of mypy, I just checked for that. We do not want to be explicit, now that we're importing fro typing_extensions?

Copy link
Member

Choose a reason for hiding this comment

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

I think even the stubs packages from typeshed (for example https://pypi.org/project/types-psutil/) do not have typing_extensions as a dependency (neither does pandas-stubs).

If it is a new dependency, it probably should be added to the whatsnew (there might be other places where it needs to be added as well).

Copy link
Member

Choose a reason for hiding this comment

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

we have had discussions about this before and the outcome was that we do not use typing_extensions.

IIUC we don't need it with the latest mypy (1.0.0) when checking with python 3.11

16 changes: 7 additions & 9 deletions pandas/_libs/sparse.pyi
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from typing import (
Sequence,
TypeVar,
)
from typing import Sequence

import numpy as np

from pandas._typing import npt

_SparseIndexT = TypeVar("_SparseIndexT", bound=SparseIndex)
from pandas._typing import (
Self,
npt,
)

class SparseIndex:
length: int
Expand All @@ -24,8 +22,8 @@ class SparseIndex:
def lookup_array(self, indexer: npt.NDArray[np.int32]) -> npt.NDArray[np.int32]: ...
def to_int_index(self) -> IntIndex: ...
def to_block_index(self) -> BlockIndex: ...
def intersect(self: _SparseIndexT, y_: SparseIndex) -> _SparseIndexT: ...
def make_union(self: _SparseIndexT, y_: SparseIndex) -> _SparseIndexT: ...
def intersect(self, y_: SparseIndex) -> Self: ...
def make_union(self, y_: SparseIndex) -> Self: ...

class IntIndex(SparseIndex):
indices: npt.NDArray[np.int32]
Expand Down
21 changes: 12 additions & 9 deletions pandas/_libs/tslibs/offsets.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ from typing import (
import numpy as np

from pandas._libs.tslibs.nattype import NaTType
from pandas._typing import npt
from pandas._typing import (
Self,
npt,
)

from .timedeltas import Timedelta

Expand All @@ -39,40 +42,40 @@ class BaseOffset:
@overload
def __add__(self, other: npt.NDArray[np.object_]) -> npt.NDArray[np.object_]: ...
@overload
def __add__(self: _BaseOffsetT, other: BaseOffset) -> _BaseOffsetT: ...
def __add__(self, other: BaseOffset) -> Self: ...
@overload
def __add__(self, other: _DatetimeT) -> _DatetimeT: ...
@overload
def __add__(self, other: _TimedeltaT) -> _TimedeltaT: ...
@overload
def __radd__(self, other: npt.NDArray[np.object_]) -> npt.NDArray[np.object_]: ...
@overload
def __radd__(self: _BaseOffsetT, other: BaseOffset) -> _BaseOffsetT: ...
def __radd__(self, other: BaseOffset) -> Self: ...
@overload
def __radd__(self, other: _DatetimeT) -> _DatetimeT: ...
@overload
def __radd__(self, other: _TimedeltaT) -> _TimedeltaT: ...
@overload
def __radd__(self, other: NaTType) -> NaTType: ...
def __sub__(self: _BaseOffsetT, other: BaseOffset) -> _BaseOffsetT: ...
def __sub__(self, other: BaseOffset) -> Self: ...
@overload
def __rsub__(self, other: npt.NDArray[np.object_]) -> npt.NDArray[np.object_]: ...
@overload
def __rsub__(self: _BaseOffsetT, other: BaseOffset) -> _BaseOffsetT: ...
def __rsub__(self, other: BaseOffset): ...
@overload
def __rsub__(self, other: _DatetimeT) -> _DatetimeT: ...
@overload
def __rsub__(self, other: _TimedeltaT) -> _TimedeltaT: ...
@overload
def __mul__(self, other: np.ndarray) -> np.ndarray: ...
@overload
def __mul__(self: _BaseOffsetT, other: int) -> _BaseOffsetT: ...
def __mul__(self, other: int): ...
@overload
def __rmul__(self, other: np.ndarray) -> np.ndarray: ...
@overload
def __rmul__(self: _BaseOffsetT, other: int) -> _BaseOffsetT: ...
def __neg__(self: _BaseOffsetT) -> _BaseOffsetT: ...
def copy(self: _BaseOffsetT) -> _BaseOffsetT: ...
def __rmul__(self, other: int) -> Self: ...
def __neg__(self) -> Self: ...
def copy(self) -> Self: ...
@property
def name(self) -> str: ...
@property
Expand Down
11 changes: 7 additions & 4 deletions pandas/_libs/tslibs/timedeltas.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ from pandas._libs.tslibs import (
NaTType,
Tick,
)
from pandas._typing import npt
from pandas._typing import (
Self,
npt,
)

# This should be kept consistent with the keys in the dict timedelta_abbrevs
# in pandas/_libs/tslibs/timedeltas.pyx
Expand Down Expand Up @@ -111,9 +114,9 @@ class Timedelta(timedelta):
@property
def asm8(self) -> np.timedelta64: ...
# TODO: round/floor/ceil could return NaT?
def round(self: _S, freq: str) -> _S: ...
def floor(self: _S, freq: str) -> _S: ...
def ceil(self: _S, freq: str) -> _S: ...
def round(self, freq: str) -> Self: ...
def floor(self, freq: str) -> Self: ...
def ceil(self, freq: str) -> Self: ...
@property
def resolution_string(self) -> str: ...
def __add__(self, other: timedelta) -> Timedelta: ...
Expand Down
57 changes: 25 additions & 32 deletions pandas/_libs/tslibs/timestamps.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ from pandas._libs.tslibs import (
Tick,
Timedelta,
)
from pandas._typing import Self

_DatetimeT = TypeVar("_DatetimeT", bound=datetime)

Expand Down Expand Up @@ -80,30 +81,28 @@ class Timestamp(datetime):
@property
def fold(self) -> int: ...
@classmethod
def fromtimestamp(
cls: type[_DatetimeT], ts: float, tz: _tzinfo | None = ...
) -> _DatetimeT: ...
def fromtimestamp(cls, ts: float, tz: _tzinfo | None = ...) -> Self: ...
@classmethod
def utcfromtimestamp(cls: type[_DatetimeT], ts: float) -> _DatetimeT: ...
def utcfromtimestamp(cls, ts: float) -> Self: ...
@classmethod
def today(cls: type[_DatetimeT], tz: _tzinfo | str | None = ...) -> _DatetimeT: ...
def today(cls, tz: _tzinfo | str | None = ...) -> Self: ...
@classmethod
def fromordinal(
cls: type[_DatetimeT],
cls,
ordinal: int,
tz: _tzinfo | str | None = ...,
) -> _DatetimeT: ...
) -> Self: ...
@classmethod
def now(cls: type[_DatetimeT], tz: _tzinfo | str | None = ...) -> _DatetimeT: ...
def now(cls, tz: _tzinfo | str | None = ...) -> Self: ...
@classmethod
def utcnow(cls: type[_DatetimeT]) -> _DatetimeT: ...
def utcnow(cls) -> Self: ...
# error: Signature of "combine" incompatible with supertype "datetime"
@classmethod
def combine( # type: ignore[override]
cls, date: _date, time: _time
) -> datetime: ...
@classmethod
def fromisoformat(cls: type[_DatetimeT], date_string: str) -> _DatetimeT: ...
def fromisoformat(cls, date_string: str) -> Self: ...
def strftime(self, format: str) -> str: ...
def __format__(self, fmt: str) -> str: ...
def toordinal(self) -> int: ...
Expand All @@ -116,7 +115,7 @@ class Timestamp(datetime):
# LSP violation: nanosecond is not present in datetime.datetime.replace
# and has positional args following it
def replace( # type: ignore[override]
self: _DatetimeT,
self,
year: int | None = ...,
month: int | None = ...,
day: int | None = ...,
Expand All @@ -127,11 +126,9 @@ class Timestamp(datetime):
nanosecond: int | None = ...,
tzinfo: _tzinfo | type[object] | None = ...,
fold: int | None = ...,
) -> _DatetimeT: ...
) -> Self: ...
# LSP violation: datetime.datetime.astimezone has a default value for tz
def astimezone( # type: ignore[override]
self: _DatetimeT, tz: _tzinfo | None
) -> _DatetimeT: ...
def astimezone(self, tz: _tzinfo | None) -> Self: ... # type: ignore[override]
def ctime(self) -> str: ...
def isoformat(self, sep: str = ..., timespec: str = ...) -> str: ...
@classmethod
Expand All @@ -147,16 +144,12 @@ class Timestamp(datetime):
@overload # type: ignore[override]
def __add__(self, other: np.ndarray) -> np.ndarray: ...
@overload
def __add__(
self: _DatetimeT, other: timedelta | np.timedelta64 | Tick
) -> _DatetimeT: ...
def __radd__(self: _DatetimeT, other: timedelta) -> _DatetimeT: ...
def __add__(self, other: timedelta | np.timedelta64 | Tick) -> Self: ...
def __radd__(self, other: timedelta) -> Self: ...
@overload # type: ignore[override]
def __sub__(self, other: datetime) -> Timedelta: ...
@overload
def __sub__(
self: _DatetimeT, other: timedelta | np.timedelta64 | Tick
) -> _DatetimeT: ...
def __sub__(self, other: timedelta | np.timedelta64 | Tick) -> Self: ...
def __hash__(self) -> int: ...
def weekday(self) -> int: ...
def isoweekday(self) -> int: ...
Expand All @@ -181,25 +174,25 @@ class Timestamp(datetime):
def to_julian_date(self) -> np.float64: ...
@property
def asm8(self) -> np.datetime64: ...
def tz_convert(self: _DatetimeT, tz: _tzinfo | str | None) -> _DatetimeT: ...
def tz_convert(self, tz: _tzinfo | str | None) -> Self: ...
# TODO: could return NaT?
def tz_localize(
self: _DatetimeT,
self,
tz: _tzinfo | str | None,
ambiguous: str = ...,
nonexistent: str = ...,
) -> _DatetimeT: ...
def normalize(self: _DatetimeT) -> _DatetimeT: ...
) -> Self: ...
def normalize(self) -> Self: ...
# TODO: round/floor/ceil could return NaT?
def round(
self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ...
) -> _DatetimeT: ...
self, freq: str, ambiguous: bool | str = ..., nonexistent: str = ...
) -> Self: ...
def floor(
self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ...
) -> _DatetimeT: ...
self, freq: str, ambiguous: bool | str = ..., nonexistent: str = ...
) -> Self: ...
def ceil(
self: _DatetimeT, freq: str, ambiguous: bool | str = ..., nonexistent: str = ...
) -> _DatetimeT: ...
self, freq: str, ambiguous: bool | str = ..., nonexistent: str = ...
) -> Self: ...
def day_name(self, locale: str | None = ...) -> str: ...
def month_name(self, locale: str | None = ...) -> str: ...
@property
Expand Down
6 changes: 6 additions & 0 deletions pandas/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
tzinfo,
)
from os import PathLike
import sys
from typing import (
TYPE_CHECKING,
Any,
Expand Down Expand Up @@ -83,8 +84,13 @@
# Name "npt._ArrayLikeInt_co" is not defined [name-defined]
NumpySorter = Optional[npt._ArrayLikeInt_co] # type: ignore[name-defined]

if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self # pyright: reportUnusedImport = false
Copy link
Member

Choose a reason for hiding this comment

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

I guess you could make Self equivalent to Any here. IIRC we did something similar before to enable the latest typing features

Copy link
Member

Choose a reason for hiding this comment

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

We type check using a single version of Python. There are capabilities in mypy to set the Python version to check against regardless of the version used. We don't do that.

So i'm not sure when this import is actually needed.

else:
npt: Any = None
Self: Any = None

HashableT = TypeVar("HashableT", bound=Hashable)

Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,5 @@ pyyaml
requests
pygments
sphinx-toggleprompt
typing_extensions; python_version<"3.11"
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need this

setuptools>=61.0.0
2 changes: 0 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ ignore =
E731,
# found modulo formatter (incorrect picks up mod operations)
Y002,
# Use "_typeshed.Self" instead of class-bound TypeVar
Y019,
# Docstrings should not be included in stubs
Y021,
# Use typing_extensions.TypeAlias for type aliases
Expand Down