diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 49ee440c5..5ff17037a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,26 +26,12 @@ jobs: - name: Install Poetry run: pip install poetry - - name: Determine poetry cache-dir - run: | - echo "::set-output name=PATH::$(poetry config cache-dir)" - id: cache_path - - - name: Cache project dependencies + - name: Cache poetry.lock id : cache uses: actions/cache@v3 - with: - path: | - ${{ steps.cache_path.outputs.PATH }} - poetry.lock - key: ${{ matrix.os }}-${{ matrix.python-version }}-poetry-${{ hashFiles('pyproject.toml') }} - restore-keys: ${{ matrix.os }}-${{ matrix.python-version }}-poetry- - - - name: Delete poetry.lock on cache miss - if: steps.cache.outputs.cache-hit != 'true' - uses: JesseTG/rm@v1.0.3 with: path: poetry.lock + key: poetry-${{ hashFiles('pyproject.toml') }} - name: Install project dependencies run: poetry install -vvv --no-root diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 7d44d7649..ca5ce32ac 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -200,5 +200,5 @@ XMLParsers = Literal["lxml", "etree"] # Any plain Python or numpy function Function = Union[np.ufunc, Callable[..., Any]] GroupByObject = Union[ - Label, List[Label], Function, Series, np.ndarray, Mapping[Label, Any] + Label, List[Label], Function, Series, np.ndarray, Mapping[Label, Any], Index ] diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index 21f73e136..f14f71da2 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -5,6 +5,7 @@ import datetime as _dt from typing import ( Any, Callable, + ClassVar, Dict, Hashable, Iterable, @@ -183,6 +184,8 @@ class DataFrame(NDFrame, OpsMixin): Index, Series, ] + __hash__: ClassVar[None] # type: ignore[assignment] + def __new__( cls, data: Optional[Union[_ListLike, DataFrame, Dict[Any, Any]]] = ..., @@ -428,7 +431,7 @@ class DataFrame(NDFrame, OpsMixin): *, axis: Axis = ..., index: Hashable | Sequence[Hashable] = ..., - columns: Hashable | Sequence[Hashable] = ..., + columns: Hashable | Sequence[Hashable] | Index = ..., level: Optional[Level] = ..., inplace: Literal[True], errors: IgnoreRaise = ..., @@ -440,7 +443,7 @@ class DataFrame(NDFrame, OpsMixin): *, axis: Axis = ..., index: Hashable | Sequence[Hashable] = ..., - columns: Hashable | Sequence[Hashable] = ..., + columns: Hashable | Sequence[Hashable] | Index = ..., level: Optional[Level] = ..., inplace: Literal[False] = ..., errors: IgnoreRaise = ..., @@ -452,7 +455,7 @@ class DataFrame(NDFrame, OpsMixin): *, axis: Axis = ..., index: Hashable | Sequence[Hashable] = ..., - columns: Hashable | Sequence[Hashable] = ..., + columns: Hashable | Sequence[Hashable] | Index = ..., level: Optional[Level] = ..., inplace: bool = ..., errors: IgnoreRaise = ..., diff --git a/pandas-stubs/core/generic.pyi b/pandas-stubs/core/generic.pyi index 71ab8de23..058962d9d 100644 --- a/pandas-stubs/core/generic.pyi +++ b/pandas-stubs/core/generic.pyi @@ -2,6 +2,7 @@ import sys from typing import ( Any, Callable, + ClassVar, Dict, Hashable, Iterator, @@ -48,6 +49,8 @@ _bool = bool _str = str class NDFrame(PandasObject, indexing.IndexingMixin): + __hash__: ClassVar[None] # type: ignore[assignment] + def __new__( cls, data: BlockManager, @@ -89,7 +92,6 @@ class NDFrame(PandasObject, indexing.IndexingMixin): def bool(self) -> _bool: ... def __abs__(self) -> NDFrame: ... def __round__(self, decimals: int = ...) -> NDFrame: ... - def __hash__(self): ... def __iter__(self) -> Iterator: ... def keys(self): ... def iteritems(self): ... diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 3a893d9f3..dfbe9c757 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -1,5 +1,6 @@ from typing import ( Callable, + ClassVar, Dict, Hashable, Iterable, @@ -41,6 +42,8 @@ class InvalidIndexError(Exception): ... _str = str class Index(IndexOpsMixin, PandasObject): + __hash__: ClassVar[None] # type: ignore[assignment] + def __new__( cls, data: Iterable = ..., @@ -169,7 +172,6 @@ class Index(IndexOpsMixin, PandasObject): def where(self, cond, other=...): ... def is_type_compatible(self, kind) -> bool: ... def __contains__(self, key) -> bool: ... - def __hash__(self) -> int: ... def __setitem__(self, key, value) -> None: ... @overload def __getitem__( diff --git a/pandas-stubs/core/indexes/frozen.pyi b/pandas-stubs/core/indexes/frozen.pyi index 309777c86..e23878fa6 100644 --- a/pandas-stubs/core/indexes/frozen.pyi +++ b/pandas-stubs/core/indexes/frozen.pyi @@ -8,4 +8,4 @@ class FrozenList(PandasObject, list): def __eq__(self, other) -> bool: ... def __mul__(self, other): ... def __reduce__(self): ... - def __hash__(self): ... + def __hash__(self) -> int: ... # type: ignore[override] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 4612a4f52..9d73c4e1d 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -5,6 +5,7 @@ from datetime import ( from typing import ( Any, Callable, + ClassVar, Dict, Generic, Hashable, @@ -138,6 +139,8 @@ class _LocIndexerSeries(_LocIndexer, Generic[S1]): class Series(IndexOpsMixin, NDFrame, Generic[S1]): _ListLike = Union[ArrayLike, Dict[_str, np.ndarray], List, Tuple, Index] + __hash__: ClassVar[None] + @overload def __new__( cls, diff --git a/tests/test_frame.py b/tests/test_frame.py index 31e768cb4..16a0a95c5 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -7,6 +7,7 @@ TYPE_CHECKING, Any, Dict, + Hashable, Iterable, List, Tuple, @@ -1141,3 +1142,20 @@ def test_frame_ndarray_assignmment() -> None: df_b = pd.DataFrame({"a": [0.0] * 10, "b": [1.0] * 10}) df_b.iloc[:, :] = np.array([[-1.0, np.inf]] * 10) + + +def test_not_hashable() -> None: + # GH 113 + assert assert_type(pd.DataFrame.__hash__, None) is None + assert assert_type(pd.DataFrame().__hash__, None) is None + assert assert_type(pd.Series.__hash__, None) is None + assert assert_type(pd.Series([], dtype=object).__hash__, None) is None + assert assert_type(pd.Index.__hash__, None) is None + assert assert_type(pd.Index([]).__hash__, None) is None + + def test_func(h: Hashable): + pass + + test_func(pd.DataFrame()) # type: ignore[arg-type] + test_func(pd.Series([], dtype=object)) # type: ignore[arg-type] + test_func(pd.Index([])) # type: ignore[arg-type]