From c5d256495c9bd5cc137be9decb07391c6bc41d5b Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sun, 11 Feb 2024 00:45:23 +0100 Subject: [PATCH 1/6] CoW: Remove a few copy=False statements --- pandas/core/apply.py | 4 ++-- pandas/core/computation/align.py | 2 +- pandas/core/groupby/generic.py | 4 ++-- pandas/core/groupby/groupby.py | 10 +++++----- pandas/core/indexing.py | 7 ++++--- pandas/core/internals/construction.py | 4 ++-- pandas/core/methods/describe.py | 2 +- pandas/core/reshape/encoding.py | 2 +- pandas/core/strings/accessor.py | 1 - pandas/core/window/ewm.py | 2 +- pandas/core/window/rolling.py | 2 +- pandas/io/parsers/base_parser.py | 2 +- pandas/plotting/_matplotlib/core.py | 2 +- pandas/plotting/_matplotlib/hist.py | 2 +- 14 files changed, 23 insertions(+), 23 deletions(-) diff --git a/pandas/core/apply.py b/pandas/core/apply.py index 6265faade2281..8bc1392f3c850 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -1361,7 +1361,7 @@ def infer_to_same_shape(self, results: ResType, res_index: Index) -> DataFrame: result.index = res_index # infer dtypes - result = result.infer_objects(copy=False) + result = result.infer_objects() return result @@ -1873,7 +1873,7 @@ def relabel_result( # assign the new user-provided "named aggregation" as index names, and reindex # it based on the whole user-provided names. s.index = reordered_indexes[idx : idx + len(fun)] - reordered_result_in_dict[col] = s.reindex(columns, copy=False) + reordered_result_in_dict[col] = s.reindex(columns) idx = idx + len(fun) return reordered_result_in_dict diff --git a/pandas/core/computation/align.py b/pandas/core/computation/align.py index ea293538bae8f..a666e3e61d98a 100644 --- a/pandas/core/computation/align.py +++ b/pandas/core/computation/align.py @@ -134,7 +134,7 @@ def _align_core(terms): w, category=PerformanceWarning, stacklevel=find_stack_level() ) - obj = ti.reindex(reindexer, axis=axis, copy=False) + obj = ti.reindex(reindexer, axis=axis) terms[i].update(obj) terms[i].update(terms[i].value.values) diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index ca8bfcb0c81af..30559ae91ce41 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -1648,7 +1648,7 @@ def _wrap_applied_output( res_index = self._grouper.result_index result = self.obj._constructor(index=res_index, columns=data.columns) - result = result.astype(data.dtypes, copy=False) + result = result.astype(data.dtypes) return result # GH12824 @@ -1815,7 +1815,7 @@ def _transform_general(self, func, engine, engine_kwargs, *args, **kwargs): concat_index = obj.columns concatenated = concat(applied, axis=0, verify_integrity=False) - concatenated = concatenated.reindex(concat_index, axis=1, copy=False) + concatenated = concatenated.reindex(concat_index, axis=1) return self._set_result_index_ordered(concatenated) __examples_dataframe_doc = dedent( diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 2ac069deaad36..b1dfabcf0cb34 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -1241,7 +1241,7 @@ def _concat_objects( indexer, _ = result.index.get_indexer_non_unique(target) result = result.take(indexer, axis=0) else: - result = result.reindex(ax, axis=0, copy=False) + result = result.reindex(ax, axis=0) else: result = concat(values, axis=0) @@ -1269,18 +1269,18 @@ def _set_result_index_ordered( if self._grouper.is_monotonic and not self._grouper.has_dropped_na: # shortcut if we have an already ordered grouper - result = result.set_axis(index, axis=0, copy=False) + result = result.set_axis(index, axis=0) return result # row order is scrambled => sort the rows by position in original index original_positions = Index(self._grouper.result_ilocs) - result = result.set_axis(original_positions, axis=0, copy=False) + result = result.set_axis(original_positions, axis=0) result = result.sort_index(axis=0) if self._grouper.has_dropped_na: # Add back in any missing rows due to dropna - index here is integral # with values referring to the row of the input so can use RangeIndex result = result.reindex(RangeIndex(len(index)), axis=0) - result = result.set_axis(index, axis=0, copy=False) + result = result.set_axis(index, axis=0) return result @@ -1913,7 +1913,7 @@ def _wrap_transform_fast_result(self, result: NDFrameT) -> NDFrameT: # for each col, reshape to size of original frame by take operation ids = self._grouper.ids - result = result.reindex(self._grouper.result_index, axis=0, copy=False) + result = result.reindex(self._grouper.result_index, axis=0) if self.obj.ndim == 1: # i.e. SeriesGroupBy diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index b127f62faf827..7d31467c6f309 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -2280,7 +2280,7 @@ def _setitem_with_indexer_missing(self, indexer, value): has_dtype = hasattr(value, "dtype") if isinstance(value, ABCSeries): # append a Series - value = value.reindex(index=self.obj.columns, copy=True) + value = value.reindex(index=self.obj.columns) value.name = indexer elif isinstance(value, dict): value = Series( @@ -2310,7 +2310,7 @@ def _setitem_with_indexer_missing(self, indexer, value): if not has_dtype: # i.e. if we already had a Series or ndarray, keep that # dtype. But if we had a list or dict, then do inference - df = df.infer_objects(copy=False) + df = df.infer_objects() self.obj._mgr = df._mgr else: self.obj._mgr = self.obj._append(value)._mgr @@ -2383,7 +2383,8 @@ def ravel(i): # we have a frame, with multiple indexers on both axes; and a # series, so need to broadcast (see GH5206) if sum_aligners == self.ndim and all(is_sequence(_) for _ in indexer): - ser_values = ser.reindex(obj.axes[0][indexer[0]], copy=True)._values + # TODO(CoW): copy shouldn't be needed here + ser_values = ser.reindex(obj.axes[0][indexer[0]]).copy()._values # single indexer if len(indexer) > 1 and not multiindex_indexer: diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index ff5e8e35f92ab..047c25f4931a6 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -519,11 +519,11 @@ def _homogenize( for val in data: if isinstance(val, (ABCSeries, Index)): if dtype is not None: - val = val.astype(dtype, copy=False) + val = val.astype(dtype) if isinstance(val, ABCSeries) and val.index is not index: # Forces alignment. No need to copy data since we # are putting it into an ndarray later - val = val.reindex(index, copy=False) + val = val.reindex(index) refs.append(val._references) val = val._values else: diff --git a/pandas/core/methods/describe.py b/pandas/core/methods/describe.py index c620bb9d17976..337b2f7952213 100644 --- a/pandas/core/methods/describe.py +++ b/pandas/core/methods/describe.py @@ -173,7 +173,7 @@ def describe(self, percentiles: Sequence[float] | np.ndarray) -> DataFrame: col_names = reorder_columns(ldesc) d = concat( - [x.reindex(col_names, copy=False) for x in ldesc], + [x.reindex(col_names) for x in ldesc], axis=1, sort=False, ) diff --git a/pandas/core/reshape/encoding.py b/pandas/core/reshape/encoding.py index fae5c082c72a0..c7649f9eb8418 100644 --- a/pandas/core/reshape/encoding.py +++ b/pandas/core/reshape/encoding.py @@ -339,7 +339,7 @@ def get_empty_frame(data) -> DataFrame: ) sparse_series.append(Series(data=sarr, index=index, name=col, copy=False)) - return concat(sparse_series, axis=1, copy=False) + return concat(sparse_series, axis=1) else: # ensure ndarray layout is column-major diff --git a/pandas/core/strings/accessor.py b/pandas/core/strings/accessor.py index bd523969fba13..e12347f5689b7 100644 --- a/pandas/core/strings/accessor.py +++ b/pandas/core/strings/accessor.py @@ -661,7 +661,6 @@ def cat( join=(join if join == "inner" else "outer"), keys=range(len(others)), sort=False, - copy=False, ) data, others = data.align(others, join=join) others = [others[x] for x in others] # again list of Series diff --git a/pandas/core/window/ewm.py b/pandas/core/window/ewm.py index 01d1787d46ca0..9b21a23b1aefe 100644 --- a/pandas/core/window/ewm.py +++ b/pandas/core/window/ewm.py @@ -1072,7 +1072,7 @@ def mean(self, *args, update=None, update_times=None, **kwargs): result_kwargs["columns"] = self._selected_obj.columns else: result_kwargs["name"] = self._selected_obj.name - np_array = self._selected_obj.astype(np.float64, copy=False).to_numpy() + np_array = self._selected_obj.astype(np.float64).to_numpy() ewma_func = generate_online_numba_ewma_func( **get_jit_arguments(self.engine_kwargs) ) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index b0048d5024064..9e42a9033fb66 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -270,7 +270,7 @@ def _create_data(self, obj: NDFrameT, numeric_only: bool = False) -> NDFrameT: """ # filter out the on from the object if self.on is not None and not isinstance(self.on, Index) and obj.ndim == 2: - obj = obj.reindex(columns=obj.columns.difference([self.on]), copy=False) + obj = obj.reindex(columns=obj.columns.difference([self.on])) if obj.ndim > 1 and numeric_only: obj = self._make_numeric_only(obj) return obj diff --git a/pandas/io/parsers/base_parser.py b/pandas/io/parsers/base_parser.py index 3aef0692d5f59..6a3834be20d39 100644 --- a/pandas/io/parsers/base_parser.py +++ b/pandas/io/parsers/base_parser.py @@ -1354,7 +1354,7 @@ def _isindex(colspec): date_cols.update(old_names) if isinstance(data_dict, DataFrame): - data_dict = concat([DataFrame(new_data), data_dict], axis=1, copy=False) + data_dict = concat([DataFrame(new_data), data_dict], axis=1) else: data_dict.update(new_data) new_cols.extend(columns) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index be771a4029b4f..dbd2743345a38 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -678,7 +678,7 @@ def _compute_plot_data(self) -> None: # GH16953, infer_objects is needed as fallback, for ``Series`` # with ``dtype == object`` - data = data.infer_objects(copy=False) + data = data.infer_objects() include_type = [np.number, "datetime", "datetimetz", "timedelta"] # GH23719, allow plotting boolean diff --git a/pandas/plotting/_matplotlib/hist.py b/pandas/plotting/_matplotlib/hist.py index d521d91ab3b7b..d9d1df128d199 100644 --- a/pandas/plotting/_matplotlib/hist.py +++ b/pandas/plotting/_matplotlib/hist.py @@ -94,7 +94,7 @@ def _adjust_bins(self, bins: int | np.ndarray | list[np.ndarray]): def _calculate_bins(self, data: Series | DataFrame, bins) -> np.ndarray: """Calculate bins given data""" - nd_values = data.infer_objects(copy=False)._get_numeric_data() + nd_values = data.infer_objects()._get_numeric_data() values = np.ravel(nd_values) values = values[~isna(values)] From 138b85a3509d70bfa58853102708217179e64709 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sun, 11 Feb 2024 01:25:31 +0100 Subject: [PATCH 2/6] Cow: Deprecate copy keyword from first set of methods --- doc/source/whatsnew/v3.0.0.rst | 23 ++++++ pandas/core/frame.py | 3 +- pandas/core/generic.py | 79 +++++++++++++++---- pandas/core/series.py | 3 +- pandas/tests/copy_view/test_astype.py | 2 +- .../tests/copy_view/test_copy_deprecation.py | 53 +++++++++++++ pandas/tests/copy_view/test_methods.py | 28 +++---- pandas/tests/frame/indexing/test_where.py | 2 +- pandas/tests/frame/methods/test_align.py | 2 +- pandas/tests/frame/methods/test_astype.py | 10 +-- pandas/tests/frame/methods/test_describe.py | 4 +- pandas/tests/frame/methods/test_reindex.py | 35 +------- pandas/tests/frame/methods/test_tz_convert.py | 5 +- .../tests/frame/methods/test_tz_localize.py | 5 +- pandas/tests/indexing/test_loc.py | 2 +- pandas/tests/series/methods/test_align.py | 8 +- .../series/methods/test_infer_objects.py | 4 +- 17 files changed, 177 insertions(+), 91 deletions(-) create mode 100644 pandas/tests/copy_view/test_copy_deprecation.py diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 8b8f5bf3d028c..f4d9e5e1850e7 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -94,6 +94,29 @@ Other API changes Deprecations ~~~~~~~~~~~~ + +Copy keyword +^^^^^^^^^^^^ + +The ``copy`` keyword argument in the following methods is deprecated and +will be removed in a future version: + +- :meth:`DataFrame.truncate` / :meth:`Series.truncate` +- :meth:`DataFrame.tz_convert` / :meth:`Series.tz_convert` +- :meth:`DataFrame.tz_localize` / :meth:`Series.tz_localize` +- :meth:`DataFrame.infer_objects` / :meth:`Series.infer_objects` +- :meth:`DataFrame.align` / :meth:`Series.align` +- :meth:`DataFrame.astype` / :meth:`Series.astype` +- :meth:`DataFrame.reindex` / :meth:`Series.reindex` +- :meth:`DataFrame.reindex_like` / :meth:`Series.reindex_like` + +Copy-on-Write utilizes a lazy copy mechanism that defers copying the data until +necessary. Use ``.copy`` to trigger an eager copy. The copy keyword has no effect +starting with 3.0, so it can be safely removed from your code. + +Other Deprecations +^^^^^^^^^^^^^^^^^^ + - Deprecated :meth:`Timestamp.utcfromtimestamp`, use ``Timestamp.fromtimestamp(ts, "UTC")`` instead (:issue:`56680`) - Deprecated :meth:`Timestamp.utcnow`, use ``Timestamp.now("UTC")`` instead (:issue:`56680`) - diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 591c02933c4bc..f356f42be8154 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -5031,7 +5031,7 @@ def reindex( columns=None, axis: Axis | None = None, method: ReindexMethod | None = None, - copy: bool | None = None, + copy: bool | lib.NoDefault = lib.no_default, level: Level | None = None, fill_value: Scalar | None = np.nan, limit: int | None = None, @@ -5047,6 +5047,7 @@ def reindex( fill_value=fill_value, limit=limit, tolerance=tolerance, + copy=copy, ) @overload diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 8e0767d9b3699..7a14c82574196 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -4263,12 +4263,24 @@ def _is_view(self) -> bool: """Return boolean indicating if self is view of another array""" return self._mgr.is_view + @staticmethod + def _check_copy_deprecation(copy): + if copy is not lib.no_default: + warnings.warn( + "The copy keyword is deprecated and will be removed in a future " + "version. Copy-on-Write is active in pandas since 3.0 which utilizes " + "a lazy copy mechanism that defers copies until necessary. Use " + ".copy() to make an eager copy if necessary.", + DeprecationWarning, + stacklevel=find_stack_level(), + ) + @final def reindex_like( self, other, method: Literal["backfill", "bfill", "pad", "ffill", "nearest"] | None = None, - copy: bool | None = None, + copy: bool | lib.NoDefault = lib.no_default, limit: int | None = None, tolerance=None, ) -> Self: @@ -4296,7 +4308,7 @@ def reindex_like( * backfill / bfill: use next valid observation to fill gap * nearest: use nearest valid observations to fill gap. - copy : bool, default True + copy : bool, default False Return a new object, even if the passed indexes are the same. .. note:: @@ -4310,6 +4322,8 @@ def reindex_like( You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + + .. deprecated:: 3.0.0 limit : int, default None Maximum number of consecutive labels to fill for inexact matches. tolerance : optional @@ -4378,6 +4392,7 @@ def reindex_like( 2014-02-14 NaN NaN NaN 2014-02-15 35.1 NaN medium """ + self._check_copy_deprecation(copy) d = other._construct_axes_dict( axes=self._AXIS_ORDERS, method=method, @@ -5027,7 +5042,7 @@ def reindex( columns=None, axis: Axis | None = None, method: ReindexMethod | None = None, - copy: bool | None = None, + copy: bool | lib.NoDefault = lib.no_default, level: Level | None = None, fill_value: Scalar | None = np.nan, limit: int | None = None, @@ -5054,7 +5069,7 @@ def reindex( * backfill / bfill: Use next valid observation to fill gap. * nearest: Use nearest valid observations to fill gap. - copy : bool, default True + copy : bool, default False Return a new object, even if the passed indexes are the same. .. note:: @@ -5068,6 +5083,8 @@ def reindex( You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + + .. deprecated:: 3.0.0 level : int or name Broadcast across a level, matching Index values on the passed MultiIndex level. @@ -5245,6 +5262,7 @@ def reindex( """ # TODO: Decide if we care about having different examples for different # kinds + self._check_copy_deprecation(copy) if index is not None and columns is not None and labels is not None: raise TypeError("Cannot specify all of 'labels', 'index', 'columns'.") @@ -6151,7 +6169,10 @@ def dtypes(self): @final def astype( - self, dtype, copy: bool | None = None, errors: IgnoreRaise = "raise" + self, + dtype, + copy: bool | lib.NoDefault = lib.no_default, + errors: IgnoreRaise = "raise", ) -> Self: """ Cast a pandas object to a specified dtype ``dtype``. @@ -6164,7 +6185,7 @@ def astype( mapping, e.g. {col: dtype, ...}, where col is a column label and dtype is a numpy.dtype or Python type to cast one or more of the DataFrame's columns to column-specific types. - copy : bool, default True + copy : bool, default False Return a copy when ``copy=True`` (be very careful setting ``copy=False`` as changes to values then may propagate to other pandas objects). @@ -6180,6 +6201,8 @@ def astype( You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + + .. deprecated:: 3.0.0 errors : {'raise', 'ignore'}, default 'raise' Control raising of exceptions on invalid data for provided dtype. @@ -6269,6 +6292,7 @@ def astype( 2 2020-01-03 dtype: datetime64[ns] """ + self._check_copy_deprecation(copy) if is_dict_like(dtype): if self.ndim == 1: # i.e. Series if len(dtype) > 1 or self.name not in dtype: @@ -6496,7 +6520,7 @@ def __deepcopy__(self, memo=None) -> Self: return self.copy(deep=True) @final - def infer_objects(self, copy: bool | None = None) -> Self: + def infer_objects(self, copy: bool | lib.NoDefault = lib.no_default) -> Self: """ Attempt to infer better dtypes for object columns. @@ -6507,7 +6531,7 @@ def infer_objects(self, copy: bool | None = None) -> Self: Parameters ---------- - copy : bool, default True + copy : bool, default False Whether to make a copy for non-object or non-inferable columns or Series. @@ -6523,6 +6547,8 @@ def infer_objects(self, copy: bool | None = None) -> Self: You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + .. deprecated:: 3.0.0 + Returns ------- same type as input object @@ -6552,6 +6578,7 @@ def infer_objects(self, copy: bool | None = None) -> Self: A int64 dtype: object """ + self._check_copy_deprecation(copy) new_mgr = self._mgr.convert() res = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) return res.__finalize__(self, method="infer_objects") @@ -9599,7 +9626,7 @@ def align( join: AlignJoin = "outer", axis: Axis | None = None, level: Level | None = None, - copy: bool | None = None, + copy: bool | lib.NoDefault = lib.no_default, fill_value: Hashable | None = None, method: FillnaOptions | None | lib.NoDefault = lib.no_default, limit: int | None | lib.NoDefault = lib.no_default, @@ -9628,7 +9655,7 @@ def align( level : int or level name, default None Broadcast across a level, matching Index values on the passed MultiIndex level. - copy : bool, default True + copy : bool, default False Always returns new objects. If copy=False and no reindexing is required then original objects are returned. @@ -9643,6 +9670,8 @@ def align( You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + + .. deprecated:: 3.0.0 fill_value : scalar, default np.nan Value to use for missing values. Defaults to NaN, but can be any "compatible" value. @@ -9745,6 +9774,8 @@ def align( 3 60.0 70.0 80.0 90.0 NaN 4 600.0 700.0 800.0 900.0 NaN """ + self._check_copy_deprecation(copy) + if ( method is not lib.no_default or limit is not lib.no_default @@ -10638,7 +10669,7 @@ def truncate( before=None, after=None, axis: Axis | None = None, - copy: bool | None = None, + copy: bool | lib.NoDefault = lib.no_default, ) -> Self: """ Truncate a Series or DataFrame before and after some index value. @@ -10655,7 +10686,7 @@ def truncate( axis : {0 or 'index', 1 or 'columns'}, optional Axis to truncate. Truncates the index (rows) by default. For `Series` this parameter is unused and defaults to 0. - copy : bool, default is True, + copy : bool, default is False, Return a copy of the truncated section. .. note:: @@ -10670,6 +10701,8 @@ def truncate( You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + .. deprecated:: 3.0.0 + Returns ------- type of caller @@ -10775,6 +10808,8 @@ def truncate( 2016-01-10 23:59:58 1 2016-01-10 23:59:59 1 """ + self._check_copy_deprecation(copy) + if axis is None: axis = 0 axis = self._get_axis_number(axis) @@ -10813,7 +10848,11 @@ def truncate( @final @doc(klass=_shared_doc_kwargs["klass"]) def tz_convert( - self, tz, axis: Axis = 0, level=None, copy: bool | None = None + self, + tz, + axis: Axis = 0, + level=None, + copy: bool | lib.NoDefault = lib.no_default, ) -> Self: """ Convert tz-aware axis to target time zone. @@ -10828,7 +10867,7 @@ def tz_convert( level : int, str, default None If axis is a MultiIndex, convert a specific level. Otherwise must be None. - copy : bool, default True + copy : bool, default False Also make a copy of the underlying data. .. note:: @@ -10843,6 +10882,8 @@ def tz_convert( You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + .. deprecated:: 3.0.0 + Returns ------- {klass} @@ -10872,6 +10913,7 @@ def tz_convert( 2018-09-14 23:30:00 1 dtype: int64 """ + self._check_copy_deprecation(copy) axis = self._get_axis_number(axis) ax = self._get_axis(axis) @@ -10909,7 +10951,7 @@ def tz_localize( tz, axis: Axis = 0, level=None, - copy: bool | None = None, + copy: bool | lib.NoDefault = lib.no_default, ambiguous: TimeAmbiguous = "raise", nonexistent: TimeNonexistent = "raise", ) -> Self: @@ -10929,7 +10971,7 @@ def tz_localize( level : int, str, default None If axis ia a MultiIndex, localize a specific level. Otherwise must be None. - copy : bool, default True + copy : bool, default False Also make a copy of the underlying data. .. note:: @@ -10943,6 +10985,8 @@ def tz_localize( You can already get the future behavior and improvements through enabling copy on write ``pd.options.mode.copy_on_write = True`` + + .. deprecated:: 3.0.0 ambiguous : 'infer', bool, bool-ndarray, 'NaT', default 'raise' When clocks moved backward due to DST, ambiguous times may arise. For example in Central European Time (UTC+01), when going from @@ -11068,6 +11112,7 @@ def tz_localize( 2015-03-29 03:30:00+02:00 1 dtype: int64 """ + self._check_copy_deprecation(copy) nonexistent_options = ("raise", "NaT", "shift_forward", "shift_backward") if nonexistent not in nonexistent_options and not isinstance( nonexistent, dt.timedelta @@ -12009,7 +12054,7 @@ def _inplace_method(self, other, op) -> Self: # this makes sure that we are aligned like the input # we are updating inplace - self._update_inplace(result.reindex_like(self, copy=False)) + self._update_inplace(result.reindex_like(self)) return self @final diff --git a/pandas/core/series.py b/pandas/core/series.py index d5eaa2125b301..33efb26197dd4 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -4829,7 +4829,7 @@ def reindex( # type: ignore[override] *, axis: Axis | None = None, method: ReindexMethod | None = None, - copy: bool | None = None, + copy: bool | lib.NoDefault = lib.no_default, level: Level | None = None, fill_value: Scalar | None = None, limit: int | None = None, @@ -4842,6 +4842,7 @@ def reindex( # type: ignore[override] fill_value=fill_value, limit=limit, tolerance=tolerance, + copy=copy, ) @overload # type: ignore[override] diff --git a/pandas/tests/copy_view/test_astype.py b/pandas/tests/copy_view/test_astype.py index f280e2143fee0..62e8abdf8e5a7 100644 --- a/pandas/tests/copy_view/test_astype.py +++ b/pandas/tests/copy_view/test_astype.py @@ -147,7 +147,7 @@ def test_astype_string_read_only_on_pickle_roundrip(): base = Series(np.array([(1, 2), None, 1], dtype="object")) base_copy = pickle.loads(pickle.dumps(base)) base_copy._values.flags.writeable = False - base_copy.astype("string[pyarrow]", copy=False) + base_copy.astype("string[pyarrow]") tm.assert_series_equal(base, base_copy) diff --git a/pandas/tests/copy_view/test_copy_deprecation.py b/pandas/tests/copy_view/test_copy_deprecation.py new file mode 100644 index 0000000000000..ca57c02112131 --- /dev/null +++ b/pandas/tests/copy_view/test_copy_deprecation.py @@ -0,0 +1,53 @@ +import pytest + +import pandas as pd +import pandas._testing as tm + + +@pytest.mark.parametrize( + "meth, kwargs", + [ + ("truncate", {}), + ("tz_convert", {"tz": "UTC"}), + ("tz_localize", {"tz": "UTC"}), + ("infer_objects", {}), + ("astype", {"dtype": "float64"}), + ("reindex", {"index": [2, 0, 1]}), + ], +) +def test_copy_deprecation(meth, kwargs): + df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) + + if meth in ("tz_convert", "tz_localize"): + tz = None if meth == "tz_localize" else "US/Eastern" + df.index = pd.date_range("2020-01-01", freq="D", periods=len(df), tz=tz) + + with tm.assert_produces_warning(DeprecationWarning, match="copy"): + getattr(df, meth)(copy=False, **kwargs) + + with tm.assert_produces_warning(DeprecationWarning, match="copy"): + getattr(df.a, meth)(copy=False, **kwargs) + + +def test_copy_deprecation_reindex_like_align(): + df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) + # Somehow the stack level check is incorrect here + with tm.assert_produces_warning( + DeprecationWarning, match="copy", check_stacklevel=False + ): + df.reindex_like(df, copy=False) + + with tm.assert_produces_warning( + DeprecationWarning, match="copy", check_stacklevel=False + ): + df.a.reindex_like(df.a, copy=False) + + with tm.assert_produces_warning( + DeprecationWarning, match="copy", check_stacklevel=False + ): + df.align(df, copy=False) + + with tm.assert_produces_warning( + DeprecationWarning, match="copy", check_stacklevel=False + ): + df.a.align(df.a, copy=False) diff --git a/pandas/tests/copy_view/test_methods.py b/pandas/tests/copy_view/test_methods.py index 356b31a82f5ff..ae202f40aafaf 100644 --- a/pandas/tests/copy_view/test_methods.py +++ b/pandas/tests/copy_view/test_methods.py @@ -73,6 +73,7 @@ def test_copy_shallow(using_copy_on_write): assert np.shares_memory(get_array(df_copy, "a"), get_array(df, "a")) +@pytest.mark.filterwarnings("ignore", category=DeprecationWarning) @pytest.mark.parametrize("copy", [True, None, False]) @pytest.mark.parametrize( "method", @@ -148,6 +149,7 @@ def test_methods_copy_keyword(request, method, copy, using_copy_on_write): assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a")) +@pytest.mark.filterwarnings("ignore", category=DeprecationWarning) @pytest.mark.parametrize("copy", [True, None, False]) @pytest.mark.parametrize( "method", @@ -619,39 +621,37 @@ def test_align_series(using_copy_on_write): tm.assert_series_equal(ser_other, ser_orig) -def test_align_copy_false(using_copy_on_write): +def test_align_copy_false(): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) df_orig = df.copy() - df2, df3 = df.align(df, copy=False) + df2, df3 = df.align(df) assert np.shares_memory(get_array(df, "b"), get_array(df2, "b")) assert np.shares_memory(get_array(df, "a"), get_array(df2, "a")) - if using_copy_on_write: - df2.loc[0, "a"] = 0 - tm.assert_frame_equal(df, df_orig) # Original is unchanged + df2.loc[0, "a"] = 0 + tm.assert_frame_equal(df, df_orig) # Original is unchanged - df3.loc[0, "a"] = 0 - tm.assert_frame_equal(df, df_orig) # Original is unchanged + df3.loc[0, "a"] = 0 + tm.assert_frame_equal(df, df_orig) # Original is unchanged -def test_align_with_series_copy_false(using_copy_on_write): +def test_align_with_series_copy_false(): df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) ser = Series([1, 2, 3], name="x") ser_orig = ser.copy() df_orig = df.copy() - df2, ser2 = df.align(ser, copy=False, axis=0) + df2, ser2 = df.align(ser, axis=0) assert np.shares_memory(get_array(df, "b"), get_array(df2, "b")) assert np.shares_memory(get_array(df, "a"), get_array(df2, "a")) assert np.shares_memory(get_array(ser, "x"), get_array(ser2, "x")) - if using_copy_on_write: - df2.loc[0, "a"] = 0 - tm.assert_frame_equal(df, df_orig) # Original is unchanged + df2.loc[0, "a"] = 0 + tm.assert_frame_equal(df, df_orig) # Original is unchanged - ser2.loc[0] = 0 - tm.assert_series_equal(ser, ser_orig) # Original is unchanged + ser2.loc[0] = 0 + tm.assert_series_equal(ser, ser_orig) # Original is unchanged def test_to_frame(using_copy_on_write): diff --git a/pandas/tests/frame/indexing/test_where.py b/pandas/tests/frame/indexing/test_where.py index 954055acb6619..cd8ca4ee73092 100644 --- a/pandas/tests/frame/indexing/test_where.py +++ b/pandas/tests/frame/indexing/test_where.py @@ -177,7 +177,7 @@ def test_where_set(self, where_frame, float_string_frame, mixed_int_frame): def _check_set(df, cond, check_dtypes=True): dfi = df.copy() - econd = cond.reindex_like(df).fillna(True).infer_objects(copy=False) + econd = cond.reindex_like(df).fillna(True).infer_objects() expected = dfi.mask(~econd) return_value = dfi.where(cond, np.nan, inplace=True) diff --git a/pandas/tests/frame/methods/test_align.py b/pandas/tests/frame/methods/test_align.py index aa539dd0b2dbe..4229a2234f40d 100644 --- a/pandas/tests/frame/methods/test_align.py +++ b/pandas/tests/frame/methods/test_align.py @@ -52,7 +52,7 @@ def test_align_float(self, float_frame): af, bf = float_frame.align(float_frame) assert af._mgr is not float_frame._mgr - af, bf = float_frame.align(float_frame, copy=False) + af, bf = float_frame.align(float_frame) assert af._mgr is not float_frame._mgr # axis = 0 diff --git a/pandas/tests/frame/methods/test_astype.py b/pandas/tests/frame/methods/test_astype.py index 84e642f47417b..55f8052d05cf1 100644 --- a/pandas/tests/frame/methods/test_astype.py +++ b/pandas/tests/frame/methods/test_astype.py @@ -122,11 +122,11 @@ def test_astype_with_exclude_string(self, float_frame): def test_astype_with_view_float(self, float_frame): # this is the only real reason to do it this way tf = np.round(float_frame).astype(np.int32) - tf.astype(np.float32, copy=False) + tf.astype(np.float32) # TODO(wesm): verification? tf = float_frame.astype(np.float64) - tf.astype(np.int64, copy=False) + tf.astype(np.int64) def test_astype_with_view_mixed_float(self, mixed_float_frame): tf = mixed_float_frame.reindex(columns=["A", "B", "C"]) @@ -865,7 +865,7 @@ def construct_array_type(cls): def test_frame_astype_no_copy(): # GH 42501 df = DataFrame({"a": [1, 4, None, 5], "b": [6, 7, 8, 9]}, dtype=object) - result = df.astype({"a": Int16DtypeNoCopy()}, copy=False) + result = df.astype({"a": Int16DtypeNoCopy()}) assert result.a.dtype == pd.Int16Dtype() assert np.shares_memory(df.b.values, result.b.values) @@ -876,7 +876,7 @@ def test_astype_copies(dtype): # GH#50984 pytest.importorskip("pyarrow") df = DataFrame({"a": [1, 2, 3]}, dtype=dtype) - result = df.astype("int64[pyarrow]", copy=True) + result = df.astype("int64[pyarrow]") df.iloc[0, 0] = 100 expected = DataFrame({"a": [1, 2, 3]}, dtype="int64[pyarrow]") tm.assert_frame_equal(result, expected) @@ -888,5 +888,5 @@ def test_astype_to_string_not_modifying_input(string_storage, val): df = DataFrame({"a": ["a", "b", val]}) expected = df.copy() with option_context("mode.string_storage", string_storage): - df.astype("string", copy=False) + df.astype("string") tm.assert_frame_equal(df, expected) diff --git a/pandas/tests/frame/methods/test_describe.py b/pandas/tests/frame/methods/test_describe.py index 5beb09940acf3..e9206e86b7b08 100644 --- a/pandas/tests/frame/methods/test_describe.py +++ b/pandas/tests/frame/methods/test_describe.py @@ -318,9 +318,7 @@ def test_describe_tz_values2(self): "max", "std", ] - expected = pd.concat([s1_, s2_], axis=1, keys=["s1", "s2"]).reindex( - idx, copy=False - ) + expected = pd.concat([s1_, s2_], axis=1, keys=["s1", "s2"]).reindex(idx) result = df.describe(include="all") tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/frame/methods/test_reindex.py b/pandas/tests/frame/methods/test_reindex.py index 229ca6e6b683a..45109991c4553 100644 --- a/pandas/tests/frame/methods/test_reindex.py +++ b/pandas/tests/frame/methods/test_reindex.py @@ -159,37 +159,6 @@ def test_reindex_tzaware_fill_value(self): expected[1] = expected[1].astype(res.dtypes[1]) tm.assert_frame_equal(res, expected) - def test_reindex_copies(self): - # based on asv time_reindex_axis1 - N = 10 - df = DataFrame(np.random.default_rng(2).standard_normal((N * 10, N))) - cols = np.arange(N) - np.random.default_rng(2).shuffle(cols) - - result = df.reindex(columns=cols, copy=True) - assert not np.shares_memory(result[0]._values, df[0]._values) - - # pass both columns and index - result2 = df.reindex(columns=cols, index=df.index, copy=True) - assert not np.shares_memory(result2[0]._values, df[0]._values) - - def test_reindex_copies_ea(self): - # https://github.com/pandas-dev/pandas/pull/51197 - # also ensure to honor copy keyword for ExtensionDtypes - N = 10 - df = DataFrame( - np.random.default_rng(2).standard_normal((N * 10, N)), dtype="Float64" - ) - cols = np.arange(N) - np.random.default_rng(2).shuffle(cols) - - result = df.reindex(columns=cols, copy=True) - assert np.shares_memory(result[0].array._data, df[0].array._data) - - # pass both columns and index - result2 = df.reindex(columns=cols, index=df.index, copy=True) - assert np.shares_memory(result2[0].array._data, df[0].array._data) - def test_reindex_date_fill_value(self): # passing date to dt64 is deprecated; enforced in 2.0 to cast to object arr = date_range("2016-01-01", periods=6).values.reshape(3, 2) @@ -635,9 +604,7 @@ def test_reindex(self, float_frame): tm.assert_index_equal(series.index, nonContigFrame.index) # corner cases - - # Same index, copies values but not index if copy=False - newFrame = float_frame.reindex(float_frame.index, copy=False) + newFrame = float_frame.reindex(float_frame.index) assert newFrame.index.is_(float_frame.index) # length zero diff --git a/pandas/tests/frame/methods/test_tz_convert.py b/pandas/tests/frame/methods/test_tz_convert.py index 90bec4dfb5be6..e9209f218bca9 100644 --- a/pandas/tests/frame/methods/test_tz_convert.py +++ b/pandas/tests/frame/methods/test_tz_convert.py @@ -117,15 +117,14 @@ def test_tz_convert_and_localize_bad_input(self, fn): with pytest.raises(ValueError, match="not valid"): getattr(df, fn)("US/Pacific", level=1) - @pytest.mark.parametrize("copy", [True, False]) - def test_tz_convert_copy_inplace_mutate(self, copy, frame_or_series): + def test_tz_convert_copy_inplace_mutate(self, frame_or_series): # GH#6326 obj = frame_or_series( np.arange(0, 5), index=date_range("20131027", periods=5, freq="h", tz="Europe/Berlin"), ) orig = obj.copy() - result = obj.tz_convert("UTC", copy=copy) + result = obj.tz_convert("UTC") expected = frame_or_series(np.arange(0, 5), index=obj.index.tz_convert("UTC")) tm.assert_equal(result, expected) tm.assert_equal(obj, orig) diff --git a/pandas/tests/frame/methods/test_tz_localize.py b/pandas/tests/frame/methods/test_tz_localize.py index b167afc17f484..c0f5a90a9d2ee 100644 --- a/pandas/tests/frame/methods/test_tz_localize.py +++ b/pandas/tests/frame/methods/test_tz_localize.py @@ -50,14 +50,13 @@ def test_tz_localize_naive(self, frame_or_series): with pytest.raises(TypeError, match="Already tz-aware"): ts.tz_localize("US/Eastern") - @pytest.mark.parametrize("copy", [True, False]) - def test_tz_localize_copy_inplace_mutate(self, copy, frame_or_series): + def test_tz_localize_copy_inplace_mutate(self, frame_or_series): # GH#6326 obj = frame_or_series( np.arange(0, 5), index=date_range("20131027", periods=5, freq="1h", tz=None) ) orig = obj.copy() - result = obj.tz_localize("UTC", copy=copy) + result = obj.tz_localize("UTC") expected = frame_or_series( np.arange(0, 5), index=date_range("20131027", periods=5, freq="1h", tz="UTC"), diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index f263f92b4f0eb..7208c688bd217 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -666,7 +666,7 @@ def test_loc_setitem_consistency_slice_column_len(self): df.loc[:, ("Respondent", "EndDate")] = to_datetime( df.loc[:, ("Respondent", "EndDate")] ) - df = df.infer_objects(copy=False) + df = df.infer_objects() # Adding a new key df.loc[:, ("Respondent", "Duration")] = ( diff --git a/pandas/tests/series/methods/test_align.py b/pandas/tests/series/methods/test_align.py index df3dd6f4d8ab0..6495c2ce6ff67 100644 --- a/pandas/tests/series/methods/test_align.py +++ b/pandas/tests/series/methods/test_align.py @@ -100,7 +100,7 @@ def test_align_nocopy(datetime_series): # do not copy a = datetime_series.copy() - ra, _ = a.align(b, join="left", copy=False) + ra, _ = a.align(b, join="left") ra[:5] = 5 assert not (a[:5] == 5).any() @@ -114,17 +114,17 @@ def test_align_nocopy(datetime_series): # do not copy a = datetime_series.copy() b = datetime_series[:5].copy() - _, rb = a.align(b, join="right", copy=False) + _, rb = a.align(b, join="right") rb[:2] = 5 assert not (b[:2] == 5).any() def test_align_same_index(datetime_series): - a, b = datetime_series.align(datetime_series, copy=False) + a, b = datetime_series.align(datetime_series) assert a.index.is_(datetime_series.index) assert b.index.is_(datetime_series.index) - a, b = datetime_series.align(datetime_series, copy=True) + a, b = datetime_series.align(datetime_series) assert a.index is not datetime_series.index assert b.index is not datetime_series.index assert a.index.is_(datetime_series.index) diff --git a/pandas/tests/series/methods/test_infer_objects.py b/pandas/tests/series/methods/test_infer_objects.py index 29abac6b3780e..0d411e08a0107 100644 --- a/pandas/tests/series/methods/test_infer_objects.py +++ b/pandas/tests/series/methods/test_infer_objects.py @@ -13,12 +13,12 @@ def test_copy(self, index_or_series): # case where we don't need to do inference because it is already non-object obj = index_or_series(np.array([1, 2, 3], dtype="int64")) - result = obj.infer_objects(copy=False) + result = obj.infer_objects() assert tm.shares_memory(result, obj) # case where we try to do inference but can't do better than object obj2 = index_or_series(np.array(["foo", 2], dtype=object)) - result2 = obj2.infer_objects(copy=False) + result2 = obj2.infer_objects() assert tm.shares_memory(result2, obj2) def test_infer_objects_series(self, index_or_series): From 838e3c7445b3524484c565df5a18ac7e3918d2ca Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sun, 11 Feb 2024 01:42:13 +0100 Subject: [PATCH 3/6] Fixup --- pandas/core/reshape/encoding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/reshape/encoding.py b/pandas/core/reshape/encoding.py index c7649f9eb8418..a5e9b25dfd4c4 100644 --- a/pandas/core/reshape/encoding.py +++ b/pandas/core/reshape/encoding.py @@ -502,7 +502,7 @@ def from_dummies( # index data with a list of all columns that are dummies try: - data_to_decode = data.astype("boolean", copy=False) + data_to_decode = data.astype("boolean") except TypeError as err: raise TypeError("Passed DataFrame contains non-dummy data") from err From 2fd7e808faaaa52e9ab8bf585aec1ca6083501df Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sun, 11 Feb 2024 14:04:57 +0100 Subject: [PATCH 4/6] Update --- pandas/core/tools/datetimes.py | 2 +- pandas/io/pytables.py | 2 +- pandas/io/sql.py | 4 ++-- pandas/tests/arithmetic/test_timedelta64.py | 4 ++-- pandas/tests/generic/test_finalize.py | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 6c8c2c7e5009e..a982bd95cb017 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -1201,7 +1201,7 @@ def coerce(values): # prevent overflow in case of int8 or int16 if is_integer_dtype(values.dtype): - values = values.astype("int64", copy=False) + values = values.astype("int64") return values values = ( diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index 1e11a9783f0e1..45475ef55af09 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -3299,7 +3299,7 @@ def read( # with CoW, concat ignores the copy keyword. Here, we still want # to copy to enforce optimized column-major layout out = out.copy() - out = out.reindex(columns=items, copy=False) + out = out.reindex(columns=items) return out return DataFrame(columns=axes[0], index=axes[1]) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 08f99a4d3093a..e9745b0fe53cc 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -1325,12 +1325,12 @@ def _harmonize_columns( self.frame[col_name] = _handle_date_column(df_col, utc=utc) elif dtype_backend == "numpy" and col_type is float: # floats support NA, can always convert! - self.frame[col_name] = df_col.astype(col_type, copy=False) + self.frame[col_name] = df_col.astype(col_type) elif dtype_backend == "numpy" and len(df_col) == df_col.count(): # No NA values, can convert ints and bools if col_type is np.dtype("int64") or col_type is bool: - self.frame[col_name] = df_col.astype(col_type, copy=False) + self.frame[col_name] = df_col.astype(col_type) except KeyError: pass # this column not in results diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 3e9508bd2f504..d4f19cf3eeb33 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -1299,8 +1299,8 @@ def test_td64arr_add_sub_offset_index(self, names, box_with_array): ) tdi = tm.box_expected(tdi, box) - expected = tm.box_expected(expected, box).astype(object, copy=False) - expected_sub = tm.box_expected(expected_sub, box).astype(object, copy=False) + expected = tm.box_expected(expected, box).astype(object) + expected_sub = tm.box_expected(expected_sub, box).astype(object) with tm.assert_produces_warning(PerformanceWarning): res = tdi + other diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index 7cf5ccc4ed24f..fd815c85a89b3 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -492,9 +492,9 @@ def test_binops(request, args, annotate, all_binary_operators): ] if is_cmp and isinstance(left, pd.DataFrame) and isinstance(right, pd.Series): # in 2.0 silent alignment on comparisons was removed xref GH#28759 - left, right = left.align(right, axis=1, copy=False) + left, right = left.align(right, axis=1) elif is_cmp and isinstance(left, pd.Series) and isinstance(right, pd.DataFrame): - right, left = right.align(left, axis=1, copy=False) + right, left = right.align(left, axis=1) result = all_binary_operators(left, right) assert result.attrs == {"a": 1} From d7b15905f275f4ef8e2e6ed89c4a4b25e20345ea Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sun, 11 Feb 2024 14:49:04 +0100 Subject: [PATCH 5/6] Update --- pandas/tests/copy_view/test_methods.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/copy_view/test_methods.py b/pandas/tests/copy_view/test_methods.py index ae202f40aafaf..5de59e4d91ee0 100644 --- a/pandas/tests/copy_view/test_methods.py +++ b/pandas/tests/copy_view/test_methods.py @@ -73,7 +73,7 @@ def test_copy_shallow(using_copy_on_write): assert np.shares_memory(get_array(df_copy, "a"), get_array(df, "a")) -@pytest.mark.filterwarnings("ignore", category=DeprecationWarning) +@pytest.mark.filterwarnings("ignore:DeprecationWarning") @pytest.mark.parametrize("copy", [True, None, False]) @pytest.mark.parametrize( "method", @@ -149,7 +149,7 @@ def test_methods_copy_keyword(request, method, copy, using_copy_on_write): assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a")) -@pytest.mark.filterwarnings("ignore", category=DeprecationWarning) +@pytest.mark.filterwarnings("ignore:DeprecationWarning") @pytest.mark.parametrize("copy", [True, None, False]) @pytest.mark.parametrize( "method", From d39b66af9bb76464483a77a10e033bbabd9a96d3 Mon Sep 17 00:00:00 2001 From: Patrick Hoefler Date: Sun, 11 Feb 2024 14:50:09 +0100 Subject: [PATCH 6/6] Update --- pandas/tests/copy_view/test_methods.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/copy_view/test_methods.py b/pandas/tests/copy_view/test_methods.py index 5de59e4d91ee0..898472371735f 100644 --- a/pandas/tests/copy_view/test_methods.py +++ b/pandas/tests/copy_view/test_methods.py @@ -73,7 +73,7 @@ def test_copy_shallow(using_copy_on_write): assert np.shares_memory(get_array(df_copy, "a"), get_array(df, "a")) -@pytest.mark.filterwarnings("ignore:DeprecationWarning") +@pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("copy", [True, None, False]) @pytest.mark.parametrize( "method", @@ -149,7 +149,7 @@ def test_methods_copy_keyword(request, method, copy, using_copy_on_write): assert not np.shares_memory(get_array(df2, "a"), get_array(df, "a")) -@pytest.mark.filterwarnings("ignore:DeprecationWarning") +@pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("copy", [True, None, False]) @pytest.mark.parametrize( "method",