From 89b56a45f0548ace8e959c6197a3abeb30545857 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Mon, 3 May 2021 15:12:49 +0100 Subject: [PATCH 1/9] make frame and series non-hashable --- doc/source/whatsnew/v1.3.0.rst | 1 + pandas/core/arrays/base.py | 6 ++++-- pandas/core/frame.py | 14 +++++++------- pandas/core/generic.py | 9 ++++----- pandas/core/indexes/base.py | 7 ++++--- pandas/core/reshape/pivot.py | 21 ++++++++++----------- pandas/core/series.py | 1 - pandas/tests/frame/test_api.py | 2 +- pandas/tests/series/test_api.py | 2 +- 9 files changed, 32 insertions(+), 31 deletions(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 84f9dae8a0850..23f8df370cd07 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -612,6 +612,7 @@ Other API changes - Partially initialized :class:`CategoricalDtype` (i.e. those with ``categories=None`` objects will no longer compare as equal to fully initialized dtype objects. - Accessing ``_constructor_expanddim`` on a :class:`DataFrame` and ``_constructor_sliced`` on a :class:`Series` now raise an ``AttributeError``. Previously a ``NotImplementedError`` was raised (:issue:`38782`) - Added new ``engine`` and ``**engine_kwargs`` parameters to :meth:`DataFrame.to_sql` to support other future "SQL engines". Currently we still only use ``SQLAlchemy`` under the hood, but more engines are planned to be supported such as ``turbodbc`` (:issue:`36893`) +- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``"'Series' objects are mutable, thus they cannot be hashed"`` (:issue:`40013`) Build ===== diff --git a/pandas/core/arrays/base.py b/pandas/core/arrays/base.py index f337589c35583..532898539b820 100644 --- a/pandas/core/arrays/base.py +++ b/pandas/core/arrays/base.py @@ -1302,8 +1302,10 @@ def _reduce(self, name: str, *, skipna: bool = True, **kwargs): """ raise TypeError(f"cannot perform {name} with type {self.dtype}") - def __hash__(self) -> int: - raise TypeError(f"unhashable type: {repr(type(self).__name__)}") + # https://github.com/python/typeshed/issues/2148#issuecomment-520783318 + # Incompatible types in assignment (expression has type "None", base class + # "object" defined the type as "Callable[[object], int]") + __hash__: None # type: ignore[assignment] # ------------------------------------------------------------------------ # Non-Optimized Default Methods diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 2941b6ac01904..171f831c30a8e 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -6152,26 +6152,26 @@ def f(vals) -> tuple[np.ndarray, int]: return labels.astype("i8", copy=False), len(shape) if subset is None: - subset = self.columns + subset_iterable: Iterable = self.columns elif ( not np.iterable(subset) or isinstance(subset, str) or isinstance(subset, tuple) and subset in self.columns ): - subset = (subset,) - - # needed for mypy since can't narrow types using np.iterable - subset = cast(Iterable, subset) + subset_iterable = (subset,) + else: + # needed for mypy since can't narrow types using np.iterable + subset_iterable = cast(Iterable, subset) # Verify all columns in subset exist in the queried dataframe # Otherwise, raise a KeyError, same as if you try to __getitem__ with a # key that doesn't exist. - diff = Index(subset).difference(self.columns) + diff = Index(subset_iterable).difference(self.columns) if not diff.empty: raise KeyError(diff) - vals = (col.values for name, col in self.items() if name in subset) + vals = (col.values for name, col in self.items() if name in subset_iterable) labels, shape = map(list, zip(*map(f, vals))) ids = get_group_index( diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0d39f13afc426..8c2afed502ded 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1872,11 +1872,10 @@ def _drop_labels_or_levels(self, keys, axis: int = 0): # ---------------------------------------------------------------------- # Iteration - def __hash__(self) -> int: - raise TypeError( - f"{repr(type(self).__name__)} objects are mutable, " - f"thus they cannot be hashed" - ) + # https://github.com/python/typeshed/issues/2148#issuecomment-520783318 + # Incompatible types in assignment (expression has type "None", base class + # "object" defined the type as "Callable[[object], int]") + __hash__: None # type: ignore[assignment] def __iter__(self): """ diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 83946491f32a8..c16b83ac7ef50 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4558,9 +4558,10 @@ def __contains__(self, key: Any) -> bool: except (OverflowError, TypeError, ValueError): return False - @final - def __hash__(self): - raise TypeError(f"unhashable type: {repr(type(self).__name__)}") + # https://github.com/python/typeshed/issues/2148#issuecomment-520783318 + # Incompatible types in assignment (expression has type "None", base class + # "object" defined the type as "Callable[[object], int]") + __hash__: None # type: ignore[assignment] @final def __setitem__(self, key, value): diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index 51556fda6da04..7a5c2677307e2 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -482,7 +482,7 @@ def pivot( if columns is None: raise TypeError("pivot() missing 1 required argument: 'columns'") - columns = com.convert_to_list_like(columns) + columns_listlike = com.convert_to_list_like(columns) if values is None: if index is not None: @@ -494,28 +494,27 @@ def pivot( # error: Unsupported operand types for + ("List[Any]" and "ExtensionArray") # error: Unsupported left operand type for + ("ExtensionArray") indexed = data.set_index( - cols + columns, append=append # type: ignore[operator] + cols + columns_listlike, append=append # type: ignore[operator] ) else: if index is None: - index = [Series(data.index, name=data.index.name)] + index_list = [Series(data.index, name=data.index.name)] else: - index = com.convert_to_list_like(index) - index = [data[idx] for idx in index] + index_list = [data[idx] for idx in com.convert_to_list_like(index)] - data_columns = [data[col] for col in columns] - index.extend(data_columns) - index = MultiIndex.from_arrays(index) + data_columns = [data[col] for col in columns_listlike] + index_list.extend(data_columns) + multiindex = MultiIndex.from_arrays(index_list) if is_list_like(values) and not isinstance(values, tuple): # Exclude tuple because it is seen as a single column name values = cast(Sequence[Hashable], values) indexed = data._constructor( - data[values]._values, index=index, columns=values + data[values]._values, index=multiindex, columns=values ) else: - indexed = data._constructor_sliced(data[values]._values, index=index) - return indexed.unstack(columns) + indexed = data._constructor_sliced(data[values]._values, index=multiindex) + return indexed.unstack(columns_listlike) def crosstab( diff --git a/pandas/core/series.py b/pandas/core/series.py index c8e9898f9462a..17ceff1c9542b 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -272,7 +272,6 @@ class Series(base.IndexOpsMixin, generic.NDFrame): hasnans = property( # type: ignore[assignment] base.IndexOpsMixin.hasnans.func, doc=base.IndexOpsMixin.hasnans.__doc__ ) - __hash__ = generic.NDFrame.__hash__ _mgr: SingleManager div: Callable[[Series, Any], Series] rdiv: Callable[[Series, Any], Series] diff --git a/pandas/tests/frame/test_api.py b/pandas/tests/frame/test_api.py index 76cfd77d254f2..49649c1487f13 100644 --- a/pandas/tests/frame/test_api.py +++ b/pandas/tests/frame/test_api.py @@ -91,7 +91,7 @@ def test_not_hashable(self): empty_frame = DataFrame() df = DataFrame([1]) - msg = "'DataFrame' objects are mutable, thus they cannot be hashed" + msg = "unhashable type: 'DataFrame'" with pytest.raises(TypeError, match=msg): hash(df) with pytest.raises(TypeError, match=msg): diff --git a/pandas/tests/series/test_api.py b/pandas/tests/series/test_api.py index eddf57c1e88f3..b49c209a59a06 100644 --- a/pandas/tests/series/test_api.py +++ b/pandas/tests/series/test_api.py @@ -101,7 +101,7 @@ def test_index_tab_completion(self, index): def test_not_hashable(self): s_empty = Series(dtype=object) s = Series([1]) - msg = "'Series' objects are mutable, thus they cannot be hashed" + msg = "unhashable type: 'Series'" with pytest.raises(TypeError, match=msg): hash(s_empty) with pytest.raises(TypeError, match=msg): From 31593c3e2ee84c2e3849c6f9e01d849033fd2a89 Mon Sep 17 00:00:00 2001 From: MarcoGorelli Date: Fri, 18 Jun 2021 09:49:07 +0100 Subject: [PATCH 2/9] move to v1.4.0 whatsnew, declare type before if --- doc/source/whatsnew/v1.3.0.rst | 2 -- doc/source/whatsnew/v1.4.0.rst | 2 +- pandas/core/frame.py | 3 ++- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 804658f643879..454a10eaa3781 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -700,8 +700,6 @@ Other API changes ^^^^^^^^^^^^^^^^^ - Partially initialized :class:`CategoricalDtype` objects (i.e. those with ``categories=None``) will no longer compare as equal to fully initialized dtype objects (:issue:`38516`) - Accessing ``_constructor_expanddim`` on a :class:`DataFrame` and ``_constructor_sliced`` on a :class:`Series` now raise an ``AttributeError``. Previously a ``NotImplementedError`` was raised (:issue:`38782`) -- Added new ``engine`` and ``**engine_kwargs`` parameters to :meth:`DataFrame.to_sql` to support other future "SQL engines". Currently we still only use ``SQLAlchemy`` under the hood, but more engines are planned to be supported such as ``turbodbc`` (:issue:`36893`) -- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``"'Series' objects are mutable, thus they cannot be hashed"`` (:issue:`40013`) - Added new ``engine`` and ``**engine_kwargs`` parameters to :meth:`DataFrame.to_sql` to support other future "SQL engines". Currently we still only use ``SQLAlchemy`` under the hood, but more engines are planned to be supported such as `turbodbc `_ (:issue:`36893`) - Removed redundant ``freq`` from :class:`PeriodIndex` string representation (:issue:`41653`) - :meth:`ExtensionDtype.construct_array_type` is now a required method instead of an optional one for :class:`ExtensionDtype` subclasses (:issue:`24860`) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 9859f12a34621..ed13242cbab84 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -87,7 +87,7 @@ See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for mor Other API changes ^^^^^^^^^^^^^^^^^ -- +- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``"'Series' objects are mutable, thus they cannot be hashed"`` (:issue:`40013`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 84d787fbe9c98..f2cb5696e5af3 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -6181,8 +6181,9 @@ def f(vals) -> tuple[np.ndarray, int]: labels, shape = algorithms.factorize(vals, size_hint=len(self)) return labels.astype("i8", copy=False), len(shape) + subset_iterable: Iterable if subset is None: - subset_iterable: Iterable = self.columns + subset_iterable = self.columns elif ( not np.iterable(subset) or isinstance(subset, str) From c4c2ec1820f9ccbfaeab7f947ca4d716bf1fcbc1 Mon Sep 17 00:00:00 2001 From: MarcoGorelli Date: Fri, 18 Jun 2021 10:04:09 +0100 Subject: [PATCH 3/9] add test for index --- doc/source/whatsnew/v1.4.0.rst | 2 +- pandas/tests/indexes/test_base.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index ed13242cbab84..68b3a66be72fb 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -87,7 +87,7 @@ See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for mor Other API changes ^^^^^^^^^^^^^^^^^ -- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``"'Series' objects are mutable, thus they cannot be hashed"`` (:issue:`40013`) +- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``'Series' objects are mutable, thus they cannot be hashed`` (:issue:`40013`) - .. --------------------------------------------------------------------------- diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index d7abaf0b5dfbe..53c50fb1855f0 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -1777,3 +1777,11 @@ def test_drop_duplicates_pos_args_deprecation(): result = idx.drop_duplicates("last") expected = Index([2, 3, 1]) tm.assert_index_equal(expected, result) + + +def test_not_hashable(): + # GH#40013 + idx = Index([1, 2, 3]) + msg = "unhashable type: 'Int64Index'" + with pytest.raises(TypeError, match=msg): + hash(idx) From 3af90218754dad8f4ecc3850b5d07e650ad967ed Mon Sep 17 00:00:00 2001 From: MarcoGorelli Date: Fri, 18 Jun 2021 10:09:49 +0100 Subject: [PATCH 4/9] test extensionarray --- pandas/tests/extension/test_common.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pandas/tests/extension/test_common.py b/pandas/tests/extension/test_common.py index e43650c291200..ff554c34a3943 100644 --- a/pandas/tests/extension/test_common.py +++ b/pandas/tests/extension/test_common.py @@ -79,3 +79,11 @@ def test_astype_no_copy(): def test_is_extension_array_dtype(dtype): assert isinstance(dtype, dtypes.ExtensionDtype) assert is_extension_array_dtype(dtype) + + +def test_astype_non_hashable(): + # GH#40013 + arr = DummyArray(np.array([1, 2, 3], dtype=np.int64)) + msg = "unhashable type: 'DummyArray'" + with pytest.raises(TypeError, match=msg): + hash(arr) From f913f04fad9e513d7a57f573503e82929c50ba24 Mon Sep 17 00:00:00 2001 From: MarcoGorelli Date: Fri, 18 Jun 2021 10:25:01 +0100 Subject: [PATCH 5/9] revert pandas/tests/indexes/test_base.py --- pandas/tests/indexes/test_base.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 53c50fb1855f0..d7abaf0b5dfbe 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -1777,11 +1777,3 @@ def test_drop_duplicates_pos_args_deprecation(): result = idx.drop_duplicates("last") expected = Index([2, 3, 1]) tm.assert_index_equal(expected, result) - - -def test_not_hashable(): - # GH#40013 - idx = Index([1, 2, 3]) - msg = "unhashable type: 'Int64Index'" - with pytest.raises(TypeError, match=msg): - hash(idx) From d05deef6da384f2ee25c3cc0f98cc48e025f4b1d Mon Sep 17 00:00:00 2001 From: MarcoGorelli Date: Fri, 18 Jun 2021 10:27:18 +0100 Subject: [PATCH 6/9] revert pandas/tests/extension/test_common.py --- pandas/tests/extension/test_common.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pandas/tests/extension/test_common.py b/pandas/tests/extension/test_common.py index ff554c34a3943..e43650c291200 100644 --- a/pandas/tests/extension/test_common.py +++ b/pandas/tests/extension/test_common.py @@ -79,11 +79,3 @@ def test_astype_no_copy(): def test_is_extension_array_dtype(dtype): assert isinstance(dtype, dtypes.ExtensionDtype) assert is_extension_array_dtype(dtype) - - -def test_astype_non_hashable(): - # GH#40013 - arr = DummyArray(np.array([1, 2, 3], dtype=np.int64)) - msg = "unhashable type: 'DummyArray'" - with pytest.raises(TypeError, match=msg): - hash(arr) From a05b86c379f14b2a16e1cd7c58828800cc22a1ab Mon Sep 17 00:00:00 2001 From: MarcoGorelli Date: Fri, 18 Jun 2021 16:53:08 +0100 Subject: [PATCH 7/9] move to 1.3.0 --- doc/source/whatsnew/v1.3.0.rst | 1 + doc/source/whatsnew/v1.4.0.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 454a10eaa3781..767d65167de51 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -703,6 +703,7 @@ Other API changes - Added new ``engine`` and ``**engine_kwargs`` parameters to :meth:`DataFrame.to_sql` to support other future "SQL engines". Currently we still only use ``SQLAlchemy`` under the hood, but more engines are planned to be supported such as `turbodbc `_ (:issue:`36893`) - Removed redundant ``freq`` from :class:`PeriodIndex` string representation (:issue:`41653`) - :meth:`ExtensionDtype.construct_array_type` is now a required method instead of an optional one for :class:`ExtensionDtype` subclasses (:issue:`24860`) +- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``'Series' objects are mutable, thus they cannot be hashed`` (:issue:`40013`) .. _whatsnew_130.api_breaking.build: diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 68b3a66be72fb..9859f12a34621 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -87,7 +87,7 @@ See :ref:`install.dependencies` and :ref:`install.optional_dependencies` for mor Other API changes ^^^^^^^^^^^^^^^^^ -- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``'Series' objects are mutable, thus they cannot be hashed`` (:issue:`40013`) +- - .. --------------------------------------------------------------------------- From 78abb2350b5994d7337767b46f677dd07d3ab634 Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Sat, 26 Jun 2021 13:49:06 +0100 Subject: [PATCH 8/9] cast self.columns to Sequence[Hashable] --- doc/source/whatsnew/v1.3.0.rst | 2 +- pandas/core/frame.py | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index acccf5e109964..076320aa22a7f 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -707,7 +707,7 @@ Other API changes - Added new ``engine`` and ``**engine_kwargs`` parameters to :meth:`DataFrame.to_sql` to support other future "SQL engines". Currently we still only use ``SQLAlchemy`` under the hood, but more engines are planned to be supported such as `turbodbc `_ (:issue:`36893`) - Removed redundant ``freq`` from :class:`PeriodIndex` string representation (:issue:`41653`) - :meth:`ExtensionDtype.construct_array_type` is now a required method instead of an optional one for :class:`ExtensionDtype` subclasses (:issue:`24860`) -- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``'Series' objects are mutable, thus they cannot be hashed``. Furthermore, ``isinstance(Series, abc.collections.Hashable)`` will now return ``False`` (:issue:`40013`) +- Calling ``hash`` on non-hashable pandas objects will now raise ``TypeError`` with the built-in error message (e.g. ``unhashable type: 'Series'``). Previously it would raise a custom message such as ``'Series' objects are mutable, thus they cannot be hashed``. Furthermore, ``isinstance(, abc.collections.Hashable)`` will now return ``False`` (:issue:`40013`) .. _whatsnew_130.api_breaking.build: diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 5b4316f6054c1..13e822b0616ed 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -6179,28 +6179,27 @@ def f(vals) -> tuple[np.ndarray, int]: labels, shape = algorithms.factorize(vals, size_hint=len(self)) return labels.astype("i8", copy=False), len(shape) - subset_iterable: Sequence if subset is None: - subset_iterable = self.columns + subset = cast(Sequence[Hashable], self.columns) elif ( not np.iterable(subset) or isinstance(subset, str) or isinstance(subset, tuple) and subset in self.columns ): - subset_iterable = (subset,) - else: - # needed for mypy since can't narrow types using np.iterable - subset_iterable = cast(Sequence, subset) + subset = (subset,) + + # needed for mypy since can't narrow types using np.iterable + subset = cast(Sequence, subset) # Verify all columns in subset exist in the queried dataframe # Otherwise, raise a KeyError, same as if you try to __getitem__ with a # key that doesn't exist. - diff = Index(subset_iterable).difference(self.columns) + diff = Index(subset).difference(self.columns) if not diff.empty: raise KeyError(diff) - vals = (col.values for name, col in self.items() if name in subset_iterable) + vals = (col.values for name, col in self.items() if name in subset) labels, shape = map(list, zip(*map(f, vals))) ids = get_group_index( From dee8b0b7053758b28d53a11ab2f3fb09a8cb5fae Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Sat, 26 Jun 2021 13:51:56 +0100 Subject: [PATCH 9/9] ignore mypy error, pending on 28770 --- pandas/core/frame.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 13e822b0616ed..7063d064d892e 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -6180,7 +6180,10 @@ def f(vals) -> tuple[np.ndarray, int]: return labels.astype("i8", copy=False), len(shape) if subset is None: - subset = cast(Sequence[Hashable], self.columns) + # Incompatible types in assignment + # (expression has type "Index", variable has type "Sequence[Any]") + # (pending on https://github.com/pandas-dev/pandas/issues/28770) + subset = self.columns # type: ignore[assignment] elif ( not np.iterable(subset) or isinstance(subset, str)